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