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> ¶ms,
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> ¶ms,
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