OLD | NEW |
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 #define _CRT_SECURE_NO_WARNINGS | 5 #define _CRT_SECURE_NO_WARNINGS |
6 | 6 |
7 #include <deque> | 7 #include <deque> |
8 | 8 |
9 #include "base/callback.h" | 9 #include "base/callback.h" |
10 #include "base/message_loop.h" | 10 #include "base/message_loop.h" |
| 11 #include "base/task.h" |
| 12 #include "media/base/buffers.h" |
11 #include "media/base/mock_filters.h" | 13 #include "media/base/mock_filters.h" |
| 14 #include "media/base/mock_task.h" |
| 15 #include "media/ffmpeg/ffmpeg_common.h" |
| 16 #include "media/filters/omx_video_decode_engine.h" |
| 17 #include "media/filters/video_decode_engine.h" |
12 #include "media/omx/mock_omx.h" | 18 #include "media/omx/mock_omx.h" |
13 #include "testing/gtest/include/gtest/gtest.h" | 19 #include "testing/gtest/include/gtest/gtest.h" |
14 | 20 |
15 using ::testing::_; | 21 using ::testing::_; |
16 using ::testing::DoAll; | 22 using ::testing::DoAll; |
17 using ::testing::InSequence; | 23 using ::testing::InSequence; |
18 using ::testing::IsNull; | 24 using ::testing::IsNull; |
19 using ::testing::NotNull; | 25 using ::testing::NotNull; |
20 using ::testing::Return; | 26 using ::testing::Return; |
21 using ::testing::SaveArg; | 27 using ::testing::SaveArg; |
22 using ::testing::SetArgumentPointee; | 28 using ::testing::SetArgumentPointee; |
23 using ::testing::StrEq; | 29 using ::testing::StrEq; |
24 using ::testing::StrictMock; | 30 using ::testing::StrictMock; |
25 | 31 |
26 // Temporarily disable omx_codec_unittests during heavy refactoring. | |
27 #if 0 | |
28 namespace { | 32 namespace { |
29 | 33 |
30 const int kBufferCount = 3; | 34 const int kBufferCount = 3; |
31 const int kBufferSize = 4096; | 35 const int kBufferSize = 4096; |
32 const char* kRoleName = "awsome"; | 36 const char* kComponentName = "OMX.google.video_decoder.avc"; |
33 const char* kComponentName = "OMX.google.mock.awsome"; | |
34 | 37 |
35 } // namespace | 38 } // namespace |
36 | 39 |
37 namespace media { | 40 namespace media { |
38 | |
39 ACTION(ReturnComponentName) { | 41 ACTION(ReturnComponentName) { |
40 strcpy(((char**)arg2)[0], kComponentName); | 42 strcpy(((char**)arg2)[0], kComponentName); |
41 } | 43 } |
42 | 44 |
43 ACTION(GetHandle) { | 45 ACTION(GetHandle) { |
44 *arg0 = MockOmx::get()->component(); | 46 *arg0 = MockOmx::get()->component(); |
45 MockOmx::get()->component()->pApplicationPrivate = arg2; | 47 MockOmx::get()->component()->pApplicationPrivate = arg2; |
46 memcpy(MockOmx::get()->callbacks(), arg3, sizeof(OMX_CALLBACKTYPE)); | 48 memcpy(MockOmx::get()->callbacks(), arg3, sizeof(OMX_CALLBACKTYPE)); |
47 } | 49 } |
48 | 50 |
49 ACTION(GetParameterVideoInit) { | 51 ACTION(GetParameterVideoInit) { |
50 ((OMX_PORT_PARAM_TYPE*)arg1)->nStartPortNumber = 0; | 52 ((OMX_PORT_PARAM_TYPE*)arg1)->nStartPortNumber = 0; |
51 } | 53 } |
52 | 54 |
53 ACTION(GetParameterPortDefinition) { | 55 ACTION(GetParameterPortDefinition) { |
54 OMX_PARAM_PORTDEFINITIONTYPE* port_format = | 56 OMX_PARAM_PORTDEFINITIONTYPE* port_format = |
55 (OMX_PARAM_PORTDEFINITIONTYPE*)arg1; | 57 (OMX_PARAM_PORTDEFINITIONTYPE*)arg1; |
56 CHECK(port_format->nPortIndex == 0 || port_format->nPortIndex == 1); | 58 CHECK(port_format->nPortIndex == 0 || port_format->nPortIndex == 1); |
57 if (port_format->nPortIndex == 0) | 59 if (port_format->nPortIndex == 0) |
58 port_format->eDir = OMX_DirInput; | 60 port_format->eDir = OMX_DirInput; |
59 else | 61 else |
60 port_format->eDir = OMX_DirOutput; | 62 port_format->eDir = OMX_DirOutput; |
61 port_format->nBufferCountMin = kBufferCount; | 63 port_format->nBufferCountMin = kBufferCount; |
| 64 port_format->nBufferCountActual = kBufferCount; |
62 port_format->nBufferSize = kBufferSize; | 65 port_format->nBufferSize = kBufferSize; |
63 } | 66 } |
64 | 67 |
65 ACTION(AllocateBuffer) { | 68 ACTION(AllocateBuffer) { |
66 *arg0 = new OMX_BUFFERHEADERTYPE(); | 69 *arg0 = new OMX_BUFFERHEADERTYPE(); |
67 memset(*arg0, 0, sizeof(OMX_BUFFERHEADERTYPE)); | 70 memset(*arg0, 0, sizeof(OMX_BUFFERHEADERTYPE)); |
68 (*arg0)->pBuffer = new uint8[kBufferSize]; | 71 (*arg0)->nAllocLen = arg3; |
| 72 (*arg0)->pBuffer = new uint8[arg3]; |
| 73 (*arg0)->nOutputPortIndex = 1; |
| 74 (*arg0)->nInputPortIndex = OMX_ALL; |
69 } | 75 } |
70 | 76 |
71 ACTION(UseBuffer) { | 77 ACTION(UseBuffer) { |
72 *arg0 = new OMX_BUFFERHEADERTYPE(); | 78 *arg0 = new OMX_BUFFERHEADERTYPE(); |
73 memset(*arg0, 0, sizeof(OMX_BUFFERHEADERTYPE)); | 79 memset(*arg0, 0, sizeof(OMX_BUFFERHEADERTYPE)); |
| 80 (*arg0)->nOutputPortIndex = OMX_ALL; |
| 81 (*arg0)->nInputPortIndex = 0; |
74 } | 82 } |
75 | 83 |
76 ACTION(FreeBuffer) { | 84 ACTION(FreeBuffer) { |
77 delete [] arg1->pBuffer; | 85 if (1 == arg1->nOutputPortIndex) |
| 86 delete [] arg1->pBuffer; |
78 delete arg1; | 87 delete arg1; |
79 } | 88 } |
80 | 89 |
81 ACTION_P2(SendEvent, event, data1) { | 90 ACTION_P3(SendEvent, event, data1, data2) { |
82 // TODO(hclam): pass data2 and event data. | |
83 (*MockOmx::get()->callbacks()->EventHandler)( | 91 (*MockOmx::get()->callbacks()->EventHandler)( |
84 MockOmx::get()->component(), | 92 MockOmx::get()->component(), |
85 MockOmx::get()->component()->pApplicationPrivate, | 93 MockOmx::get()->component()->pApplicationPrivate, |
86 event, static_cast<OMX_U32>(data1), 0, NULL); | 94 event, static_cast<OMX_U32>(data1), static_cast<OMX_U32>(data2), NULL); |
87 } | 95 } |
88 | 96 |
89 ACTION(FillBuffer) { | 97 ACTION_P(EmptyBufferDone, output_pool_ptr) { |
90 arg0->nFlags = 0; | 98 (*MockOmx::get()->callbacks()->EmptyBufferDone)( |
91 arg0->nFilledLen = kBufferSize; | 99 MockOmx::get()->component(), |
| 100 MockOmx::get()->component()->pApplicationPrivate, |
| 101 arg0); |
| 102 OMX_BUFFERHEADERTYPE* out_buffer = output_pool_ptr->front(); |
| 103 output_pool_ptr->pop_front(); |
| 104 if (arg0->nFlags & OMX_BUFFERFLAG_EOS) |
| 105 out_buffer->nFlags |= OMX_BUFFERFLAG_EOS; |
| 106 out_buffer->nFilledLen = kBufferSize; |
92 (*MockOmx::get()->callbacks()->FillBufferDone)( | 107 (*MockOmx::get()->callbacks()->FillBufferDone)( |
93 MockOmx::get()->component(), | 108 MockOmx::get()->component(), |
94 MockOmx::get()->component()->pApplicationPrivate, | 109 MockOmx::get()->component()->pApplicationPrivate, |
95 arg0); | 110 out_buffer); |
| 111 } |
| 112 |
| 113 ACTION_P(EnqueueOutputBuffer, output_pool_ptr) { |
| 114 output_pool_ptr->push_back(arg0); |
96 } | 115 } |
97 | 116 |
98 ACTION(FillEosBuffer) { | 117 ACTION(FillEosBuffer) { |
99 arg0->nFlags = OMX_BUFFERFLAG_EOS; | 118 arg0->nFlags = OMX_BUFFERFLAG_EOS; |
100 arg0->nFilledLen = 0; | 119 arg0->nFilledLen = 0; |
101 (*MockOmx::get()->callbacks()->FillBufferDone)( | 120 (*MockOmx::get()->callbacks()->FillBufferDone)( |
102 MockOmx::get()->component(), | 121 MockOmx::get()->component(), |
103 MockOmx::get()->component()->pApplicationPrivate, | 122 MockOmx::get()->component()->pApplicationPrivate, |
104 arg0); | 123 arg0); |
105 } | 124 } |
106 | 125 |
107 class MockOmxConfigurator : public OmxConfigurator { | 126 class TestBuffer : public media::Buffer { |
108 public: | 127 public: |
109 MockOmxConfigurator() | 128 TestBuffer() : size_(0), data_(NULL) { } |
110 : OmxConfigurator(MediaFormat(), MediaFormat()) {} | 129 explicit TestBuffer(int size) : size_(size) { |
| 130 if (size) |
| 131 data_.reset(new uint8[size]); |
| 132 else |
| 133 data_.reset(NULL); |
| 134 } |
| 135 virtual const uint8* GetData() const { |
| 136 return data_.get(); |
| 137 } |
| 138 virtual size_t GetDataSize() const { |
| 139 return size_; |
| 140 } |
| 141 private: |
| 142 virtual ~TestBuffer() { } |
111 | 143 |
112 MOCK_CONST_METHOD0(GetRoleName, std::string()); | 144 int size_; |
113 MOCK_CONST_METHOD3(ConfigureIOPorts, | 145 scoped_array<uint8> data_; |
114 bool(OMX_COMPONENTTYPE* component, | 146 DISALLOW_COPY_AND_ASSIGN(TestBuffer); |
115 OMX_PARAM_PORTDEFINITIONTYPE* input_fef, | |
116 OMX_PARAM_PORTDEFINITIONTYPE* output_def)); | |
117 }; | 147 }; |
118 | 148 |
119 class OmxCodecTest : public testing::Test { | 149 class OmxCodecTest : public testing::Test { |
120 public: | 150 public: |
121 OmxCodecTest () | 151 OmxCodecTest () |
122 : omx_codec_(new OmxCodec(&message_loop_)) { | 152 : got_eos_(false), |
123 omx_codec_->Setup(&mock_configurator_); | 153 omx_engine_(new OmxVideoDecodeEngine()) { |
| 154 av_stream_.codec = &av_codec_context_; |
| 155 av_codec_context_.width = 16; |
| 156 av_codec_context_.height = 16; |
| 157 feed_done_cb_ = |
| 158 NewCallback(this, &OmxCodecTest::EmptyBufferDoneCallback); |
| 159 decode_done_cb_ = |
| 160 NewCallback(this, &OmxCodecTest::FillBufferDoneCallback); |
124 } | 161 } |
125 | 162 |
126 ~OmxCodecTest() { | 163 ~OmxCodecTest() { |
127 CHECK(output_units_.size() == 0); | |
128 } | 164 } |
129 | 165 |
130 protected: | 166 protected: |
131 void ExpectSettings() { | 167 void ExpectSettings() { |
132 // Return the component name. | 168 // Return the component name. |
133 EXPECT_CALL(*MockOmx::get(), GetComponentsOfRole(_, _, IsNull())) | 169 EXPECT_CALL(*MockOmx::get(), GetComponentsOfRole(_, _, IsNull())) |
134 .WillOnce(DoAll(SetArgumentPointee<1>(1), | 170 .WillOnce(DoAll(SetArgumentPointee<1>(1), |
135 Return(OMX_ErrorNone))); | 171 Return(OMX_ErrorNone))); |
136 EXPECT_CALL(*MockOmx::get(), GetComponentsOfRole(_, _, NotNull())) | 172 EXPECT_CALL(*MockOmx::get(), GetComponentsOfRole(_, _, NotNull())) |
137 .WillOnce(DoAll(SetArgumentPointee<1>(1), | 173 .WillOnce(DoAll(SetArgumentPointee<1>(1), |
138 ReturnComponentName(), | 174 ReturnComponentName(), |
139 Return(OMX_ErrorNone))); | 175 Return(OMX_ErrorNone))); |
140 | 176 |
141 // Handle get parameter calls. | 177 // Handle get parameter calls. |
142 EXPECT_CALL(*MockOmx::get(), | 178 EXPECT_CALL(*MockOmx::get(), |
143 GetParameter(OMX_IndexParamVideoInit, NotNull())) | 179 GetParameter(OMX_IndexParamVideoInit, NotNull())) |
144 .WillRepeatedly(DoAll(GetParameterVideoInit(), Return(OMX_ErrorNone))); | 180 .WillRepeatedly(DoAll(GetParameterVideoInit(), Return(OMX_ErrorNone))); |
145 EXPECT_CALL(*MockOmx::get(), | 181 EXPECT_CALL(*MockOmx::get(), |
146 GetParameter(OMX_IndexParamPortDefinition, NotNull())) | 182 GetParameter(OMX_IndexParamPortDefinition, NotNull())) |
147 .WillRepeatedly(DoAll(GetParameterPortDefinition(), | 183 .WillRepeatedly(DoAll(GetParameterPortDefinition(), |
148 Return(OMX_ErrorNone))); | 184 Return(OMX_ErrorNone))); |
149 | 185 |
150 // Ignore all set parameter calls. | 186 // Ignore all set parameter calls. |
151 EXPECT_CALL(*MockOmx::get(), SetParameter(_, _)) | 187 EXPECT_CALL(*MockOmx::get(), SetParameter(_, _)) |
152 .WillRepeatedly(Return(OMX_ErrorNone)); | 188 .WillRepeatedly(Return(OMX_ErrorNone)); |
153 | |
154 // Expect calling to configurator once. | |
155 EXPECT_CALL(mock_configurator_, | |
156 ConfigureIOPorts(MockOmx::get()->component(), _, _)) | |
157 .WillOnce(Return(true)); | |
158 | |
159 EXPECT_CALL(mock_configurator_, GetRoleName()) | |
160 .WillRepeatedly(Return(kRoleName)); | |
161 } | 189 } |
162 | 190 |
163 void ExpectToLoaded() { | 191 void ExpectToLoaded() { |
164 InSequence s; | 192 InSequence s; |
165 | 193 |
166 // Expect initialization. | 194 // Expect initialization. |
167 EXPECT_CALL(*MockOmx::get(), Init()) | 195 EXPECT_CALL(*MockOmx::get(), Init()) |
168 .WillOnce(Return(OMX_ErrorNone)); | 196 .WillOnce(Return(OMX_ErrorNone)); |
169 | 197 |
170 // Return the handle. | 198 // Return the handle. |
171 EXPECT_CALL(*MockOmx::get(), | 199 EXPECT_CALL(*MockOmx::get(), |
172 GetHandle(NotNull(), StrEq(kComponentName), | 200 GetHandle(NotNull(), StrEq(kComponentName), |
173 NotNull(), NotNull())) | 201 NotNull(), NotNull())) |
174 .WillOnce(DoAll(GetHandle(), | 202 .WillOnce(DoAll(GetHandle(), |
175 Return(OMX_ErrorNone))); | 203 Return(OMX_ErrorNone))); |
176 } | 204 } |
177 | 205 |
178 void ExpectLoadedToIdle() { | 206 void ExpectLoadedToIdle() { |
179 InSequence s; | 207 InSequence s; |
180 | 208 |
181 // Expect transition to idle. | 209 // Expect transition to idle. |
182 EXPECT_CALL(*MockOmx::get(), | 210 EXPECT_CALL(*MockOmx::get(), |
183 SendCommand(OMX_CommandStateSet, OMX_StateIdle, _)) | 211 SendCommand(OMX_CommandStateSet, OMX_StateIdle, _)) |
184 .WillOnce( | 212 .WillOnce( |
185 DoAll( | 213 DoAll( |
186 SendEvent(OMX_EventCmdComplete, OMX_CommandStateSet), | 214 SendEvent(OMX_EventCmdComplete, OMX_CommandStateSet, |
| 215 OMX_StateIdle), |
187 Return(OMX_ErrorNone))); | 216 Return(OMX_ErrorNone))); |
188 | 217 |
189 // Expect allocation of buffers. | 218 // Expect allocation of buffers. |
190 EXPECT_CALL(*MockOmx::get(), | 219 EXPECT_CALL(*MockOmx::get(), |
191 UseBuffer(NotNull(), 0, IsNull(), kBufferSize, _)) | 220 UseBuffer(NotNull(), 0, NotNull(), kBufferSize, _)) |
192 .Times(kBufferCount) | 221 .Times(kBufferCount) |
193 .WillRepeatedly(DoAll(UseBuffer(), Return(OMX_ErrorNone))); | 222 .WillRepeatedly(DoAll(UseBuffer(), Return(OMX_ErrorNone))); |
194 | 223 |
195 // Expect allocation of output buffers and send command complete. | 224 // Expect allocation of output buffers and send command complete. |
196 EXPECT_CALL(*MockOmx::get(), | 225 EXPECT_CALL(*MockOmx::get(), |
197 AllocateBuffer(NotNull(), 1, IsNull(), kBufferSize)) | 226 AllocateBuffer(NotNull(), 1, IsNull(), kBufferSize)) |
198 .Times(kBufferCount) | 227 .Times(kBufferCount) |
199 .WillRepeatedly(DoAll(AllocateBuffer(), Return(OMX_ErrorNone))); | 228 .WillRepeatedly(DoAll(AllocateBuffer(), Return(OMX_ErrorNone))); |
200 } | 229 } |
201 | 230 |
202 void ExpectToExecuting() { | 231 void ExpectToExecuting() { |
203 InSequence s; | 232 InSequence s; |
204 | 233 |
205 // Expect transition to executing. | 234 // Expect transition to executing. |
206 EXPECT_CALL(*MockOmx::get(), | 235 EXPECT_CALL(*MockOmx::get(), |
207 SendCommand(OMX_CommandStateSet, OMX_StateExecuting, _)) | 236 SendCommand(OMX_CommandStateSet, OMX_StateExecuting, _)) |
208 .WillOnce(DoAll( | 237 .WillOnce(DoAll( |
209 SendEvent(OMX_EventCmdComplete, OMX_CommandStateSet), | 238 SendEvent(OMX_EventCmdComplete, OMX_CommandStateSet, |
| 239 OMX_StateExecuting), |
210 Return(OMX_ErrorNone))); | 240 Return(OMX_ErrorNone))); |
211 | 241 |
212 // Expect initial FillThisBuffer() calls. | 242 // Expect initial FillThisBuffer() calls. |
213 EXPECT_CALL(*MockOmx::get(), FillThisBuffer(NotNull())) | 243 EXPECT_CALL(*MockOmx::get(), FillThisBuffer(NotNull())) |
214 .Times(kBufferCount) | 244 .Times(kBufferCount) |
215 .WillRepeatedly(DoAll(FillBuffer(), Return(OMX_ErrorNone))); | 245 .WillRepeatedly(DoAll(EnqueueOutputBuffer(&output_pool_), |
| 246 Return(OMX_ErrorNone))); |
216 } | 247 } |
217 | 248 |
218 void ExpectToIdle() { | 249 void ExpectToIdle() { |
219 // Expect going to idle | 250 // Expect going to idle |
220 EXPECT_CALL(*MockOmx::get(), | 251 EXPECT_CALL(*MockOmx::get(), |
221 SendCommand(OMX_CommandStateSet, OMX_StateIdle, _)) | 252 SendCommand(OMX_CommandStateSet, OMX_StateIdle, _)) |
222 .WillOnce(DoAll( | 253 .WillOnce(DoAll( |
223 SendEvent(OMX_EventCmdComplete, OMX_CommandStateSet), | 254 SendEvent(OMX_EventCmdComplete, OMX_CommandStateSet, OMX_StateIdle), |
224 Return(OMX_ErrorNone))); | 255 Return(OMX_ErrorNone))); |
225 } | 256 } |
226 | 257 |
227 void ExpectIdleToLoaded() { | 258 void ExpectIdleToLoaded() { |
228 InSequence s; | 259 InSequence s; |
229 | 260 |
230 // Expect transition to loaded. | 261 // Expect transition to loaded. |
231 EXPECT_CALL(*MockOmx::get(), | 262 EXPECT_CALL(*MockOmx::get(), |
232 SendCommand(OMX_CommandStateSet, OMX_StateLoaded, _)) | 263 SendCommand(OMX_CommandStateSet, OMX_StateLoaded, _)) |
233 .WillOnce(DoAll( | 264 .WillOnce(DoAll( |
234 SendEvent(OMX_EventCmdComplete, OMX_CommandStateSet), | 265 SendEvent(OMX_EventCmdComplete, OMX_CommandStateSet, |
| 266 OMX_StateLoaded), |
235 Return(OMX_ErrorNone))); | 267 Return(OMX_ErrorNone))); |
236 | 268 |
237 // Expect free buffer for input port. | 269 // Expect free buffer for input port. |
238 EXPECT_CALL(*MockOmx::get(), FreeBuffer(0, NotNull())) | 270 EXPECT_CALL(*MockOmx::get(), FreeBuffer(0, NotNull())) |
239 .Times(kBufferCount) | 271 .Times(kBufferCount) |
240 .WillRepeatedly(DoAll(FreeBuffer(), Return(OMX_ErrorNone))); | 272 .WillRepeatedly(DoAll(FreeBuffer(), Return(OMX_ErrorNone))); |
241 | 273 |
242 EXPECT_CALL(*MockOmx::get(), FreeBuffer(1, NotNull())) | 274 EXPECT_CALL(*MockOmx::get(), FreeBuffer(1, NotNull())) |
243 .Times(kBufferCount) | 275 .Times(kBufferCount) |
244 .WillRepeatedly(DoAll(FreeBuffer(), Return(OMX_ErrorNone))); | 276 .WillRepeatedly(DoAll(FreeBuffer(), Return(OMX_ErrorNone))); |
245 } | 277 } |
246 | 278 |
247 void ExpectToEmpty() { | 279 void ExpectToEmpty() { |
248 InSequence s; | 280 InSequence s; |
249 | 281 |
250 EXPECT_CALL(*MockOmx::get(), FreeHandle(MockOmx::get()->component())) | 282 EXPECT_CALL(*MockOmx::get(), FreeHandle(MockOmx::get()->component())) |
251 .WillOnce(Return(OMX_ErrorNone)); | 283 .WillOnce(Return(OMX_ErrorNone)); |
252 EXPECT_CALL(*MockOmx::get(), Deinit()) | 284 EXPECT_CALL(*MockOmx::get(), Deinit()) |
253 .WillOnce(Return(OMX_ErrorNone)); | 285 .WillOnce(Return(OMX_ErrorNone)); |
254 } | 286 } |
255 | 287 |
256 // TODO(hclam): Make a more generic about when to stop. | 288 // TODO(hclam): Make a more generic about when to stop. |
257 void ExpectStart() { | 289 void ExpectStart() { |
258 ExpectToLoaded(); | 290 ExpectToLoaded(); |
259 ExpectLoadedToIdle(); | 291 ExpectLoadedToIdle(); |
260 ExpectToExecuting(); | 292 ExpectToExecuting(); |
| 293 EXPECT_CALL(init_done_cb_task_, Run()); |
261 } | 294 } |
262 | 295 |
263 void ExpectStop() { | 296 void ExpectStop() { |
| 297 EXPECT_CALL(stop_callback_, OnFilterCallback()); |
| 298 EXPECT_CALL(stop_callback_, OnCallbackDestroyed()); |
264 ExpectToIdle(); | 299 ExpectToIdle(); |
265 ExpectIdleToLoaded(); | 300 ExpectIdleToLoaded(); |
266 ExpectToEmpty(); | 301 ExpectToEmpty(); |
267 } | 302 } |
268 | 303 |
269 void ReadCallback(OMX_BUFFERHEADERTYPE* buffer) { | 304 void EmptyBufferDoneCallback(scoped_refptr<Buffer> buffer) { |
270 output_units_.push_back(buffer); | 305 input_units_.push_back(buffer); |
271 } | 306 } |
272 | 307 |
273 void MakeReadRequest() { | 308 void FillBufferDoneCallback(scoped_refptr<VideoFrame> frame) { |
274 omx_codec_->Read(NewCallback(this, &OmxCodecTest::ReadCallback)); | 309 output_units_.push_back(frame); |
| 310 if (frame.get() == NULL) |
| 311 got_eos_ = true; |
275 } | 312 } |
276 | 313 |
277 void SaveFillThisBuffer(OMX_BUFFERHEADERTYPE* buffer) { | 314 void InitializeInputBuffers(int count) { |
278 fill_this_buffer_received_.push_back(buffer); | 315 for (int i = 0; i < count; ++i) { |
| 316 scoped_refptr<Buffer> buffer_ref = new TestBuffer(i + 1); |
| 317 input_units_.push_back(buffer_ref); |
| 318 } |
279 } | 319 } |
280 | 320 |
281 void ExpectAndSaveFillThisBuffer() { | 321 void MakeEmptyBufferRequest() { |
282 EXPECT_CALL(*MockOmx::get(), FillThisBuffer(NotNull())) | 322 scoped_refptr<Buffer> buffer = input_units_.front(); |
283 .WillOnce(DoAll(Invoke(this, &OmxCodecTest::SaveFillThisBuffer), | 323 input_units_.pop_front(); |
284 Return(OMX_ErrorNone))) | 324 omx_engine_->EmptyThisBuffer(buffer); |
285 .RetiresOnSaturation(); | |
286 } | 325 } |
287 | 326 |
288 std::deque<OMX_BUFFERHEADERTYPE*> output_units_; | 327 void SendEOSInputBuffer() { |
| 328 input_units_.pop_front(); |
| 329 scoped_refptr<Buffer> buffer_ref = new TestBuffer(); |
| 330 input_units_.push_front(buffer_ref); |
| 331 EXPECT_CALL(*MockOmx::get(), EmptyThisBuffer(NotNull())) |
| 332 .WillOnce(DoAll(EmptyBufferDone(&output_pool_), Return(OMX_ErrorNone))) |
| 333 .RetiresOnSaturation(); |
| 334 MakeEmptyBufferRequest(); |
| 335 message_loop_.RunAllPending(); |
| 336 } |
| 337 |
| 338 std::deque<scoped_refptr<Buffer> > input_units_; |
| 339 std::deque<scoped_refptr<VideoFrame> > output_units_; |
289 std::deque<OMX_BUFFERHEADERTYPE*> fill_this_buffer_received_; | 340 std::deque<OMX_BUFFERHEADERTYPE*> fill_this_buffer_received_; |
| 341 std::deque<OMX_BUFFERHEADERTYPE*> output_pool_; |
290 | 342 |
291 MockOmx mock_omx_; | 343 MockOmx mock_omx_; |
292 MockOmxConfigurator mock_configurator_; | |
293 | 344 |
| 345 bool got_eos_; |
294 MessageLoop message_loop_; | 346 MessageLoop message_loop_; |
295 scoped_refptr<OmxCodec> omx_codec_; | 347 scoped_refptr<OmxVideoDecodeEngine> omx_engine_; |
| 348 |
| 349 AVStream av_stream_; |
| 350 AVCodecContext av_codec_context_; |
| 351 |
| 352 VideoDecodeEngine::EmptyThisBufferCallback* feed_done_cb_; |
| 353 VideoDecodeEngine::FillThisBufferCallback* decode_done_cb_; |
| 354 TaskMocker init_done_cb_task_; |
296 | 355 |
297 MockFilterCallback stop_callback_; | 356 MockFilterCallback stop_callback_; |
298 | 357 |
299 private: | 358 private: |
300 DISALLOW_COPY_AND_ASSIGN(OmxCodecTest); | 359 DISALLOW_COPY_AND_ASSIGN(OmxCodecTest); |
301 }; | 360 }; |
302 | 361 |
303 TEST_F(OmxCodecTest, SimpleStartAndStop) { | 362 TEST_F(OmxCodecTest, SimpleStartAndStop) { |
304 ExpectSettings(); | 363 ExpectSettings(); |
305 ExpectStart(); | 364 ExpectStart(); |
306 omx_codec_->Start(); | 365 omx_engine_->Initialize(&message_loop_, |
| 366 &av_stream_, |
| 367 feed_done_cb_, |
| 368 decode_done_cb_, |
| 369 init_done_cb_task_.CreateTask()); |
307 message_loop_.RunAllPending(); | 370 message_loop_.RunAllPending(); |
308 | 371 |
309 EXPECT_CALL(stop_callback_, OnFilterCallback()); | 372 EXPECT_EQ(VideoDecodeEngine::kNormal, omx_engine_->state()); |
310 EXPECT_CALL(stop_callback_, OnCallbackDestroyed()); | 373 |
311 ExpectStop(); | 374 ExpectStop(); |
312 omx_codec_->Stop(stop_callback_.NewCallback()); | 375 omx_engine_->Stop(stop_callback_.NewCallback()); |
313 message_loop_.RunAllPending(); | 376 message_loop_.RunAllPending(); |
314 } | 377 } |
315 | 378 |
316 TEST_F(OmxCodecTest, EndOfStream) { | 379 TEST_F(OmxCodecTest, NormalFlow) { |
317 ExpectSettings(); | 380 ExpectSettings(); |
318 ExpectStart(); | 381 ExpectStart(); |
319 omx_codec_->Start(); | 382 omx_engine_->Initialize(&message_loop_, |
| 383 &av_stream_, |
| 384 feed_done_cb_, |
| 385 decode_done_cb_, |
| 386 init_done_cb_task_.CreateTask()); |
320 message_loop_.RunAllPending(); | 387 message_loop_.RunAllPending(); |
321 | 388 |
322 // Make read requests, OmxCodec should have gotten kBufferCount | 389 EXPECT_EQ(VideoDecodeEngine::kNormal, omx_engine_->state()); |
323 // buffers already. | 390 |
| 391 // Allocate bitstream buffers. |
| 392 InitializeInputBuffers(kBufferCount); |
| 393 |
| 394 // Make emptybuffer requests. |
324 EXPECT_EQ(0u, output_units_.size()); | 395 EXPECT_EQ(0u, output_units_.size()); |
| 396 int count = output_pool_.size(); |
325 for (int i = 0; i < kBufferCount; ++i) { | 397 for (int i = 0; i < kBufferCount; ++i) { |
326 // Give buffers back to OmxCodec. OmxCodec will make a new | 398 // Give input buffers to OmxVideoDecodeEngine. OmxVideoDecodeEngine will |
327 // FillThisBuffer() call for each read. | 399 // make a new FillThisBuffer() call for each read. |
| 400 EXPECT_CALL(*MockOmx::get(), EmptyThisBuffer(NotNull())) |
| 401 .WillOnce(DoAll(EmptyBufferDone(&output_pool_), Return(OMX_ErrorNone))) |
| 402 .RetiresOnSaturation(); |
328 EXPECT_CALL(*MockOmx::get(), FillThisBuffer(NotNull())) | 403 EXPECT_CALL(*MockOmx::get(), FillThisBuffer(NotNull())) |
329 .WillOnce(DoAll(FillEosBuffer(), Return(OMX_ErrorNone))) | 404 .WillOnce(DoAll(EnqueueOutputBuffer(&output_pool_), |
| 405 Return(OMX_ErrorNone))) |
330 .RetiresOnSaturation(); | 406 .RetiresOnSaturation(); |
331 MakeReadRequest(); | 407 MakeEmptyBufferRequest(); |
332 } | 408 } |
333 message_loop_.RunAllPending(); | 409 message_loop_.RunAllPending(); |
334 CHECK(kBufferCount == static_cast<int>(output_units_.size())); | 410 EXPECT_EQ(kBufferCount, static_cast<int>(input_units_.size())); |
335 | 411 EXPECT_EQ(kBufferCount, static_cast<int>(output_units_.size())); |
336 // Make sure buffers received are in order. | 412 EXPECT_EQ(count, static_cast<int>(output_pool_.size())); |
337 for (int i = 0; i < kBufferCount; ++i) { | |
338 // TODO(jiesun): How to verify this now? | |
339 // EXPECT_EQ(i, output_units_[i].first); | |
340 EXPECT_TRUE(output_units_[i] != NULL); | |
341 } | |
342 | |
343 output_units_.clear(); | 413 output_units_.clear(); |
344 | 414 |
345 // Make some read requests and make sure end-of-stream buffer id | 415 // Send EndOfStream, expect eos flag. |
346 // are received. | 416 SendEOSInputBuffer(); |
347 EXPECT_EQ(0u, output_units_.size()); | 417 EXPECT_EQ(kBufferCount, static_cast<int>(input_units_.size())); |
348 for (int i = 0; i < 2 * kBufferCount; ++i) { | 418 EXPECT_EQ(1, static_cast<int>(output_units_.size())); |
349 MakeReadRequest(); | 419 EXPECT_EQ(count-1, static_cast<int>(output_pool_.size())); |
350 } | 420 EXPECT_EQ(true, got_eos_); |
351 message_loop_.RunAllPending(); | |
352 EXPECT_EQ(2 * kBufferCount, static_cast<int>(output_units_.size())); | |
353 | 421 |
354 for (size_t i = 0; i <output_units_.size(); ++i) { | 422 // Shutdown. |
355 EXPECT_EQ(NULL, output_units_[i]); | |
356 } | |
357 output_units_.clear(); | |
358 | |
359 // Stop OmxCodec. | |
360 EXPECT_CALL(stop_callback_, OnFilterCallback()); | |
361 EXPECT_CALL(stop_callback_, OnCallbackDestroyed()); | |
362 ExpectStop(); | 423 ExpectStop(); |
363 omx_codec_->Stop(stop_callback_.NewCallback()); | 424 omx_engine_->Stop(stop_callback_.NewCallback()); |
364 message_loop_.RunAllPending(); | 425 message_loop_.RunAllPending(); |
365 } | 426 } |
366 | 427 |
367 TEST_F(OmxCodecTest, OutputFlowControl) { | 428 TEST_F(OmxCodecTest, RecycleInputBuffers) { |
368 ExpectSettings(); | 429 ExpectSettings(); |
369 ExpectStart(); | 430 ExpectStart(); |
370 omx_codec_->Start(); | 431 omx_engine_->Initialize(&message_loop_, |
| 432 &av_stream_, |
| 433 feed_done_cb_, |
| 434 decode_done_cb_, |
| 435 init_done_cb_task_.CreateTask()); |
371 message_loop_.RunAllPending(); | 436 message_loop_.RunAllPending(); |
372 | 437 |
373 // Since initial FillThisBuffer() calls are made and fulfilled during | 438 EXPECT_EQ(VideoDecodeEngine::kNormal, omx_engine_->state()); |
374 // start. Reads issued to OmxCodec will be fulfilled now. | 439 |
| 440 // Allocate bitstream buffers. |
| 441 InitializeInputBuffers(kBufferCount); |
| 442 |
| 443 // Make emptybuffer requests, also recycle input buffers |
375 EXPECT_EQ(0u, output_units_.size()); | 444 EXPECT_EQ(0u, output_units_.size()); |
376 for (int i = 0; i < kBufferCount; ++i) { | 445 int count = output_pool_.size(); |
377 ExpectAndSaveFillThisBuffer(); | 446 int repeat_count = kBufferCount * 2; |
378 MakeReadRequest(); | 447 for (int i = 0; i < repeat_count; ++i) { |
| 448 // Give input buffers to OmxVideoDecodeEngine. OmxVideoDecodeEngine will |
| 449 // make a new FillThisBuffer() call for each read. |
| 450 EXPECT_CALL(*MockOmx::get(), EmptyThisBuffer(NotNull())) |
| 451 .WillOnce(DoAll(EmptyBufferDone(&output_pool_), Return(OMX_ErrorNone))) |
| 452 .RetiresOnSaturation(); |
| 453 EXPECT_CALL(*MockOmx::get(), FillThisBuffer(NotNull())) |
| 454 .WillOnce(DoAll(EnqueueOutputBuffer(&output_pool_), |
| 455 Return(OMX_ErrorNone))) |
| 456 .RetiresOnSaturation(); |
| 457 MakeEmptyBufferRequest(); |
| 458 message_loop_.RunAllPending(); |
| 459 CHECK(kBufferCount == static_cast<int>(input_units_.size())); |
| 460 CHECK(((i % kBufferCount) + 1) == |
| 461 static_cast<int>(input_units_.back()->GetDataSize())); |
379 } | 462 } |
380 message_loop_.RunAllPending(); | 463 message_loop_.RunAllPending(); |
381 CHECK(kBufferCount == static_cast<int>(output_units_.size())); | 464 EXPECT_EQ(kBufferCount, static_cast<int>(input_units_.size())); |
382 | 465 EXPECT_EQ(repeat_count, static_cast<int>(output_units_.size())); |
383 // Make sure buffers received are in order. | 466 EXPECT_EQ(count, static_cast<int>(output_pool_.size())); |
384 for (int i = 0; i < kBufferCount; ++i) { | |
385 EXPECT_TRUE(output_units_[i] != NULL); | |
386 } | |
387 | |
388 output_units_.clear(); | 467 output_units_.clear(); |
389 | 468 |
390 // In each loop, perform the following actions: | 469 // Send EndOfStream, expect eos flag. |
391 // 1. Make a read request to OmxCodec. | 470 SendEOSInputBuffer(); |
392 // 2. Fake a response for FillBufferDone(). | 471 EXPECT_EQ(kBufferCount, static_cast<int>(input_units_.size())); |
393 // 3. Expect read response received. | 472 EXPECT_EQ(1, static_cast<int>(output_units_.size())); |
394 // 4. NULL buffer is returned in first time | 473 EXPECT_EQ(count-1, static_cast<int>(output_pool_.size())); |
395 for (int i = 0; i < kBufferCount + 1; ++i) { | 474 EXPECT_EQ(true, got_eos_); |
396 // 1. First make a read request. | |
397 // Since a buffer is given back to OmxCodec component after first time, | |
398 // a FillThisBuffer() is called to OmxCodec component. | |
399 if (i > 0) { | |
400 EXPECT_CALL(*MockOmx::get(), FillThisBuffer(NotNull())) | |
401 .WillOnce(Return(OMX_ErrorNone)) | |
402 .RetiresOnSaturation(); | |
403 } | |
404 MakeReadRequest(); | |
405 | 475 |
406 // 2. Then fake a response from OpenMAX, only |kBufferCount| times | 476 // Shutdown. |
407 if (i < kBufferCount) { | |
408 OMX_BUFFERHEADERTYPE* buffer = fill_this_buffer_received_.front(); | |
409 fill_this_buffer_received_.pop_front(); | |
410 buffer->nFlags = 0; | |
411 buffer->nFilledLen = kBufferSize; | |
412 (*MockOmx::get()->callbacks()->FillBufferDone)( | |
413 MockOmx::get()->component(), | |
414 MockOmx::get()->component()->pApplicationPrivate, | |
415 buffer); | |
416 } | |
417 | |
418 // Make sure actions are completed. | |
419 message_loop_.RunAllPending(); | |
420 | |
421 // 3. Expect read response received. | |
422 // The above action will cause a read callback be called and we should | |
423 // receive one buffer now. Also expect the buffer id be received in | |
424 // reverse order. | |
425 EXPECT_EQ(1u, output_units_.size()); | |
426 //EXPECT_EQ(kBufferCount - i - 1, output_units_.front().first); | |
427 | |
428 output_units_.pop_front(); | |
429 | |
430 // Make sure actions are completed. | |
431 message_loop_.RunAllPending(); | |
432 } | |
433 | |
434 // Now issue kBufferCount reads to OmxCodec. | |
435 EXPECT_EQ(0u, output_units_.size()); | |
436 | |
437 // Stop OmxCodec. | |
438 EXPECT_CALL(stop_callback_, OnFilterCallback()); | |
439 EXPECT_CALL(stop_callback_, OnCallbackDestroyed()); | |
440 ExpectStop(); | 477 ExpectStop(); |
441 omx_codec_->Stop(stop_callback_.NewCallback()); | 478 omx_engine_->Stop(stop_callback_.NewCallback()); |
442 message_loop_.RunAllPending(); | 479 message_loop_.RunAllPending(); |
443 } | 480 } |
444 | 481 |
445 // TODO(hclam): Add test case for dynamic port config. | 482 // TODO(hclam): Add test case for dynamic port config. |
446 // TODO(hclam): Create a more complicated test case so that read | 483 // TODO(hclam): Create a more complicated test case so that read |
447 // requests and reply from FillThisBuffer() arrives out of order. | 484 // requests and reply from FillThisBuffer() arrives out of order. |
448 // TODO(hclam): Add test case for Feed(). | |
449 | 485 |
450 } // namespace media | 486 } // namespace media |
451 | |
452 #endif | |
OLD | NEW |