2 * Copyright (C) 2009 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 //#define LOG_NDEBUG 0
19 #include <utils/Log.h>
23 #include "../include/OMX.h"
25 #include "../include/OMXNodeInstance.h"
27 #include <binder/IMemory.h>
28 #include <media/stagefright/MediaDebug.h>
29 #include <utils/threads.h>
31 #include "OMXMaster.h"
33 #include <OMX_Component.h>
37 ////////////////////////////////////////////////////////////////////////////////
39 // This provides the underlying Thread used by CallbackDispatcher.
40 // Note that deriving CallbackDispatcher from Thread does not work.
42 struct OMX::CallbackDispatcherThread : public Thread {
43 CallbackDispatcherThread(CallbackDispatcher *dispatcher)
44 : mDispatcher(dispatcher) {
48 CallbackDispatcher *mDispatcher;
52 CallbackDispatcherThread(const CallbackDispatcherThread &);
53 CallbackDispatcherThread &operator=(const CallbackDispatcherThread &);
56 ////////////////////////////////////////////////////////////////////////////////
58 struct OMX::CallbackDispatcher : public RefBase {
59 CallbackDispatcher(OMXNodeInstance *owner);
61 void post(const omx_message &msg);
66 virtual ~CallbackDispatcher();
71 OMXNodeInstance *mOwner;
73 Condition mQueueChanged;
74 List<omx_message> mQueue;
76 sp<CallbackDispatcherThread> mThread;
78 void dispatch(const omx_message &msg);
80 CallbackDispatcher(const CallbackDispatcher &);
81 CallbackDispatcher &operator=(const CallbackDispatcher &);
84 OMX::CallbackDispatcher::CallbackDispatcher(OMXNodeInstance *owner)
87 mThread = new CallbackDispatcherThread(this);
88 mThread->run("OMXCallbackDisp", ANDROID_PRIORITY_AUDIO);
91 OMX::CallbackDispatcher::~CallbackDispatcher() {
93 Mutex::Autolock autoLock(mLock);
96 mQueueChanged.signal();
99 // A join on self can happen if the last ref to CallbackDispatcher
100 // is released within the CallbackDispatcherThread loop
101 status_t status = mThread->join();
102 if (status != WOULD_BLOCK) {
103 // Other than join to self, the only other error return codes are
104 // whatever readyToRun() returns, and we don't override that
105 CHECK_EQ(status, NO_ERROR);
109 void OMX::CallbackDispatcher::post(const omx_message &msg) {
110 Mutex::Autolock autoLock(mLock);
112 mQueue.push_back(msg);
113 mQueueChanged.signal();
116 void OMX::CallbackDispatcher::dispatch(const omx_message &msg) {
117 if (mOwner == NULL) {
118 LOGV("Would have dispatched a message to a node that's already gone.");
121 mOwner->onMessage(msg);
124 bool OMX::CallbackDispatcher::loop() {
129 Mutex::Autolock autoLock(mLock);
130 while (!mDone && mQueue.empty()) {
131 mQueueChanged.wait(mLock);
138 msg = *mQueue.begin();
139 mQueue.erase(mQueue.begin());
148 ////////////////////////////////////////////////////////////////////////////////
150 bool OMX::CallbackDispatcherThread::threadLoop() {
151 return mDispatcher->loop();
154 ////////////////////////////////////////////////////////////////////////////////
157 : mMaster(new OMXMaster),
166 void OMX::binderDied(const wp<IBinder> &the_late_who) {
167 OMXNodeInstance *instance;
170 Mutex::Autolock autoLock(mLock);
172 ssize_t index = mLiveNodes.indexOfKey(the_late_who);
175 instance = mLiveNodes.editValueAt(index);
176 mLiveNodes.removeItemsAt(index);
178 index = mDispatchers.indexOfKey(instance->nodeID());
180 mDispatchers.removeItemsAt(index);
182 invalidateNodeID_l(instance->nodeID());
185 instance->onObserverDied(mMaster);
188 bool OMX::livesLocally(pid_t pid) {
189 return pid == getpid();
192 status_t OMX::listNodes(List<ComponentInfo> *list) {
196 char componentName[256];
197 while (mMaster->enumerateComponents(
198 componentName, sizeof(componentName), index) == OMX_ErrorNone) {
199 list->push_back(ComponentInfo());
200 ComponentInfo &info = *--list->end();
202 info.mName = componentName;
204 Vector<String8> roles;
206 mMaster->getRolesOfComponent(componentName, &roles);
208 if (err == OMX_ErrorNone) {
209 for (OMX_U32 i = 0; i < roles.size(); ++i) {
210 info.mRoles.push_back(roles[i]);
220 status_t OMX::allocateNode(
221 const char *name, const sp<IOMXObserver> &observer, node_id *node) {
222 Mutex::Autolock autoLock(mLock);
226 OMXNodeInstance *instance = new OMXNodeInstance(this, observer);
228 OMX_COMPONENTTYPE *handle;
229 OMX_ERRORTYPE err = mMaster->makeComponentInstance(
230 name, &OMXNodeInstance::kCallbacks,
233 if (err != OMX_ErrorNone) {
234 LOGV("FAILED to allocate omx component '%s'", name);
236 instance->onGetHandleFailed();
238 return UNKNOWN_ERROR;
241 *node = makeNodeID(instance);
242 mDispatchers.add(*node, new CallbackDispatcher(instance));
244 instance->setHandle(*node, handle);
246 mLiveNodes.add(observer->asBinder(), instance);
247 observer->asBinder()->linkToDeath(this);
252 status_t OMX::freeNode(node_id node) {
253 OMXNodeInstance *instance = findInstance(node);
255 ssize_t index = mLiveNodes.indexOfKey(instance->observer()->asBinder());
257 mLiveNodes.removeItemsAt(index);
259 instance->observer()->asBinder()->unlinkToDeath(this);
261 status_t err = instance->freeNode(mMaster);
264 Mutex::Autolock autoLock(mLock);
265 index = mDispatchers.indexOfKey(node);
267 mDispatchers.removeItemsAt(index);
273 status_t OMX::sendCommand(
274 node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) {
275 return findInstance(node)->sendCommand(cmd, param);
278 status_t OMX::getParameter(
279 node_id node, OMX_INDEXTYPE index,
280 void *params, size_t size) {
281 return findInstance(node)->getParameter(
282 index, params, size);
285 status_t OMX::setParameter(
286 node_id node, OMX_INDEXTYPE index,
287 const void *params, size_t size) {
288 return findInstance(node)->setParameter(
289 index, params, size);
292 status_t OMX::getConfig(
293 node_id node, OMX_INDEXTYPE index,
294 void *params, size_t size) {
295 return findInstance(node)->getConfig(
296 index, params, size);
299 status_t OMX::setConfig(
300 node_id node, OMX_INDEXTYPE index,
301 const void *params, size_t size) {
302 return findInstance(node)->setConfig(
303 index, params, size);
306 status_t OMX::enableGraphicBuffers(
307 node_id node, OMX_U32 port_index, OMX_BOOL enable) {
308 return findInstance(node)->enableGraphicBuffers(port_index, enable);
311 status_t OMX::getGraphicBufferUsage(
312 node_id node, OMX_U32 port_index, OMX_U32* usage) {
313 return findInstance(node)->getGraphicBufferUsage(port_index, usage);
316 status_t OMX::storeMetaDataInBuffers(
317 node_id node, OMX_U32 port_index, OMX_BOOL enable) {
318 return findInstance(node)->storeMetaDataInBuffers(port_index, enable);
321 status_t OMX::useBuffer(
322 node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms,
324 return findInstance(node)->useBuffer(
325 port_index, params, buffer);
328 status_t OMX::useGraphicBuffer(
329 node_id node, OMX_U32 port_index,
330 const sp<GraphicBuffer> &graphicBuffer, buffer_id *buffer) {
331 return findInstance(node)->useGraphicBuffer(
332 port_index, graphicBuffer, buffer);
335 status_t OMX::allocateBuffer(
336 node_id node, OMX_U32 port_index, size_t size,
337 buffer_id *buffer, void **buffer_data) {
338 return findInstance(node)->allocateBuffer(
339 port_index, size, buffer, buffer_data);
342 status_t OMX::allocateBufferWithBackup(
343 node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms,
345 return findInstance(node)->allocateBufferWithBackup(
346 port_index, params, buffer);
349 status_t OMX::freeBuffer(node_id node, OMX_U32 port_index, buffer_id buffer) {
350 return findInstance(node)->freeBuffer(
354 status_t OMX::fillBuffer(node_id node, buffer_id buffer) {
355 return findInstance(node)->fillBuffer(buffer);
358 status_t OMX::emptyBuffer(
361 OMX_U32 range_offset, OMX_U32 range_length,
362 OMX_U32 flags, OMX_TICKS timestamp) {
363 return findInstance(node)->emptyBuffer(
364 buffer, range_offset, range_length, flags, timestamp);
367 status_t OMX::getExtensionIndex(
369 const char *parameter_name,
370 OMX_INDEXTYPE *index) {
371 return findInstance(node)->getExtensionIndex(
372 parameter_name, index);
375 OMX_ERRORTYPE OMX::OnEvent(
377 OMX_IN OMX_EVENTTYPE eEvent,
378 OMX_IN OMX_U32 nData1,
379 OMX_IN OMX_U32 nData2,
380 OMX_IN OMX_PTR pEventData) {
381 LOGV("OnEvent(%d, %ld, %ld)", eEvent, nData1, nData2);
384 msg.type = omx_message::EVENT;
386 msg.u.event_data.event = eEvent;
387 msg.u.event_data.data1 = nData1;
388 msg.u.event_data.data2 = nData2;
390 findDispatcher(node)->post(msg);
392 return OMX_ErrorNone;
395 OMX_ERRORTYPE OMX::OnEmptyBufferDone(
396 node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) {
397 LOGV("OnEmptyBufferDone buffer=%p", pBuffer);
400 msg.type = omx_message::EMPTY_BUFFER_DONE;
402 msg.u.buffer_data.buffer = pBuffer;
404 findDispatcher(node)->post(msg);
406 return OMX_ErrorNone;
409 OMX_ERRORTYPE OMX::OnFillBufferDone(
410 node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) {
411 LOGV("OnFillBufferDone buffer=%p", pBuffer);
414 msg.type = omx_message::FILL_BUFFER_DONE;
416 msg.u.extended_buffer_data.buffer = pBuffer;
417 msg.u.extended_buffer_data.range_offset = pBuffer->nOffset;
418 msg.u.extended_buffer_data.range_length = pBuffer->nFilledLen;
419 msg.u.extended_buffer_data.flags = pBuffer->nFlags;
420 msg.u.extended_buffer_data.timestamp = pBuffer->nTimeStamp;
421 msg.u.extended_buffer_data.platform_private = pBuffer->pPlatformPrivate;
422 msg.u.extended_buffer_data.data_ptr = pBuffer->pBuffer;
424 findDispatcher(node)->post(msg);
426 return OMX_ErrorNone;
429 OMX::node_id OMX::makeNodeID(OMXNodeInstance *instance) {
430 // mLock is already held.
432 node_id node = (node_id)++mNodeCounter;
433 mNodeIDToInstance.add(node, instance);
438 OMXNodeInstance *OMX::findInstance(node_id node) {
439 Mutex::Autolock autoLock(mLock);
441 ssize_t index = mNodeIDToInstance.indexOfKey(node);
443 return index < 0 ? NULL : mNodeIDToInstance.valueAt(index);
446 sp<OMX::CallbackDispatcher> OMX::findDispatcher(node_id node) {
447 Mutex::Autolock autoLock(mLock);
449 ssize_t index = mDispatchers.indexOfKey(node);
451 return index < 0 ? NULL : mDispatchers.valueAt(index);
454 void OMX::invalidateNodeID(node_id node) {
455 Mutex::Autolock autoLock(mLock);
456 invalidateNodeID_l(node);
459 void OMX::invalidateNodeID_l(node_id node) {
461 mNodeIDToInstance.removeItem(node);
464 } // namespace android