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