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