OMX.cpp revision e40cda70eec141fa05cbcca1de420fdb22b98be6
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::useBuffer(
335        node_id node, OMX_U32 port_index, const sp<IMemory> &params,
336        buffer_id *buffer) {
337    return findInstance(node)->useBuffer(
338            port_index, params, buffer);
339}
340
341status_t OMX::useGraphicBuffer(
342        node_id node, OMX_U32 port_index,
343        const sp<GraphicBuffer> &graphicBuffer, buffer_id *buffer) {
344    return findInstance(node)->useGraphicBuffer(
345            port_index, graphicBuffer, buffer);
346}
347
348status_t OMX::createInputSurface(
349        node_id node, OMX_U32 port_index,
350        sp<IGraphicBufferProducer> *bufferProducer) {
351    return findInstance(node)->createInputSurface(
352            port_index, bufferProducer);
353}
354
355status_t OMX::signalEndOfInputStream(node_id node) {
356    return findInstance(node)->signalEndOfInputStream();
357}
358
359status_t OMX::allocateBuffer(
360        node_id node, OMX_U32 port_index, size_t size,
361        buffer_id *buffer, void **buffer_data) {
362    return findInstance(node)->allocateBuffer(
363            port_index, size, buffer, buffer_data);
364}
365
366status_t OMX::allocateBufferWithBackup(
367        node_id node, OMX_U32 port_index, const sp<IMemory> &params,
368        buffer_id *buffer) {
369    return findInstance(node)->allocateBufferWithBackup(
370            port_index, params, buffer);
371}
372
373status_t OMX::freeBuffer(node_id node, OMX_U32 port_index, buffer_id buffer) {
374    return findInstance(node)->freeBuffer(
375            port_index, buffer);
376}
377
378status_t OMX::fillBuffer(node_id node, buffer_id buffer) {
379    return findInstance(node)->fillBuffer(buffer);
380}
381
382status_t OMX::emptyBuffer(
383        node_id node,
384        buffer_id buffer,
385        OMX_U32 range_offset, OMX_U32 range_length,
386        OMX_U32 flags, OMX_TICKS timestamp) {
387    return findInstance(node)->emptyBuffer(
388            buffer, range_offset, range_length, flags, timestamp);
389}
390
391status_t OMX::getExtensionIndex(
392        node_id node,
393        const char *parameter_name,
394        OMX_INDEXTYPE *index) {
395    return findInstance(node)->getExtensionIndex(
396            parameter_name, index);
397}
398
399status_t OMX::setInternalOption(
400        node_id node,
401        OMX_U32 port_index,
402        InternalOptionType type,
403        const void *data,
404        size_t size) {
405    return findInstance(node)->setInternalOption(port_index, type, data, size);
406}
407
408OMX_ERRORTYPE OMX::OnEvent(
409        node_id node,
410        OMX_IN OMX_EVENTTYPE eEvent,
411        OMX_IN OMX_U32 nData1,
412        OMX_IN OMX_U32 nData2,
413        OMX_IN OMX_PTR pEventData) {
414    ALOGV("OnEvent(%d, %ld, %ld)", eEvent, nData1, nData2);
415
416    // Forward to OMXNodeInstance.
417    findInstance(node)->onEvent(eEvent, nData1, nData2);
418
419    omx_message msg;
420    msg.type = omx_message::EVENT;
421    msg.node = node;
422    msg.u.event_data.event = eEvent;
423    msg.u.event_data.data1 = nData1;
424    msg.u.event_data.data2 = nData2;
425
426    findDispatcher(node)->post(msg);
427
428    return OMX_ErrorNone;
429}
430
431OMX_ERRORTYPE OMX::OnEmptyBufferDone(
432        node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) {
433    ALOGV("OnEmptyBufferDone buffer=%p", pBuffer);
434
435    omx_message msg;
436    msg.type = omx_message::EMPTY_BUFFER_DONE;
437    msg.node = node;
438    msg.u.buffer_data.buffer = pBuffer;
439
440    findDispatcher(node)->post(msg);
441
442    return OMX_ErrorNone;
443}
444
445OMX_ERRORTYPE OMX::OnFillBufferDone(
446        node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) {
447    ALOGV("OnFillBufferDone buffer=%p", pBuffer);
448
449    omx_message msg;
450    msg.type = omx_message::FILL_BUFFER_DONE;
451    msg.node = node;
452    msg.u.extended_buffer_data.buffer = pBuffer;
453    msg.u.extended_buffer_data.range_offset = pBuffer->nOffset;
454    msg.u.extended_buffer_data.range_length = pBuffer->nFilledLen;
455    msg.u.extended_buffer_data.flags = pBuffer->nFlags;
456    msg.u.extended_buffer_data.timestamp = pBuffer->nTimeStamp;
457    msg.u.extended_buffer_data.platform_private = pBuffer->pPlatformPrivate;
458    msg.u.extended_buffer_data.data_ptr = pBuffer->pBuffer;
459
460    findDispatcher(node)->post(msg);
461
462    return OMX_ErrorNone;
463}
464
465OMX::node_id OMX::makeNodeID(OMXNodeInstance *instance) {
466    // mLock is already held.
467
468    node_id node = (node_id)++mNodeCounter;
469    mNodeIDToInstance.add(node, instance);
470
471    return node;
472}
473
474OMXNodeInstance *OMX::findInstance(node_id node) {
475    Mutex::Autolock autoLock(mLock);
476
477    ssize_t index = mNodeIDToInstance.indexOfKey(node);
478
479    return index < 0 ? NULL : mNodeIDToInstance.valueAt(index);
480}
481
482sp<OMX::CallbackDispatcher> OMX::findDispatcher(node_id node) {
483    Mutex::Autolock autoLock(mLock);
484
485    ssize_t index = mDispatchers.indexOfKey(node);
486
487    return index < 0 ? NULL : mDispatchers.valueAt(index);
488}
489
490void OMX::invalidateNodeID(node_id node) {
491    Mutex::Autolock autoLock(mLock);
492    invalidateNodeID_l(node);
493}
494
495void OMX::invalidateNodeID_l(node_id node) {
496    // mLock is held.
497    mNodeIDToInstance.removeItem(node);
498}
499
500}  // namespace android
501