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