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 "OmxDataDecoder.h"
8 #include "OmxPromiseLayer.h"
9 #include "PureOmxPlatformLayer.h"
10 #include "OmxCoreLibLinker.h"
11
12 #ifdef LOG
13 # undef LOG
14 #endif
15
16 #define LOG(arg, ...) \
17 MOZ_LOG( \
18 sPDMLog, mozilla::LogLevel::Debug, \
19 ("PureOmxPlatformLayer(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
20 #define LOG_BUF(arg, ...) \
21 MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, \
22 ("PureOmxBufferData(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
23
24 namespace mozilla {
25
26 #define OMX_FUNC(func) extern typeof(func)* func;
27 #include "OmxFunctionList.h"
28 #undef OMX_FUNC
29
PureOmxBufferData(const PureOmxPlatformLayer & aPlatformLayer,const OMX_PARAM_PORTDEFINITIONTYPE & aPortDef)30 PureOmxBufferData::PureOmxBufferData(
31 const PureOmxPlatformLayer& aPlatformLayer,
32 const OMX_PARAM_PORTDEFINITIONTYPE& aPortDef)
33 : BufferData(nullptr), mPlatformLayer(aPlatformLayer), mPortDef(aPortDef) {
34 LOG_BUF("");
35
36 if (ShouldUseEGLImage()) {
37 // TODO
38 LOG_BUF(
39 "OMX_UseEGLImage() seems available but using it isn't implemented "
40 "yet.");
41 }
42
43 OMX_ERRORTYPE err;
44 err = OMX_AllocateBuffer(mPlatformLayer.GetComponent(), &mBuffer,
45 mPortDef.nPortIndex, this, mPortDef.nBufferSize);
46 if (err != OMX_ErrorNone) {
47 LOG_BUF("Failed to allocate the buffer!: 0x%08x", err);
48 }
49 }
50
~PureOmxBufferData()51 PureOmxBufferData::~PureOmxBufferData() {
52 LOG_BUF("");
53 ReleaseBuffer();
54 }
55
ReleaseBuffer()56 void PureOmxBufferData::ReleaseBuffer() {
57 LOG_BUF("");
58
59 if (mBuffer) {
60 OMX_ERRORTYPE err;
61 err = OMX_FreeBuffer(mPlatformLayer.GetComponent(), mPortDef.nPortIndex,
62 mBuffer);
63 if (err != OMX_ErrorNone) {
64 LOG_BUF("Failed to free the buffer!: 0x%08x", err);
65 }
66 mBuffer = nullptr;
67 }
68 }
69
ShouldUseEGLImage()70 bool PureOmxBufferData::ShouldUseEGLImage() {
71 OMX_ERRORTYPE err;
72 err = OMX_UseEGLImage(mPlatformLayer.GetComponent(), nullptr,
73 mPortDef.nPortIndex, nullptr, nullptr);
74 return (err != OMX_ErrorNotImplemented);
75 }
76
77 /* static */
Init(void)78 bool PureOmxPlatformLayer::Init(void) {
79 if (!OmxCoreLibLinker::Link()) {
80 return false;
81 }
82
83 OMX_ERRORTYPE err = OMX_Init();
84 if (err != OMX_ErrorNone) {
85 MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug,
86 ("PureOmxPlatformLayer::%s: Failed to initialize OMXCore: 0x%08x",
87 __func__, err));
88 return false;
89 }
90
91 return true;
92 }
93
94 /* static */
95 OMX_CALLBACKTYPE PureOmxPlatformLayer::sCallbacks = {
96 EventHandler, EmptyBufferDone, FillBufferDone};
97
PureOmxPlatformLayer(OmxDataDecoder * aDataDecoder,OmxPromiseLayer * aPromiseLayer,TaskQueue * aTaskQueue,layers::ImageContainer * aImageContainer)98 PureOmxPlatformLayer::PureOmxPlatformLayer(
99 OmxDataDecoder* aDataDecoder, OmxPromiseLayer* aPromiseLayer,
100 TaskQueue* aTaskQueue, layers::ImageContainer* aImageContainer)
101 : mComponent(nullptr),
102 mDataDecoder(aDataDecoder),
103 mPromiseLayer(aPromiseLayer),
104 mTaskQueue(aTaskQueue),
105 mImageContainer(aImageContainer) {
106 LOG("");
107 }
108
~PureOmxPlatformLayer()109 PureOmxPlatformLayer::~PureOmxPlatformLayer() { LOG(""); }
110
111 OMX_ERRORTYPE
InitOmxToStateLoaded(const TrackInfo * aInfo)112 PureOmxPlatformLayer::InitOmxToStateLoaded(const TrackInfo* aInfo) {
113 LOG("");
114
115 if (!aInfo) {
116 return OMX_ErrorUndefined;
117 }
118 mInfo = aInfo;
119
120 return CreateComponent();
121 }
122
123 OMX_ERRORTYPE
EmptyThisBuffer(BufferData * aData)124 PureOmxPlatformLayer::EmptyThisBuffer(BufferData* aData) {
125 LOG("");
126 return OMX_EmptyThisBuffer(mComponent, aData->mBuffer);
127 }
128
129 OMX_ERRORTYPE
FillThisBuffer(BufferData * aData)130 PureOmxPlatformLayer::FillThisBuffer(BufferData* aData) {
131 LOG("");
132 return OMX_FillThisBuffer(mComponent, aData->mBuffer);
133 }
134
135 OMX_ERRORTYPE
SendCommand(OMX_COMMANDTYPE aCmd,OMX_U32 aParam1,OMX_PTR aCmdData)136 PureOmxPlatformLayer::SendCommand(OMX_COMMANDTYPE aCmd, OMX_U32 aParam1,
137 OMX_PTR aCmdData) {
138 LOG("aCmd: 0x%08x", aCmd);
139 if (!mComponent) {
140 return OMX_ErrorUndefined;
141 }
142 return OMX_SendCommand(mComponent, aCmd, aParam1, aCmdData);
143 }
144
FindPortDefinition(OMX_DIRTYPE aType,OMX_PARAM_PORTDEFINITIONTYPE & portDef)145 nsresult PureOmxPlatformLayer::FindPortDefinition(
146 OMX_DIRTYPE aType, OMX_PARAM_PORTDEFINITIONTYPE& portDef) {
147 nsTArray<uint32_t> portIndex;
148 GetPortIndices(portIndex);
149 for (auto idx : portIndex) {
150 InitOmxParameter(&portDef);
151 portDef.nPortIndex = idx;
152
153 OMX_ERRORTYPE err;
154 err = GetParameter(OMX_IndexParamPortDefinition, &portDef,
155 sizeof(OMX_PARAM_PORTDEFINITIONTYPE));
156 if (err != OMX_ErrorNone) {
157 return NS_ERROR_FAILURE;
158 } else if (portDef.eDir == aType) {
159 LOG("Found OMX_IndexParamPortDefinition: port: %d, type: %d",
160 portDef.nPortIndex, portDef.eDir);
161 return NS_OK;
162 }
163 }
164 return NS_ERROR_FAILURE;
165 }
166
AllocateOmxBuffer(OMX_DIRTYPE aType,BUFFERLIST * aBufferList)167 nsresult PureOmxPlatformLayer::AllocateOmxBuffer(OMX_DIRTYPE aType,
168 BUFFERLIST* aBufferList) {
169 LOG("aType: %d", aType);
170
171 OMX_PARAM_PORTDEFINITIONTYPE portDef;
172 nsresult result = FindPortDefinition(aType, portDef);
173 if (result != NS_OK) {
174 return result;
175 }
176
177 LOG("nBufferCountActual: %d, nBufferSize: %d", portDef.nBufferCountActual,
178 portDef.nBufferSize);
179
180 for (OMX_U32 i = 0; i < portDef.nBufferCountActual; ++i) {
181 RefPtr<PureOmxBufferData> buffer = new PureOmxBufferData(*this, portDef);
182 aBufferList->AppendElement(buffer);
183 }
184
185 return NS_OK;
186 }
187
ReleaseOmxBuffer(OMX_DIRTYPE aType,BUFFERLIST * aBufferList)188 nsresult PureOmxPlatformLayer::ReleaseOmxBuffer(OMX_DIRTYPE aType,
189 BUFFERLIST* aBufferList) {
190 LOG("aType: 0x%08x", aType);
191
192 uint32_t len = aBufferList->Length();
193 for (uint32_t i = 0; i < len; i++) {
194 PureOmxBufferData* buffer =
195 static_cast<PureOmxBufferData*>(aBufferList->ElementAt(i).get());
196
197 // All raw OpenMAX buffers have to be released here to flush
198 // OMX_CommandStateSet for switching the state to OMX_StateLoaded.
199 // See OmxDataDecoder::DoAsyncShutdown() for more detail.
200 buffer->ReleaseBuffer();
201 }
202 aBufferList->Clear();
203
204 return NS_OK;
205 }
206
207 OMX_ERRORTYPE
GetState(OMX_STATETYPE * aType)208 PureOmxPlatformLayer::GetState(OMX_STATETYPE* aType) {
209 LOG("");
210
211 if (mComponent) {
212 return OMX_GetState(mComponent, aType);
213 }
214
215 return OMX_ErrorUndefined;
216 }
217
218 OMX_ERRORTYPE
GetParameter(OMX_INDEXTYPE aParamIndex,OMX_PTR aComponentParameterStructure,OMX_U32 aComponentParameterSize)219 PureOmxPlatformLayer::GetParameter(OMX_INDEXTYPE aParamIndex,
220 OMX_PTR aComponentParameterStructure,
221 OMX_U32 aComponentParameterSize) {
222 LOG("aParamIndex: 0x%08x", aParamIndex);
223
224 if (!mComponent) {
225 return OMX_ErrorUndefined;
226 }
227
228 return OMX_GetParameter(mComponent, aParamIndex,
229 aComponentParameterStructure);
230 }
231
232 OMX_ERRORTYPE
SetParameter(OMX_INDEXTYPE aParamIndex,OMX_PTR aComponentParameterStructure,OMX_U32 aComponentParameterSize)233 PureOmxPlatformLayer::SetParameter(OMX_INDEXTYPE aParamIndex,
234 OMX_PTR aComponentParameterStructure,
235 OMX_U32 aComponentParameterSize) {
236 LOG("aParamIndex: 0x%08x", aParamIndex);
237
238 if (!mComponent) {
239 return OMX_ErrorUndefined;
240 }
241
242 return OMX_SetParameter(mComponent, aParamIndex,
243 aComponentParameterStructure);
244 }
245
Shutdown()246 nsresult PureOmxPlatformLayer::Shutdown() {
247 LOG("");
248 if (mComponent) {
249 OMX_FreeHandle(mComponent);
250 mComponent = nullptr;
251 }
252 mPromiseLayer = nullptr;
253 mDataDecoder = nullptr;
254 return NS_OK;
255 }
256
257 /* static */
EventHandler(OMX_HANDLETYPE hComponent,OMX_PTR pAppData,OMX_EVENTTYPE eEventType,OMX_U32 nData1,OMX_U32 nData2,OMX_PTR pEventData)258 OMX_ERRORTYPE PureOmxPlatformLayer::EventHandler(OMX_HANDLETYPE hComponent,
259 OMX_PTR pAppData,
260 OMX_EVENTTYPE eEventType,
261 OMX_U32 nData1, OMX_U32 nData2,
262 OMX_PTR pEventData) {
263 PureOmxPlatformLayer* self = static_cast<PureOmxPlatformLayer*>(pAppData);
264 nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
265 "mozilla::PureOmxPlatformLayer::EventHandler",
266 [self, eEventType, nData1, nData2, pEventData]() {
267 self->EventHandler(eEventType, nData1, nData2, pEventData);
268 });
269 nsresult rv = self->mTaskQueue->Dispatch(r.forget());
270 return NS_SUCCEEDED(rv) ? OMX_ErrorNone : OMX_ErrorUndefined;
271 }
272
273 /* static */
EmptyBufferDone(OMX_HANDLETYPE hComponent,OMX_IN OMX_PTR pAppData,OMX_IN OMX_BUFFERHEADERTYPE * pBuffer)274 OMX_ERRORTYPE PureOmxPlatformLayer::EmptyBufferDone(
275 OMX_HANDLETYPE hComponent, OMX_IN OMX_PTR pAppData,
276 OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) {
277 PureOmxPlatformLayer* self = static_cast<PureOmxPlatformLayer*>(pAppData);
278 nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
279 "mozilla::PureOmxPlatformLayer::EmptyBufferDone",
280 [self, pBuffer]() { self->EmptyBufferDone(pBuffer); });
281 nsresult rv = self->mTaskQueue->Dispatch(r.forget());
282 return NS_SUCCEEDED(rv) ? OMX_ErrorNone : OMX_ErrorUndefined;
283 }
284
285 /* static */
FillBufferDone(OMX_OUT OMX_HANDLETYPE hComponent,OMX_OUT OMX_PTR pAppData,OMX_OUT OMX_BUFFERHEADERTYPE * pBuffer)286 OMX_ERRORTYPE PureOmxPlatformLayer::FillBufferDone(
287 OMX_OUT OMX_HANDLETYPE hComponent, OMX_OUT OMX_PTR pAppData,
288 OMX_OUT OMX_BUFFERHEADERTYPE* pBuffer) {
289 PureOmxPlatformLayer* self = static_cast<PureOmxPlatformLayer*>(pAppData);
290 nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
291 "mozilla::PureOmxPlatformLayer::FillBufferDone",
292 [self, pBuffer]() { self->FillBufferDone(pBuffer); });
293 nsresult rv = self->mTaskQueue->Dispatch(r.forget());
294 return NS_SUCCEEDED(rv) ? OMX_ErrorNone : OMX_ErrorUndefined;
295 }
296
297 OMX_ERRORTYPE
EventHandler(OMX_EVENTTYPE eEventType,OMX_U32 nData1,OMX_U32 nData2,OMX_PTR pEventData)298 PureOmxPlatformLayer::EventHandler(OMX_EVENTTYPE eEventType, OMX_U32 nData1,
299 OMX_U32 nData2, OMX_PTR pEventData) {
300 bool handled = mPromiseLayer->Event(eEventType, nData1, nData2);
301 LOG("eEventType: 0x%08x, handled: %d", eEventType, handled);
302 return OMX_ErrorNone;
303 }
304
305 OMX_ERRORTYPE
EmptyBufferDone(OMX_IN OMX_BUFFERHEADERTYPE * pBuffer)306 PureOmxPlatformLayer::EmptyBufferDone(OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) {
307 PureOmxBufferData* buffer =
308 static_cast<PureOmxBufferData*>(pBuffer->pAppPrivate);
309 OMX_DIRTYPE portDirection = buffer->GetPortDirection();
310 LOG("PortDirection: %d", portDirection);
311 mPromiseLayer->EmptyFillBufferDone(portDirection, buffer);
312 return OMX_ErrorNone;
313 }
314
315 OMX_ERRORTYPE
FillBufferDone(OMX_OUT OMX_BUFFERHEADERTYPE * pBuffer)316 PureOmxPlatformLayer::FillBufferDone(OMX_OUT OMX_BUFFERHEADERTYPE* pBuffer) {
317 PureOmxBufferData* buffer =
318 static_cast<PureOmxBufferData*>(pBuffer->pAppPrivate);
319 OMX_DIRTYPE portDirection = buffer->GetPortDirection();
320 LOG("PortDirection: %d", portDirection);
321 mPromiseLayer->EmptyFillBufferDone(portDirection, buffer);
322 return OMX_ErrorNone;
323 }
324
SupportsMimeType(const nsACString & aMimeType)325 bool PureOmxPlatformLayer::SupportsMimeType(const nsACString& aMimeType) {
326 return FindStandardComponent(aMimeType, nullptr);
327 }
328
GetStandardComponentRole(const nsACString & aMimeType,nsACString & aRole)329 static bool GetStandardComponentRole(const nsACString& aMimeType,
330 nsACString& aRole) {
331 if (aMimeType.EqualsLiteral("video/avc") ||
332 aMimeType.EqualsLiteral("video/mp4") ||
333 aMimeType.EqualsLiteral("video/mp4v-es")) {
334 aRole.Assign("video_decoder.avc");
335 return true;
336 } else if (aMimeType.EqualsLiteral("audio/mp4a-latm") ||
337 aMimeType.EqualsLiteral("audio/mp4") ||
338 aMimeType.EqualsLiteral("audio/aac")) {
339 aRole.Assign("audio_decoder.aac");
340 return true;
341 }
342 return false;
343 }
344
345 /* static */
FindStandardComponent(const nsACString & aMimeType,nsACString * aComponentName)346 bool PureOmxPlatformLayer::FindStandardComponent(const nsACString& aMimeType,
347 nsACString* aComponentName) {
348 nsAutoCString role;
349 if (!GetStandardComponentRole(aMimeType, role)) return false;
350
351 OMX_U32 nComponents = 0;
352 OMX_ERRORTYPE err;
353 err = OMX_GetComponentsOfRole(const_cast<OMX_STRING>(role.Data()),
354 &nComponents, nullptr);
355 if (err != OMX_ErrorNone || nComponents <= 0) {
356 return false;
357 }
358 if (!aComponentName) {
359 return true;
360 }
361
362 // TODO:
363 // Only the first component will be used.
364 // We should detect the most preferred component.
365 OMX_U8* componentNames[1];
366 UniquePtr<OMX_U8[]> componentName;
367 componentName = MakeUniqueFallible<OMX_U8[]>(OMX_MAX_STRINGNAME_SIZE);
368 componentNames[0] = componentName.get();
369 nComponents = 1;
370 err = OMX_GetComponentsOfRole(const_cast<OMX_STRING>(role.Data()),
371 &nComponents, componentNames);
372 if (err == OMX_ErrorNone) {
373 MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug,
374 ("PureOmxPlatformLayer::%s: A component has been found for %s: %s",
375 __func__, aMimeType.Data(), componentNames[0]));
376 aComponentName->Assign(reinterpret_cast<char*>(componentNames[0]));
377 }
378
379 return err == OMX_ErrorNone;
380 }
381
382 OMX_ERRORTYPE
CreateComponent(const nsACString * aComponentName)383 PureOmxPlatformLayer::CreateComponent(const nsACString* aComponentName) {
384 nsAutoCString componentName;
385 if (aComponentName) {
386 componentName = *aComponentName;
387 } else if (!FindStandardComponent(mInfo->mMimeType, &componentName)) {
388 return OMX_ErrorComponentNotFound;
389 }
390
391 OMX_ERRORTYPE err;
392 err = OMX_GetHandle(&mComponent, const_cast<OMX_STRING>(componentName.Data()),
393 this, &sCallbacks);
394
395 const char* mime = mInfo->mMimeType.Data();
396 if (err == OMX_ErrorNone) {
397 LOG("Succeeded to create the component for %s", mime);
398 } else {
399 LOG("Failed to create the component for %s: 0x%08x", mime, err);
400 }
401
402 return err;
403 }
404
405 } // namespace mozilla
406