OMX.cpp revision 5b65c7043dada0c89d3a941742666ac40ea35746
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/QComHardwareRenderer.h>
31#include <media/stagefright/SoftwareRenderer.h>
32#include <media/stagefright/TIHardwareRenderer.h>
33#include <media/stagefright/VideoRenderer.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    : mDispatcher(new CallbackDispatcher(this)),
184      mNodeCounter(0) {
185}
186
187void OMX::binderDied(const wp<IBinder> &the_late_who) {
188    OMXNodeInstance *instance;
189
190    {
191        Mutex::Autolock autoLock(mLock);
192
193        ssize_t index = mLiveNodes.indexOfKey(the_late_who);
194        CHECK(index >= 0);
195
196        instance = mLiveNodes.editValueAt(index);
197        mLiveNodes.removeItemsAt(index);
198
199        invalidateNodeID_l(instance->nodeID());
200    }
201
202    instance->onObserverDied();
203}
204
205status_t OMX::listNodes(List<String8> *list) {
206    OMX_MasterInit();  // XXX Put this somewhere else.
207
208    list->clear();
209
210    OMX_U32 index = 0;
211    char componentName[256];
212    while (OMX_MasterComponentNameEnum(componentName, sizeof(componentName), index)
213               == OMX_ErrorNone) {
214        list->push_back(String8(componentName));
215
216        ++index;
217    }
218
219    return OK;
220}
221
222status_t OMX::allocateNode(
223        const char *name, const sp<IOMXObserver> &observer, node_id *node) {
224    Mutex::Autolock autoLock(mLock);
225
226    *node = 0;
227
228    OMX_MasterInit();  // XXX Put this somewhere else.
229
230    OMXNodeInstance *instance = new OMXNodeInstance(this, observer);
231
232    OMX_HANDLETYPE handle;
233    OMX_ERRORTYPE err = OMX_MasterGetHandle(
234            &handle, const_cast<char *>(name), instance,
235            &OMXNodeInstance::kCallbacks);
236
237    if (err != OMX_ErrorNone) {
238        LOGE("FAILED to allocate omx component '%s'", name);
239
240        instance->onGetHandleFailed();
241
242        return UNKNOWN_ERROR;
243    }
244
245    *node = makeNodeID(instance);
246
247    instance->setHandle(*node, handle);
248
249    mLiveNodes.add(observer->asBinder(), instance);
250    observer->asBinder()->linkToDeath(this);
251
252    return OK;
253}
254
255status_t OMX::freeNode(node_id node) {
256    OMXNodeInstance *instance = findInstance(node);
257
258    ssize_t index = mLiveNodes.indexOfKey(instance->observer()->asBinder());
259    CHECK(index >= 0);
260    mLiveNodes.removeItemsAt(index);
261    instance->observer()->asBinder()->unlinkToDeath(this);
262
263    return instance->freeNode();
264}
265
266status_t OMX::sendCommand(
267        node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) {
268    return findInstance(node)->sendCommand(cmd, param);
269}
270
271status_t OMX::getParameter(
272        node_id node, OMX_INDEXTYPE index,
273        void *params, size_t size) {
274    return findInstance(node)->getParameter(
275            index, params, size);
276}
277
278status_t OMX::setParameter(
279        node_id node, OMX_INDEXTYPE index,
280        const void *params, size_t size) {
281    return findInstance(node)->setParameter(
282            index, params, size);
283}
284
285status_t OMX::getConfig(
286        node_id node, OMX_INDEXTYPE index,
287        void *params, size_t size) {
288    return findInstance(node)->getConfig(
289            index, params, size);
290}
291
292status_t OMX::setConfig(
293        node_id node, OMX_INDEXTYPE index,
294        const void *params, size_t size) {
295    return findInstance(node)->setConfig(
296            index, params, size);
297}
298
299status_t OMX::useBuffer(
300        node_id node, OMX_U32 port_index, const sp<IMemory> &params,
301        buffer_id *buffer) {
302    return findInstance(node)->useBuffer(
303            port_index, params, buffer);
304}
305
306status_t OMX::allocateBuffer(
307        node_id node, OMX_U32 port_index, size_t size,
308        buffer_id *buffer) {
309    return findInstance(node)->allocateBuffer(
310            port_index, size, buffer);
311}
312
313status_t OMX::allocateBufferWithBackup(
314        node_id node, OMX_U32 port_index, const sp<IMemory> &params,
315        buffer_id *buffer) {
316    return findInstance(node)->allocateBufferWithBackup(
317            port_index, params, buffer);
318}
319
320status_t OMX::freeBuffer(node_id node, OMX_U32 port_index, buffer_id buffer) {
321    return findInstance(node)->freeBuffer(
322            port_index, buffer);
323}
324
325status_t OMX::fillBuffer(node_id node, buffer_id buffer) {
326    return findInstance(node)->fillBuffer(buffer);
327}
328
329status_t OMX::emptyBuffer(
330        node_id node,
331        buffer_id buffer,
332        OMX_U32 range_offset, OMX_U32 range_length,
333        OMX_U32 flags, OMX_TICKS timestamp) {
334    return findInstance(node)->emptyBuffer(
335            buffer, range_offset, range_length, flags, timestamp);
336}
337
338status_t OMX::getExtensionIndex(
339        node_id node,
340        const char *parameter_name,
341        OMX_INDEXTYPE *index) {
342    return findInstance(node)->getExtensionIndex(
343            parameter_name, index);
344}
345
346OMX_ERRORTYPE OMX::OnEvent(
347        node_id node,
348        OMX_IN OMX_EVENTTYPE eEvent,
349        OMX_IN OMX_U32 nData1,
350        OMX_IN OMX_U32 nData2,
351        OMX_IN OMX_PTR pEventData) {
352    LOGV("OnEvent(%d, %ld, %ld)", eEvent, nData1, nData2);
353
354    omx_message msg;
355    msg.type = omx_message::EVENT;
356    msg.node = node;
357    msg.u.event_data.event = eEvent;
358    msg.u.event_data.data1 = nData1;
359    msg.u.event_data.data2 = nData2;
360
361    mDispatcher->post(msg);
362
363    return OMX_ErrorNone;
364}
365
366OMX_ERRORTYPE OMX::OnEmptyBufferDone(
367        node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) {
368    LOGV("OnEmptyBufferDone buffer=%p", pBuffer);
369
370    omx_message msg;
371    msg.type = omx_message::EMPTY_BUFFER_DONE;
372    msg.node = node;
373    msg.u.buffer_data.buffer = pBuffer;
374
375    mDispatcher->post(msg);
376
377    return OMX_ErrorNone;
378}
379
380OMX_ERRORTYPE OMX::OnFillBufferDone(
381        node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) {
382    LOGV("OnFillBufferDone buffer=%p", pBuffer);
383
384    omx_message msg;
385    msg.type = omx_message::FILL_BUFFER_DONE;
386    msg.node = node;
387    msg.u.extended_buffer_data.buffer = pBuffer;
388    msg.u.extended_buffer_data.range_offset = pBuffer->nOffset;
389    msg.u.extended_buffer_data.range_length = pBuffer->nFilledLen;
390    msg.u.extended_buffer_data.flags = pBuffer->nFlags;
391    msg.u.extended_buffer_data.timestamp = pBuffer->nTimeStamp;
392    msg.u.extended_buffer_data.platform_private = pBuffer->pPlatformPrivate;
393
394    mDispatcher->post(msg);
395
396    return OMX_ErrorNone;
397}
398
399OMX::node_id OMX::makeNodeID(OMXNodeInstance *instance) {
400    // mLock is already held.
401
402    node_id node = (node_id)++mNodeCounter;
403    mNodeIDToInstance.add(node, instance);
404
405    return node;
406}
407
408OMXNodeInstance *OMX::findInstance(node_id node) {
409    Mutex::Autolock autoLock(mLock);
410
411    ssize_t index = mNodeIDToInstance.indexOfKey(node);
412
413    return index < 0 ? NULL : mNodeIDToInstance.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
428sp<IOMXRenderer> OMX::createRenderer(
429        const sp<ISurface> &surface,
430        const char *componentName,
431        OMX_COLOR_FORMATTYPE colorFormat,
432        size_t encodedWidth, size_t encodedHeight,
433        size_t displayWidth, size_t displayHeight) {
434    VideoRenderer *impl = NULL;
435
436    static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
437
438    if (colorFormat == OMX_QCOM_COLOR_FormatYVU420SemiPlanar
439        && !strncmp(componentName, "OMX.qcom.video.decoder.", 23)) {
440        LOGW("Using QComHardwareRenderer.");
441        impl =
442            new QComHardwareRenderer(
443                    surface,
444                    displayWidth, displayHeight,
445                    encodedWidth, encodedHeight);
446    } else if (colorFormat == OMX_COLOR_FormatCbYCrY
447            && !strcmp(componentName, "OMX.TI.Video.Decoder")) {
448        LOGW("Using TIHardwareRenderer.");
449        impl =
450            new TIHardwareRenderer(
451                    surface,
452                    displayWidth, displayHeight,
453                    encodedWidth, encodedHeight);
454    } else {
455        LOGW("Using software renderer.");
456        impl = new SoftwareRenderer(
457                colorFormat,
458                surface,
459                displayWidth, displayHeight,
460                encodedWidth, encodedHeight);
461    }
462
463    return new OMXRenderer(impl);
464}
465
466OMXRenderer::OMXRenderer(VideoRenderer *impl)
467    : mImpl(impl) {
468}
469
470OMXRenderer::~OMXRenderer() {
471    delete mImpl;
472    mImpl = NULL;
473}
474
475void OMXRenderer::render(IOMX::buffer_id buffer) {
476    OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
477
478    mImpl->render(
479            header->pBuffer + header->nOffset,
480            header->nFilledLen,
481            header->pPlatformPrivate);
482}
483
484}  // namespace android
485
486