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

Side by Side Diff: media/video/ffmpeg_video_decode_engine_unittest.cc

Issue 8417019: Simplify VideoDecodeEngine interface by making everything synchronous. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fix for CaptureVideoDecoder Created 9 years, 1 month 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
« no previous file with comments | « media/video/ffmpeg_video_decode_engine.cc ('k') | media/video/video_decode_engine.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/memory/scoped_ptr.h"
6 #include "base/message_loop.h"
7 #include "media/base/data_buffer.h"
8 #include "media/base/pipeline.h"
9 #include "media/base/test_data_util.h"
10 #include "media/filters/ffmpeg_glue.h"
11 #include "media/video/ffmpeg_video_decode_engine.h"
12 #include "testing/gmock/include/gmock/gmock.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14
15 using ::testing::_;
16 using ::testing::DoAll;
17 using ::testing::Return;
18 using ::testing::ReturnNull;
19 using ::testing::SaveArg;
20 using ::testing::SetArgumentPointee;
21 using ::testing::StrictMock;
22
23 namespace media {
24
25 static const VideoFrame::Format kVideoFormat = VideoFrame::YV12;
26 static const gfx::Size kCodedSize(320, 240);
27 static const gfx::Rect kVisibleRect(320, 240);
28 static const gfx::Size kNaturalSize(522, 288);
29 static const AVRational kFrameRate = { 100, 1 };
30 static const AVRational kAspectRatio = { 1, 1 };
31
32 ACTION_P2(DemuxComplete, engine, buffer) {
33 engine->ConsumeVideoSample(buffer);
34 }
35
36 class FFmpegVideoDecodeEngineTest
37 : public testing::Test,
38 public VideoDecodeEngine::EventHandler {
39 public:
40 FFmpegVideoDecodeEngineTest()
41 : config_(kCodecVP8, kVideoFormat, kCodedSize, kVisibleRect,
42 kFrameRate.num, kFrameRate.den,
43 kAspectRatio.num, kAspectRatio.den,
44 NULL, 0) {
45 CHECK(FFmpegGlue::GetInstance());
46
47 // Setup FFmpeg structures.
48 frame_buffer_.reset(new uint8[kCodedSize.GetArea()]);
49
50 test_engine_.reset(new FFmpegVideoDecodeEngine());
51
52 ReadTestDataFile("vp8-I-frame-320x240", &i_frame_buffer_);
53 ReadTestDataFile("vp8-corrupt-I-frame", &corrupt_i_frame_buffer_);
54
55 end_of_stream_buffer_ = new DataBuffer(0);
56 }
57
58 ~FFmpegVideoDecodeEngineTest() {
59 test_engine_.reset();
60 }
61
62 void Initialize() {
63 EXPECT_CALL(*this, OnInitializeComplete(true));
64 test_engine_->Initialize(this, config_);
65 }
66
67 // Decodes the single compressed frame in |buffer| and writes the
68 // uncompressed output to |video_frame|. This method works with single
69 // and multithreaded decoders. End of stream buffers are used to trigger
70 // the frame to be returned in the multithreaded decoder case.
71 void DecodeASingleFrame(const scoped_refptr<Buffer>& buffer,
72 scoped_refptr<VideoFrame>* video_frame) {
73 EXPECT_CALL(*this, ProduceVideoSample(_))
74 .WillOnce(DemuxComplete(test_engine_.get(), buffer))
75 .WillRepeatedly(DemuxComplete(test_engine_.get(),
76 end_of_stream_buffer_));
77
78 EXPECT_CALL(*this, ConsumeVideoFrame(_, _))
79 .WillOnce(SaveArg<0>(video_frame));
80 CallProduceVideoFrame();
81 }
82
83 // Decodes |i_frame_buffer_| and then decodes the data contained in
84 // the file named |test_file_name|. This function expects both buffers
85 // to decode to frames that are the same size.
86 void DecodeIFrameThenTestFile(const std::string& test_file_name) {
87 Initialize();
88
89 scoped_refptr<VideoFrame> video_frame_a;
90 scoped_refptr<VideoFrame> video_frame_b;
91
92 scoped_refptr<Buffer> buffer;
93 ReadTestDataFile(test_file_name, &buffer);
94
95 EXPECT_CALL(*this, ProduceVideoSample(_))
96 .WillOnce(DemuxComplete(test_engine_.get(), i_frame_buffer_))
97 .WillOnce(DemuxComplete(test_engine_.get(), buffer))
98 .WillRepeatedly(DemuxComplete(test_engine_.get(),
99 end_of_stream_buffer_));
100
101 EXPECT_CALL(*this, ConsumeVideoFrame(_, _))
102 .WillOnce(SaveArg<0>(&video_frame_a))
103 .WillOnce(SaveArg<0>(&video_frame_b));
104 CallProduceVideoFrame();
105 CallProduceVideoFrame();
106
107 size_t expected_width = static_cast<size_t>(kVisibleRect.width());
108 size_t expected_height = static_cast<size_t>(kVisibleRect.height());
109
110 EXPECT_EQ(expected_width, video_frame_a->width());
111 EXPECT_EQ(expected_height, video_frame_a->height());
112 EXPECT_EQ(expected_width, video_frame_b->width());
113 EXPECT_EQ(expected_height, video_frame_b->height());
114 }
115
116 // VideoDecodeEngine::EventHandler implementation.
117 MOCK_METHOD2(ConsumeVideoFrame,
118 void(scoped_refptr<VideoFrame>, const PipelineStatistics&));
119 MOCK_METHOD1(ProduceVideoSample, void(scoped_refptr<Buffer>));
120 MOCK_METHOD1(OnInitializeComplete, void(bool));
121 MOCK_METHOD0(OnUninitializeComplete, void());
122 MOCK_METHOD0(OnFlushComplete, void());
123 MOCK_METHOD0(OnSeekComplete, void());
124 MOCK_METHOD0(OnError, void());
125
126 void CallProduceVideoFrame() {
127 test_engine_->ProduceVideoFrame(VideoFrame::CreateFrame(
128 VideoFrame::YV12, kVisibleRect.width(), kVisibleRect.height(),
129 kNoTimestamp, kNoTimestamp));
130 }
131
132 protected:
133 VideoDecoderConfig config_;
134 scoped_ptr<FFmpegVideoDecodeEngine> test_engine_;
135 scoped_array<uint8_t> frame_buffer_;
136 scoped_refptr<Buffer> i_frame_buffer_;
137 scoped_refptr<Buffer> corrupt_i_frame_buffer_;
138 scoped_refptr<Buffer> end_of_stream_buffer_;
139
140 private:
141 DISALLOW_COPY_AND_ASSIGN(FFmpegVideoDecodeEngineTest);
142 };
143
144 TEST_F(FFmpegVideoDecodeEngineTest, Initialize_Normal) {
145 Initialize();
146 }
147
148 TEST_F(FFmpegVideoDecodeEngineTest, Initialize_FindDecoderFails) {
149 VideoDecoderConfig config(kUnknownVideoCodec, kVideoFormat,
150 kCodedSize, kVisibleRect,
151 kFrameRate.num, kFrameRate.den,
152 kAspectRatio.num, kAspectRatio.den,
153 NULL, 0);
154
155 // Test avcodec_find_decoder() returning NULL.
156 EXPECT_CALL(*this, OnInitializeComplete(false));
157 test_engine_->Initialize(this, config);
158 }
159
160 TEST_F(FFmpegVideoDecodeEngineTest, Initialize_OpenDecoderFails) {
161 // Specify Theora w/o extra data so that avcodec_open() fails.
162 VideoDecoderConfig config(kCodecTheora, kVideoFormat,
163 kCodedSize, kVisibleRect,
164 kFrameRate.num, kFrameRate.den,
165 kAspectRatio.num, kAspectRatio.den,
166 NULL, 0);
167 EXPECT_CALL(*this, OnInitializeComplete(false));
168 test_engine_->Initialize(this, config);
169 }
170
171 TEST_F(FFmpegVideoDecodeEngineTest, Initialize_UnsupportedPixelFormat) {
172 // Ensure decoder handles unsupport pixel formats without crashing.
173 VideoDecoderConfig config(kCodecVP8, VideoFrame::INVALID,
174 kCodedSize, kVisibleRect,
175 kFrameRate.num, kFrameRate.den,
176 kAspectRatio.num, kAspectRatio.den,
177 NULL, 0);
178 EXPECT_CALL(*this, OnInitializeComplete(false));
179 test_engine_->Initialize(this, config);
180 }
181
182 TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_Normal) {
183 Initialize();
184
185 // Simulate decoding a single frame.
186 scoped_refptr<VideoFrame> video_frame;
187 DecodeASingleFrame(i_frame_buffer_, &video_frame);
188
189 // |video_frame| timestamp is 0 because we set the timestamp based off
190 // the buffer timestamp.
191 ASSERT_TRUE(video_frame);
192 EXPECT_EQ(0, video_frame->GetTimestamp().ToInternalValue());
193 EXPECT_EQ(10000, video_frame->GetDuration().ToInternalValue());
194 }
195
196
197 // Verify current behavior for 0 byte frames. FFmpeg simply ignores
198 // the 0 byte frames.
199 TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_0ByteFrame) {
200 Initialize();
201
202 scoped_refptr<DataBuffer> zero_byte_buffer = new DataBuffer(1);
203
204 scoped_refptr<VideoFrame> video_frame_a;
205 scoped_refptr<VideoFrame> video_frame_b;
206 scoped_refptr<VideoFrame> video_frame_c;
207
208 EXPECT_CALL(*this, ProduceVideoSample(_))
209 .WillOnce(DemuxComplete(test_engine_.get(), i_frame_buffer_))
210 .WillOnce(DemuxComplete(test_engine_.get(), zero_byte_buffer))
211 .WillOnce(DemuxComplete(test_engine_.get(), i_frame_buffer_))
212 .WillRepeatedly(DemuxComplete(test_engine_.get(),
213 end_of_stream_buffer_));
214
215 EXPECT_CALL(*this, ConsumeVideoFrame(_, _))
216 .WillOnce(SaveArg<0>(&video_frame_a))
217 .WillOnce(SaveArg<0>(&video_frame_b))
218 .WillOnce(SaveArg<0>(&video_frame_c));
219 CallProduceVideoFrame();
220 CallProduceVideoFrame();
221 CallProduceVideoFrame();
222
223 EXPECT_TRUE(video_frame_a);
224 EXPECT_TRUE(video_frame_b);
225 EXPECT_FALSE(video_frame_c);
226 }
227
228
229 TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_DecodeError) {
230 Initialize();
231
232 EXPECT_CALL(*this, ProduceVideoSample(_))
233 .WillOnce(DemuxComplete(test_engine_.get(), corrupt_i_frame_buffer_))
234 .WillRepeatedly(DemuxComplete(test_engine_.get(), i_frame_buffer_));
235 EXPECT_CALL(*this, OnError());
236
237 CallProduceVideoFrame();
238 }
239
240 // Multi-threaded decoders have different behavior than single-threaded
241 // decoders at the end of the stream. Multithreaded decoders hide errors
242 // that happen on the last |codec_context_->thread_count| frames to avoid
243 // prematurely signalling EOS. This test just exposes that behavior so we can
244 // detect if it changes.
245 TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_DecodeErrorAtEndOfStream) {
246 Initialize();
247
248 EXPECT_CALL(*this, ProduceVideoSample(_))
249 .WillOnce(DemuxComplete(test_engine_.get(), corrupt_i_frame_buffer_))
250 .WillRepeatedly(DemuxComplete(test_engine_.get(), end_of_stream_buffer_));
251
252 scoped_refptr<VideoFrame> video_frame;
253 EXPECT_CALL(*this, ConsumeVideoFrame(_, _))
254 .WillOnce(SaveArg<0>(&video_frame));
255 CallProduceVideoFrame();
256
257 EXPECT_FALSE(video_frame);
258 }
259
260 // Decode |i_frame_buffer_| and then a frame with a larger width and verify
261 // the output size didn't change.
262 // TODO(acolwell): Fix InvalidRead detected by Valgrind
263 //TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_LargerWidth) {
264 // DecodeIFrameThenTestFile("vp8-I-frame-640x240");
265 //}
266
267 // Decode |i_frame_buffer_| and then a frame with a smaller width and verify
268 // the output size didn't change.
269 TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_SmallerWidth) {
270 DecodeIFrameThenTestFile("vp8-I-frame-160x240");
271 }
272
273 // Decode |i_frame_buffer_| and then a frame with a larger height and verify
274 // the output size didn't change.
275 // TODO(acolwell): Fix InvalidRead detected by Valgrind
276 //TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_LargerHeight) {
277 // DecodeIFrameThenTestFile("vp8-I-frame-320x480");
278 //}
279
280 // Decode |i_frame_buffer_| and then a frame with a smaller height and verify
281 // the output size didn't change.
282 TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_SmallerHeight) {
283 DecodeIFrameThenTestFile("vp8-I-frame-320x120");
284 }
285
286 } // namespace media
OLDNEW
« no previous file with comments | « media/video/ffmpeg_video_decode_engine.cc ('k') | media/video/video_decode_engine.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698