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