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