1/* 2 * Copyright (c) 2014 The WebM project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11#include <cstdio> 12#include <cstdlib> 13#include <string> 14#include "third_party/googletest/src/include/gtest/gtest.h" 15#include "./vpx_config.h" 16#include "test/codec_factory.h" 17#include "test/decode_test_driver.h" 18#include "test/ivf_video_source.h" 19#include "test/md5_helper.h" 20#include "test/util.h" 21#if CONFIG_WEBM_IO 22#include "test/webm_video_source.h" 23#endif 24#include "vpx_mem/vpx_mem.h" 25 26namespace { 27 28using std::string; 29 30#if CONFIG_WEBM_IO 31 32struct PauseFileList { 33 const char *name; 34 // md5 sum for decoded frames which does not include skipped frames. 35 const char *expected_md5; 36 const int pause_frame_num; 37}; 38 39// Decodes |filename| with |num_threads|. Pause at the specified frame_num, 40// seek to next key frame and then continue decoding until the end. Return 41// the md5 of the decoded frames which does not include skipped frames. 42string DecodeFileWithPause(const string &filename, int num_threads, 43 int pause_num) { 44 libvpx_test::WebMVideoSource video(filename); 45 video.Init(); 46 int in_frames = 0; 47 int out_frames = 0; 48 49 vpx_codec_dec_cfg_t cfg = {0}; 50 cfg.threads = num_threads; 51 vpx_codec_flags_t flags = 0; 52 flags |= VPX_CODEC_USE_FRAME_THREADING; 53 libvpx_test::VP9Decoder decoder(cfg, flags, 0); 54 55 libvpx_test::MD5 md5; 56 video.Begin(); 57 58 do { 59 ++in_frames; 60 const vpx_codec_err_t res = 61 decoder.DecodeFrame(video.cxdata(), video.frame_size()); 62 if (res != VPX_CODEC_OK) { 63 EXPECT_EQ(VPX_CODEC_OK, res) << decoder.DecodeError(); 64 break; 65 } 66 67 // Pause at specified frame number. 68 if (in_frames == pause_num) { 69 // Flush the decoder and then seek to next key frame. 70 decoder.DecodeFrame(NULL, 0); 71 video.SeekToNextKeyFrame(); 72 } else { 73 video.Next(); 74 } 75 76 // Flush the decoder at the end of the video. 77 if (!video.cxdata()) 78 decoder.DecodeFrame(NULL, 0); 79 80 libvpx_test::DxDataIterator dec_iter = decoder.GetDxData(); 81 const vpx_image_t *img; 82 83 // Get decompressed data 84 while ((img = dec_iter.Next())) { 85 ++out_frames; 86 md5.Add(img); 87 } 88 } while (video.cxdata() != NULL); 89 90 EXPECT_EQ(in_frames, out_frames) << 91 "Input frame count does not match output frame count"; 92 93 return string(md5.Get()); 94} 95 96void DecodeFilesWithPause(const PauseFileList files[]) { 97 for (const PauseFileList *iter = files; iter->name != NULL; ++iter) { 98 SCOPED_TRACE(iter->name); 99 for (int t = 2; t <= 8; ++t) { 100 EXPECT_EQ(iter->expected_md5, 101 DecodeFileWithPause(iter->name, t, iter->pause_frame_num)) 102 << "threads = " << t; 103 } 104 } 105} 106 107TEST(VP9MultiThreadedFrameParallel, PauseSeekResume) { 108 // vp90-2-07-frame_parallel-1.webm is a 40 frame video file with 109 // 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 "89772591e6ef461f9fa754f916c78ed8", 26 }, 117 { NULL, NULL, 0 }, 118 }; 119 DecodeFilesWithPause(files); 120} 121 122struct FileList { 123 const char *name; 124 // md5 sum for decoded frames which does not include corrupted frames. 125 const char *expected_md5; 126 // Expected number of decoded frames which does not include corrupted frames. 127 const int expected_frame_count; 128}; 129 130// Decodes |filename| with |num_threads|. Return the md5 of the decoded 131// frames which does not include corrupted frames. 132string DecodeFile(const string &filename, int num_threads, 133 int expected_frame_count) { 134 libvpx_test::WebMVideoSource video(filename); 135 video.Init(); 136 137 vpx_codec_dec_cfg_t cfg = vpx_codec_dec_cfg_t(); 138 cfg.threads = num_threads; 139 const vpx_codec_flags_t flags = VPX_CODEC_USE_FRAME_THREADING; 140 libvpx_test::VP9Decoder decoder(cfg, flags, 0); 141 142 libvpx_test::MD5 md5; 143 video.Begin(); 144 145 int out_frames = 0; 146 do { 147 const vpx_codec_err_t res = 148 decoder.DecodeFrame(video.cxdata(), video.frame_size()); 149 // TODO(hkuang): frame parallel mode should return an error on corruption. 150 if (res != VPX_CODEC_OK) { 151 EXPECT_EQ(VPX_CODEC_OK, res) << decoder.DecodeError(); 152 break; 153 } 154 155 video.Next(); 156 157 // Flush the decoder at the end of the video. 158 if (!video.cxdata()) 159 decoder.DecodeFrame(NULL, 0); 160 161 libvpx_test::DxDataIterator dec_iter = decoder.GetDxData(); 162 const vpx_image_t *img; 163 164 // Get decompressed data 165 while ((img = dec_iter.Next())) { 166 ++out_frames; 167 md5.Add(img); 168 } 169 } while (video.cxdata() != NULL); 170 171 EXPECT_EQ(expected_frame_count, out_frames) << 172 "Input frame count does not match expected output frame count"; 173 174 return string(md5.Get()); 175} 176 177void DecodeFiles(const FileList files[]) { 178 for (const FileList *iter = files; iter->name != NULL; ++iter) { 179 SCOPED_TRACE(iter->name); 180 for (int t = 2; t <= 8; ++t) { 181 EXPECT_EQ(iter->expected_md5, 182 DecodeFile(iter->name, t, iter->expected_frame_count)) 183 << "threads = " << t; 184 } 185 } 186} 187 188TEST(VP9MultiThreadedFrameParallel, InvalidFileTest) { 189 static const FileList files[] = { 190 // invalid-vp90-2-07-frame_parallel-1.webm is a 40 frame video file with 191 // one key frame for every ten frames. The 11th frame has corrupted data. 192 { "invalid-vp90-2-07-frame_parallel-1.webm", 193 "0549d0f45f60deaef8eb708e6c0eb6cb", 30 }, 194 // invalid-vp90-2-07-frame_parallel-2.webm is a 40 frame video file with 195 // one key frame for every ten frames. The 1st and 31st frames have 196 // corrupted data. 197 { "invalid-vp90-2-07-frame_parallel-2.webm", 198 "6a1f3cf6f9e7a364212fadb9580d525e", 20 }, 199 // invalid-vp90-2-07-frame_parallel-3.webm is a 40 frame video file with 200 // one key frame for every ten frames. The 5th and 13th frames have 201 // corrupted data. 202 { "invalid-vp90-2-07-frame_parallel-3.webm", 203 "8256544308de926b0681e04685b98677", 27 }, 204 { NULL, NULL, 0 }, 205 }; 206 DecodeFiles(files); 207} 208 209TEST(VP9MultiThreadedFrameParallel, ValidFileTest) { 210 static const FileList files[] = { 211#if CONFIG_VP9_HIGHBITDEPTH 212 { "vp92-2-20-10bit-yuv420.webm", 213 "a16b99df180c584e8db2ffeda987d293", 10 }, 214#endif 215 { NULL, NULL, 0 }, 216 }; 217 DecodeFiles(files); 218} 219#endif // CONFIG_WEBM_IO 220} // namespace 221