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