OMX.cpp revision 78d26445a7dfe8f49d7005185f28b01cffe80adf
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        invalidateNodeID_l(instance->nodeID());
168    }
169
170    instance->onObserverDied(mMaster);
171}
172
173bool OMX::livesLocally(pid_t pid) {
174    return pid == getpid();
175}
176
177status_t OMX::listNodes(List<ComponentInfo> *list) {
178    list->clear();
179
180    OMX_U32 index = 0;
181    char componentName[256];
182    while (mMaster->enumerateComponents(
183                componentName, sizeof(componentName), index) == OMX_ErrorNone) {
184        list->push_back(ComponentInfo());
185        ComponentInfo &info = *--list->end();
186
187        info.mName = componentName;
188
189        Vector<String8> roles;
190        OMX_ERRORTYPE err =
191            mMaster->getRolesOfComponent(componentName, &roles);
192
193        if (err == OMX_ErrorNone) {
194            for (OMX_U32 i = 0; i < roles.size(); ++i) {
195                info.mRoles.push_back(roles[i]);
196            }
197        }
198
199        ++index;
200    }
201
202    return OK;
203}
204
205status_t OMX::allocateNode(
206        const char *name, const sp<IOMXObserver> &observer, node_id *node) {
207    Mutex::Autolock autoLock(mLock);
208
209    *node = 0;
210
211    OMXNodeInstance *instance = new OMXNodeInstance(this, observer);
212
213    OMX_COMPONENTTYPE *handle;
214    OMX_ERRORTYPE err = mMaster->makeComponentInstance(
215            name, &OMXNodeInstance::kCallbacks,
216            instance, &handle);
217
218    if (err != OMX_ErrorNone) {
219        LOGV("FAILED to allocate omx component '%s'", name);
220
221        instance->onGetHandleFailed();
222
223        return UNKNOWN_ERROR;
224    }
225
226    *node = makeNodeID(instance);
227    mDispatchers.add(*node, new CallbackDispatcher(instance));
228
229    instance->setHandle(*node, handle);
230
231    mLiveNodes.add(observer->asBinder(), instance);
232    observer->asBinder()->linkToDeath(this);
233
234    return OK;
235}
236
237status_t OMX::freeNode(node_id node) {
238    OMXNodeInstance *instance = findInstance(node);
239
240    ssize_t index = mLiveNodes.indexOfKey(instance->observer()->asBinder());
241    CHECK(index >= 0);
242    mLiveNodes.removeItemsAt(index);
243    instance->observer()->asBinder()->unlinkToDeath(this);
244
245    return instance->freeNode(mMaster);
246}
247
248status_t OMX::sendCommand(
249        node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) {
250    return findInstance(node)->sendCommand(cmd, param);
251}
252
253status_t OMX::getParameter(
254        node_id node, OMX_INDEXTYPE index,
255        void *params, size_t size) {
256    return findInstance(node)->getParameter(
257            index, params, size);
258}
259
260status_t OMX::setParameter(
261        node_id node, OMX_INDEXTYPE index,
262        const void *params, size_t size) {
263    return findInstance(node)->setParameter(
264            index, params, size);
265}
266
267status_t OMX::getConfig(
268        node_id node, OMX_INDEXTYPE index,
269        void *params, size_t size) {
270    return findInstance(node)->getConfig(
271            index, params, size);
272}
273
274status_t OMX::setConfig(
275        node_id node, OMX_INDEXTYPE index,
276        const void *params, size_t size) {
277    return findInstance(node)->setConfig(
278            index, params, size);
279}
280
281status_t OMX::useBuffer(
282        node_id node, OMX_U32 port_index, const sp<IMemory> &params,
283        buffer_id *buffer) {
284    return findInstance(node)->useBuffer(
285            port_index, params, buffer);
286}
287
288status_t OMX::allocateBuffer(
289        node_id node, OMX_U32 port_index, size_t size,
290        buffer_id *buffer, void **buffer_data) {
291    return findInstance(node)->allocateBuffer(
292            port_index, size, buffer, buffer_data);
293}
294
295status_t OMX::allocateBufferWithBackup(
296        node_id node, OMX_U32 port_index, const sp<IMemory> &params,
297        buffer_id *buffer) {
298    return findInstance(node)->allocateBufferWithBackup(
299            port_index, params, buffer);
300}
301
302status_t OMX::freeBuffer(node_id node, OMX_U32 port_index, buffer_id buffer) {
303    return findInstance(node)->freeBuffer(
304            port_index, buffer);
305}
306
307status_t OMX::fillBuffer(node_id node, buffer_id buffer) {
308    return findInstance(node)->fillBuffer(buffer);
309}
310
311status_t OMX::emptyBuffer(
312        node_id node,
313        buffer_id buffer,
314        OMX_U32 range_offset, OMX_U32 range_length,
315        OMX_U32 flags, OMX_TICKS timestamp) {
316    return findInstance(node)->emptyBuffer(
317            buffer, range_offset, range_length, flags, timestamp);
318}
319
320status_t OMX::getExtensionIndex(
321        node_id node,
322        const char *parameter_name,
323        OMX_INDEXTYPE *index) {
324    return findInstance(node)->getExtensionIndex(
325            parameter_name, index);
326}
327
328OMX_ERRORTYPE OMX::OnEvent(
329        node_id node,
330        OMX_IN OMX_EVENTTYPE eEvent,
331        OMX_IN OMX_U32 nData1,
332        OMX_IN OMX_U32 nData2,
333        OMX_IN OMX_PTR pEventData) {
334    LOGV("OnEvent(%d, %ld, %ld)", eEvent, nData1, nData2);
335
336    omx_message msg;
337    msg.type = omx_message::EVENT;
338    msg.node = node;
339    msg.u.event_data.event = eEvent;
340    msg.u.event_data.data1 = nData1;
341    msg.u.event_data.data2 = nData2;
342
343    findDispatcher(node)->post(msg);
344
345    return OMX_ErrorNone;
346}
347
348OMX_ERRORTYPE OMX::OnEmptyBufferDone(
349        node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) {
350    LOGV("OnEmptyBufferDone buffer=%p", pBuffer);
351
352    omx_message msg;
353    msg.type = omx_message::EMPTY_BUFFER_DONE;
354    msg.node = node;
355    msg.u.buffer_data.buffer = pBuffer;
356
357    findDispatcher(node)->post(msg);
358
359    return OMX_ErrorNone;
360}
361
362OMX_ERRORTYPE OMX::OnFillBufferDone(
363        node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) {
364    LOGV("OnFillBufferDone buffer=%p", pBuffer);
365
366    omx_message msg;
367    msg.type = omx_message::FILL_BUFFER_DONE;
368    msg.node = node;
369    msg.u.extended_buffer_data.buffer = pBuffer;
370    msg.u.extended_buffer_data.range_offset = pBuffer->nOffset;
371    msg.u.extended_buffer_data.range_length = pBuffer->nFilledLen;
372    msg.u.extended_buffer_data.flags = pBuffer->nFlags;
373    msg.u.extended_buffer_data.timestamp = pBuffer->nTimeStamp;
374    msg.u.extended_buffer_data.platform_private = pBuffer->pPlatformPrivate;
375    msg.u.extended_buffer_data.data_ptr = pBuffer->pBuffer;
376
377    findDispatcher(node)->post(msg);
378
379    return OMX_ErrorNone;
380}
381
382OMX::node_id OMX::makeNodeID(OMXNodeInstance *instance) {
383    // mLock is already held.
384
385    node_id node = (node_id)++mNodeCounter;
386    mNodeIDToInstance.add(node, instance);
387
388    return node;
389}
390
391OMXNodeInstance *OMX::findInstance(node_id node) {
392    Mutex::Autolock autoLock(mLock);
393
394    ssize_t index = mNodeIDToInstance.indexOfKey(node);
395
396    return index < 0 ? NULL : mNodeIDToInstance.valueAt(index);
397}
398
399sp<OMX::CallbackDispatcher> OMX::findDispatcher(node_id node) {
400    Mutex::Autolock autoLock(mLock);
401
402    ssize_t index = mDispatchers.indexOfKey(node);
403
404    return index < 0 ? NULL : mDispatchers.valueAt(index);
405}
406
407void OMX::invalidateNodeID(node_id node) {
408    Mutex::Autolock autoLock(mLock);
409    invalidateNodeID_l(node);
410}
411
412void OMX::invalidateNodeID_l(node_id node) {
413    // mLock is held.
414    mNodeIDToInstance.removeItem(node);
415}
416
417////////////////////////////////////////////////////////////////////////////////
418
419struct SharedVideoRenderer : public VideoRenderer {
420    SharedVideoRenderer(void *libHandle, VideoRenderer *obj)
421        : mLibHandle(libHandle),
422          mObj(obj) {
423    }
424
425    virtual ~SharedVideoRenderer() {
426        delete mObj;
427        mObj = NULL;
428
429        dlclose(mLibHandle);
430        mLibHandle = NULL;
431    }
432
433    virtual void render(
434            const void *data, size_t size, void *platformPrivate) {
435        return mObj->render(data, size, platformPrivate);
436    }
437
438private:
439    void *mLibHandle;
440    VideoRenderer *mObj;
441
442    SharedVideoRenderer(const SharedVideoRenderer &);
443    SharedVideoRenderer &operator=(const SharedVideoRenderer &);
444};
445
446sp<IOMXRenderer> OMX::createRenderer(
447        const sp<ISurface> &surface,
448        const char *componentName,
449        OMX_COLOR_FORMATTYPE colorFormat,
450        size_t encodedWidth, size_t encodedHeight,
451        size_t displayWidth, size_t displayHeight) {
452    Mutex::Autolock autoLock(mLock);
453
454    VideoRenderer *impl = NULL;
455
456    void *libHandle = dlopen("libstagefrighthw.so", RTLD_NOW);
457
458    if (libHandle) {
459        typedef VideoRenderer *(*CreateRendererFunc)(
460                const sp<ISurface> &surface,
461                const char *componentName,
462                OMX_COLOR_FORMATTYPE colorFormat,
463                size_t displayWidth, size_t displayHeight,
464                size_t decodedWidth, size_t decodedHeight);
465
466        CreateRendererFunc func =
467            (CreateRendererFunc)dlsym(
468                    libHandle,
469                    "_Z14createRendererRKN7android2spINS_8ISurfaceEEEPKc20"
470                    "OMX_COLOR_FORMATTYPEjjjj");
471
472        if (func) {
473            impl = (*func)(surface, componentName, colorFormat,
474                    displayWidth, displayHeight, encodedWidth, encodedHeight);
475
476            if (impl) {
477                impl = new SharedVideoRenderer(libHandle, impl);
478                libHandle = NULL;
479            }
480        }
481
482        if (libHandle) {
483            dlclose(libHandle);
484            libHandle = NULL;
485        }
486    }
487
488    if (!impl) {
489        LOGW("Using software renderer.");
490        impl = new SoftwareRenderer(
491                colorFormat,
492                surface,
493                displayWidth, displayHeight,
494                encodedWidth, encodedHeight);
495    }
496
497    return new OMXRenderer(impl);
498}
499
500OMXRenderer::OMXRenderer(VideoRenderer *impl)
501    : mImpl(impl) {
502}
503
504OMXRenderer::~OMXRenderer() {
505    delete mImpl;
506    mImpl = NULL;
507}
508
509void OMXRenderer::render(IOMX::buffer_id buffer) {
510    OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
511
512    mImpl->render(
513            header->pBuffer + header->nOffset,
514            header->nFilledLen,
515            header->pPlatformPrivate);
516}
517
518}  // namespace android
519
520