vp9_frame_parallel_test.cc 6.58 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
/*
 *  Copyright (c) 2014 The WebM project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include <cstdio>
#include <cstdlib>
#include <string>
#include "third_party/googletest/src/include/gtest/gtest.h"
#include "./vpx_config.h"
#include "test/codec_factory.h"
#include "test/decode_test_driver.h"
#include "test/ivf_video_source.h"
#include "test/md5_helper.h"
#include "test/util.h"
#if CONFIG_WEBM_IO
#include "test/webm_video_source.h"
#endif
#include "vpx_mem/vpx_mem.h"

namespace {

using std::string;

#if CONFIG_WEBM_IO

32
struct PauseFileList {
33 34 35 36 37 38 39 40 41
  const char *name;
  // md5 sum for decoded frames which does not include skipped frames.
  const char *expected_md5;
  const int pause_frame_num;
};

// Decodes |filename| with |num_threads|. Pause at the specified frame_num,
// seek to next key frame and then continue decoding until the end. Return
// the md5 of the decoded frames which does not include skipped frames.
42 43
string DecodeFileWithPause(const string &filename, int num_threads,
                           int pause_num) {
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
  libvpx_test::WebMVideoSource video(filename);
  video.Init();
  int in_frames = 0;
  int out_frames = 0;

  vpx_codec_dec_cfg_t cfg = {0};
  cfg.threads = num_threads;
  vpx_codec_flags_t flags = 0;
  flags |= VPX_CODEC_USE_FRAME_THREADING;
  libvpx_test::VP9Decoder decoder(cfg, flags, 0);

  libvpx_test::MD5 md5;
  video.Begin();

  do {
    ++in_frames;
    const vpx_codec_err_t res =
        decoder.DecodeFrame(video.cxdata(), video.frame_size());
    if (res != VPX_CODEC_OK) {
      EXPECT_EQ(VPX_CODEC_OK, res) << decoder.DecodeError();
      break;
    }

    // Pause at specified frame number.
    if (in_frames == pause_num) {
      // Flush the decoder and then seek to next key frame.
      decoder.DecodeFrame(NULL, 0);
      video.SeekToNextKeyFrame();
    } else {
      video.Next();
    }

    // Flush the decoder at the end of the video.
    if (!video.cxdata())
      decoder.DecodeFrame(NULL, 0);

    libvpx_test::DxDataIterator dec_iter = decoder.GetDxData();
    const vpx_image_t *img;

    // Get decompressed data
    while ((img = dec_iter.Next())) {
      ++out_frames;
      md5.Add(img);
    }
  } while (video.cxdata() != NULL);

  EXPECT_EQ(in_frames, out_frames) <<
      "Input frame count does not match output frame count";

  return string(md5.Get());
}

96 97
void DecodeFilesWithPause(const PauseFileList files[]) {
  for (const PauseFileList *iter = files; iter->name != NULL; ++iter) {
98 99 100
    SCOPED_TRACE(iter->name);
    for (int t = 2; t <= 8; ++t) {
      EXPECT_EQ(iter->expected_md5,
101
                DecodeFileWithPause(iter->name, t, iter->pause_frame_num))
102 103 104 105 106 107 108 109
          << "threads = " << t;
    }
  }
}

TEST(VP9MultiThreadedFrameParallel, PauseSeekResume) {
  // vp90-2-07-frame_parallel-1.webm is a 40 frame video file with
  // one key frame for every ten frames.
110
  static const PauseFileList files[] = {
111
    { "vp90-2-07-frame_parallel-1.webm",
112
      "6ea7c3875d67252e7caf2bc6e75b36b1", 6 },
113
    { "vp90-2-07-frame_parallel-1.webm",
114
      "4bb634160c7356a8d7d4299b6dc83a45", 12 },
115
    { "vp90-2-07-frame_parallel-1.webm",
116 117
      "89772591e6ef461f9fa754f916c78ed8", 26 },
    { NULL, NULL, 0 },
118
  };
119
  DecodeFilesWithPause(files);
120 121
}

122
struct FileList {
123 124 125 126 127 128 129 130 131
  const char *name;
  // md5 sum for decoded frames which does not include corrupted frames.
  const char *expected_md5;
  // Expected number of decoded frames which does not include corrupted frames.
  const int expected_frame_count;
};

// Decodes |filename| with |num_threads|. Return the md5 of the decoded
// frames which does not include corrupted frames.
132 133
string DecodeFile(const string &filename, int num_threads,
                  int expected_frame_count) {
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
  libvpx_test::WebMVideoSource video(filename);
  video.Init();

  vpx_codec_dec_cfg_t cfg = vpx_codec_dec_cfg_t();
  cfg.threads = num_threads;
  const vpx_codec_flags_t flags = VPX_CODEC_USE_FRAME_THREADING;
  libvpx_test::VP9Decoder decoder(cfg, flags, 0);

  libvpx_test::MD5 md5;
  video.Begin();

  int out_frames = 0;
  do {
    const vpx_codec_err_t res =
        decoder.DecodeFrame(video.cxdata(), video.frame_size());
    // TODO(hkuang): frame parallel mode should return an error on corruption.
    if (res != VPX_CODEC_OK) {
      EXPECT_EQ(VPX_CODEC_OK, res) << decoder.DecodeError();
      break;
    }

    video.Next();

    // Flush the decoder at the end of the video.
    if (!video.cxdata())
      decoder.DecodeFrame(NULL, 0);

    libvpx_test::DxDataIterator dec_iter = decoder.GetDxData();
    const vpx_image_t *img;

    // Get decompressed data
    while ((img = dec_iter.Next())) {
      ++out_frames;
      md5.Add(img);
    }
  } while (video.cxdata() != NULL);

  EXPECT_EQ(expected_frame_count, out_frames) <<
      "Input frame count does not match expected output frame count";

  return string(md5.Get());
}

177 178
void DecodeFiles(const FileList files[]) {
  for (const FileList *iter = files; iter->name != NULL; ++iter) {
179 180 181
    SCOPED_TRACE(iter->name);
    for (int t = 2; t <= 8; ++t) {
      EXPECT_EQ(iter->expected_md5,
182
                DecodeFile(iter->name, t, iter->expected_frame_count))
183 184 185 186 187
          << "threads = " << t;
    }
  }
}

188
TEST(VP9MultiThreadedFrameParallel, InvalidFileTest) {
189
  static const FileList files[] = {
190 191 192
    // invalid-vp90-2-07-frame_parallel-1.webm is a 40 frame video file with
    // one key frame for every ten frames. The 11th frame has corrupted data.
    { "invalid-vp90-2-07-frame_parallel-1.webm",
193
      "0549d0f45f60deaef8eb708e6c0eb6cb", 30 },
194 195 196 197
    // invalid-vp90-2-07-frame_parallel-2.webm is a 40 frame video file with
    // one key frame for every ten frames. The 1st and 31st frames have
    // corrupted data.
    { "invalid-vp90-2-07-frame_parallel-2.webm",
198
      "6a1f3cf6f9e7a364212fadb9580d525e", 20 },
199 200 201 202
    // invalid-vp90-2-07-frame_parallel-3.webm is a 40 frame video file with
    // one key frame for every ten frames. The 5th and 13th frames have
    // corrupted data.
    { "invalid-vp90-2-07-frame_parallel-3.webm",
203 204
      "8256544308de926b0681e04685b98677", 27 },
    { NULL, NULL, 0 },
205
  };
206
  DecodeFiles(files);
207 208
}

209 210 211 212 213 214 215 216 217 218
TEST(VP9MultiThreadedFrameParallel, ValidFileTest) {
  static const FileList files[] = {
#if CONFIG_VP9_HIGHBITDEPTH
    { "vp92-2-20-10bit-yuv420.webm",
      "a16b99df180c584e8db2ffeda987d293", 10 },
#endif
    { NULL, NULL, 0 },
  };
  DecodeFiles(files);
}
219 220
#endif  // CONFIG_WEBM_IO
}  // namespace