OmxPromiseLayer.cpp (12115B)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim:set ts=2 sw=2 sts=2 et cindent: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "OmxPromiseLayer.h" 8 9 #include "ImageContainer.h" 10 #include "OmxDataDecoder.h" 11 #include "OmxPlatformLayer.h" 12 13 #ifdef LOG 14 # undef LOG 15 #endif 16 17 #define LOG(arg, ...) \ 18 MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, \ 19 ("OmxPromiseLayer(%p)::%s: " arg, this, __func__, ##__VA_ARGS__)) 20 21 namespace mozilla { 22 23 OmxPromiseLayer::OmxPromiseLayer(TaskQueue* aTaskQueue, 24 OmxDataDecoder* aDataDecoder, 25 layers::ImageContainer* aImageContainer) 26 : mTaskQueue(aTaskQueue) { 27 mPlatformLayer.reset(OmxPlatformLayer::Create(aDataDecoder, this, aTaskQueue, 28 aImageContainer)); 29 MOZ_ASSERT(!!mPlatformLayer); 30 } 31 32 RefPtr<OmxPromiseLayer::OmxCommandPromise> OmxPromiseLayer::Init( 33 const TrackInfo* aInfo) { 34 MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn()); 35 36 OMX_ERRORTYPE err = mPlatformLayer->InitOmxToStateLoaded(aInfo); 37 if (err != OMX_ErrorNone) { 38 OmxCommandFailureHolder failure(OMX_ErrorUndefined, OMX_CommandStateSet); 39 return OmxCommandPromise::CreateAndReject(failure, __func__); 40 } 41 42 OMX_STATETYPE state = GetState(); 43 if (state == OMX_StateLoaded) { 44 return OmxCommandPromise::CreateAndResolve(OMX_CommandStateSet, __func__); 45 } 46 if (state == OMX_StateIdle) { 47 return SendCommand(OMX_CommandStateSet, OMX_StateIdle, nullptr); 48 } 49 50 OmxCommandFailureHolder failure(OMX_ErrorUndefined, OMX_CommandStateSet); 51 return OmxCommandPromise::CreateAndReject(failure, __func__); 52 } 53 54 OMX_ERRORTYPE 55 OmxPromiseLayer::Config() { 56 MOZ_ASSERT(GetState() == OMX_StateLoaded); 57 58 return mPlatformLayer->Config(); 59 } 60 61 RefPtr<OmxPromiseLayer::OmxBufferPromise> OmxPromiseLayer::FillBuffer( 62 BufferData* aData) { 63 MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn()); 64 LOG("buffer %p", aData->mBuffer); 65 66 RefPtr<OmxBufferPromise> p = aData->mPromise.Ensure(__func__); 67 68 OMX_ERRORTYPE err = mPlatformLayer->FillThisBuffer(aData); 69 70 if (err != OMX_ErrorNone) { 71 OmxBufferFailureHolder failure(err, aData); 72 aData->mPromise.Reject(std::move(failure), __func__); 73 } else { 74 aData->mStatus = BufferData::BufferStatus::OMX_COMPONENT; 75 GetBufferHolders(OMX_DirOutput)->AppendElement(aData); 76 } 77 78 return p; 79 } 80 81 RefPtr<OmxPromiseLayer::OmxBufferPromise> OmxPromiseLayer::EmptyBuffer( 82 BufferData* aData) { 83 MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn()); 84 LOG("buffer %p, size %lu", aData->mBuffer, aData->mBuffer->nFilledLen); 85 86 RefPtr<OmxBufferPromise> p = aData->mPromise.Ensure(__func__); 87 88 OMX_ERRORTYPE err = mPlatformLayer->EmptyThisBuffer(aData); 89 90 if (err != OMX_ErrorNone) { 91 OmxBufferFailureHolder failure(err, aData); 92 aData->mPromise.Reject(std::move(failure), __func__); 93 } else { 94 if (aData->mRawData) { 95 mRawDatas.AppendElement(std::move(aData->mRawData)); 96 } 97 aData->mStatus = BufferData::BufferStatus::OMX_COMPONENT; 98 GetBufferHolders(OMX_DirInput)->AppendElement(aData); 99 } 100 101 return p; 102 } 103 104 OmxPromiseLayer::BUFFERLIST* OmxPromiseLayer::GetBufferHolders( 105 OMX_DIRTYPE aType) { 106 MOZ_ASSERT(aType == OMX_DirInput || aType == OMX_DirOutput); 107 108 if (aType == OMX_DirInput) { 109 return &mInbufferHolders; 110 } 111 112 return &mOutbufferHolders; 113 } 114 115 already_AddRefed<MediaRawData> OmxPromiseLayer::FindAndRemoveRawData( 116 OMX_TICKS aTimecode) { 117 for (auto raw : mRawDatas) { 118 if (raw->mTime.ToMicroseconds() == aTimecode) { 119 mRawDatas.RemoveElement(raw); 120 return raw.forget(); 121 } 122 } 123 return nullptr; 124 } 125 126 already_AddRefed<BufferData> OmxPromiseLayer::FindAndRemoveBufferHolder( 127 OMX_DIRTYPE aType, BufferData::BufferID aId) { 128 MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn()); 129 130 RefPtr<BufferData> holder; 131 BUFFERLIST* holders = GetBufferHolders(aType); 132 133 for (uint32_t i = 0; i < holders->Length(); i++) { 134 if (holders->ElementAt(i)->ID() == aId) { 135 holder = holders->ElementAt(i); 136 holders->RemoveElementAt(i); 137 return holder.forget(); 138 } 139 } 140 141 return nullptr; 142 } 143 144 already_AddRefed<BufferData> OmxPromiseLayer::FindBufferById( 145 OMX_DIRTYPE aType, BufferData::BufferID aId) { 146 MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn()); 147 148 RefPtr<BufferData> holder; 149 BUFFERLIST* holders = GetBufferHolders(aType); 150 151 for (uint32_t i = 0; i < holders->Length(); i++) { 152 if (holders->ElementAt(i)->ID() == aId) { 153 holder = holders->ElementAt(i); 154 return holder.forget(); 155 } 156 } 157 158 return nullptr; 159 } 160 161 void OmxPromiseLayer::EmptyFillBufferDone(OMX_DIRTYPE aType, 162 BufferData* aData) { 163 if (aData) { 164 LOG("type %d, buffer %p", aType, aData->mBuffer); 165 if (aType == OMX_DirOutput) { 166 aData->mRawData = nullptr; 167 aData->mRawData = FindAndRemoveRawData(aData->mBuffer->nTimeStamp); 168 } 169 aData->mStatus = BufferData::BufferStatus::OMX_CLIENT; 170 aData->mPromise.Resolve(aData, __func__); 171 } else { 172 LOG("type %d, no buffer", aType); 173 } 174 } 175 176 void OmxPromiseLayer::EmptyFillBufferDone(OMX_DIRTYPE aType, 177 BufferData::BufferID aID) { 178 RefPtr<BufferData> holder = FindAndRemoveBufferHolder(aType, aID); 179 EmptyFillBufferDone(aType, holder); 180 } 181 182 RefPtr<OmxPromiseLayer::OmxCommandPromise> OmxPromiseLayer::SendCommand( 183 OMX_COMMANDTYPE aCmd, OMX_U32 aParam1, OMX_PTR aCmdData) { 184 if (aCmd == OMX_CommandFlush) { 185 // It doesn't support another flush commands before previous one is 186 // completed. 187 MOZ_RELEASE_ASSERT(!mFlushCommands.Length()); 188 189 // Some coomponents don't send event with OMX_ALL, they send flush complete 190 // event with input port and another event for output port. 191 // In prupose of better compatibility, we interpret the OMX_ALL to 192 // OMX_DirInput and OMX_DirOutput flush separately. 193 OMX_DIRTYPE types[] = {OMX_DIRTYPE::OMX_DirInput, 194 OMX_DIRTYPE::OMX_DirOutput}; 195 for (const auto type : types) { 196 if ((aParam1 == type) || (aParam1 == OMX_ALL)) { 197 mFlushCommands.AppendElement(FlushCommand({type, aCmdData})); 198 } 199 200 if (type == OMX_DirInput) { 201 // Clear all buffered raw data. 202 mRawDatas.Clear(); 203 } 204 } 205 206 // Don't overlay more than one flush command, some components can't overlay 207 // flush commands. So here we send another flush after receiving the 208 // previous flush completed event. 209 if (mFlushCommands.Length()) { 210 OMX_ERRORTYPE err = mPlatformLayer->SendCommand( 211 OMX_CommandFlush, mFlushCommands.ElementAt(0).type, 212 mFlushCommands.ElementAt(0).cmd); 213 if (err != OMX_ErrorNone) { 214 OmxCommandFailureHolder failure(OMX_ErrorNotReady, OMX_CommandFlush); 215 return OmxCommandPromise::CreateAndReject(failure, __func__); 216 } 217 } else { 218 LOG("OMX_CommandFlush parameter error"); 219 OmxCommandFailureHolder failure(OMX_ErrorNotReady, OMX_CommandFlush); 220 return OmxCommandPromise::CreateAndReject(failure, __func__); 221 } 222 } else { 223 OMX_ERRORTYPE err = mPlatformLayer->SendCommand(aCmd, aParam1, aCmdData); 224 if (err != OMX_ErrorNone) { 225 OmxCommandFailureHolder failure(OMX_ErrorNotReady, aCmd); 226 return OmxCommandPromise::CreateAndReject(failure, __func__); 227 } 228 } 229 230 RefPtr<OmxCommandPromise> p; 231 if (aCmd == OMX_CommandStateSet) { 232 p = mCommandStatePromise.Ensure(__func__); 233 } else if (aCmd == OMX_CommandFlush) { 234 p = mFlushPromise.Ensure(__func__); 235 } else if (aCmd == OMX_CommandPortEnable) { 236 p = mPortEnablePromise.Ensure(__func__); 237 } else if (aCmd == OMX_CommandPortDisable) { 238 p = mPortDisablePromise.Ensure(__func__); 239 } else { 240 LOG("error unsupport command"); 241 MOZ_ASSERT(0); 242 } 243 244 return p; 245 } 246 247 bool OmxPromiseLayer::Event(OMX_EVENTTYPE aEvent, OMX_U32 aData1, 248 OMX_U32 aData2) { 249 OMX_COMMANDTYPE cmd = (OMX_COMMANDTYPE)aData1; 250 switch (aEvent) { 251 case OMX_EventCmdComplete: { 252 if (cmd == OMX_CommandStateSet) { 253 mCommandStatePromise.Resolve(OMX_CommandStateSet, __func__); 254 } else if (cmd == OMX_CommandFlush) { 255 MOZ_RELEASE_ASSERT(mFlushCommands.ElementAt(0).type == aData2); 256 LOG("OMX_CommandFlush completed port type %lu", aData2); 257 mFlushCommands.RemoveElementAt(0); 258 259 // Sending next flush command. 260 if (mFlushCommands.Length()) { 261 OMX_ERRORTYPE err = mPlatformLayer->SendCommand( 262 OMX_CommandFlush, mFlushCommands.ElementAt(0).type, 263 mFlushCommands.ElementAt(0).cmd); 264 if (err != OMX_ErrorNone) { 265 OmxCommandFailureHolder failure(OMX_ErrorNotReady, 266 OMX_CommandFlush); 267 mFlushPromise.Reject(failure, __func__); 268 } 269 } else { 270 mFlushPromise.Resolve(OMX_CommandFlush, __func__); 271 } 272 } else if (cmd == OMX_CommandPortDisable) { 273 mPortDisablePromise.Resolve(OMX_CommandPortDisable, __func__); 274 } else if (cmd == OMX_CommandPortEnable) { 275 mPortEnablePromise.Resolve(OMX_CommandPortEnable, __func__); 276 } 277 break; 278 } 279 case OMX_EventError: { 280 if (cmd == OMX_CommandStateSet) { 281 OmxCommandFailureHolder failure(OMX_ErrorUndefined, 282 OMX_CommandStateSet); 283 mCommandStatePromise.Reject(failure, __func__); 284 } else if (cmd == OMX_CommandFlush) { 285 OmxCommandFailureHolder failure(OMX_ErrorUndefined, OMX_CommandFlush); 286 mFlushPromise.Reject(failure, __func__); 287 } else if (cmd == OMX_CommandPortDisable) { 288 OmxCommandFailureHolder failure(OMX_ErrorUndefined, 289 OMX_CommandPortDisable); 290 mPortDisablePromise.Reject(failure, __func__); 291 } else if (cmd == OMX_CommandPortEnable) { 292 OmxCommandFailureHolder failure(OMX_ErrorUndefined, 293 OMX_CommandPortEnable); 294 mPortEnablePromise.Reject(failure, __func__); 295 } else { 296 return false; 297 } 298 break; 299 } 300 default: { 301 return false; 302 } 303 } 304 return true; 305 } 306 307 nsresult OmxPromiseLayer::AllocateOmxBuffer(OMX_DIRTYPE aType, 308 BUFFERLIST* aBuffers) { 309 return mPlatformLayer->AllocateOmxBuffer(aType, aBuffers); 310 } 311 312 nsresult OmxPromiseLayer::ReleaseOmxBuffer(OMX_DIRTYPE aType, 313 BUFFERLIST* aBuffers) { 314 return mPlatformLayer->ReleaseOmxBuffer(aType, aBuffers); 315 } 316 317 OMX_STATETYPE 318 OmxPromiseLayer::GetState() { 319 OMX_STATETYPE state; 320 OMX_ERRORTYPE err = mPlatformLayer->GetState(&state); 321 return err == OMX_ErrorNone ? state : OMX_StateInvalid; 322 } 323 324 OMX_ERRORTYPE 325 OmxPromiseLayer::GetParameter(OMX_INDEXTYPE aParamIndex, 326 OMX_PTR aComponentParameterStructure, 327 OMX_U32 aComponentParameterSize) { 328 return mPlatformLayer->GetParameter(aParamIndex, aComponentParameterStructure, 329 aComponentParameterSize); 330 } 331 332 OMX_ERRORTYPE 333 OmxPromiseLayer::SetParameter(OMX_INDEXTYPE aParamIndex, 334 OMX_PTR aComponentParameterStructure, 335 OMX_U32 aComponentParameterSize) { 336 return mPlatformLayer->SetParameter(aParamIndex, aComponentParameterStructure, 337 aComponentParameterSize); 338 } 339 340 OMX_U32 341 OmxPromiseLayer::InputPortIndex() { return mPlatformLayer->InputPortIndex(); } 342 343 OMX_U32 344 OmxPromiseLayer::OutputPortIndex() { return mPlatformLayer->OutputPortIndex(); } 345 346 nsresult OmxPromiseLayer::Shutdown() { 347 LOG(""); 348 MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn()); 349 MOZ_ASSERT(!GetBufferHolders(OMX_DirInput)->Length()); 350 MOZ_ASSERT(!GetBufferHolders(OMX_DirOutput)->Length()); 351 return mPlatformLayer->Shutdown(); 352 } 353 354 } // namespace mozilla