OMX.cpp revision 0a5ca668c6f7d45706e9aec4a1dfec0aacc6d233
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//#define LOG_NDEBUG 0
18#define LOG_TAG "OMX"
19#include <utils/Log.h>
20
21#include <dlfcn.h>
22
23#include <sys/prctl.h>
24#include <sys/resource.h>
25
26#include "../include/OMX.h"
27
28#include "../include/OMXNodeInstance.h"
29
30#include <binder/IMemory.h>
31#include <media/stagefright/MediaDebug.h>
32#include <utils/threads.h>
33
34#include "OMXMaster.h"
35
36#include <OMX_Component.h>
37
38namespace android {
39
40////////////////////////////////////////////////////////////////////////////////
41
42struct OMX::CallbackDispatcher : public RefBase {
43    CallbackDispatcher(OMXNodeInstance *owner);
44
45    void post(const omx_message &msg);
46
47protected:
48    virtual ~CallbackDispatcher();
49
50private:
51    Mutex mLock;
52
53    OMXNodeInstance *mOwner;
54    bool mDone;
55    Condition mQueueChanged;
56    List<omx_message> mQueue;
57
58    pthread_t mThread;
59
60    void dispatch(const omx_message &msg);
61
62    static void *ThreadWrapper(void *me);
63    void threadEntry();
64
65    CallbackDispatcher(const CallbackDispatcher &);
66    CallbackDispatcher &operator=(const CallbackDispatcher &);
67};
68
69OMX::CallbackDispatcher::CallbackDispatcher(OMXNodeInstance *owner)
70    : mOwner(owner),
71      mDone(false) {
72    pthread_attr_t attr;
73    pthread_attr_init(&attr);
74    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
75
76    pthread_create(&mThread, &attr, ThreadWrapper, this);
77
78    pthread_attr_destroy(&attr);
79}
80
81OMX::CallbackDispatcher::~CallbackDispatcher() {
82    {
83        Mutex::Autolock autoLock(mLock);
84
85        mDone = true;
86        mQueueChanged.signal();
87    }
88
89    void *dummy;
90    pthread_join(mThread, &dummy);
91}
92
93void OMX::CallbackDispatcher::post(const omx_message &msg) {
94    Mutex::Autolock autoLock(mLock);
95
96    mQueue.push_back(msg);
97    mQueueChanged.signal();
98}
99
100void OMX::CallbackDispatcher::dispatch(const omx_message &msg) {
101    if (mOwner == NULL) {
102        LOGV("Would have dispatched a message to a node that's already gone.");
103        return;
104    }
105    mOwner->onMessage(msg);
106}
107
108// static
109void *OMX::CallbackDispatcher::ThreadWrapper(void *me) {
110    static_cast<CallbackDispatcher *>(me)->threadEntry();
111
112    return NULL;
113}
114
115void OMX::CallbackDispatcher::threadEntry() {
116    setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_AUDIO);
117    prctl(PR_SET_NAME, (unsigned long)"OMXCallbackDisp", 0, 0, 0);
118
119    for (;;) {
120        omx_message msg;
121
122        {
123            Mutex::Autolock autoLock(mLock);
124            while (!mDone && mQueue.empty()) {
125                mQueueChanged.wait(mLock);
126            }
127
128            if (mDone) {
129                break;
130            }
131
132            msg = *mQueue.begin();
133            mQueue.erase(mQueue.begin());
134        }
135
136        dispatch(msg);
137    }
138}
139
140////////////////////////////////////////////////////////////////////////////////
141
142OMX::OMX()
143    : mMaster(new OMXMaster),
144      mNodeCounter(0) {
145}
146
147OMX::~OMX() {
148    delete mMaster;
149    mMaster = NULL;
150}
151
152void OMX::binderDied(const wp<IBinder> &the_late_who) {
153    OMXNodeInstance *instance;
154
155    {
156        Mutex::Autolock autoLock(mLock);
157
158        ssize_t index = mLiveNodes.indexOfKey(the_late_who);
159        CHECK(index >= 0);
160
161        instance = mLiveNodes.editValueAt(index);
162        mLiveNodes.removeItemsAt(index);
163
164        index = mDispatchers.indexOfKey(instance->nodeID());
165        CHECK(index >= 0);
166        mDispatchers.removeItemsAt(index);
167
168        invalidateNodeID_l(instance->nodeID());
169    }
170
171    instance->onObserverDied(mMaster);
172}
173
174bool OMX::livesLocally(pid_t pid) {
175    return pid == getpid();
176}
177
178status_t OMX::listNodes(List<ComponentInfo> *list) {
179    list->clear();
180
181    OMX_U32 index = 0;
182    char componentName[256];
183    while (mMaster->enumerateComponents(
184                componentName, sizeof(componentName), index) == OMX_ErrorNone) {
185        list->push_back(ComponentInfo());
186        ComponentInfo &info = *--list->end();
187
188        info.mName = componentName;
189
190        Vector<String8> roles;
191        OMX_ERRORTYPE err =
192            mMaster->getRolesOfComponent(componentName, &roles);
193
194        if (err == OMX_ErrorNone) {
195            for (OMX_U32 i = 0; i < roles.size(); ++i) {
196                info.mRoles.push_back(roles[i]);
197            }
198        }
199
200        ++index;
201    }
202
203    return OK;
204}
205
206status_t OMX::allocateNode(
207        const char *name, const sp<IOMXObserver> &observer, node_id *node) {
208    Mutex::Autolock autoLock(mLock);
209
210    *node = 0;
211
212    OMXNodeInstance *instance = new OMXNodeInstance(this, observer);
213
214    OMX_COMPONENTTYPE *handle;
215    OMX_ERRORTYPE err = mMaster->makeComponentInstance(
216            name, &OMXNodeInstance::kCallbacks,
217            instance, &handle);
218
219    if (err != OMX_ErrorNone) {
220        LOGV("FAILED to allocate omx component '%s'", name);
221
222        instance->onGetHandleFailed();
223
224        return UNKNOWN_ERROR;
225    }
226
227    *node = makeNodeID(instance);
228    mDispatchers.add(*node, new CallbackDispatcher(instance));
229
230    instance->setHandle(*node, handle);
231
232    mLiveNodes.add(observer->asBinder(), instance);
233    observer->asBinder()->linkToDeath(this);
234
235    return OK;
236}
237
238status_t OMX::freeNode(node_id node) {
239    OMXNodeInstance *instance = findInstance(node);
240
241    ssize_t index = mLiveNodes.indexOfKey(instance->observer()->asBinder());
242    CHECK(index >= 0);
243    mLiveNodes.removeItemsAt(index);
244
245    instance->observer()->asBinder()->unlinkToDeath(this);
246
247    status_t err = instance->freeNode(mMaster);
248
249    index = mDispatchers.indexOfKey(node);
250    CHECK(index >= 0);
251    mDispatchers.removeItemsAt(index);
252
253    return err;
254}
255
256status_t OMX::sendCommand(
257        node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) {
258    return findInstance(node)->sendCommand(cmd, param);
259}
260
261status_t OMX::getParameter(
262        node_id node, OMX_INDEXTYPE index,
263        void *params, size_t size) {
264    return findInstance(node)->getParameter(
265            index, params, size);
266}
267
268status_t OMX::setParameter(
269        node_id node, OMX_INDEXTYPE index,
270        const void *params, size_t size) {
271    return findInstance(node)->setParameter(
272            index, params, size);
273}
274
275status_t OMX::getConfig(
276        node_id node, OMX_INDEXTYPE index,
277        void *params, size_t size) {
278    return findInstance(node)->getConfig(
279            index, params, size);
280}
281
282status_t OMX::setConfig(
283        node_id node, OMX_INDEXTYPE index,
284        const void *params, size_t size) {
285    return findInstance(node)->setConfig(
286            index, params, size);
287}
288
289status_t OMX::enableGraphicBuffers(
290        node_id node, OMX_U32 port_index, OMX_BOOL enable) {
291    return findInstance(node)->enableGraphicBuffers(port_index, enable);
292}
293
294status_t OMX::storeMetaDataInBuffers(
295        node_id node, OMX_U32 port_index, OMX_BOOL enable) {
296    return findInstance(node)->storeMetaDataInBuffers(port_index, enable);
297}
298
299status_t OMX::useBuffer(
300        node_id node, OMX_U32 port_index, const sp<IMemory> &params,
301        buffer_id *buffer) {
302    return findInstance(node)->useBuffer(
303            port_index, params, buffer);
304}
305
306status_t OMX::useGraphicBuffer(
307        node_id node, OMX_U32 port_index,
308        const sp<GraphicBuffer> &graphicBuffer, buffer_id *buffer) {
309    return findInstance(node)->useGraphicBuffer(
310            port_index, graphicBuffer, buffer);
311}
312
313status_t OMX::allocateBuffer(
314        node_id node, OMX_U32 port_index, size_t size,
315        buffer_id *buffer, void **buffer_data) {
316    return findInstance(node)->allocateBuffer(
317            port_index, size, buffer, buffer_data);
318}
319
320status_t OMX::allocateBufferWithBackup(
321        node_id node, OMX_U32 port_index, const sp<IMemory> &params,
322        buffer_id *buffer) {
323    return findInstance(node)->allocateBufferWithBackup(
324            port_index, params, buffer);
325}
326
327status_t OMX::freeBuffer(node_id node, OMX_U32 port_index, buffer_id buffer) {
328    return findInstance(node)->freeBuffer(
329            port_index, buffer);
330}
331
332status_t OMX::fillBuffer(node_id node, buffer_id buffer) {
333    return findInstance(node)->fillBuffer(buffer);
334}
335
336status_t OMX::emptyBuffer(
337        node_id node,
338        buffer_id buffer,
339        OMX_U32 range_offset, OMX_U32 range_length,
340        OMX_U32 flags, OMX_TICKS timestamp) {
341    return findInstance(node)->emptyBuffer(
342            buffer, range_offset, range_length, flags, timestamp);
343}
344
345status_t OMX::getExtensionIndex(
346        node_id node,
347        const char *parameter_name,
348        OMX_INDEXTYPE *index) {
349    return findInstance(node)->getExtensionIndex(
350            parameter_name, index);
351}
352
353OMX_ERRORTYPE OMX::OnEvent(
354        node_id node,
355        OMX_IN OMX_EVENTTYPE eEvent,
356        OMX_IN OMX_U32 nData1,
357        OMX_IN OMX_U32 nData2,
358        OMX_IN OMX_PTR pEventData) {
359    LOGV("OnEvent(%d, %ld, %ld)", eEvent, nData1, nData2);
360
361    omx_message msg;
362    msg.type = omx_message::EVENT;
363    msg.node = node;
364    msg.u.event_data.event = eEvent;
365    msg.u.event_data.data1 = nData1;
366    msg.u.event_data.data2 = nData2;
367
368    findDispatcher(node)->post(msg);
369
370    return OMX_ErrorNone;
371}
372
373OMX_ERRORTYPE OMX::OnEmptyBufferDone(
374        node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) {
375    LOGV("OnEmptyBufferDone buffer=%p", pBuffer);
376
377    omx_message msg;
378    msg.type = omx_message::EMPTY_BUFFER_DONE;
379    msg.node = node;
380    msg.u.buffer_data.buffer = pBuffer;
381
382    findDispatcher(node)->post(msg);
383
384    return OMX_ErrorNone;
385}
386
387OMX_ERRORTYPE OMX::OnFillBufferDone(
388        node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) {
389    LOGV("OnFillBufferDone buffer=%p", pBuffer);
390
391    omx_message msg;
392    msg.type = omx_message::FILL_BUFFER_DONE;
393    msg.node = node;
394    msg.u.extended_buffer_data.buffer = pBuffer;
395    msg.u.extended_buffer_data.range_offset = pBuffer->nOffset;
396    msg.u.extended_buffer_data.range_length = pBuffer->nFilledLen;
397    msg.u.extended_buffer_data.flags = pBuffer->nFlags;
398    msg.u.extended_buffer_data.timestamp = pBuffer->nTimeStamp;
399    msg.u.extended_buffer_data.platform_private = pBuffer->pPlatformPrivate;
400    msg.u.extended_buffer_data.data_ptr = pBuffer->pBuffer;
401
402    findDispatcher(node)->post(msg);
403
404    return OMX_ErrorNone;
405}
406
407OMX::node_id OMX::makeNodeID(OMXNodeInstance *instance) {
408    // mLock is already held.
409
410    node_id node = (node_id)++mNodeCounter;
411    mNodeIDToInstance.add(node, instance);
412
413    return node;
414}
415
416OMXNodeInstance *OMX::findInstance(node_id node) {
417    Mutex::Autolock autoLock(mLock);
418
419    ssize_t index = mNodeIDToInstance.indexOfKey(node);
420
421    return index < 0 ? NULL : mNodeIDToInstance.valueAt(index);
422}
423
424sp<OMX::CallbackDispatcher> OMX::findDispatcher(node_id node) {
425    Mutex::Autolock autoLock(mLock);
426
427    ssize_t index = mDispatchers.indexOfKey(node);
428
429    return index < 0 ? NULL : mDispatchers.valueAt(index);
430}
431
432void OMX::invalidateNodeID(node_id node) {
433    Mutex::Autolock autoLock(mLock);
434    invalidateNodeID_l(node);
435}
436
437void OMX::invalidateNodeID_l(node_id node) {
438    // mLock is held.
439    mNodeIDToInstance.removeItem(node);
440}
441
442}  // namespace android
443