Coverage Report

Created: 2018-09-25 14:53

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