OMX.cpp revision e870772a78ffe08b1c14a791e368f1499f1be0f3
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#include "OMXRenderer.h"
28
29#include "../include/OMXNodeInstance.h"
30#include "../include/SoftwareRenderer.h"
31
32#include <binder/IMemory.h>
33#include <media/stagefright/MediaDebug.h>
34#include <media/stagefright/VideoRenderer.h>
35#include <utils/threads.h>
36
37#include "OMXMaster.h"
38
39#include <OMX_Component.h>
40
41namespace android {
42
43////////////////////////////////////////////////////////////////////////////////
44
45struct OMX::CallbackDispatcher : public RefBase {
46    CallbackDispatcher(OMXNodeInstance *owner);
47
48    void post(const omx_message &msg);
49
50protected:
51    virtual ~CallbackDispatcher();
52
53private:
54    Mutex mLock;
55
56    OMXNodeInstance *mOwner;
57    bool mDone;
58    Condition mQueueChanged;
59    List<omx_message> mQueue;
60
61    pthread_t mThread;
62
63    void dispatch(const omx_message &msg);
64
65    static void *ThreadWrapper(void *me);
66    void threadEntry();
67
68    CallbackDispatcher(const CallbackDispatcher &);
69    CallbackDispatcher &operator=(const CallbackDispatcher &);
70};
71
72OMX::CallbackDispatcher::CallbackDispatcher(OMXNodeInstance *owner)
73    : mOwner(owner),
74      mDone(false) {
75    pthread_attr_t attr;
76    pthread_attr_init(&attr);
77    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
78
79    pthread_create(&mThread, &attr, ThreadWrapper, this);
80
81    pthread_attr_destroy(&attr);
82}
83
84OMX::CallbackDispatcher::~CallbackDispatcher() {
85    {
86        Mutex::Autolock autoLock(mLock);
87
88        mDone = true;
89        mQueueChanged.signal();
90    }
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    setpriority(PRIO_PROCESS, 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    index = mDispatchers.indexOfKey(node);
253    CHECK(index >= 0);
254    mDispatchers.removeItemsAt(index);
255
256    return err;
257}
258
259status_t OMX::sendCommand(
260        node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) {
261    return findInstance(node)->sendCommand(cmd, param);
262}
263
264status_t OMX::getParameter(
265        node_id node, OMX_INDEXTYPE index,
266        void *params, size_t size) {
267    return findInstance(node)->getParameter(
268            index, params, size);
269}
270
271status_t OMX::setParameter(
272        node_id node, OMX_INDEXTYPE index,
273        const void *params, size_t size) {
274    return findInstance(node)->setParameter(
275            index, params, size);
276}
277
278status_t OMX::getConfig(
279        node_id node, OMX_INDEXTYPE index,
280        void *params, size_t size) {
281    return findInstance(node)->getConfig(
282            index, params, size);
283}
284
285status_t OMX::setConfig(
286        node_id node, OMX_INDEXTYPE index,
287        const void *params, size_t size) {
288    return findInstance(node)->setConfig(
289            index, params, size);
290}
291
292status_t OMX::enableGraphicBuffers(
293        node_id node, OMX_U32 port_index, OMX_BOOL enable) {
294    return findInstance(node)->enableGraphicBuffers(port_index, enable);
295}
296
297status_t OMX::storeMetaDataInBuffers(
298        node_id node, OMX_U32 port_index, OMX_BOOL enable) {
299    return findInstance(node)->storeMetaDataInBuffers(port_index, enable);
300}
301
302status_t OMX::useBuffer(
303        node_id node, OMX_U32 port_index, const sp<IMemory> &params,
304        buffer_id *buffer) {
305    return findInstance(node)->useBuffer(
306            port_index, params, buffer);
307}
308
309status_t OMX::useGraphicBuffer(
310        node_id node, OMX_U32 port_index,
311        const sp<GraphicBuffer> &graphicBuffer, buffer_id *buffer) {
312    return findInstance(node)->useGraphicBuffer(
313            port_index, graphicBuffer, buffer);
314}
315
316status_t OMX::allocateBuffer(
317        node_id node, OMX_U32 port_index, size_t size,
318        buffer_id *buffer, void **buffer_data) {
319    return findInstance(node)->allocateBuffer(
320            port_index, size, buffer, buffer_data);
321}
322
323status_t OMX::allocateBufferWithBackup(
324        node_id node, OMX_U32 port_index, const sp<IMemory> &params,
325        buffer_id *buffer) {
326    return findInstance(node)->allocateBufferWithBackup(
327            port_index, params, buffer);
328}
329
330status_t OMX::freeBuffer(node_id node, OMX_U32 port_index, buffer_id buffer) {
331    return findInstance(node)->freeBuffer(
332            port_index, buffer);
333}
334
335status_t OMX::fillBuffer(node_id node, buffer_id buffer) {
336    return findInstance(node)->fillBuffer(buffer);
337}
338
339status_t OMX::emptyBuffer(
340        node_id node,
341        buffer_id buffer,
342        OMX_U32 range_offset, OMX_U32 range_length,
343        OMX_U32 flags, OMX_TICKS timestamp) {
344    return findInstance(node)->emptyBuffer(
345            buffer, range_offset, range_length, flags, timestamp);
346}
347
348status_t OMX::getExtensionIndex(
349        node_id node,
350        const char *parameter_name,
351        OMX_INDEXTYPE *index) {
352    return findInstance(node)->getExtensionIndex(
353            parameter_name, index);
354}
355
356OMX_ERRORTYPE OMX::OnEvent(
357        node_id node,
358        OMX_IN OMX_EVENTTYPE eEvent,
359        OMX_IN OMX_U32 nData1,
360        OMX_IN OMX_U32 nData2,
361        OMX_IN OMX_PTR pEventData) {
362    LOGV("OnEvent(%d, %ld, %ld)", eEvent, nData1, nData2);
363
364    omx_message msg;
365    msg.type = omx_message::EVENT;
366    msg.node = node;
367    msg.u.event_data.event = eEvent;
368    msg.u.event_data.data1 = nData1;
369    msg.u.event_data.data2 = nData2;
370
371    findDispatcher(node)->post(msg);
372
373    return OMX_ErrorNone;
374}
375
376OMX_ERRORTYPE OMX::OnEmptyBufferDone(
377        node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) {
378    LOGV("OnEmptyBufferDone buffer=%p", pBuffer);
379
380    omx_message msg;
381    msg.type = omx_message::EMPTY_BUFFER_DONE;
382    msg.node = node;
383    msg.u.buffer_data.buffer = pBuffer;
384
385    findDispatcher(node)->post(msg);
386
387    return OMX_ErrorNone;
388}
389
390OMX_ERRORTYPE OMX::OnFillBufferDone(
391        node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) {
392    LOGV("OnFillBufferDone buffer=%p", pBuffer);
393
394    omx_message msg;
395    msg.type = omx_message::FILL_BUFFER_DONE;
396    msg.node = node;
397    msg.u.extended_buffer_data.buffer = pBuffer;
398    msg.u.extended_buffer_data.range_offset = pBuffer->nOffset;
399    msg.u.extended_buffer_data.range_length = pBuffer->nFilledLen;
400    msg.u.extended_buffer_data.flags = pBuffer->nFlags;
401    msg.u.extended_buffer_data.timestamp = pBuffer->nTimeStamp;
402    msg.u.extended_buffer_data.platform_private = pBuffer->pPlatformPrivate;
403    msg.u.extended_buffer_data.data_ptr = pBuffer->pBuffer;
404
405    findDispatcher(node)->post(msg);
406
407    return OMX_ErrorNone;
408}
409
410OMX::node_id OMX::makeNodeID(OMXNodeInstance *instance) {
411    // mLock is already held.
412
413    node_id node = (node_id)++mNodeCounter;
414    mNodeIDToInstance.add(node, instance);
415
416    return node;
417}
418
419OMXNodeInstance *OMX::findInstance(node_id node) {
420    Mutex::Autolock autoLock(mLock);
421
422    ssize_t index = mNodeIDToInstance.indexOfKey(node);
423
424    return index < 0 ? NULL : mNodeIDToInstance.valueAt(index);
425}
426
427sp<OMX::CallbackDispatcher> OMX::findDispatcher(node_id node) {
428    Mutex::Autolock autoLock(mLock);
429
430    ssize_t index = mDispatchers.indexOfKey(node);
431
432    return index < 0 ? NULL : mDispatchers.valueAt(index);
433}
434
435void OMX::invalidateNodeID(node_id node) {
436    Mutex::Autolock autoLock(mLock);
437    invalidateNodeID_l(node);
438}
439
440void OMX::invalidateNodeID_l(node_id node) {
441    // mLock is held.
442    mNodeIDToInstance.removeItem(node);
443}
444
445////////////////////////////////////////////////////////////////////////////////
446
447struct SharedVideoRenderer : public VideoRenderer {
448    SharedVideoRenderer(void *libHandle, VideoRenderer *obj)
449        : mLibHandle(libHandle),
450          mObj(obj) {
451    }
452
453    virtual ~SharedVideoRenderer() {
454        delete mObj;
455        mObj = NULL;
456
457        dlclose(mLibHandle);
458        mLibHandle = NULL;
459    }
460
461    virtual void render(
462            const void *data, size_t size, void *platformPrivate) {
463        return mObj->render(data, size, platformPrivate);
464    }
465
466private:
467    void *mLibHandle;
468    VideoRenderer *mObj;
469
470    SharedVideoRenderer(const SharedVideoRenderer &);
471    SharedVideoRenderer &operator=(const SharedVideoRenderer &);
472};
473
474sp<IOMXRenderer> OMX::createRenderer(
475        const sp<ISurface> &surface,
476        const char *componentName,
477        OMX_COLOR_FORMATTYPE colorFormat,
478        size_t encodedWidth, size_t encodedHeight,
479        size_t displayWidth, size_t displayHeight) {
480    Mutex::Autolock autoLock(mLock);
481
482    VideoRenderer *impl = NULL;
483
484    void *libHandle = dlopen("libstagefrighthw.so", RTLD_NOW);
485
486    if (libHandle) {
487        typedef VideoRenderer *(*CreateRendererFunc)(
488                const sp<ISurface> &surface,
489                const char *componentName,
490                OMX_COLOR_FORMATTYPE colorFormat,
491                size_t displayWidth, size_t displayHeight,
492                size_t decodedWidth, size_t decodedHeight);
493
494        CreateRendererFunc func =
495            (CreateRendererFunc)dlsym(
496                    libHandle,
497                    "_Z14createRendererRKN7android2spINS_8ISurfaceEEEPKc20"
498                    "OMX_COLOR_FORMATTYPEjjjj");
499
500        if (func) {
501            impl = (*func)(surface, componentName, colorFormat,
502                    displayWidth, displayHeight, encodedWidth, encodedHeight);
503
504            if (impl) {
505                impl = new SharedVideoRenderer(libHandle, impl);
506                libHandle = NULL;
507            }
508        }
509
510        if (libHandle) {
511            dlclose(libHandle);
512            libHandle = NULL;
513        }
514    }
515
516    if (!impl) {
517#if 0
518        LOGW("Using software renderer.");
519        impl = new SoftwareRenderer(
520                colorFormat,
521                surface,
522                displayWidth, displayHeight,
523                encodedWidth, encodedHeight);
524#else
525        CHECK(!"Should not be here.");
526        return NULL;
527#endif
528    }
529
530    return new OMXRenderer(impl);
531}
532
533OMXRenderer::OMXRenderer(VideoRenderer *impl)
534    : mImpl(impl) {
535}
536
537OMXRenderer::~OMXRenderer() {
538    delete mImpl;
539    mImpl = NULL;
540}
541
542void OMXRenderer::render(IOMX::buffer_id buffer) {
543    OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
544
545    mImpl->render(
546            header->pBuffer + header->nOffset,
547            header->nFilledLen,
548            header->pPlatformPrivate);
549}
550
551}  // namespace android
552