OMX.cpp revision ca9718b81d1edb3d094a11502737293dcb7526e7
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/MediaDebug.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_AUDIO);
89}
90
91OMX::CallbackDispatcher::~CallbackDispatcher() {
92    {
93        Mutex::Autolock autoLock(mLock);
94
95        mDone = true;
96        mQueueChanged.signal();
97    }
98
99    // Don't call join on myself
100    status_t status = mThread->join();
101    CHECK(status == NO_ERROR);
102}
103
104void OMX::CallbackDispatcher::post(const omx_message &msg) {
105    Mutex::Autolock autoLock(mLock);
106
107    mQueue.push_back(msg);
108    mQueueChanged.signal();
109}
110
111void OMX::CallbackDispatcher::dispatch(const omx_message &msg) {
112    if (mOwner == NULL) {
113        LOGV("Would have dispatched a message to a node that's already gone.");
114        return;
115    }
116    mOwner->onMessage(msg);
117}
118
119bool OMX::CallbackDispatcher::loop() {
120    for (;;) {
121        omx_message msg;
122
123        {
124            Mutex::Autolock autoLock(mLock);
125            while (!mDone && mQueue.empty()) {
126                mQueueChanged.wait(mLock);
127            }
128
129            if (mDone) {
130                break;
131            }
132
133            msg = *mQueue.begin();
134            mQueue.erase(mQueue.begin());
135        }
136
137        dispatch(msg);
138    }
139
140    return false;
141}
142
143////////////////////////////////////////////////////////////////////////////////
144
145bool OMX::CallbackDispatcherThread::threadLoop() {
146    return mDispatcher->loop();
147}
148
149////////////////////////////////////////////////////////////////////////////////
150
151OMX::OMX()
152    : mMaster(new OMXMaster),
153      mNodeCounter(0) {
154}
155
156OMX::~OMX() {
157    delete mMaster;
158    mMaster = NULL;
159}
160
161void OMX::binderDied(const wp<IBinder> &the_late_who) {
162    OMXNodeInstance *instance;
163
164    {
165        Mutex::Autolock autoLock(mLock);
166
167        ssize_t index = mLiveNodes.indexOfKey(the_late_who);
168        CHECK(index >= 0);
169
170        instance = mLiveNodes.editValueAt(index);
171        mLiveNodes.removeItemsAt(index);
172
173        index = mDispatchers.indexOfKey(instance->nodeID());
174        CHECK(index >= 0);
175        mDispatchers.removeItemsAt(index);
176
177        invalidateNodeID_l(instance->nodeID());
178    }
179
180    instance->onObserverDied(mMaster);
181}
182
183bool OMX::livesLocally(pid_t pid) {
184    return pid == getpid();
185}
186
187status_t OMX::listNodes(List<ComponentInfo> *list) {
188    list->clear();
189
190    OMX_U32 index = 0;
191    char componentName[256];
192    while (mMaster->enumerateComponents(
193                componentName, sizeof(componentName), index) == OMX_ErrorNone) {
194        list->push_back(ComponentInfo());
195        ComponentInfo &info = *--list->end();
196
197        info.mName = componentName;
198
199        Vector<String8> roles;
200        OMX_ERRORTYPE err =
201            mMaster->getRolesOfComponent(componentName, &roles);
202
203        if (err == OMX_ErrorNone) {
204            for (OMX_U32 i = 0; i < roles.size(); ++i) {
205                info.mRoles.push_back(roles[i]);
206            }
207        }
208
209        ++index;
210    }
211
212    return OK;
213}
214
215status_t OMX::allocateNode(
216        const char *name, const sp<IOMXObserver> &observer, node_id *node) {
217    Mutex::Autolock autoLock(mLock);
218
219    *node = 0;
220
221    OMXNodeInstance *instance = new OMXNodeInstance(this, observer);
222
223    OMX_COMPONENTTYPE *handle;
224    OMX_ERRORTYPE err = mMaster->makeComponentInstance(
225            name, &OMXNodeInstance::kCallbacks,
226            instance, &handle);
227
228    if (err != OMX_ErrorNone) {
229        LOGV("FAILED to allocate omx component '%s'", name);
230
231        instance->onGetHandleFailed();
232
233        return UNKNOWN_ERROR;
234    }
235
236    *node = makeNodeID(instance);
237    mDispatchers.add(*node, new CallbackDispatcher(instance));
238
239    instance->setHandle(*node, handle);
240
241    mLiveNodes.add(observer->asBinder(), instance);
242    observer->asBinder()->linkToDeath(this);
243
244    return OK;
245}
246
247status_t OMX::freeNode(node_id node) {
248    OMXNodeInstance *instance = findInstance(node);
249
250    ssize_t index = mLiveNodes.indexOfKey(instance->observer()->asBinder());
251    CHECK(index >= 0);
252    mLiveNodes.removeItemsAt(index);
253
254    instance->observer()->asBinder()->unlinkToDeath(this);
255
256    status_t err = instance->freeNode(mMaster);
257
258    {
259        Mutex::Autolock autoLock(mLock);
260        index = mDispatchers.indexOfKey(node);
261        CHECK(index >= 0);
262        mDispatchers.removeItemsAt(index);
263    }
264
265    return err;
266}
267
268status_t OMX::sendCommand(
269        node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) {
270    return findInstance(node)->sendCommand(cmd, param);
271}
272
273status_t OMX::getParameter(
274        node_id node, OMX_INDEXTYPE index,
275        void *params, size_t size) {
276    return findInstance(node)->getParameter(
277            index, params, size);
278}
279
280status_t OMX::setParameter(
281        node_id node, OMX_INDEXTYPE index,
282        const void *params, size_t size) {
283    return findInstance(node)->setParameter(
284            index, params, size);
285}
286
287status_t OMX::getConfig(
288        node_id node, OMX_INDEXTYPE index,
289        void *params, size_t size) {
290    return findInstance(node)->getConfig(
291            index, params, size);
292}
293
294status_t OMX::setConfig(
295        node_id node, OMX_INDEXTYPE index,
296        const void *params, size_t size) {
297    return findInstance(node)->setConfig(
298            index, params, size);
299}
300
301status_t OMX::enableGraphicBuffers(
302        node_id node, OMX_U32 port_index, OMX_BOOL enable) {
303    return findInstance(node)->enableGraphicBuffers(port_index, enable);
304}
305
306status_t OMX::getGraphicBufferUsage(
307        node_id node, OMX_U32 port_index, OMX_U32* usage) {
308    return findInstance(node)->getGraphicBufferUsage(port_index, usage);
309}
310
311status_t OMX::storeMetaDataInBuffers(
312        node_id node, OMX_U32 port_index, OMX_BOOL enable) {
313    return findInstance(node)->storeMetaDataInBuffers(port_index, enable);
314}
315
316status_t OMX::useBuffer(
317        node_id node, OMX_U32 port_index, const sp<IMemory> &params,
318        buffer_id *buffer) {
319    return findInstance(node)->useBuffer(
320            port_index, params, buffer);
321}
322
323status_t OMX::useGraphicBuffer(
324        node_id node, OMX_U32 port_index,
325        const sp<GraphicBuffer> &graphicBuffer, buffer_id *buffer) {
326    return findInstance(node)->useGraphicBuffer(
327            port_index, graphicBuffer, buffer);
328}
329
330status_t OMX::allocateBuffer(
331        node_id node, OMX_U32 port_index, size_t size,
332        buffer_id *buffer, void **buffer_data) {
333    return findInstance(node)->allocateBuffer(
334            port_index, size, buffer, buffer_data);
335}
336
337status_t OMX::allocateBufferWithBackup(
338        node_id node, OMX_U32 port_index, const sp<IMemory> &params,
339        buffer_id *buffer) {
340    return findInstance(node)->allocateBufferWithBackup(
341            port_index, params, buffer);
342}
343
344status_t OMX::freeBuffer(node_id node, OMX_U32 port_index, buffer_id buffer) {
345    return findInstance(node)->freeBuffer(
346            port_index, buffer);
347}
348
349status_t OMX::fillBuffer(node_id node, buffer_id buffer) {
350    return findInstance(node)->fillBuffer(buffer);
351}
352
353status_t OMX::emptyBuffer(
354        node_id node,
355        buffer_id buffer,
356        OMX_U32 range_offset, OMX_U32 range_length,
357        OMX_U32 flags, OMX_TICKS timestamp) {
358    return findInstance(node)->emptyBuffer(
359            buffer, range_offset, range_length, flags, timestamp);
360}
361
362status_t OMX::getExtensionIndex(
363        node_id node,
364        const char *parameter_name,
365        OMX_INDEXTYPE *index) {
366    return findInstance(node)->getExtensionIndex(
367            parameter_name, index);
368}
369
370OMX_ERRORTYPE OMX::OnEvent(
371        node_id node,
372        OMX_IN OMX_EVENTTYPE eEvent,
373        OMX_IN OMX_U32 nData1,
374        OMX_IN OMX_U32 nData2,
375        OMX_IN OMX_PTR pEventData) {
376    LOGV("OnEvent(%d, %ld, %ld)", eEvent, nData1, nData2);
377
378    omx_message msg;
379    msg.type = omx_message::EVENT;
380    msg.node = node;
381    msg.u.event_data.event = eEvent;
382    msg.u.event_data.data1 = nData1;
383    msg.u.event_data.data2 = nData2;
384
385    findDispatcher(node)->post(msg);
386
387    return OMX_ErrorNone;
388}
389
390OMX_ERRORTYPE OMX::OnEmptyBufferDone(
391        node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) {
392    LOGV("OnEmptyBufferDone buffer=%p", pBuffer);
393
394    omx_message msg;
395    msg.type = omx_message::EMPTY_BUFFER_DONE;
396    msg.node = node;
397    msg.u.buffer_data.buffer = pBuffer;
398
399    findDispatcher(node)->post(msg);
400
401    return OMX_ErrorNone;
402}
403
404OMX_ERRORTYPE OMX::OnFillBufferDone(
405        node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) {
406    LOGV("OnFillBufferDone buffer=%p", pBuffer);
407
408    omx_message msg;
409    msg.type = omx_message::FILL_BUFFER_DONE;
410    msg.node = node;
411    msg.u.extended_buffer_data.buffer = pBuffer;
412    msg.u.extended_buffer_data.range_offset = pBuffer->nOffset;
413    msg.u.extended_buffer_data.range_length = pBuffer->nFilledLen;
414    msg.u.extended_buffer_data.flags = pBuffer->nFlags;
415    msg.u.extended_buffer_data.timestamp = pBuffer->nTimeStamp;
416    msg.u.extended_buffer_data.platform_private = pBuffer->pPlatformPrivate;
417    msg.u.extended_buffer_data.data_ptr = pBuffer->pBuffer;
418
419    findDispatcher(node)->post(msg);
420
421    return OMX_ErrorNone;
422}
423
424OMX::node_id OMX::makeNodeID(OMXNodeInstance *instance) {
425    // mLock is already held.
426
427    node_id node = (node_id)++mNodeCounter;
428    mNodeIDToInstance.add(node, instance);
429
430    return node;
431}
432
433OMXNodeInstance *OMX::findInstance(node_id node) {
434    Mutex::Autolock autoLock(mLock);
435
436    ssize_t index = mNodeIDToInstance.indexOfKey(node);
437
438    return index < 0 ? NULL : mNodeIDToInstance.valueAt(index);
439}
440
441sp<OMX::CallbackDispatcher> OMX::findDispatcher(node_id node) {
442    Mutex::Autolock autoLock(mLock);
443
444    ssize_t index = mDispatchers.indexOfKey(node);
445
446    return index < 0 ? NULL : mDispatchers.valueAt(index);
447}
448
449void OMX::invalidateNodeID(node_id node) {
450    Mutex::Autolock autoLock(mLock);
451    invalidateNodeID_l(node);
452}
453
454void OMX::invalidateNodeID_l(node_id node) {
455    // mLock is held.
456    mNodeIDToInstance.removeItem(node);
457}
458
459}  // namespace android
460