OMX.cpp revision 8ae1d0bdcef22f2bdd8d283e0e615f3ba6c3f4cd
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 "../include/OMX.h"
24#include "OMXRenderer.h"
25
26#include "../include/OMXNodeInstance.h"
27#include "../include/SoftwareRenderer.h"
28
29#include <binder/IMemory.h>
30#include <media/stagefright/MediaDebug.h>
31#include <media/stagefright/VideoRenderer.h>
32
33#include "OMXMaster.h"
34
35#include <OMX_Component.h>
36
37namespace android {
38
39////////////////////////////////////////////////////////////////////////////////
40
41struct OMX::CallbackDispatcher : public RefBase {
42    CallbackDispatcher(OMX *owner);
43
44    void post(const omx_message &msg);
45
46protected:
47    virtual ~CallbackDispatcher();
48
49private:
50    Mutex mLock;
51
52    OMX *mOwner;
53    bool mDone;
54    Condition mQueueChanged;
55    List<omx_message> mQueue;
56
57    pthread_t mThread;
58
59    void dispatch(const omx_message &msg);
60
61    static void *ThreadWrapper(void *me);
62    void threadEntry();
63
64    CallbackDispatcher(const CallbackDispatcher &);
65    CallbackDispatcher &operator=(const CallbackDispatcher &);
66};
67
68OMX::CallbackDispatcher::CallbackDispatcher(OMX *owner)
69    : mOwner(owner),
70      mDone(false) {
71    pthread_attr_t attr;
72    pthread_attr_init(&attr);
73    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
74
75    pthread_create(&mThread, &attr, ThreadWrapper, this);
76
77    pthread_attr_destroy(&attr);
78}
79
80OMX::CallbackDispatcher::~CallbackDispatcher() {
81    {
82        Mutex::Autolock autoLock(mLock);
83
84        mDone = true;
85        mQueueChanged.signal();
86    }
87
88    void *dummy;
89    pthread_join(mThread, &dummy);
90}
91
92void OMX::CallbackDispatcher::post(const omx_message &msg) {
93    Mutex::Autolock autoLock(mLock);
94    mQueue.push_back(msg);
95    mQueueChanged.signal();
96}
97
98void OMX::CallbackDispatcher::dispatch(const omx_message &msg) {
99    OMXNodeInstance *instance = mOwner->findInstance(msg.node);
100    if (instance == NULL) {
101        LOGV("Would have dispatched a message to a node that's already gone.");
102        return;
103    }
104    instance->onMessage(msg);
105}
106
107// static
108void *OMX::CallbackDispatcher::ThreadWrapper(void *me) {
109    static_cast<CallbackDispatcher *>(me)->threadEntry();
110
111    return NULL;
112}
113
114void OMX::CallbackDispatcher::threadEntry() {
115    for (;;) {
116        omx_message msg;
117
118        {
119            Mutex::Autolock autoLock(mLock);
120            while (!mDone && mQueue.empty()) {
121                mQueueChanged.wait(mLock);
122            }
123
124            if (mDone) {
125                break;
126            }
127
128            msg = *mQueue.begin();
129            mQueue.erase(mQueue.begin());
130        }
131
132        dispatch(msg);
133    }
134}
135
136////////////////////////////////////////////////////////////////////////////////
137
138class BufferMeta {
139public:
140    BufferMeta(OMX *owner, const sp<IMemory> &mem, bool is_backup = false)
141        : mOwner(owner),
142          mMem(mem),
143          mIsBackup(is_backup) {
144    }
145
146    BufferMeta(OMX *owner, size_t size)
147        : mOwner(owner),
148          mSize(size),
149          mIsBackup(false) {
150    }
151
152    void CopyFromOMX(const OMX_BUFFERHEADERTYPE *header) {
153        if (!mIsBackup) {
154            return;
155        }
156
157        memcpy((OMX_U8 *)mMem->pointer() + header->nOffset,
158               header->pBuffer + header->nOffset,
159               header->nFilledLen);
160    }
161
162    void CopyToOMX(const OMX_BUFFERHEADERTYPE *header) {
163        if (!mIsBackup) {
164            return;
165        }
166
167        memcpy(header->pBuffer + header->nOffset,
168               (const OMX_U8 *)mMem->pointer() + header->nOffset,
169               header->nFilledLen);
170    }
171
172private:
173    OMX *mOwner;
174    sp<IMemory> mMem;
175    size_t mSize;
176    bool mIsBackup;
177
178    BufferMeta(const BufferMeta &);
179    BufferMeta &operator=(const BufferMeta &);
180};
181
182OMX::OMX()
183    : mMaster(new OMXMaster),
184      mDispatcher(new CallbackDispatcher(this)),
185      mNodeCounter(0) {
186}
187
188OMX::~OMX() {
189    delete mMaster;
190    mMaster = NULL;
191}
192
193void OMX::binderDied(const wp<IBinder> &the_late_who) {
194    OMXNodeInstance *instance;
195
196    {
197        Mutex::Autolock autoLock(mLock);
198
199        ssize_t index = mLiveNodes.indexOfKey(the_late_who);
200        CHECK(index >= 0);
201
202        instance = mLiveNodes.editValueAt(index);
203        mLiveNodes.removeItemsAt(index);
204
205        invalidateNodeID_l(instance->nodeID());
206    }
207
208    instance->onObserverDied(mMaster);
209}
210
211#if 0
212static void dumpRoles(OMXMaster *master, const char *name) {
213    Vector<String8> roles;
214    OMX_ERRORTYPE err = master->getRolesOfComponent(name, &roles);
215
216    if (err != OMX_ErrorNone) {
217        LOGE("Could not get roles for component '%s'.", name);
218        return;
219    }
220
221    if (roles.isEmpty()) {
222        LOGE("Component '%s' has NO roles!", name);
223        return;
224    }
225
226    LOGI("Component '%s' has the following roles:", name);
227
228    for (size_t i = 0; i < roles.size(); ++i) {
229        LOGI("%d) %s", i + 1, roles[i].string());
230    }
231}
232#endif
233
234status_t OMX::listNodes(List<String8> *list) {
235    list->clear();
236
237    OMX_U32 index = 0;
238    char componentName[256];
239    while (mMaster->enumerateComponents(
240                componentName, sizeof(componentName), index) == OMX_ErrorNone) {
241        list->push_back(String8(componentName));
242
243        // dumpRoles(mMaster, componentName);
244
245        ++index;
246    }
247
248    return OK;
249}
250
251status_t OMX::allocateNode(
252        const char *name, const sp<IOMXObserver> &observer, node_id *node) {
253    Mutex::Autolock autoLock(mLock);
254
255    *node = 0;
256
257    OMXNodeInstance *instance = new OMXNodeInstance(this, observer);
258
259    OMX_COMPONENTTYPE *handle;
260    OMX_ERRORTYPE err = mMaster->makeComponentInstance(
261            name, &OMXNodeInstance::kCallbacks,
262            instance, &handle);
263
264    if (err != OMX_ErrorNone) {
265        LOGV("FAILED to allocate omx component '%s'", name);
266
267        instance->onGetHandleFailed();
268
269        return UNKNOWN_ERROR;
270    }
271
272    *node = makeNodeID(instance);
273
274    instance->setHandle(*node, handle);
275
276    mLiveNodes.add(observer->asBinder(), instance);
277    observer->asBinder()->linkToDeath(this);
278
279    return OK;
280}
281
282status_t OMX::freeNode(node_id node) {
283    OMXNodeInstance *instance = findInstance(node);
284
285    ssize_t index = mLiveNodes.indexOfKey(instance->observer()->asBinder());
286    CHECK(index >= 0);
287    mLiveNodes.removeItemsAt(index);
288    instance->observer()->asBinder()->unlinkToDeath(this);
289
290    return instance->freeNode(mMaster);
291}
292
293status_t OMX::sendCommand(
294        node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) {
295    return findInstance(node)->sendCommand(cmd, param);
296}
297
298status_t OMX::getParameter(
299        node_id node, OMX_INDEXTYPE index,
300        void *params, size_t size) {
301    return findInstance(node)->getParameter(
302            index, params, size);
303}
304
305status_t OMX::setParameter(
306        node_id node, OMX_INDEXTYPE index,
307        const void *params, size_t size) {
308    return findInstance(node)->setParameter(
309            index, params, size);
310}
311
312status_t OMX::getConfig(
313        node_id node, OMX_INDEXTYPE index,
314        void *params, size_t size) {
315    return findInstance(node)->getConfig(
316            index, params, size);
317}
318
319status_t OMX::setConfig(
320        node_id node, OMX_INDEXTYPE index,
321        const void *params, size_t size) {
322    return findInstance(node)->setConfig(
323            index, params, size);
324}
325
326status_t OMX::useBuffer(
327        node_id node, OMX_U32 port_index, const sp<IMemory> &params,
328        buffer_id *buffer) {
329    return findInstance(node)->useBuffer(
330            port_index, params, buffer);
331}
332
333status_t OMX::allocateBuffer(
334        node_id node, OMX_U32 port_index, size_t size,
335        buffer_id *buffer) {
336    return findInstance(node)->allocateBuffer(
337            port_index, size, buffer);
338}
339
340status_t OMX::allocateBufferWithBackup(
341        node_id node, OMX_U32 port_index, const sp<IMemory> &params,
342        buffer_id *buffer) {
343    return findInstance(node)->allocateBufferWithBackup(
344            port_index, params, buffer);
345}
346
347status_t OMX::freeBuffer(node_id node, OMX_U32 port_index, buffer_id buffer) {
348    return findInstance(node)->freeBuffer(
349            port_index, buffer);
350}
351
352status_t OMX::fillBuffer(node_id node, buffer_id buffer) {
353    return findInstance(node)->fillBuffer(buffer);
354}
355
356status_t OMX::emptyBuffer(
357        node_id node,
358        buffer_id buffer,
359        OMX_U32 range_offset, OMX_U32 range_length,
360        OMX_U32 flags, OMX_TICKS timestamp) {
361    return findInstance(node)->emptyBuffer(
362            buffer, range_offset, range_length, flags, timestamp);
363}
364
365status_t OMX::getExtensionIndex(
366        node_id node,
367        const char *parameter_name,
368        OMX_INDEXTYPE *index) {
369    return findInstance(node)->getExtensionIndex(
370            parameter_name, index);
371}
372
373OMX_ERRORTYPE OMX::OnEvent(
374        node_id node,
375        OMX_IN OMX_EVENTTYPE eEvent,
376        OMX_IN OMX_U32 nData1,
377        OMX_IN OMX_U32 nData2,
378        OMX_IN OMX_PTR pEventData) {
379    LOGV("OnEvent(%d, %ld, %ld)", eEvent, nData1, nData2);
380
381    omx_message msg;
382    msg.type = omx_message::EVENT;
383    msg.node = node;
384    msg.u.event_data.event = eEvent;
385    msg.u.event_data.data1 = nData1;
386    msg.u.event_data.data2 = nData2;
387
388    mDispatcher->post(msg);
389
390    return OMX_ErrorNone;
391}
392
393OMX_ERRORTYPE OMX::OnEmptyBufferDone(
394        node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) {
395    LOGV("OnEmptyBufferDone buffer=%p", pBuffer);
396
397    omx_message msg;
398    msg.type = omx_message::EMPTY_BUFFER_DONE;
399    msg.node = node;
400    msg.u.buffer_data.buffer = pBuffer;
401
402    mDispatcher->post(msg);
403
404    return OMX_ErrorNone;
405}
406
407OMX_ERRORTYPE OMX::OnFillBufferDone(
408        node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) {
409    LOGV("OnFillBufferDone buffer=%p", pBuffer);
410
411    omx_message msg;
412    msg.type = omx_message::FILL_BUFFER_DONE;
413    msg.node = node;
414    msg.u.extended_buffer_data.buffer = pBuffer;
415    msg.u.extended_buffer_data.range_offset = pBuffer->nOffset;
416    msg.u.extended_buffer_data.range_length = pBuffer->nFilledLen;
417    msg.u.extended_buffer_data.flags = pBuffer->nFlags;
418    msg.u.extended_buffer_data.timestamp = pBuffer->nTimeStamp;
419    msg.u.extended_buffer_data.platform_private = pBuffer->pPlatformPrivate;
420
421    mDispatcher->post(msg);
422
423    return OMX_ErrorNone;
424}
425
426OMX::node_id OMX::makeNodeID(OMXNodeInstance *instance) {
427    // mLock is already held.
428
429    node_id node = (node_id)++mNodeCounter;
430    mNodeIDToInstance.add(node, instance);
431
432    return node;
433}
434
435OMXNodeInstance *OMX::findInstance(node_id node) {
436    Mutex::Autolock autoLock(mLock);
437
438    ssize_t index = mNodeIDToInstance.indexOfKey(node);
439
440    return index < 0 ? NULL : mNodeIDToInstance.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////////////////////////////////////////////////////////////////////////////////
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    static void *libHandle = NULL;
466
467    if (!libHandle) {
468        libHandle = dlopen("libstagefrighthw.so", RTLD_NOW);
469    }
470
471    if (libHandle) {
472        typedef VideoRenderer *(*CreateRendererFunc)(
473                const sp<ISurface> &surface,
474                const char *componentName,
475                OMX_COLOR_FORMATTYPE colorFormat,
476                size_t displayWidth, size_t displayHeight,
477                size_t decodedWidth, size_t decodedHeight);
478
479        CreateRendererFunc func =
480            (CreateRendererFunc)dlsym(
481                    libHandle,
482                    "_Z14createRendererRKN7android2spINS_8ISurfaceEEEPKc20"
483                    "OMX_COLOR_FORMATTYPEjjjj");
484
485        if (func) {
486            impl = (*func)(surface, componentName, colorFormat,
487                    displayWidth, displayHeight, encodedWidth, encodedHeight);
488        }
489    }
490
491    if (!impl) {
492        LOGW("Using software renderer.");
493        impl = new SoftwareRenderer(
494                colorFormat,
495                surface,
496                displayWidth, displayHeight,
497                encodedWidth, encodedHeight);
498    }
499
500    return new OMXRenderer(impl);
501}
502
503OMXRenderer::OMXRenderer(VideoRenderer *impl)
504    : mImpl(impl) {
505}
506
507OMXRenderer::~OMXRenderer() {
508    delete mImpl;
509    mImpl = NULL;
510}
511
512void OMXRenderer::render(IOMX::buffer_id buffer) {
513    OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
514
515    mImpl->render(
516            header->pBuffer + header->nOffset,
517            header->nFilledLen,
518            header->pPlatformPrivate);
519}
520
521}  // namespace android
522
523