| 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 |