OMX.cpp revision d411b4ca2945cd8974a3a78199fce94646950128
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
25#include "../include/OMXNodeInstance.h"
26
27#include <binder/IMemory.h>
28#include <media/stagefright/foundation/ADebug.h>
29#include <utils/threads.h>
30
31#include "OMXMaster.h"
32
33#include <OMX_Component.h>
34
35namespace android {
36
37////////////////////////////////////////////////////////////////////////////////
38
39// This provides the underlying Thread used by CallbackDispatcher.
40// Note that deriving CallbackDispatcher from Thread does not work.
41
42struct OMX::CallbackDispatcherThread : public Thread {
43    CallbackDispatcherThread(CallbackDispatcher *dispatcher)
44        : mDispatcher(dispatcher) {
45    }
46
47private:
48    CallbackDispatcher *mDispatcher;
49
50    bool threadLoop();
51
52    CallbackDispatcherThread(const CallbackDispatcherThread &);
53    CallbackDispatcherThread &operator=(const CallbackDispatcherThread &);
54};
55
56////////////////////////////////////////////////////////////////////////////////
57
58struct OMX::CallbackDispatcher : public RefBase {
59    CallbackDispatcher(OMXNodeInstance *owner);
60
61    void post(const omx_message &msg);
62
63    bool loop();
64
65protected:
66    virtual ~CallbackDispatcher();
67
68private:
69    Mutex mLock;
70
71    OMXNodeInstance *mOwner;
72    bool mDone;
73    Condition mQueueChanged;
74    List<omx_message> mQueue;
75
76    sp<CallbackDispatcherThread> mThread;
77
78    void dispatch(const omx_message &msg);
79
80    CallbackDispatcher(const CallbackDispatcher &);
81    CallbackDispatcher &operator=(const CallbackDispatcher &);
82};
83
84OMX::CallbackDispatcher::CallbackDispatcher(OMXNodeInstance *owner)
85    : mOwner(owner),
86      mDone(false) {
87    mThread = new CallbackDispatcherThread(this);
88    mThread->run("OMXCallbackDisp", ANDROID_PRIORITY_FOREGROUND);
89}
90
91OMX::CallbackDispatcher::~CallbackDispatcher() {
92    {
93        Mutex::Autolock autoLock(mLock);
94
95        mDone = true;
96        mQueueChanged.signal();
97    }
98
99    // A join on self can happen if the last ref to CallbackDispatcher
100    // is released within the CallbackDispatcherThread loop
101    status_t status = mThread->join();
102    if (status != WOULD_BLOCK) {
103        // Other than join to self, the only other error return codes are
104        // whatever readyToRun() returns, and we don't override that
105        CHECK_EQ(status, (status_t)NO_ERROR);
106    }
107}
108
109void OMX::CallbackDispatcher::post(const omx_message &msg) {
110    Mutex::Autolock autoLock(mLock);
111
112    mQueue.push_back(msg);
113    mQueueChanged.signal();
114}
115
116void OMX::CallbackDispatcher::dispatch(const omx_message &msg) {
117    if (mOwner == NULL) {
118        ALOGV("Would have dispatched a message to a node that's already gone.");
119        return;
120    }
121    mOwner->onMessage(msg);
122}
123
124bool OMX::CallbackDispatcher::loop() {
125    for (;;) {
126        omx_message msg;
127
128        {
129            Mutex::Autolock autoLock(mLock);
130            while (!mDone && mQueue.empty()) {
131                mQueueChanged.wait(mLock);
132            }
133
134            if (mDone) {
135                break;
136            }
137
138            msg = *mQueue.begin();
139            mQueue.erase(mQueue.begin());
140        }
141
142        dispatch(msg);
143    }
144
145    return false;
146}
147
148////////////////////////////////////////////////////////////////////////////////
149
150bool OMX::CallbackDispatcherThread::threadLoop() {
151    return mDispatcher->loop();
152}
153
154////////////////////////////////////////////////////////////////////////////////
155
156OMX::OMX()
157    : mMaster(new OMXMaster),
158      mNodeCounter(0) {
159}
160
161OMX::~OMX() {
162    delete mMaster;
163    mMaster = NULL;
164}
165
166void OMX::binderDied(const wp<IBinder> &the_late_who) {
167    OMXNodeInstance *instance;
168
169    {
170        Mutex::Autolock autoLock(mLock);
171
172        ssize_t index = mLiveNodes.indexOfKey(the_late_who);
173        CHECK(index >= 0);
174
175        instance = mLiveNodes.editValueAt(index);
176        mLiveNodes.removeItemsAt(index);
177
178        index = mDispatchers.indexOfKey(instance->nodeID());
179        CHECK(index >= 0);
180        mDispatchers.removeItemsAt(index);
181
182        invalidateNodeID_l(instance->nodeID());
183    }
184
185    instance->onObserverDied(mMaster);
186}
187
188bool OMX::livesLocally(node_id /* node */, pid_t pid) {
189    return pid == getpid();
190}
191
192status_t OMX::listNodes(List<ComponentInfo> *list) {
193    list->clear();
194
195    OMX_U32 index = 0;
196    char componentName[256];
197    while (mMaster->enumerateComponents(
198                componentName, sizeof(componentName), index) == OMX_ErrorNone) {
199        list->push_back(ComponentInfo());
200        ComponentInfo &info = *--list->end();
201
202        info.mName = componentName;
203
204        Vector<String8> roles;
205        OMX_ERRORTYPE err =
206            mMaster->getRolesOfComponent(componentName, &roles);
207
208        if (err == OMX_ErrorNone) {
209            for (OMX_U32 i = 0; i < roles.size(); ++i) {
210                info.mRoles.push_back(roles[i]);
211            }
212        }
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    OMXNodeInstance *instance = new OMXNodeInstance(this, observer);
227
228    OMX_COMPONENTTYPE *handle;
229    OMX_ERRORTYPE err = mMaster->makeComponentInstance(
230            name, &OMXNodeInstance::kCallbacks,
231            instance, &handle);
232
233    if (err != OMX_ErrorNone) {
234        ALOGV("FAILED to allocate omx component '%s'", name);
235
236        instance->onGetHandleFailed();
237
238        return UNKNOWN_ERROR;
239    }
240
241    *node = makeNodeID(instance);
242    mDispatchers.add(*node, new CallbackDispatcher(instance));
243
244    instance->setHandle(*node, handle);
245
246    mLiveNodes.add(observer->asBinder(), instance);
247    observer->asBinder()->linkToDeath(this);
248
249    return OK;
250}
251
252status_t OMX::freeNode(node_id node) {
253    OMXNodeInstance *instance = findInstance(node);
254
255    {
256        Mutex::Autolock autoLock(mLock);
257        ssize_t index = mLiveNodes.indexOfKey(instance->observer()->asBinder());
258        if (index < 0) {
259            // This could conceivably happen if the observer dies at roughly the
260            // same time that a client attempts to free the node explicitly.
261            return OK;
262        }
263        mLiveNodes.removeItemsAt(index);
264    }
265
266    instance->observer()->asBinder()->unlinkToDeath(this);
267
268    status_t err = instance->freeNode(mMaster);
269
270    {
271        Mutex::Autolock autoLock(mLock);
272        ssize_t index = mDispatchers.indexOfKey(node);
273        CHECK(index >= 0);
274        mDispatchers.removeItemsAt(index);
275    }
276
277    return err;
278}
279
280status_t OMX::sendCommand(
281        node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) {
282    return findInstance(node)->sendCommand(cmd, param);
283}
284
285status_t OMX::getParameter(
286        node_id node, OMX_INDEXTYPE index,
287        void *params, size_t size) {
288    return findInstance(node)->getParameter(
289            index, params, size);
290}
291
292status_t OMX::setParameter(
293        node_id node, OMX_INDEXTYPE index,
294        const void *params, size_t size) {
295    return findInstance(node)->setParameter(
296            index, params, size);
297}
298
299status_t OMX::getConfig(
300        node_id node, OMX_INDEXTYPE index,
301        void *params, size_t size) {
302    return findInstance(node)->getConfig(
303            index, params, size);
304}
305
306status_t OMX::setConfig(
307        node_id node, OMX_INDEXTYPE index,
308        const void *params, size_t size) {
309    return findInstance(node)->setConfig(
310            index, params, size);
311}
312
313status_t OMX::getState(
314        node_id node, OMX_STATETYPE* state) {
315    return findInstance(node)->getState(
316            state);
317}
318
319status_t OMX::enableGraphicBuffers(
320        node_id node, OMX_U32 port_index, OMX_BOOL enable) {
321    return findInstance(node)->enableGraphicBuffers(port_index, enable);
322}
323
324status_t OMX::getGraphicBufferUsage(
325        node_id node, OMX_U32 port_index, OMX_U32* usage) {
326    return findInstance(node)->getGraphicBufferUsage(port_index, usage);
327}
328
329status_t OMX::storeMetaDataInBuffers(
330        node_id node, OMX_U32 port_index, OMX_BOOL enable) {
331    return findInstance(node)->storeMetaDataInBuffers(port_index, enable);
332}
333
334status_t OMX::prepareForAdaptivePlayback(
335        node_id node, OMX_U32 portIndex, OMX_BOOL enable,
336        OMX_U32 maxFrameWidth, OMX_U32 maxFrameHeight) {
337    return findInstance(node)->prepareForAdaptivePlayback(
338            portIndex, enable, maxFrameWidth, maxFrameHeight);
339}
340
341status_t OMX::useBuffer(
342        node_id node, OMX_U32 port_index, const sp<IMemory> &params,
343        buffer_id *buffer) {
344    return findInstance(node)->useBuffer(
345            port_index, params, buffer);
346}
347
348status_t OMX::useGraphicBuffer(
349        node_id node, OMX_U32 port_index,
350        const sp<GraphicBuffer> &graphicBuffer, buffer_id *buffer) {
351    return findInstance(node)->useGraphicBuffer(
352            port_index, graphicBuffer, buffer);
353}
354
355status_t OMX::updateGraphicBufferInMeta(
356        node_id node, OMX_U32 port_index,
357        const sp<GraphicBuffer> &graphicBuffer, buffer_id buffer) {
358    return findInstance(node)->updateGraphicBufferInMeta(
359            port_index, graphicBuffer, buffer);
360}
361
362status_t OMX::createInputSurface(
363        node_id node, OMX_U32 port_index,
364        sp<IGraphicBufferProducer> *bufferProducer) {
365    return findInstance(node)->createInputSurface(
366            port_index, bufferProducer);
367}
368
369status_t OMX::signalEndOfInputStream(node_id node) {
370    return findInstance(node)->signalEndOfInputStream();
371}
372
373status_t OMX::allocateBuffer(
374        node_id node, OMX_U32 port_index, size_t size,
375        buffer_id *buffer, void **buffer_data) {
376    return findInstance(node)->allocateBuffer(
377            port_index, size, buffer, buffer_data);
378}
379
380status_t OMX::allocateBufferWithBackup(
381        node_id node, OMX_U32 port_index, const sp<IMemory> &params,
382        buffer_id *buffer) {
383    return findInstance(node)->allocateBufferWithBackup(
384            port_index, params, buffer);
385}
386
387status_t OMX::freeBuffer(node_id node, OMX_U32 port_index, buffer_id buffer) {
388    return findInstance(node)->freeBuffer(
389            port_index, buffer);
390}
391
392status_t OMX::fillBuffer(node_id node, buffer_id buffer) {
393    return findInstance(node)->fillBuffer(buffer);
394}
395
396status_t OMX::emptyBuffer(
397        node_id node,
398        buffer_id buffer,
399        OMX_U32 range_offset, OMX_U32 range_length,
400        OMX_U32 flags, OMX_TICKS timestamp) {
401    return findInstance(node)->emptyBuffer(
402            buffer, range_offset, range_length, flags, timestamp);
403}
404
405status_t OMX::getExtensionIndex(
406        node_id node,
407        const char *parameter_name,
408        OMX_INDEXTYPE *index) {
409    return findInstance(node)->getExtensionIndex(
410            parameter_name, index);
411}
412
413status_t OMX::setInternalOption(
414        node_id node,
415        OMX_U32 port_index,
416        InternalOptionType type,
417        const void *data,
418        size_t size) {
419    return findInstance(node)->setInternalOption(port_index, type, data, size);
420}
421
422OMX_ERRORTYPE OMX::OnEvent(
423        node_id node,
424        OMX_IN OMX_EVENTTYPE eEvent,
425        OMX_IN OMX_U32 nData1,
426        OMX_IN OMX_U32 nData2,
427        OMX_IN OMX_PTR /* pEventData */) {
428    ALOGV("OnEvent(%d, %ld, %ld)", eEvent, nData1, nData2);
429
430    // Forward to OMXNodeInstance.
431    findInstance(node)->onEvent(eEvent, nData1, nData2);
432
433    omx_message msg;
434    msg.type = omx_message::EVENT;
435    msg.node = node;
436    msg.u.event_data.event = eEvent;
437    msg.u.event_data.data1 = nData1;
438    msg.u.event_data.data2 = nData2;
439
440    findDispatcher(node)->post(msg);
441
442    return OMX_ErrorNone;
443}
444
445OMX_ERRORTYPE OMX::OnEmptyBufferDone(
446        node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) {
447    ALOGV("OnEmptyBufferDone buffer=%p", pBuffer);
448
449    omx_message msg;
450    msg.type = omx_message::EMPTY_BUFFER_DONE;
451    msg.node = node;
452    msg.u.buffer_data.buffer = pBuffer;
453
454    findDispatcher(node)->post(msg);
455
456    return OMX_ErrorNone;
457}
458
459OMX_ERRORTYPE OMX::OnFillBufferDone(
460        node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) {
461    ALOGV("OnFillBufferDone buffer=%p", pBuffer);
462
463    omx_message msg;
464    msg.type = omx_message::FILL_BUFFER_DONE;
465    msg.node = node;
466    msg.u.extended_buffer_data.buffer = pBuffer;
467    msg.u.extended_buffer_data.range_offset = pBuffer->nOffset;
468    msg.u.extended_buffer_data.range_length = pBuffer->nFilledLen;
469    msg.u.extended_buffer_data.flags = pBuffer->nFlags;
470    msg.u.extended_buffer_data.timestamp = pBuffer->nTimeStamp;
471    msg.u.extended_buffer_data.platform_private = pBuffer->pPlatformPrivate;
472    msg.u.extended_buffer_data.data_ptr = pBuffer->pBuffer;
473
474    findDispatcher(node)->post(msg);
475
476    return OMX_ErrorNone;
477}
478
479OMX::node_id OMX::makeNodeID(OMXNodeInstance *instance) {
480    // mLock is already held.
481
482    node_id node = (node_id)(uintptr_t)++mNodeCounter;
483    mNodeIDToInstance.add(node, instance);
484
485    return node;
486}
487
488OMXNodeInstance *OMX::findInstance(node_id node) {
489    Mutex::Autolock autoLock(mLock);
490
491    ssize_t index = mNodeIDToInstance.indexOfKey(node);
492
493    return index < 0 ? NULL : mNodeIDToInstance.valueAt(index);
494}
495
496sp<OMX::CallbackDispatcher> OMX::findDispatcher(node_id node) {
497    Mutex::Autolock autoLock(mLock);
498
499    ssize_t index = mDispatchers.indexOfKey(node);
500
501    return index < 0 ? NULL : mDispatchers.valueAt(index);
502}
503
504void OMX::invalidateNodeID(node_id node) {
505    Mutex::Autolock autoLock(mLock);
506    invalidateNodeID_l(node);
507}
508
509void OMX::invalidateNodeID_l(node_id node) {
510    // mLock is held.
511    mNodeIDToInstance.removeItem(node);
512}
513
514}  // namespace android
515