1 /*
2  * Copyright (C) 2009 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <inttypes.h>
18 
19 //#define LOG_NDEBUG 0
20 #define LOG_TAG "OMX"
21 #include <utils/Log.h>
22 
23 #include <dlfcn.h>
24 
25 #include "../include/OMX.h"
26 
27 #include "../include/OMXNodeInstance.h"
28 
29 #include <binder/IMemory.h>
30 #include <media/stagefright/foundation/ADebug.h>
31 #include <utils/threads.h>
32 
33 #include "OMXMaster.h"
34 
35 #include <OMX_Component.h>
36 
37 namespace android {
38 
39 ////////////////////////////////////////////////////////////////////////////////
40 
41 // This provides the underlying Thread used by CallbackDispatcher.
42 // Note that deriving CallbackDispatcher from Thread does not work.
43 
44 struct OMX::CallbackDispatcherThread : public Thread {
CallbackDispatcherThreadandroid::OMX::CallbackDispatcherThread45     CallbackDispatcherThread(CallbackDispatcher *dispatcher)
46         : mDispatcher(dispatcher) {
47     }
48 
49 private:
50     CallbackDispatcher *mDispatcher;
51 
52     bool threadLoop();
53 
54     CallbackDispatcherThread(const CallbackDispatcherThread &);
55     CallbackDispatcherThread &operator=(const CallbackDispatcherThread &);
56 };
57 
58 ////////////////////////////////////////////////////////////////////////////////
59 
60 struct OMX::CallbackDispatcher : public RefBase {
61     CallbackDispatcher(OMXNodeInstance *owner);
62 
63     void post(const omx_message &msg);
64 
65     bool loop();
66 
67 protected:
68     virtual ~CallbackDispatcher();
69 
70 private:
71     Mutex mLock;
72 
73     OMXNodeInstance *mOwner;
74     bool mDone;
75     Condition mQueueChanged;
76     List<omx_message> mQueue;
77 
78     sp<CallbackDispatcherThread> mThread;
79 
80     void dispatch(const omx_message &msg);
81 
82     CallbackDispatcher(const CallbackDispatcher &);
83     CallbackDispatcher &operator=(const CallbackDispatcher &);
84 };
85 
CallbackDispatcher(OMXNodeInstance * owner)86 OMX::CallbackDispatcher::CallbackDispatcher(OMXNodeInstance *owner)
87     : mOwner(owner),
88       mDone(false) {
89     mThread = new CallbackDispatcherThread(this);
90     mThread->run("OMXCallbackDisp", ANDROID_PRIORITY_FOREGROUND);
91 }
92 
~CallbackDispatcher()93 OMX::CallbackDispatcher::~CallbackDispatcher() {
94     {
95         Mutex::Autolock autoLock(mLock);
96 
97         mDone = true;
98         mQueueChanged.signal();
99     }
100 
101     // A join on self can happen if the last ref to CallbackDispatcher
102     // is released within the CallbackDispatcherThread loop
103     status_t status = mThread->join();
104     if (status != WOULD_BLOCK) {
105         // Other than join to self, the only other error return codes are
106         // whatever readyToRun() returns, and we don't override that
107         CHECK_EQ(status, (status_t)NO_ERROR);
108     }
109 }
110 
post(const omx_message & msg)111 void OMX::CallbackDispatcher::post(const omx_message &msg) {
112     Mutex::Autolock autoLock(mLock);
113 
114     mQueue.push_back(msg);
115     mQueueChanged.signal();
116 }
117 
dispatch(const omx_message & msg)118 void OMX::CallbackDispatcher::dispatch(const omx_message &msg) {
119     if (mOwner == NULL) {
120         ALOGV("Would have dispatched a message to a node that's already gone.");
121         return;
122     }
123     mOwner->onMessage(msg);
124 }
125 
loop()126 bool OMX::CallbackDispatcher::loop() {
127     for (;;) {
128         omx_message msg;
129 
130         {
131             Mutex::Autolock autoLock(mLock);
132             while (!mDone && mQueue.empty()) {
133                 mQueueChanged.wait(mLock);
134             }
135 
136             if (mDone) {
137                 break;
138             }
139 
140             msg = *mQueue.begin();
141             mQueue.erase(mQueue.begin());
142         }
143 
144         dispatch(msg);
145     }
146 
147     return false;
148 }
149 
150 ////////////////////////////////////////////////////////////////////////////////
151 
threadLoop()152 bool OMX::CallbackDispatcherThread::threadLoop() {
153     return mDispatcher->loop();
154 }
155 
156 ////////////////////////////////////////////////////////////////////////////////
157 
OMX()158 OMX::OMX()
159     : mMaster(new OMXMaster),
160       mNodeCounter(0) {
161 }
162 
~OMX()163 OMX::~OMX() {
164     delete mMaster;
165     mMaster = NULL;
166 }
167 
binderDied(const wp<IBinder> & the_late_who)168 void OMX::binderDied(const wp<IBinder> &the_late_who) {
169     OMXNodeInstance *instance;
170 
171     {
172         Mutex::Autolock autoLock(mLock);
173 
174         ssize_t index = mLiveNodes.indexOfKey(the_late_who);
175         CHECK(index >= 0);
176 
177         instance = mLiveNodes.editValueAt(index);
178         mLiveNodes.removeItemsAt(index);
179 
180         index = mDispatchers.indexOfKey(instance->nodeID());
181         CHECK(index >= 0);
182         mDispatchers.removeItemsAt(index);
183 
184         invalidateNodeID_l(instance->nodeID());
185     }
186 
187     instance->onObserverDied(mMaster);
188 }
189 
livesLocally(node_id,pid_t pid)190 bool OMX::livesLocally(node_id /* node */, pid_t pid) {
191     return pid == getpid();
192 }
193 
listNodes(List<ComponentInfo> * list)194 status_t OMX::listNodes(List<ComponentInfo> *list) {
195     list->clear();
196 
197     OMX_U32 index = 0;
198     char componentName[256];
199     while (mMaster->enumerateComponents(
200                 componentName, sizeof(componentName), index) == OMX_ErrorNone) {
201         list->push_back(ComponentInfo());
202         ComponentInfo &info = *--list->end();
203 
204         info.mName = componentName;
205 
206         Vector<String8> roles;
207         OMX_ERRORTYPE err =
208             mMaster->getRolesOfComponent(componentName, &roles);
209 
210         if (err == OMX_ErrorNone) {
211             for (OMX_U32 i = 0; i < roles.size(); ++i) {
212                 info.mRoles.push_back(roles[i]);
213             }
214         }
215 
216         ++index;
217     }
218 
219     return OK;
220 }
221 
allocateNode(const char * name,const sp<IOMXObserver> & observer,node_id * node)222 status_t OMX::allocateNode(
223         const char *name, const sp<IOMXObserver> &observer, node_id *node) {
224     Mutex::Autolock autoLock(mLock);
225 
226     *node = 0;
227 
228     OMXNodeInstance *instance = new OMXNodeInstance(this, observer, name);
229 
230     OMX_COMPONENTTYPE *handle;
231     OMX_ERRORTYPE err = mMaster->makeComponentInstance(
232             name, &OMXNodeInstance::kCallbacks,
233             instance, &handle);
234 
235     if (err != OMX_ErrorNone) {
236         ALOGE("FAILED to allocate omx component '%s'", name);
237 
238         instance->onGetHandleFailed();
239 
240         return UNKNOWN_ERROR;
241     }
242 
243     *node = makeNodeID(instance);
244     mDispatchers.add(*node, new CallbackDispatcher(instance));
245 
246     instance->setHandle(*node, handle);
247 
248     mLiveNodes.add(observer->asBinder(), instance);
249     observer->asBinder()->linkToDeath(this);
250 
251     return OK;
252 }
253 
freeNode(node_id node)254 status_t OMX::freeNode(node_id node) {
255     OMXNodeInstance *instance = findInstance(node);
256 
257     {
258         Mutex::Autolock autoLock(mLock);
259         ssize_t index = mLiveNodes.indexOfKey(instance->observer()->asBinder());
260         if (index < 0) {
261             // This could conceivably happen if the observer dies at roughly the
262             // same time that a client attempts to free the node explicitly.
263             return OK;
264         }
265         mLiveNodes.removeItemsAt(index);
266     }
267 
268     instance->observer()->asBinder()->unlinkToDeath(this);
269 
270     status_t err = instance->freeNode(mMaster);
271 
272     {
273         Mutex::Autolock autoLock(mLock);
274         ssize_t index = mDispatchers.indexOfKey(node);
275         CHECK(index >= 0);
276         mDispatchers.removeItemsAt(index);
277     }
278 
279     return err;
280 }
281 
sendCommand(node_id node,OMX_COMMANDTYPE cmd,OMX_S32 param)282 status_t OMX::sendCommand(
283         node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) {
284     return findInstance(node)->sendCommand(cmd, param);
285 }
286 
getParameter(node_id node,OMX_INDEXTYPE index,void * params,size_t size)287 status_t OMX::getParameter(
288         node_id node, OMX_INDEXTYPE index,
289         void *params, size_t size) {
290     ALOGV("getParameter(%u %#x %p %zd)", node, index, params, size);
291     return findInstance(node)->getParameter(
292             index, params, size);
293 }
294 
setParameter(node_id node,OMX_INDEXTYPE index,const void * params,size_t size)295 status_t OMX::setParameter(
296         node_id node, OMX_INDEXTYPE index,
297         const void *params, size_t size) {
298     ALOGV("setParameter(%u %#x %p %zd)", node, index, params, size);
299     return findInstance(node)->setParameter(
300             index, params, size);
301 }
302 
getConfig(node_id node,OMX_INDEXTYPE index,void * params,size_t size)303 status_t OMX::getConfig(
304         node_id node, OMX_INDEXTYPE index,
305         void *params, size_t size) {
306     return findInstance(node)->getConfig(
307             index, params, size);
308 }
309 
setConfig(node_id node,OMX_INDEXTYPE index,const void * params,size_t size)310 status_t OMX::setConfig(
311         node_id node, OMX_INDEXTYPE index,
312         const void *params, size_t size) {
313     return findInstance(node)->setConfig(
314             index, params, size);
315 }
316 
getState(node_id node,OMX_STATETYPE * state)317 status_t OMX::getState(
318         node_id node, OMX_STATETYPE* state) {
319     return findInstance(node)->getState(
320             state);
321 }
322 
enableGraphicBuffers(node_id node,OMX_U32 port_index,OMX_BOOL enable)323 status_t OMX::enableGraphicBuffers(
324         node_id node, OMX_U32 port_index, OMX_BOOL enable) {
325     return findInstance(node)->enableGraphicBuffers(port_index, enable);
326 }
327 
getGraphicBufferUsage(node_id node,OMX_U32 port_index,OMX_U32 * usage)328 status_t OMX::getGraphicBufferUsage(
329         node_id node, OMX_U32 port_index, OMX_U32* usage) {
330     return findInstance(node)->getGraphicBufferUsage(port_index, usage);
331 }
332 
storeMetaDataInBuffers(node_id node,OMX_U32 port_index,OMX_BOOL enable)333 status_t OMX::storeMetaDataInBuffers(
334         node_id node, OMX_U32 port_index, OMX_BOOL enable) {
335     return findInstance(node)->storeMetaDataInBuffers(port_index, enable);
336 }
337 
prepareForAdaptivePlayback(node_id node,OMX_U32 portIndex,OMX_BOOL enable,OMX_U32 maxFrameWidth,OMX_U32 maxFrameHeight)338 status_t OMX::prepareForAdaptivePlayback(
339         node_id node, OMX_U32 portIndex, OMX_BOOL enable,
340         OMX_U32 maxFrameWidth, OMX_U32 maxFrameHeight) {
341     return findInstance(node)->prepareForAdaptivePlayback(
342             portIndex, enable, maxFrameWidth, maxFrameHeight);
343 }
344 
configureVideoTunnelMode(node_id node,OMX_U32 portIndex,OMX_BOOL tunneled,OMX_U32 audioHwSync,native_handle_t ** sidebandHandle)345 status_t OMX::configureVideoTunnelMode(
346         node_id node, OMX_U32 portIndex, OMX_BOOL tunneled,
347         OMX_U32 audioHwSync, native_handle_t **sidebandHandle) {
348     return findInstance(node)->configureVideoTunnelMode(
349             portIndex, tunneled, audioHwSync, sidebandHandle);
350 }
351 
useBuffer(node_id node,OMX_U32 port_index,const sp<IMemory> & params,buffer_id * buffer)352 status_t OMX::useBuffer(
353         node_id node, OMX_U32 port_index, const sp<IMemory> &params,
354         buffer_id *buffer) {
355     return findInstance(node)->useBuffer(
356             port_index, params, buffer);
357 }
358 
useGraphicBuffer(node_id node,OMX_U32 port_index,const sp<GraphicBuffer> & graphicBuffer,buffer_id * buffer)359 status_t OMX::useGraphicBuffer(
360         node_id node, OMX_U32 port_index,
361         const sp<GraphicBuffer> &graphicBuffer, buffer_id *buffer) {
362     return findInstance(node)->useGraphicBuffer(
363             port_index, graphicBuffer, buffer);
364 }
365 
updateGraphicBufferInMeta(node_id node,OMX_U32 port_index,const sp<GraphicBuffer> & graphicBuffer,buffer_id buffer)366 status_t OMX::updateGraphicBufferInMeta(
367         node_id node, OMX_U32 port_index,
368         const sp<GraphicBuffer> &graphicBuffer, buffer_id buffer) {
369     return findInstance(node)->updateGraphicBufferInMeta(
370             port_index, graphicBuffer, buffer);
371 }
372 
createInputSurface(node_id node,OMX_U32 port_index,sp<IGraphicBufferProducer> * bufferProducer)373 status_t OMX::createInputSurface(
374         node_id node, OMX_U32 port_index,
375         sp<IGraphicBufferProducer> *bufferProducer) {
376     return findInstance(node)->createInputSurface(
377             port_index, bufferProducer);
378 }
379 
signalEndOfInputStream(node_id node)380 status_t OMX::signalEndOfInputStream(node_id node) {
381     return findInstance(node)->signalEndOfInputStream();
382 }
383 
allocateBuffer(node_id node,OMX_U32 port_index,size_t size,buffer_id * buffer,void ** buffer_data)384 status_t OMX::allocateBuffer(
385         node_id node, OMX_U32 port_index, size_t size,
386         buffer_id *buffer, void **buffer_data) {
387     return findInstance(node)->allocateBuffer(
388             port_index, size, buffer, buffer_data);
389 }
390 
allocateBufferWithBackup(node_id node,OMX_U32 port_index,const sp<IMemory> & params,buffer_id * buffer)391 status_t OMX::allocateBufferWithBackup(
392         node_id node, OMX_U32 port_index, const sp<IMemory> &params,
393         buffer_id *buffer) {
394     return findInstance(node)->allocateBufferWithBackup(
395             port_index, params, buffer);
396 }
397 
freeBuffer(node_id node,OMX_U32 port_index,buffer_id buffer)398 status_t OMX::freeBuffer(node_id node, OMX_U32 port_index, buffer_id buffer) {
399     return findInstance(node)->freeBuffer(
400             port_index, buffer);
401 }
402 
fillBuffer(node_id node,buffer_id buffer)403 status_t OMX::fillBuffer(node_id node, buffer_id buffer) {
404     return findInstance(node)->fillBuffer(buffer);
405 }
406 
emptyBuffer(node_id node,buffer_id buffer,OMX_U32 range_offset,OMX_U32 range_length,OMX_U32 flags,OMX_TICKS timestamp)407 status_t OMX::emptyBuffer(
408         node_id node,
409         buffer_id buffer,
410         OMX_U32 range_offset, OMX_U32 range_length,
411         OMX_U32 flags, OMX_TICKS timestamp) {
412     return findInstance(node)->emptyBuffer(
413             buffer, range_offset, range_length, flags, timestamp);
414 }
415 
getExtensionIndex(node_id node,const char * parameter_name,OMX_INDEXTYPE * index)416 status_t OMX::getExtensionIndex(
417         node_id node,
418         const char *parameter_name,
419         OMX_INDEXTYPE *index) {
420     return findInstance(node)->getExtensionIndex(
421             parameter_name, index);
422 }
423 
setInternalOption(node_id node,OMX_U32 port_index,InternalOptionType type,const void * data,size_t size)424 status_t OMX::setInternalOption(
425         node_id node,
426         OMX_U32 port_index,
427         InternalOptionType type,
428         const void *data,
429         size_t size) {
430     return findInstance(node)->setInternalOption(port_index, type, data, size);
431 }
432 
OnEvent(node_id node,OMX_IN OMX_EVENTTYPE eEvent,OMX_IN OMX_U32 nData1,OMX_IN OMX_U32 nData2,OMX_IN OMX_PTR)433 OMX_ERRORTYPE OMX::OnEvent(
434         node_id node,
435         OMX_IN OMX_EVENTTYPE eEvent,
436         OMX_IN OMX_U32 nData1,
437         OMX_IN OMX_U32 nData2,
438         OMX_IN OMX_PTR /* pEventData */) {
439     ALOGV("OnEvent(%d, %" PRIu32", %" PRIu32 ")", eEvent, nData1, nData2);
440 
441     // Forward to OMXNodeInstance.
442     findInstance(node)->onEvent(eEvent, nData1, nData2);
443 
444     omx_message msg;
445     msg.type = omx_message::EVENT;
446     msg.node = node;
447     msg.u.event_data.event = eEvent;
448     msg.u.event_data.data1 = nData1;
449     msg.u.event_data.data2 = nData2;
450 
451     findDispatcher(node)->post(msg);
452 
453     return OMX_ErrorNone;
454 }
455 
OnEmptyBufferDone(node_id node,buffer_id buffer,OMX_IN OMX_BUFFERHEADERTYPE * pBuffer)456 OMX_ERRORTYPE OMX::OnEmptyBufferDone(
457         node_id node, buffer_id buffer, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) {
458     ALOGV("OnEmptyBufferDone buffer=%p", pBuffer);
459 
460     omx_message msg;
461     msg.type = omx_message::EMPTY_BUFFER_DONE;
462     msg.node = node;
463     msg.u.buffer_data.buffer = buffer;
464 
465     findDispatcher(node)->post(msg);
466 
467     return OMX_ErrorNone;
468 }
469 
OnFillBufferDone(node_id node,buffer_id buffer,OMX_IN OMX_BUFFERHEADERTYPE * pBuffer)470 OMX_ERRORTYPE OMX::OnFillBufferDone(
471         node_id node, buffer_id buffer, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) {
472     ALOGV("OnFillBufferDone buffer=%p", pBuffer);
473 
474     omx_message msg;
475     msg.type = omx_message::FILL_BUFFER_DONE;
476     msg.node = node;
477     msg.u.extended_buffer_data.buffer = buffer;
478     msg.u.extended_buffer_data.range_offset = pBuffer->nOffset;
479     msg.u.extended_buffer_data.range_length = pBuffer->nFilledLen;
480     msg.u.extended_buffer_data.flags = pBuffer->nFlags;
481     msg.u.extended_buffer_data.timestamp = pBuffer->nTimeStamp;
482 
483     findDispatcher(node)->post(msg);
484 
485     return OMX_ErrorNone;
486 }
487 
makeNodeID(OMXNodeInstance * instance)488 OMX::node_id OMX::makeNodeID(OMXNodeInstance *instance) {
489     // mLock is already held.
490 
491     node_id node = (node_id)++mNodeCounter;
492     mNodeIDToInstance.add(node, instance);
493 
494     return node;
495 }
496 
findInstance(node_id node)497 OMXNodeInstance *OMX::findInstance(node_id node) {
498     Mutex::Autolock autoLock(mLock);
499 
500     ssize_t index = mNodeIDToInstance.indexOfKey(node);
501 
502     return index < 0 ? NULL : mNodeIDToInstance.valueAt(index);
503 }
504 
findDispatcher(node_id node)505 sp<OMX::CallbackDispatcher> OMX::findDispatcher(node_id node) {
506     Mutex::Autolock autoLock(mLock);
507 
508     ssize_t index = mDispatchers.indexOfKey(node);
509 
510     return index < 0 ? NULL : mDispatchers.valueAt(index);
511 }
512 
invalidateNodeID(node_id node)513 void OMX::invalidateNodeID(node_id node) {
514     Mutex::Autolock autoLock(mLock);
515     invalidateNodeID_l(node);
516 }
517 
invalidateNodeID_l(node_id node)518 void OMX::invalidateNodeID_l(node_id node) {
519     // mLock is held.
520     mNodeIDToInstance.removeItem(node);
521 }
522 
523 }  // namespace android
524