Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(253)

Side by Side Diff: media/mf/test/mft_h264_decoder_unittest.cc

Issue 3156046: Changed mft_h264_decoder's API to match with video_decode_engine.h. Also chan... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 10 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <d3d9.h>
6 #include <dxva2api.h>
7 #include <mfapi.h>
8
9 #include "base/file_path.h" 5 #include "base/file_path.h"
10 #include "base/file_util.h" 6 #include "base/file_util.h"
11 #include "base/message_loop.h" 7 #include "base/message_loop.h"
12 #include "base/path_service.h" 8 #include "base/path_service.h"
13 #include "base/scoped_comptr_win.h" 9 #include "base/ref_counted.h"
14 #include "base/scoped_ptr.h" 10 #include "base/scoped_ptr.h"
15 #include "base/string_util.h" 11 #include "base/string_util.h"
12 #include "base/time.h"
16 #include "media/base/data_buffer.h" 13 #include "media/base/data_buffer.h"
17 #include "media/base/video_frame.h" 14 #include "media/base/video_frame.h"
18 #include "media/mf/d3d_util.h" 15 #include "media/filters/video_decode_engine.h"
19 #include "media/mf/file_reader_util.h" 16 #include "media/mf/file_reader_util.h"
20 #include "media/mf/mft_h264_decoder.h" 17 #include "media/mf/mft_h264_decoder.h"
21 #include "testing/gtest/include/gtest/gtest.h" 18 #include "testing/gtest/include/gtest/gtest.h"
22 19
20 using base::TimeDelta;
21
23 namespace media { 22 namespace media {
24 23
25 static const int kDecoderMaxWidth = 1920; 24 static const int kDecoderMaxWidth = 1920;
26 static const int kDecoderMaxHeight = 1088; 25 static const int kDecoderMaxHeight = 1088;
27 26
28 class FakeMftReader { 27 class BaseMftReader : public base::RefCountedThreadSafe<BaseMftReader> {
28 public:
29 virtual ~BaseMftReader() {}
30 virtual void ReadCallback(scoped_refptr<DataBuffer>* input) = 0;
31 };
32
33 class FakeMftReader : public BaseMftReader {
29 public: 34 public:
30 FakeMftReader() : frames_remaining_(20) {} 35 FakeMftReader() : frames_remaining_(20) {}
31 explicit FakeMftReader(int count) : frames_remaining_(count) {} 36 explicit FakeMftReader(int count) : frames_remaining_(count) {}
32 ~FakeMftReader() {} 37 virtual ~FakeMftReader() {}
33 38
34 // Provides garbage input to the decoder. 39 // Provides garbage input to the decoder.
35 void ReadCallback(scoped_refptr<DataBuffer>* input) { 40 virtual void ReadCallback(scoped_refptr<DataBuffer>* input) {
36 if (frames_remaining_ > 0) { 41 if (frames_remaining_ > 0) {
37 int sz = 4096; 42 int sz = 4096;
38 uint8* buf = new uint8[sz]; 43 uint8* buf = new uint8[sz];
39 memset(buf, 42, sz); 44 memset(buf, 42, sz);
40 *input = new DataBuffer(buf, sz); 45 *input = new DataBuffer(buf, sz);
41 (*input)->SetDuration(base::TimeDelta::FromMicroseconds(5000)); 46 (*input)->SetDuration(base::TimeDelta::FromMicroseconds(5000));
42 (*input)->SetTimestamp( 47 (*input)->SetTimestamp(
43 base::TimeDelta::FromMicroseconds( 48 base::TimeDelta::FromMicroseconds(
44 50000000 - frames_remaining_ * 10000)); 49 50000000 - frames_remaining_ * 10000));
45 --frames_remaining_; 50 --frames_remaining_;
46 } else { 51 } else {
47 // Emulate end of stream on the last "frame". 52 // Emulate end of stream on the last "frame".
48 *input = new DataBuffer(0); 53 *input = new DataBuffer(0);
49 } 54 }
50 } 55 }
51 int frames_remaining() const { return frames_remaining_; } 56 int frames_remaining() const { return frames_remaining_; }
52 57
53 private: 58 private:
54 int frames_remaining_; 59 int frames_remaining_;
55 }; 60 };
56 61
57 class FakeMftRenderer : public base::RefCountedThreadSafe<FakeMftRenderer> { 62 class FFmpegFileReaderWrapper : public BaseMftReader {
58 public: 63 public:
59 explicit FakeMftRenderer(scoped_refptr<MftH264Decoder> decoder) 64 FFmpegFileReaderWrapper() {}
60 : decoder_(decoder), 65 virtual ~FFmpegFileReaderWrapper() {}
61 count_(0), 66 bool InitReader(const std::string& filename) {
62 flush_countdown_(0) { 67 reader_.reset(new FFmpegFileReader(filename));
68 if (!reader_.get() || !reader_->Initialize()) {
69 reader_.reset();
70 return false;
71 }
72 return true;
63 } 73 }
64 74 virtual void ReadCallback(scoped_refptr<DataBuffer>* input) {
65 virtual ~FakeMftRenderer() {} 75 if (reader_.get()) {
66 76 reader_->Read(input);
67 virtual void WriteCallback(scoped_refptr<VideoFrame> frame) {
68 static_cast<IMFMediaBuffer*>(frame->private_buffer())->Release();
69 ++count_;
70 if (flush_countdown_ > 0) {
71 if (--flush_countdown_ == 0) {
72 decoder_->Flush();
73 }
74 } 77 }
75 MessageLoop::current()->PostTask(
76 FROM_HERE,
77 NewRunnableMethod(decoder_.get(), &MftH264Decoder::GetOutput));
78 } 78 }
79 79 bool GetWidth(int* width) {
80 virtual void Start() { 80 if (!reader_.get())
81 MessageLoop::current()->PostTask( 81 return false;
82 FROM_HERE, 82 return reader_->GetWidth(width);
83 NewRunnableMethod(decoder_.get(), &MftH264Decoder::GetOutput));
84 } 83 }
85 84 bool GetHeight(int* height) {
86 virtual void OnDecodeError(MftH264Decoder::Error error) { 85 if (!reader_.get())
87 MessageLoop::current()->Quit(); 86 return false;
87 return reader_->GetHeight(height);
88 } 88 }
89 89 scoped_ptr<FFmpegFileReader> reader_;
90 virtual void SetFlushCountdown(int countdown) {
91 flush_countdown_ = countdown;
92 }
93
94 int count() const { return count_; }
95
96 protected:
97 scoped_refptr<MftH264Decoder> decoder_;
98 int count_;
99 int flush_countdown_;
100 }; 90 };
101 91
102 class MftH264DecoderTest : public testing::Test { 92 class MftH264DecoderTest : public testing::Test {
103 public: 93 public:
104 MftH264DecoderTest() {} 94 MftH264DecoderTest() {}
105 virtual ~MftH264DecoderTest() {} 95 virtual ~MftH264DecoderTest() {}
106 96
107 protected: 97 protected:
108 virtual void SetUp() {} 98 virtual void SetUp() {}
109 virtual void TearDown() {} 99 virtual void TearDown() {}
110 }; 100 };
111 101
102 class SimpleMftH264DecoderHandler : public VideoDecodeEngine::EventHandler {
103 public:
104 SimpleMftH264DecoderHandler()
105 : init_count_(0),
106 uninit_count_(0),
107 flush_count_(0),
108 format_change_count_(0),
109 empty_buffer_callback_count_(0),
110 fill_buffer_callback_count_(0) {
111 memset(&info_, 0, sizeof(info_));
112 }
113 virtual ~SimpleMftH264DecoderHandler() {}
114 virtual void OnInitializeComplete(const VideoCodecInfo& info) {
115 info_ = info;
116 init_count_++;
117 }
118 virtual void OnUninitializeComplete() {
119 uninit_count_++;
120 }
121 virtual void OnFlushComplete() {
122 flush_count_++;
123 }
124 virtual void OnSeekComplete() {}
125 virtual void OnError() {}
126 virtual void OnFormatChange(VideoStreamInfo stream_info) {
127 format_change_count_++;
128 info_.stream_info_ = stream_info;
129 }
130 virtual void OnEmptyBufferCallback(scoped_refptr<Buffer> buffer) {
131 if (reader_.get() && decoder_.get()) {
132 empty_buffer_callback_count_++;
133 scoped_refptr<DataBuffer> input;
134 reader_->ReadCallback(&input);
135 decoder_->EmptyThisBuffer(input);
136 }
137 }
138 virtual void OnFillBufferCallback(scoped_refptr<VideoFrame> frame) {
139 fill_buffer_callback_count_++;
140 current_frame_ = frame;
141 }
142 void SetReader(scoped_refptr<BaseMftReader> reader) {
143 reader_ = reader;
144 }
145 void SetDecoder(scoped_refptr<MftH264Decoder> decoder) {
146 decoder_ = decoder;
147 }
148
149 int init_count_;
150 int uninit_count_;
151 int flush_count_;
152 int format_change_count_;
153 int empty_buffer_callback_count_;
154 int fill_buffer_callback_count_;
155 VideoCodecInfo info_;
156 scoped_refptr<BaseMftReader> reader_;
157 scoped_refptr<MftH264Decoder> decoder_;
158 scoped_refptr<VideoFrame> current_frame_;
159 };
160
112 // A simple test case for init/deinit of MF/COM libraries. 161 // A simple test case for init/deinit of MF/COM libraries.
113 TEST_F(MftH264DecoderTest, SimpleInit) { 162 TEST_F(MftH264DecoderTest, LibraryInit) {
114 EXPECT_HRESULT_SUCCEEDED( 163 EXPECT_TRUE(MftH264Decoder::StartupComLibraries());
115 CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE)); 164 MftH264Decoder::ShutdownComLibraries();
116 EXPECT_HRESULT_SUCCEEDED(MFStartup(MF_VERSION, MFSTARTUP_FULL)); 165 }
117 EXPECT_HRESULT_SUCCEEDED(MFShutdown()); 166
118 CoUninitialize(); 167 TEST_F(MftH264DecoderTest, DecoderUninitializedAtFirst) {
119 }
120
121 TEST_F(MftH264DecoderTest, InitWithDxvaButNoD3dDevice) {
122 scoped_refptr<MftH264Decoder> decoder(new MftH264Decoder(true)); 168 scoped_refptr<MftH264Decoder> decoder(new MftH264Decoder(true));
123 ASSERT_TRUE(decoder.get() != NULL); 169 ASSERT_TRUE(decoder.get());
124 FakeMftReader reader; 170 EXPECT_EQ(MftH264Decoder::kUninitialized, decoder->state());
125 scoped_refptr<FakeMftRenderer> renderer(new FakeMftRenderer(decoder)); 171 }
126 EXPECT_FALSE( 172
127 decoder->Init(NULL, 6, 7, 111, 222, 3, 1, 173 TEST_F(MftH264DecoderTest, DecoderInitMissingArgs) {
128 NewCallback(&reader, &FakeMftReader::ReadCallback), 174 VideoCodecConfig config;
129 NewCallback(renderer.get(), 175 config.width_ = 800;
130 &FakeMftRenderer::WriteCallback), 176 config.height_ = 600;
131 NewCallback(renderer.get(), 177 scoped_refptr<MftH264Decoder> decoder(new MftH264Decoder(false));
132 &FakeMftRenderer::OnDecodeError))); 178 ASSERT_TRUE(decoder.get());
133 } 179 decoder->Initialize(NULL, NULL, config);
134 180 EXPECT_EQ(MftH264Decoder::kUninitialized, decoder->state());
135 TEST_F(MftH264DecoderTest, InitMissingCallbacks) { 181 }
136 scoped_refptr<MftH264Decoder> decoder(new MftH264Decoder(false)); 182
137 ASSERT_TRUE(decoder.get() != NULL); 183 TEST_F(MftH264DecoderTest, DecoderInitNoDxva) {
138 EXPECT_FALSE(decoder->Init(NULL, 1, 3, 111, 222, 56, 34, NULL, NULL, NULL)); 184 MessageLoop loop;
185 SimpleMftH264DecoderHandler handler;
186 VideoCodecConfig config;
187 config.width_ = 800;
188 config.height_ = 600;
189 scoped_refptr<MftH264Decoder> decoder(new MftH264Decoder(false));
190 ASSERT_TRUE(decoder.get());
191 decoder->Initialize(&loop, &handler, config);
192 EXPECT_EQ(1, handler.init_count_);
193 EXPECT_EQ(MftH264Decoder::kNormal, decoder->state());
194 decoder->Uninitialize();
195 }
196
197 TEST_F(MftH264DecoderTest, DecoderInitDxva) {
198 MessageLoop loop;
199 SimpleMftH264DecoderHandler handler;
200 VideoCodecConfig config;
201 config.width_ = 800;
202 config.height_ = 600;
203 scoped_refptr<MftH264Decoder> decoder(new MftH264Decoder(true));
204 ASSERT_TRUE(decoder.get());
205 decoder->Initialize(&loop, &handler, config);
206 EXPECT_EQ(1, handler.init_count_);
207 EXPECT_EQ(MftH264Decoder::kNormal, decoder->state());
208 decoder->Uninitialize();
209 }
210
211 TEST_F(MftH264DecoderTest, DecoderUninit) {
212 MessageLoop loop;
213 SimpleMftH264DecoderHandler handler;
214 VideoCodecConfig config;
215 config.width_ = 800;
216 config.height_ = 600;
217 scoped_refptr<MftH264Decoder> decoder(new MftH264Decoder(false));
218 ASSERT_TRUE(decoder.get());
219 decoder->Initialize(&loop, &handler, config);
220 EXPECT_EQ(MftH264Decoder::kNormal, decoder->state());
221 decoder->Uninitialize();
222 EXPECT_EQ(1, handler.uninit_count_);
223 EXPECT_EQ(MftH264Decoder::kUninitialized, decoder->state());
224 }
225
226 TEST_F(MftH264DecoderTest, UninitBeforeInit) {
227 MessageLoop loop;
228 SimpleMftH264DecoderHandler handler;
229 VideoCodecConfig config;
230 config.width_ = 800;
231 config.height_ = 600;
232 scoped_refptr<MftH264Decoder> decoder(new MftH264Decoder(false));
233 ASSERT_TRUE(decoder.get());
234 decoder->Uninitialize();
235 EXPECT_EQ(0, handler.uninit_count_);
139 } 236 }
140 237
141 TEST_F(MftH264DecoderTest, InitWithNegativeDimensions) { 238 TEST_F(MftH264DecoderTest, InitWithNegativeDimensions) {
142 scoped_refptr<MftH264Decoder> decoder(new MftH264Decoder(false)); 239 MessageLoop loop;
143 ASSERT_TRUE(decoder.get() != NULL); 240 SimpleMftH264DecoderHandler handler;
144 FakeMftReader reader; 241 VideoCodecConfig config;
145 scoped_refptr<FakeMftRenderer> renderer(new FakeMftRenderer(decoder)); 242 config.width_ = -123;
146 EXPECT_TRUE(decoder->Init(NULL, 0, 6, -123, -456, 22, 4787, 243 config.height_ = -456;
147 NewCallback(&reader, &FakeMftReader::ReadCallback), 244 scoped_refptr<MftH264Decoder> decoder(new MftH264Decoder(false));
148 NewCallback(renderer.get(), 245 ASSERT_TRUE(decoder.get());
149 &FakeMftRenderer::WriteCallback), 246 decoder->Initialize(&loop, &handler, config);
150 NewCallback(renderer.get(), 247 EXPECT_EQ(MftH264Decoder::kNormal, decoder->state());
151 &FakeMftRenderer::OnDecodeError))); 248 EXPECT_EQ(kDecoderMaxWidth, handler.info_.stream_info_.surface_width_);
152 249 EXPECT_EQ(kDecoderMaxHeight, handler.info_.stream_info_.surface_height_);
153 // By default, decoder should "guess" the dimensions to be the maximum. 250 decoder->Uninitialize();
154 EXPECT_EQ(kDecoderMaxWidth, decoder->width());
155 EXPECT_EQ(kDecoderMaxHeight, decoder->height());
156 } 251 }
157 252
158 TEST_F(MftH264DecoderTest, InitWithTooHighDimensions) { 253 TEST_F(MftH264DecoderTest, InitWithTooHighDimensions) {
159 scoped_refptr<MftH264Decoder> decoder(new MftH264Decoder(false)); 254 MessageLoop loop;
160 ASSERT_TRUE(decoder.get() != NULL); 255 SimpleMftH264DecoderHandler handler;
161 FakeMftReader reader; 256 VideoCodecConfig config;
162 scoped_refptr<FakeMftRenderer> renderer(new FakeMftRenderer(decoder)); 257 config.width_ = kDecoderMaxWidth + 1;
163 EXPECT_TRUE(decoder->Init(NULL, 0, 0, 258 config.height_ = kDecoderMaxHeight + 1;
164 kDecoderMaxWidth + 1, kDecoderMaxHeight + 1, 259 scoped_refptr<MftH264Decoder> decoder(new MftH264Decoder(false));
165 0, 0, 260 ASSERT_TRUE(decoder.get());
166 NewCallback(&reader, &FakeMftReader::ReadCallback), 261 decoder->Initialize(&loop, &handler, config);
167 NewCallback(renderer.get(), 262 EXPECT_EQ(MftH264Decoder::kNormal, decoder->state());
168 &FakeMftRenderer::WriteCallback), 263 EXPECT_EQ(kDecoderMaxWidth, handler.info_.stream_info_.surface_width_);
169 NewCallback(renderer.get(), 264 EXPECT_EQ(kDecoderMaxHeight, handler.info_.stream_info_.surface_height_);
170 &FakeMftRenderer::OnDecodeError))); 265 decoder->Uninitialize();
171 266 }
172 // Decoder should truncate the dimensions to the maximum supported. 267
173 EXPECT_EQ(kDecoderMaxWidth, decoder->width()); 268 TEST_F(MftH264DecoderTest, DrainOnEmptyBuffer) {
174 EXPECT_EQ(kDecoderMaxHeight, decoder->height()); 269 MessageLoop loop;
175 } 270 SimpleMftH264DecoderHandler handler;
176 271 VideoCodecConfig config;
177 TEST_F(MftH264DecoderTest, InitWithNormalDimensions) { 272 config.width_ = 1024;
178 scoped_refptr<MftH264Decoder> decoder(new MftH264Decoder(false)); 273 config.height_ = 768;
179 ASSERT_TRUE(decoder.get() != NULL); 274 scoped_refptr<MftH264Decoder> decoder(new MftH264Decoder(false));
180 FakeMftReader reader; 275 ASSERT_TRUE(decoder.get());
181 scoped_refptr<FakeMftRenderer> renderer(new FakeMftRenderer(decoder)); 276 decoder->Initialize(&loop, &handler, config);
182 int width = 1024, height = 768; 277 EXPECT_EQ(MftH264Decoder::kNormal, decoder->state());
183 EXPECT_TRUE(decoder->Init(NULL, 0, 0, width, height, 0, 0, 278 scoped_refptr<Buffer> buffer(new DataBuffer(0));
184 NewCallback(&reader, &FakeMftReader::ReadCallback), 279
185 NewCallback(renderer.get(), 280 // Decoder should switch to drain mode because of this NULL buffer, and then
186 &FakeMftRenderer::WriteCallback), 281 // switch to kStopped when it says it needs more input during drain mode.
187 NewCallback(renderer.get(), 282 decoder->EmptyThisBuffer(buffer);
188 &FakeMftRenderer::OnDecodeError))); 283 EXPECT_EQ(MftH264Decoder::kStopped, decoder->state());
189 284
190 EXPECT_EQ(width, decoder->width()); 285 // Should have called back with one empty frame.
191 EXPECT_EQ(height, decoder->height()); 286 EXPECT_EQ(1, handler.fill_buffer_callback_count_);
192 } 287 ASSERT_TRUE(handler.current_frame_.get());
193 288 EXPECT_EQ(VideoFrame::EMPTY, handler.current_frame_->format());
194 // SendDrainMessage() is not a public method. Nonetheless it does not hurt 289 decoder->Uninitialize();
195 // to test that the decoder should not do things before it is initialized. 290 }
196 TEST_F(MftH264DecoderTest, SendDrainMessageBeforeInitDeathTest) { 291
197 scoped_refptr<MftH264Decoder> decoder(new MftH264Decoder(false));
198 ASSERT_TRUE(decoder.get() != NULL);
199 EXPECT_DEATH({ decoder->SendDrainMessage(); }, ".*initialized_.*");
200 }
201
202 // Tests draining after init, but before any input is sent.
203 TEST_F(MftH264DecoderTest, SendDrainMessageAtInit) {
204 scoped_refptr<MftH264Decoder> decoder(new MftH264Decoder(false));
205 ASSERT_TRUE(decoder.get() != NULL);
206 FakeMftReader reader;
207 scoped_refptr<FakeMftRenderer> renderer(new FakeMftRenderer(decoder));
208 ASSERT_TRUE(decoder->Init(NULL, 0, 0, 111, 222, 0, 0,
209 NewCallback(&reader, &FakeMftReader::ReadCallback),
210 NewCallback(renderer.get(),
211 &FakeMftRenderer::WriteCallback),
212 NewCallback(renderer.get(),
213 &FakeMftRenderer::OnDecodeError)));
214 EXPECT_TRUE(decoder->SendDrainMessage());
215 EXPECT_TRUE(decoder->drain_message_sent_);
216 }
217
218 TEST_F(MftH264DecoderTest, DrainOnEndOfInputStream) {
219 MessageLoop loop;
220 scoped_refptr<MftH264Decoder> decoder(new MftH264Decoder(false));
221 ASSERT_TRUE(decoder.get() != NULL);
222
223 // No frames, outputs a NULL indicating end-of-stream
224 FakeMftReader reader(0);
225 scoped_refptr<FakeMftRenderer> renderer(new FakeMftRenderer(decoder));
226 ASSERT_TRUE(decoder->Init(NULL, 0, 0, 111, 222, 0, 0,
227 NewCallback(&reader, &FakeMftReader::ReadCallback),
228 NewCallback(renderer.get(),
229 &FakeMftRenderer::WriteCallback),
230 NewCallback(renderer.get(),
231 &FakeMftRenderer::OnDecodeError)));
232 MessageLoop::current()->PostTask(
233 FROM_HERE,
234 NewRunnableMethod(renderer.get(), &FakeMftRenderer::Start));
235 MessageLoop::current()->Run();
236 EXPECT_TRUE(decoder->drain_message_sent());
237 }
238
239 // 100 input garbage samples should be enough to test whether the decoder
240 // will output decoded garbage frames.
241 TEST_F(MftH264DecoderTest, NoOutputOnGarbageInput) { 292 TEST_F(MftH264DecoderTest, NoOutputOnGarbageInput) {
242 MessageLoop loop; 293 // 100 samples of garbage.
243 scoped_refptr<MftH264Decoder> decoder(new MftH264Decoder(false)); 294 const int kNumFrames = 100;
244 ASSERT_TRUE(decoder.get() != NULL); 295 scoped_refptr<FakeMftReader> reader(new FakeMftReader(kNumFrames));
245 int num_frames = 100; 296 ASSERT_TRUE(reader.get());
246 FakeMftReader reader(num_frames); 297
247 scoped_refptr<FakeMftRenderer> renderer(new FakeMftRenderer(decoder)); 298 MessageLoop loop;
248 ASSERT_TRUE(decoder->Init(NULL, 0, 0, 111, 222, 0, 0, 299 SimpleMftH264DecoderHandler handler;
249 NewCallback(&reader, &FakeMftReader::ReadCallback), 300 VideoCodecConfig config;
250 NewCallback(renderer.get(), 301 config.width_ = 1024;
251 &FakeMftRenderer::WriteCallback), 302 config.height_ = 768;
252 NewCallback(renderer.get(), 303 scoped_refptr<MftH264Decoder> decoder(new MftH264Decoder(false));
253 &FakeMftRenderer::OnDecodeError))); 304 ASSERT_TRUE(decoder.get());
254 MessageLoop::current()->PostTask( 305 decoder->Initialize(&loop, &handler, config);
255 FROM_HERE, NewRunnableMethod(renderer.get(), &FakeMftRenderer::Start)); 306 EXPECT_EQ(MftH264Decoder::kNormal, decoder->state());
256 MessageLoop::current()->Run(); 307 handler.SetReader(reader);
257 308 handler.SetDecoder(decoder);
258 // Decoder should accept corrupt input data and silently ignore it. 309 while (MftH264Decoder::kStopped != decoder->state()) {
259 EXPECT_EQ(num_frames, decoder->frames_read()); 310 scoped_refptr<VideoFrame> frame;
260 311 decoder->FillThisBuffer(frame);
261 // Decoder should not have output anything if input is corrupt. 312 }
262 EXPECT_EQ(0, decoder->frames_decoded()); 313
263 EXPECT_EQ(0, renderer->count()); 314 // Output callback should only be invoked once - the empty frame to indicate
315 // end of stream.
316 EXPECT_EQ(1, handler.fill_buffer_callback_count_);
317 ASSERT_TRUE(handler.current_frame_.get());
318 EXPECT_EQ(VideoFrame::EMPTY, handler.current_frame_->format());
319
320 // One extra count because of the end of stream NULL sample.
321 EXPECT_EQ(kNumFrames, handler.empty_buffer_callback_count_ - 1);
322 decoder->Uninitialize();
323 }
324
325 TEST_F(MftH264DecoderTest, FlushAtStart) {
326 MessageLoop loop;
327 SimpleMftH264DecoderHandler handler;
328 VideoCodecConfig config;
329 config.width_ = 1024;
330 config.height_ = 768;
331 scoped_refptr<MftH264Decoder> decoder(new MftH264Decoder(false));
332 ASSERT_TRUE(decoder.get());
333 decoder->Initialize(&loop, &handler, config);
334 EXPECT_EQ(MftH264Decoder::kNormal, decoder->state());
335 decoder->Flush();
336
337 // Flush should succeed even if input/output are empty.
338 EXPECT_EQ(1, handler.flush_count_);
339 decoder->Uninitialize();
340 }
341
342 TEST_F(MftH264DecoderTest, NoFlushAtStopped) {
343 scoped_refptr<BaseMftReader> reader(new FakeMftReader());
344 ASSERT_TRUE(reader.get());
345
346 MessageLoop loop;
347 SimpleMftH264DecoderHandler handler;
348 VideoCodecConfig config;
349 config.width_ = 1024;
350 config.height_ = 768;
351 scoped_refptr<MftH264Decoder> decoder(new MftH264Decoder(false));
352 ASSERT_TRUE(decoder.get());
353 decoder->Initialize(&loop, &handler, config);
354 EXPECT_EQ(MftH264Decoder::kNormal, decoder->state());
355 handler.SetReader(reader);
356 handler.SetDecoder(decoder);
357 while (MftH264Decoder::kStopped != decoder->state()) {
358 scoped_refptr<VideoFrame> frame;
359 decoder->FillThisBuffer(frame);
360 }
361 EXPECT_EQ(0, handler.flush_count_);
362 int old_flush_count = handler.flush_count_;
363 decoder->Flush();
364 EXPECT_EQ(old_flush_count, handler.flush_count_);
365 decoder->Uninitialize();
264 } 366 }
265 367
266 FilePath GetVideoFilePath(const std::string& file_name) { 368 FilePath GetVideoFilePath(const std::string& file_name) {
267 FilePath path; 369 FilePath path;
268 PathService::Get(base::DIR_SOURCE_ROOT, &path); 370 PathService::Get(base::DIR_SOURCE_ROOT, &path);
269 path = path.AppendASCII("media") 371 path = path.AppendASCII("media")
270 .AppendASCII("test") 372 .AppendASCII("test")
271 .AppendASCII("data") 373 .AppendASCII("data")
272 .AppendASCII(file_name.c_str()); 374 .AppendASCII(file_name.c_str());
273 return path; 375 return path;
274 } 376 }
275 377
276 // Decodes media/test/data/bear.1280x720.mp4 which is expected to be a valid 378 void DecodeValidVideo(const std::string& filename, int num_frames, bool dxva) {
277 // H.264 video. 379 scoped_refptr<FFmpegFileReaderWrapper> reader(new FFmpegFileReaderWrapper());
278 TEST_F(MftH264DecoderTest, DecodeValidVideoDxva) { 380 ASSERT_TRUE(reader.get());
381 FilePath path = GetVideoFilePath(filename);
382 ASSERT_TRUE(file_util::PathExists(path));
383 ASSERT_TRUE(reader->InitReader(WideToASCII(path.value())));
384 int actual_width;
385 int actual_height;
386 ASSERT_TRUE(reader->GetWidth(&actual_width));
387 ASSERT_TRUE(reader->GetHeight(&actual_height));
388
279 MessageLoop loop; 389 MessageLoop loop;
280 FilePath path = GetVideoFilePath("bear.1280x720.mp4"); 390 SimpleMftH264DecoderHandler handler;
281 ASSERT_TRUE(file_util::PathExists(path)); 391 VideoCodecConfig config;
392 config.width_ = 1;
393 config.height_ = 1;
394 scoped_refptr<MftH264Decoder> decoder(new MftH264Decoder(dxva));
395 ASSERT_TRUE(decoder.get());
396 decoder->Initialize(&loop, &handler, config);
397 EXPECT_EQ(MftH264Decoder::kNormal, decoder->state());
398 handler.SetReader(reader);
399 handler.SetDecoder(decoder);
400 while (MftH264Decoder::kStopped != decoder->state()) {
401 scoped_refptr<VideoFrame> frame;
402 decoder->FillThisBuffer(frame);
403 }
282 404
283 ScopedComPtr<IDirect3D9> d3d9; 405 // We expect a format change when decoder receives enough data to determine
284 ScopedComPtr<IDirect3DDevice9> device; 406 // the actual frame width/height.
285 ScopedComPtr<IDirect3DDeviceManager9> dev_manager; 407 EXPECT_GT(handler.format_change_count_, 0);
286 dev_manager.Attach(CreateD3DDevManager(GetDesktopWindow(), 408 EXPECT_EQ(actual_width, handler.info_.stream_info_.surface_width_);
287 d3d9.Receive(), 409 EXPECT_EQ(actual_height, handler.info_.stream_info_.surface_height_);
288 device.Receive())); 410 EXPECT_GE(handler.empty_buffer_callback_count_, num_frames);
289 ASSERT_TRUE(dev_manager.get() != NULL); 411 EXPECT_EQ(num_frames, handler.fill_buffer_callback_count_ - 1);
290 412 decoder->Uninitialize();
291 scoped_refptr<MftH264Decoder> decoder(new MftH264Decoder(true));
292 ASSERT_TRUE(decoder.get() != NULL);
293 scoped_ptr<FFmpegFileReader> reader(
294 new FFmpegFileReader(WideToASCII(path.value())));
295 ASSERT_TRUE(reader->Initialize());
296 scoped_refptr<FakeMftRenderer> renderer(new FakeMftRenderer(decoder));
297 ASSERT_TRUE(decoder->Init(dev_manager.get(), 0, 0, 111, 222, 0, 0,
298 NewCallback(reader.get(), &FFmpegFileReader::Read),
299 NewCallback(renderer.get(),
300 &FakeMftRenderer::WriteCallback),
301 NewCallback(renderer.get(),
302 &FakeMftRenderer::OnDecodeError)));
303 MessageLoop::current()->PostTask(
304 FROM_HERE,
305 NewRunnableMethod(renderer.get(), &FakeMftRenderer::Start));
306 MessageLoop::current()->Run();
307
308 // If the video is valid, then it should output frames. However, for some
309 // videos, the number of frames decoded is one-off.
310 EXPECT_EQ(82, decoder->frames_read());
311 EXPECT_LE(decoder->frames_read() - decoder->frames_decoded(), 1);
312 } 413 }
313 414
314 TEST_F(MftH264DecoderTest, FlushAtInit) { 415 TEST_F(MftH264DecoderTest, DecodeValidVideoDxva) {
315 scoped_refptr<MftH264Decoder> decoder(new MftH264Decoder(false)); 416 DecodeValidVideo("bear.1280x720.mp4", 82, true);
316 ASSERT_TRUE(decoder.get() != NULL);
317 FakeMftReader reader;
318 scoped_refptr<FakeMftRenderer> renderer(new FakeMftRenderer(decoder));
319 ASSERT_TRUE(decoder->Init(NULL, 0, 0, 111, 222, 0, 0,
320 NewCallback(&reader, &FakeMftReader::ReadCallback),
321 NewCallback(renderer.get(),
322 &FakeMftRenderer::WriteCallback),
323 NewCallback(renderer.get(),
324 &FakeMftRenderer::OnDecodeError)));
325 EXPECT_TRUE(decoder->Flush());
326 } 417 }
327 418
328 TEST_F(MftH264DecoderTest, FlushAtEnd) { 419 TEST_F(MftH264DecoderTest, DecodeValidVideoNoDxva) {
329 MessageLoop loop; 420 DecodeValidVideo("bear.1280x720.mp4", 82, false);
330 scoped_refptr<MftH264Decoder> decoder(new MftH264Decoder(false));
331 ASSERT_TRUE(decoder.get() != NULL);
332
333 // No frames, outputs a NULL indicating end-of-stream
334 FakeMftReader reader(0);
335 scoped_refptr<FakeMftRenderer> renderer(new FakeMftRenderer(decoder));
336 ASSERT_TRUE(decoder->Init(NULL, 0, 0, 111, 222, 0, 0,
337 NewCallback(&reader, &FakeMftReader::ReadCallback),
338 NewCallback(renderer.get(),
339 &FakeMftRenderer::WriteCallback),
340 NewCallback(renderer.get(),
341 &FakeMftRenderer::OnDecodeError)));
342 MessageLoop::current()->PostTask(
343 FROM_HERE,
344 NewRunnableMethod(renderer.get(), &FakeMftRenderer::Start));
345 MessageLoop::current()->Run();
346 EXPECT_TRUE(decoder->Flush());
347 }
348
349 TEST_F(MftH264DecoderTest, FlushAtMiddle) {
350 MessageLoop loop;
351 FilePath path = GetVideoFilePath("bear.1280x720.mp4");
352 ASSERT_TRUE(file_util::PathExists(path));
353
354 ScopedComPtr<IDirect3D9> d3d9;
355 ScopedComPtr<IDirect3DDevice9> device;
356 ScopedComPtr<IDirect3DDeviceManager9> dev_manager;
357 dev_manager.Attach(CreateD3DDevManager(GetDesktopWindow(),
358 d3d9.Receive(),
359 device.Receive()));
360 ASSERT_TRUE(dev_manager.get() != NULL);
361
362 scoped_refptr<MftH264Decoder> decoder(new MftH264Decoder(true));
363 ASSERT_TRUE(decoder.get() != NULL);
364 scoped_ptr<FFmpegFileReader> reader(
365 new FFmpegFileReader(WideToASCII(path.value())));
366 ASSERT_TRUE(reader->Initialize());
367 scoped_refptr<FakeMftRenderer> renderer(new FakeMftRenderer(decoder));
368 ASSERT_TRUE(renderer.get());
369
370 // Flush after obtaining 40 decode frames. There are no more key frames after
371 // the first one, so we expect it to stop outputting frames after flush.
372 int flush_at_nth_decoded_frame = 40;
373 renderer->SetFlushCountdown(flush_at_nth_decoded_frame);
374 ASSERT_TRUE(decoder->Init(dev_manager.get(), 0, 0, 111, 222, 0, 0,
375 NewCallback(reader.get(), &FFmpegFileReader::Read),
376 NewCallback(renderer.get(),
377 &FakeMftRenderer::WriteCallback),
378 NewCallback(renderer.get(),
379 &FakeMftRenderer::OnDecodeError)));
380 MessageLoop::current()->PostTask(
381 FROM_HERE,
382 NewRunnableMethod(renderer.get(), &FakeMftRenderer::Start));
383 MessageLoop::current()->Run();
384 EXPECT_EQ(82, decoder->frames_read());
385 EXPECT_EQ(decoder->frames_decoded(), flush_at_nth_decoded_frame);
386 } 421 }
387 422
388 } // namespace media 423 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698