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