OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 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 | 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 "base/memory/scoped_ptr.h" | 5 #include "base/memory/scoped_ptr.h" |
6 #include "base/message_loop.h" | 6 #include "base/message_loop.h" |
7 #include "media/base/data_buffer.h" | 7 #include "media/base/data_buffer.h" |
8 #include "media/base/mock_ffmpeg.h" | |
9 #include "media/base/mock_task.h" | 8 #include "media/base/mock_task.h" |
10 #include "media/base/pipeline.h" | 9 #include "media/base/pipeline.h" |
10 #include "media/base/test_data_util.h" | |
11 #include "media/filters/ffmpeg_glue.h" | |
11 #include "media/video/ffmpeg_video_decode_engine.h" | 12 #include "media/video/ffmpeg_video_decode_engine.h" |
12 #include "testing/gmock/include/gmock/gmock.h" | 13 #include "testing/gmock/include/gmock/gmock.h" |
13 #include "testing/gtest/include/gtest/gtest.h" | 14 #include "testing/gtest/include/gtest/gtest.h" |
14 | 15 |
15 using ::testing::_; | 16 using ::testing::_; |
16 using ::testing::DoAll; | 17 using ::testing::DoAll; |
17 using ::testing::Return; | 18 using ::testing::Return; |
18 using ::testing::ReturnNull; | 19 using ::testing::ReturnNull; |
20 using ::testing::SaveArg; | |
19 using ::testing::SetArgumentPointee; | 21 using ::testing::SetArgumentPointee; |
20 using ::testing::StrictMock; | 22 using ::testing::StrictMock; |
21 | 23 |
22 namespace media { | 24 namespace media { |
23 | 25 |
24 static const int kWidth = 320; | 26 static const size_t kWidth = 320; |
25 static const int kHeight = 240; | 27 static const size_t kHeight = 240; |
26 static const int kSurfaceWidth = 522; | 28 static const int kSurfaceWidth = 522; |
27 static const int kSurfaceHeight = 288; | 29 static const int kSurfaceHeight = 288; |
28 static const AVRational kFrameRate = { 100, 1 }; | 30 static const AVRational kFrameRate = { 100, 1 }; |
29 | 31 |
30 static void InitializeFrame(uint8_t* data, int width, AVFrame* frame) { | |
31 frame->data[0] = data; | |
32 frame->data[1] = data; | |
33 frame->data[2] = data; | |
34 frame->linesize[0] = width; | |
35 frame->linesize[1] = width / 2; | |
36 frame->linesize[2] = width / 2; | |
37 } | |
38 | |
39 ACTION_P(DecodeComplete, decoder) { | |
40 decoder->set_video_frame(arg0); | |
41 } | |
42 | |
43 ACTION_P2(DemuxComplete, engine, buffer) { | 32 ACTION_P2(DemuxComplete, engine, buffer) { |
44 engine->ConsumeVideoSample(buffer); | 33 engine->ConsumeVideoSample(buffer); |
45 } | 34 } |
46 | 35 |
47 ACTION_P(SaveInitializeResult, engine) { | |
48 engine->set_video_codec_info(arg0); | |
49 } | |
50 | |
51 class FFmpegVideoDecodeEngineTest | 36 class FFmpegVideoDecodeEngineTest |
52 : public testing::Test, | 37 : public testing::Test, |
53 public VideoDecodeEngine::EventHandler { | 38 public VideoDecodeEngine::EventHandler { |
54 public: | 39 public: |
55 FFmpegVideoDecodeEngineTest() | 40 FFmpegVideoDecodeEngineTest() |
56 : config_(kCodecH264, kWidth, kHeight, kSurfaceWidth, kSurfaceHeight, | 41 : config_(kCodecVP8, kWidth, kHeight, kSurfaceWidth, kSurfaceHeight, |
57 kFrameRate.num, kFrameRate.den, NULL, 0) { | 42 kFrameRate.num, kFrameRate.den, NULL, 0) { |
43 CHECK(FFmpegGlue::GetInstance()); | |
58 | 44 |
59 // Setup FFmpeg structures. | 45 // Setup FFmpeg structures. |
60 frame_buffer_.reset(new uint8[kWidth * kHeight]); | 46 frame_buffer_.reset(new uint8[kWidth * kHeight]); |
61 memset(&yuv_frame_, 0, sizeof(yuv_frame_)); | |
62 InitializeFrame(frame_buffer_.get(), kWidth, &yuv_frame_); | |
63 | |
64 memset(&codec_context_, 0, sizeof(codec_context_)); | |
65 memset(&codec_, 0, sizeof(codec_)); | |
66 | |
67 buffer_ = new DataBuffer(1); | |
68 | 47 |
69 test_engine_.reset(new FFmpegVideoDecodeEngine()); | 48 test_engine_.reset(new FFmpegVideoDecodeEngine()); |
70 | 49 |
71 video_frame_ = VideoFrame::CreateFrame(VideoFrame::YV12, | 50 ReadTestDataFile("vp8-I-frame-320x240", &i_frame_buffer_); |
72 kWidth, | 51 |
73 kHeight, | 52 // Create a corrupt version of |i_frame_buffer_|. |
scherkus (not reviewing)
2011/08/23 14:42:08
couldn't this be a file?
| |
74 kNoTimestamp, | 53 corrupt_i_frame_buffer_ = new DataBuffer(i_frame_buffer_->GetDataSize()); |
75 kNoTimestamp); | 54 corrupt_i_frame_buffer_->SetDataSize(i_frame_buffer_->GetDataSize()); |
55 | |
56 uint8* buf = corrupt_i_frame_buffer_->GetWritableData(); | |
57 memcpy(buf, i_frame_buffer_->GetData(), | |
58 corrupt_i_frame_buffer_->GetDataSize()); | |
59 | |
60 // Corrupt bytes by flipping bits w/ xor. | |
61 for (size_t i = 0; i < corrupt_i_frame_buffer_->GetDataSize(); i++) | |
62 buf[i] ^= 0xA5; | |
63 | |
64 end_of_stream_buffer_ = new DataBuffer(0); | |
76 } | 65 } |
77 | 66 |
78 ~FFmpegVideoDecodeEngineTest() { | 67 ~FFmpegVideoDecodeEngineTest() { |
79 test_engine_.reset(); | 68 test_engine_.reset(); |
80 } | 69 } |
81 | 70 |
82 void Initialize() { | 71 void Initialize() { |
83 EXPECT_CALL(mock_ffmpeg_, AVCodecAllocContext()) | 72 VideoCodecInfo info; |
84 .WillOnce(Return(&codec_context_)); | |
85 EXPECT_CALL(mock_ffmpeg_, AVCodecFindDecoder(CODEC_ID_H264)) | |
86 .WillOnce(Return(&codec_)); | |
87 EXPECT_CALL(mock_ffmpeg_, AVCodecAllocFrame()) | |
88 .WillOnce(Return(&yuv_frame_)); | |
89 EXPECT_CALL(mock_ffmpeg_, AVCodecOpen(&codec_context_, &codec_)) | |
90 .WillOnce(Return(0)); | |
91 EXPECT_CALL(mock_ffmpeg_, AVCodecClose(&codec_context_)) | |
92 .WillOnce(Return(0)); | |
93 EXPECT_CALL(mock_ffmpeg_, AVFree(&yuv_frame_)) | |
94 .Times(1); | |
95 EXPECT_CALL(mock_ffmpeg_, AVFree(&codec_context_)) | |
96 .Times(1); | |
97 | |
98 EXPECT_CALL(*this, OnInitializeComplete(_)) | 73 EXPECT_CALL(*this, OnInitializeComplete(_)) |
99 .WillOnce(SaveInitializeResult(this)); | 74 .WillOnce(SaveArg<0>(&info)); |
100 test_engine_->Initialize(MessageLoop::current(), this, NULL, config_); | 75 test_engine_->Initialize(MessageLoop::current(), this, NULL, config_); |
101 EXPECT_TRUE(info_.success); | 76 EXPECT_TRUE(info.success); |
102 } | 77 } |
103 | 78 |
104 void Decode() { | 79 // Decodes the single compressed frame in |buffer| and writes the |
105 EXPECT_CALL(mock_ffmpeg_, AVInitPacket(_)); | 80 // uncompressed output to |video_frame|. This method works with single |
106 EXPECT_CALL(mock_ffmpeg_, | 81 // and multithreaded decoders. End of stream buffers are used to trigger |
107 AVCodecDecodeVideo2(&codec_context_, &yuv_frame_, _, _)) | 82 // the frame to be returned in the multithreaded decoder case. |
108 .WillOnce(DoAll(SetArgumentPointee<2>(1), // Simulate 1 byte frame. | 83 void DecodeASingleFrame(const scoped_refptr<Buffer>& buffer, |
109 Return(0))); | 84 scoped_refptr<VideoFrame>* video_frame) { |
85 EXPECT_CALL(*this, ProduceVideoSample(_)) | |
86 .WillOnce(DemuxComplete(test_engine_.get(), buffer)) | |
87 .WillRepeatedly(DemuxComplete(test_engine_.get(), | |
88 end_of_stream_buffer_)); | |
89 | |
90 EXPECT_CALL(*this, ConsumeVideoFrame(_, _)) | |
91 .WillOnce(SaveArg<0>(video_frame)); | |
92 CallProduceVideoFrame(); | |
93 } | |
94 | |
95 // Decodes |i_frame_buffer_| and then decodes the data contained in | |
96 // the file named |test_file_name|. This function expects both buffers | |
97 // to decode to frames that are the same size. | |
98 void DecodeIFrameThenTestFile(const std::string& test_file_name) { | |
99 Initialize(); | |
100 | |
101 scoped_refptr<VideoFrame> video_frame_a; | |
102 scoped_refptr<VideoFrame> video_frame_b; | |
103 | |
104 scoped_refptr<Buffer> buffer; | |
105 ReadTestDataFile(test_file_name, &buffer); | |
110 | 106 |
111 EXPECT_CALL(*this, ProduceVideoSample(_)) | 107 EXPECT_CALL(*this, ProduceVideoSample(_)) |
112 .WillOnce(DemuxComplete(test_engine_.get(), buffer_)); | 108 .WillOnce(DemuxComplete(test_engine_.get(), i_frame_buffer_)) |
109 .WillOnce(DemuxComplete(test_engine_.get(), buffer)) | |
110 .WillRepeatedly(DemuxComplete(test_engine_.get(), | |
111 end_of_stream_buffer_)); | |
112 | |
113 EXPECT_CALL(*this, ConsumeVideoFrame(_, _)) | 113 EXPECT_CALL(*this, ConsumeVideoFrame(_, _)) |
114 .WillOnce(DecodeComplete(this)); | 114 .WillOnce(SaveArg<0>(&video_frame_a)) |
115 test_engine_->ProduceVideoFrame(video_frame_); | 115 .WillOnce(SaveArg<0>(&video_frame_b)); |
116 } | 116 CallProduceVideoFrame(); |
117 CallProduceVideoFrame(); | |
117 | 118 |
118 void ChangeDimensions(int width, int height) { | 119 EXPECT_EQ(kWidth, video_frame_a->width()); |
119 frame_buffer_.reset(new uint8[width * height]); | 120 EXPECT_EQ(kHeight, video_frame_a->height()); |
120 InitializeFrame(frame_buffer_.get(), width, &yuv_frame_); | 121 EXPECT_EQ(kWidth, video_frame_b->width()); |
121 codec_context_.width = width; | 122 EXPECT_EQ(kHeight, video_frame_b->height()); |
122 codec_context_.height = height; | |
123 } | 123 } |
124 | 124 |
125 // VideoDecodeEngine::EventHandler implementation. | 125 // VideoDecodeEngine::EventHandler implementation. |
126 MOCK_METHOD2(ConsumeVideoFrame, | 126 MOCK_METHOD2(ConsumeVideoFrame, |
127 void(scoped_refptr<VideoFrame> video_frame, | 127 void(scoped_refptr<VideoFrame> video_frame, |
128 const PipelineStatistics& statistics)); | 128 const PipelineStatistics& statistics)); |
129 MOCK_METHOD1(ProduceVideoSample, | 129 MOCK_METHOD1(ProduceVideoSample, |
130 void(scoped_refptr<Buffer> buffer)); | 130 void(scoped_refptr<Buffer> buffer)); |
131 MOCK_METHOD1(OnInitializeComplete, | 131 MOCK_METHOD1(OnInitializeComplete, |
132 void(const VideoCodecInfo& info)); | 132 void(const VideoCodecInfo& info)); |
133 MOCK_METHOD0(OnUninitializeComplete, void()); | 133 MOCK_METHOD0(OnUninitializeComplete, void()); |
134 MOCK_METHOD0(OnFlushComplete, void()); | 134 MOCK_METHOD0(OnFlushComplete, void()); |
135 MOCK_METHOD0(OnSeekComplete, void()); | 135 MOCK_METHOD0(OnSeekComplete, void()); |
136 MOCK_METHOD0(OnError, void()); | 136 MOCK_METHOD0(OnError, void()); |
137 | 137 |
138 // Used by gmock actions. | 138 void CallProduceVideoFrame() { |
139 void set_video_frame(scoped_refptr<VideoFrame> video_frame) { | 139 test_engine_->ProduceVideoFrame(VideoFrame::CreateFrame(VideoFrame::YV12, |
140 video_frame_ = video_frame; | 140 kWidth, |
141 } | 141 kHeight, |
142 | 142 kNoTimestamp, |
143 void set_video_codec_info(const VideoCodecInfo& info) { | 143 kNoTimestamp)); |
144 info_ = info; | |
145 } | 144 } |
146 | 145 |
147 protected: | 146 protected: |
148 VideoDecoderConfig config_; | 147 VideoDecoderConfig config_; |
149 VideoCodecInfo info_; | |
150 scoped_refptr<VideoFrame> video_frame_; | |
151 scoped_ptr<FFmpegVideoDecodeEngine> test_engine_; | 148 scoped_ptr<FFmpegVideoDecodeEngine> test_engine_; |
152 scoped_array<uint8_t> frame_buffer_; | 149 scoped_array<uint8_t> frame_buffer_; |
153 StrictMock<MockFFmpeg> mock_ffmpeg_; | 150 scoped_refptr<Buffer> i_frame_buffer_; |
154 | 151 scoped_refptr<DataBuffer> corrupt_i_frame_buffer_; |
155 AVFrame yuv_frame_; | 152 scoped_refptr<Buffer> end_of_stream_buffer_; |
156 AVCodecContext codec_context_; | |
157 AVCodec codec_; | |
158 scoped_refptr<DataBuffer> buffer_; | |
159 | 153 |
160 private: | 154 private: |
161 DISALLOW_COPY_AND_ASSIGN(FFmpegVideoDecodeEngineTest); | 155 DISALLOW_COPY_AND_ASSIGN(FFmpegVideoDecodeEngineTest); |
162 }; | 156 }; |
163 | 157 |
164 TEST_F(FFmpegVideoDecodeEngineTest, Initialize_Normal) { | 158 TEST_F(FFmpegVideoDecodeEngineTest, Initialize_Normal) { |
165 Initialize(); | 159 Initialize(); |
166 } | 160 } |
167 | 161 |
168 TEST_F(FFmpegVideoDecodeEngineTest, Initialize_FindDecoderFails) { | 162 TEST_F(FFmpegVideoDecodeEngineTest, Initialize_FindDecoderFails) { |
163 VideoDecoderConfig config(kUnknown, kWidth, kHeight, kSurfaceWidth, | |
164 kSurfaceHeight, kFrameRate.num, kFrameRate.den, | |
165 NULL, 0); | |
169 // Test avcodec_find_decoder() returning NULL. | 166 // Test avcodec_find_decoder() returning NULL. |
170 EXPECT_CALL(mock_ffmpeg_, AVCodecAllocContext()) | 167 VideoCodecInfo info; |
171 .WillOnce(Return(&codec_context_)); | |
172 EXPECT_CALL(mock_ffmpeg_, AVCodecFindDecoder(CODEC_ID_H264)) | |
173 .WillOnce(ReturnNull()); | |
174 EXPECT_CALL(mock_ffmpeg_, AVCodecAllocFrame()) | |
175 .WillOnce(Return(&yuv_frame_)); | |
176 EXPECT_CALL(mock_ffmpeg_, AVCodecClose(&codec_context_)) | |
177 .WillOnce(Return(0)); | |
178 EXPECT_CALL(mock_ffmpeg_, AVFree(&yuv_frame_)) | |
179 .Times(1); | |
180 EXPECT_CALL(mock_ffmpeg_, AVFree(&codec_context_)) | |
181 .Times(1); | |
182 | |
183 EXPECT_CALL(*this, OnInitializeComplete(_)) | 168 EXPECT_CALL(*this, OnInitializeComplete(_)) |
184 .WillOnce(SaveInitializeResult(this)); | 169 .WillOnce(SaveArg<0>(&info)); |
185 test_engine_->Initialize(MessageLoop::current(), this, NULL, config_); | 170 test_engine_->Initialize(MessageLoop::current(), this, NULL, config); |
186 EXPECT_FALSE(info_.success); | 171 EXPECT_FALSE(info.success); |
187 } | 172 } |
188 | 173 |
189 TEST_F(FFmpegVideoDecodeEngineTest, Initialize_OpenDecoderFails) { | 174 TEST_F(FFmpegVideoDecodeEngineTest, Initialize_OpenDecoderFails) { |
190 // Test avcodec_open() failing. | 175 // Specify Theora w/o extra data so that avcodec_open() fails. |
191 EXPECT_CALL(mock_ffmpeg_, AVCodecAllocContext()) | 176 VideoDecoderConfig config(kCodecTheora, kWidth, kHeight, kSurfaceWidth, |
192 .WillOnce(Return(&codec_context_)); | 177 kSurfaceHeight, kFrameRate.num, kFrameRate.den, |
193 EXPECT_CALL(mock_ffmpeg_, AVCodecFindDecoder(CODEC_ID_H264)) | 178 NULL, 0); |
194 .WillOnce(Return(&codec_)); | 179 VideoCodecInfo info; |
195 EXPECT_CALL(mock_ffmpeg_, AVCodecAllocFrame()) | |
196 .WillOnce(Return(&yuv_frame_)); | |
197 EXPECT_CALL(mock_ffmpeg_, AVCodecOpen(&codec_context_, &codec_)) | |
198 .WillOnce(Return(-1)); | |
199 EXPECT_CALL(mock_ffmpeg_, AVCodecClose(&codec_context_)) | |
200 .WillOnce(Return(0)); | |
201 EXPECT_CALL(mock_ffmpeg_, AVFree(&yuv_frame_)) | |
202 .Times(1); | |
203 EXPECT_CALL(mock_ffmpeg_, AVFree(&codec_context_)) | |
204 .Times(1); | |
205 | |
206 EXPECT_CALL(*this, OnInitializeComplete(_)) | 180 EXPECT_CALL(*this, OnInitializeComplete(_)) |
207 .WillOnce(SaveInitializeResult(this)); | 181 .WillOnce(SaveArg<0>(&info)); |
208 test_engine_->Initialize(MessageLoop::current(), this, NULL, config_); | 182 test_engine_->Initialize(MessageLoop::current(), this, NULL, config); |
209 EXPECT_FALSE(info_.success); | 183 EXPECT_FALSE(info.success); |
210 } | 184 } |
211 | 185 |
212 TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_Normal) { | 186 TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_Normal) { |
213 Initialize(); | 187 Initialize(); |
214 | 188 |
215 // We rely on FFmpeg for timestamp and duration reporting. The one tricky | 189 // We rely on FFmpeg for timestamp and duration reporting. |
216 // bit is calculating the duration when |repeat_pict| > 0. | 190 const base::TimeDelta kTimestamp = base::TimeDelta::FromMicroseconds(0); |
217 const base::TimeDelta kTimestamp = base::TimeDelta::FromMicroseconds(123); | 191 const base::TimeDelta kDuration = base::TimeDelta::FromMicroseconds(10000); |
218 const base::TimeDelta kDuration = base::TimeDelta::FromMicroseconds(15000); | |
219 yuv_frame_.repeat_pict = 1; | |
220 yuv_frame_.reordered_opaque = kTimestamp.InMicroseconds(); | |
221 | 192 |
222 // Simulate decoding a single frame. | 193 // Simulate decoding a single frame. |
223 Decode(); | 194 scoped_refptr<VideoFrame> video_frame; |
195 DecodeASingleFrame(i_frame_buffer_, &video_frame); | |
224 | 196 |
225 // |video_frame_| timestamp is 0 because we set the timestamp based off | 197 // |video_frame| timestamp is 0 because we set the timestamp based off |
226 // the buffer timestamp. | 198 // the buffer timestamp. |
227 EXPECT_EQ(0, video_frame_->GetTimestamp().ToInternalValue()); | 199 ASSERT_TRUE(video_frame); |
200 EXPECT_EQ(0, video_frame->GetTimestamp().ToInternalValue()); | |
228 EXPECT_EQ(kDuration.ToInternalValue(), | 201 EXPECT_EQ(kDuration.ToInternalValue(), |
229 video_frame_->GetDuration().ToInternalValue()); | 202 video_frame->GetDuration().ToInternalValue()); |
230 } | 203 } |
231 | 204 |
205 | |
206 // Verify current behavior for 0 byte frames. FFmpeg simply ignores | |
207 // the 0 byte frames. | |
232 TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_0ByteFrame) { | 208 TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_0ByteFrame) { |
233 Initialize(); | 209 Initialize(); |
234 | 210 |
235 // Expect a bunch of avcodec calls. | 211 scoped_refptr<DataBuffer> zero_byte_buffer = new DataBuffer(1); |
236 EXPECT_CALL(mock_ffmpeg_, AVInitPacket(_)) | 212 |
237 .Times(2); | 213 scoped_refptr<VideoFrame> video_frame_a; |
238 EXPECT_CALL(mock_ffmpeg_, | 214 scoped_refptr<VideoFrame> video_frame_b; |
239 AVCodecDecodeVideo2(&codec_context_, &yuv_frame_, _, _)) | 215 scoped_refptr<VideoFrame> video_frame_c; |
240 .WillOnce(DoAll(SetArgumentPointee<2>(0), // Simulate 0 byte frame. | |
241 Return(0))) | |
242 .WillOnce(DoAll(SetArgumentPointee<2>(1), // Simulate 1 byte frame. | |
243 Return(0))); | |
244 | 216 |
245 EXPECT_CALL(*this, ProduceVideoSample(_)) | 217 EXPECT_CALL(*this, ProduceVideoSample(_)) |
246 .WillOnce(DemuxComplete(test_engine_.get(), buffer_)) | 218 .WillOnce(DemuxComplete(test_engine_.get(), i_frame_buffer_)) |
247 .WillOnce(DemuxComplete(test_engine_.get(), buffer_)); | 219 .WillOnce(DemuxComplete(test_engine_.get(), zero_byte_buffer)) |
220 .WillOnce(DemuxComplete(test_engine_.get(), i_frame_buffer_)) | |
221 .WillRepeatedly(DemuxComplete(test_engine_.get(), | |
222 end_of_stream_buffer_)); | |
223 | |
248 EXPECT_CALL(*this, ConsumeVideoFrame(_, _)) | 224 EXPECT_CALL(*this, ConsumeVideoFrame(_, _)) |
249 .WillOnce(DecodeComplete(this)); | 225 .WillOnce(SaveArg<0>(&video_frame_a)) |
250 test_engine_->ProduceVideoFrame(video_frame_); | 226 .WillOnce(SaveArg<0>(&video_frame_b)) |
227 .WillOnce(SaveArg<0>(&video_frame_c)); | |
228 CallProduceVideoFrame(); | |
229 CallProduceVideoFrame(); | |
230 CallProduceVideoFrame(); | |
251 | 231 |
252 EXPECT_TRUE(video_frame_.get()); | 232 EXPECT_TRUE(video_frame_a); |
233 EXPECT_TRUE(video_frame_b); | |
234 EXPECT_FALSE(video_frame_c); | |
253 } | 235 } |
254 | 236 |
237 | |
255 TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_DecodeError) { | 238 TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_DecodeError) { |
256 Initialize(); | 239 Initialize(); |
257 | 240 |
258 // Expect a bunch of avcodec calls. | 241 EXPECT_CALL(*this, ProduceVideoSample(_)) |
259 EXPECT_CALL(mock_ffmpeg_, AVInitPacket(_)); | 242 .WillOnce(DemuxComplete(test_engine_.get(), corrupt_i_frame_buffer_)) |
260 EXPECT_CALL(mock_ffmpeg_, | 243 .WillRepeatedly(DemuxComplete(test_engine_.get(), i_frame_buffer_)); |
261 AVCodecDecodeVideo2(&codec_context_, &yuv_frame_, _, _)) | 244 EXPECT_CALL(*this, OnError()); |
262 .WillOnce(Return(-1)); | 245 |
246 CallProduceVideoFrame(); | |
247 } | |
248 | |
249 // Multi-threaded decoders have different behavior than single-threaded | |
250 // decoders at the end of the stream. Multithreaded decoders hide errors | |
251 // that happen on the last |codec_context_->thread_count| frames to avoid | |
252 // prematurely signalling EOS. This test just exposes that behavior so we can | |
253 // detect if it changes. | |
254 TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_DecodeErrorAtEndOfStream) { | |
255 Initialize(); | |
263 | 256 |
264 EXPECT_CALL(*this, ProduceVideoSample(_)) | 257 EXPECT_CALL(*this, ProduceVideoSample(_)) |
265 .WillOnce(DemuxComplete(test_engine_.get(), buffer_)); | 258 .WillOnce(DemuxComplete(test_engine_.get(), corrupt_i_frame_buffer_)) |
266 EXPECT_CALL(*this, OnError()); | 259 .WillRepeatedly(DemuxComplete(test_engine_.get(), end_of_stream_buffer_)); |
267 | 260 |
268 test_engine_->ProduceVideoFrame(video_frame_); | 261 scoped_refptr<VideoFrame> video_frame; |
262 EXPECT_CALL(*this, ConsumeVideoFrame(_, _)) | |
263 .WillOnce(SaveArg<0>(&video_frame)); | |
264 CallProduceVideoFrame(); | |
265 | |
266 EXPECT_FALSE(video_frame); | |
269 } | 267 } |
270 | 268 |
269 // Decode |i_frame_buffer_| and then a frame with a larger width and verify | |
270 // the output size didn't change. | |
271 TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_LargerWidth) { | 271 TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_LargerWidth) { |
272 Initialize(); | 272 DecodeIFrameThenTestFile("vp8-I-frame-640x240"); |
273 ChangeDimensions(kWidth * 2, kHeight); | |
274 Decode(); | |
275 } | 273 } |
276 | 274 |
275 // Decode |i_frame_buffer_| and then a frame with a smaller width and verify | |
276 // the output size didn't change. | |
277 TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_SmallerWidth) { | 277 TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_SmallerWidth) { |
278 Initialize(); | 278 DecodeIFrameThenTestFile("vp8-I-frame-160x240"); |
279 ChangeDimensions(kWidth / 2, kHeight); | |
280 Decode(); | |
281 } | 279 } |
282 | 280 |
281 // Decode |i_frame_buffer_| and then a frame with a larger height and verify | |
282 // the output size didn't change. | |
283 TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_LargerHeight) { | 283 TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_LargerHeight) { |
284 Initialize(); | 284 DecodeIFrameThenTestFile("vp8-I-frame-320x480"); |
285 ChangeDimensions(kWidth, kHeight * 2); | |
286 Decode(); | |
287 } | 285 } |
288 | 286 |
287 // Decode |i_frame_buffer_| and then a frame with a smaller height and verify | |
288 // the output size didn't change. | |
289 TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_SmallerHeight) { | 289 TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_SmallerHeight) { |
290 Initialize(); | 290 DecodeIFrameThenTestFile("vp8-I-frame-320x120"); |
291 ChangeDimensions(kWidth, kHeight / 2); | |
292 Decode(); | |
293 } | |
294 | |
295 TEST_F(FFmpegVideoDecodeEngineTest, GetSurfaceFormat) { | |
296 Initialize(); | |
297 | |
298 // YV12 formats. | |
299 codec_context_.pix_fmt = PIX_FMT_YUV420P; | |
300 EXPECT_EQ(VideoFrame::YV12, test_engine_->GetSurfaceFormat()); | |
301 codec_context_.pix_fmt = PIX_FMT_YUVJ420P; | |
302 EXPECT_EQ(VideoFrame::YV12, test_engine_->GetSurfaceFormat()); | |
303 | |
304 // YV16 formats. | |
305 codec_context_.pix_fmt = PIX_FMT_YUV422P; | |
306 EXPECT_EQ(VideoFrame::YV16, test_engine_->GetSurfaceFormat()); | |
307 codec_context_.pix_fmt = PIX_FMT_YUVJ422P; | |
308 EXPECT_EQ(VideoFrame::YV16, test_engine_->GetSurfaceFormat()); | |
309 | |
310 // Invalid value. | |
311 codec_context_.pix_fmt = PIX_FMT_NONE; | |
312 EXPECT_EQ(VideoFrame::INVALID, test_engine_->GetSurfaceFormat()); | |
313 } | 291 } |
314 | 292 |
315 } // namespace media | 293 } // namespace media |
OLD | NEW |