OMX.cpp revision b78ff5fb6f56c679bce936078180ce61a1e97288
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    ssize_t index = mLiveNodes.indexOfKey(instance->observer()->asBinder());
256    if (index < 0) {
257        // This could conceivably happen if the observer dies at roughly the
258        // same time that a client attempts to free the node explicitly.
259        return OK;
260    }
261    mLiveNodes.removeItemsAt(index);
262
263    instance->observer()->asBinder()->unlinkToDeath(this);
264
265    status_t err = instance->freeNode(mMaster);
266
267    {
268        Mutex::Autolock autoLock(mLock);
269        index = mDispatchers.indexOfKey(node);
270        CHECK(index >= 0);
271        mDispatchers.removeItemsAt(index);
272    }
273
274    return err;
275}
276
277status_t OMX::sendCommand(
278        node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) {
279    return findInstance(node)->sendCommand(cmd, param);
280}
281
282status_t OMX::getParameter(
283        node_id node, OMX_INDEXTYPE index,
284        void *params, size_t size) {
285    return findInstance(node)->getParameter(
286            index, params, size);
287}
288
289status_t OMX::setParameter(
290        node_id node, OMX_INDEXTYPE index,
291        const void *params, size_t size) {
292    return findInstance(node)->setParameter(
293            index, params, size);
294}
295
296status_t OMX::getConfig(
297        node_id node, OMX_INDEXTYPE index,
298        void *params, size_t size) {
299    return findInstance(node)->getConfig(
300            index, params, size);
301}
302
303status_t OMX::setConfig(
304        node_id node, OMX_INDEXTYPE index,
305        const void *params, size_t size) {
306    return findInstance(node)->setConfig(
307            index, params, size);
308}
309
310status_t OMX::getState(
311        node_id node, OMX_STATETYPE* state) {
312    return findInstance(node)->getState(
313            state);
314}
315
316status_t OMX::enableGraphicBuffers(
317        node_id node, OMX_U32 port_index, OMX_BOOL enable) {
318    return findInstance(node)->enableGraphicBuffers(port_index, enable);
319}
320
321status_t OMX::getGraphicBufferUsage(
322        node_id node, OMX_U32 port_index, OMX_U32* usage) {
323    return findInstance(node)->getGraphicBufferUsage(port_index, usage);
324}
325
326status_t OMX::storeMetaDataInBuffers(
327        node_id node, OMX_U32 port_index, OMX_BOOL enable) {
328    return findInstance(node)->storeMetaDataInBuffers(port_index, enable);
329}
330
331status_t OMX::useBuffer(
332        node_id node, OMX_U32 port_index, const sp<IMemory> &params,
333        buffer_id *buffer) {
334    return findInstance(node)->useBuffer(
335            port_index, params, buffer);
336}
337
338status_t OMX::useGraphicBuffer(
339        node_id node, OMX_U32 port_index,
340        const sp<GraphicBuffer> &graphicBuffer, buffer_id *buffer) {
341    return findInstance(node)->useGraphicBuffer(
342            port_index, graphicBuffer, buffer);
343}
344
345status_t OMX::allocateBuffer(
346        node_id node, OMX_U32 port_index, size_t size,
347        buffer_id *buffer, void **buffer_data) {
348    return findInstance(node)->allocateBuffer(
349            port_index, size, buffer, buffer_data);
350}
351
352status_t OMX::allocateBufferWithBackup(
353        node_id node, OMX_U32 port_index, const sp<IMemory> &params,
354        buffer_id *buffer) {
355    return findInstance(node)->allocateBufferWithBackup(
356            port_index, params, buffer);
357}
358
359status_t OMX::freeBuffer(node_id node, OMX_U32 port_index, buffer_id buffer) {
360    return findInstance(node)->freeBuffer(
361            port_index, buffer);
362}
363
364status_t OMX::fillBuffer(node_id node, buffer_id buffer) {
365    return findInstance(node)->fillBuffer(buffer);
366}
367
368status_t OMX::emptyBuffer(
369        node_id node,
370        buffer_id buffer,
371        OMX_U32 range_offset, OMX_U32 range_length,
372        OMX_U32 flags, OMX_TICKS timestamp) {
373    return findInstance(node)->emptyBuffer(
374            buffer, range_offset, range_length, flags, timestamp);
375}
376
377status_t OMX::getExtensionIndex(
378        node_id node,
379        const char *parameter_name,
380        OMX_INDEXTYPE *index) {
381    return findInstance(node)->getExtensionIndex(
382            parameter_name, index);
383}
384
385OMX_ERRORTYPE OMX::OnEvent(
386        node_id node,
387        OMX_IN OMX_EVENTTYPE eEvent,
388        OMX_IN OMX_U32 nData1,
389        OMX_IN OMX_U32 nData2,
390        OMX_IN OMX_PTR pEventData) {
391    ALOGV("OnEvent(%d, %ld, %ld)", eEvent, nData1, nData2);
392
393    omx_message msg;
394    msg.type = omx_message::EVENT;
395    msg.node = node;
396    msg.u.event_data.event = eEvent;
397    msg.u.event_data.data1 = nData1;
398    msg.u.event_data.data2 = nData2;
399
400    findDispatcher(node)->post(msg);
401
402    return OMX_ErrorNone;
403}
404
405OMX_ERRORTYPE OMX::OnEmptyBufferDone(
406        node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) {
407    ALOGV("OnEmptyBufferDone buffer=%p", pBuffer);
408
409    omx_message msg;
410    msg.type = omx_message::EMPTY_BUFFER_DONE;
411    msg.node = node;
412    msg.u.buffer_data.buffer = pBuffer;
413
414    findDispatcher(node)->post(msg);
415
416    return OMX_ErrorNone;
417}
418
419OMX_ERRORTYPE OMX::OnFillBufferDone(
420        node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) {
421    ALOGV("OnFillBufferDone buffer=%p", pBuffer);
422
423    omx_message msg;
424    msg.type = omx_message::FILL_BUFFER_DONE;
425    msg.node = node;
426    msg.u.extended_buffer_data.buffer = pBuffer;
427    msg.u.extended_buffer_data.range_offset = pBuffer->nOffset;
428    msg.u.extended_buffer_data.range_length = pBuffer->nFilledLen;
429    msg.u.extended_buffer_data.flags = pBuffer->nFlags;
430    msg.u.extended_buffer_data.timestamp = pBuffer->nTimeStamp;
431    msg.u.extended_buffer_data.platform_private = pBuffer->pPlatformPrivate;
432    msg.u.extended_buffer_data.data_ptr = pBuffer->pBuffer;
433
434    findDispatcher(node)->post(msg);
435
436    return OMX_ErrorNone;
437}
438
439OMX::node_id OMX::makeNodeID(OMXNodeInstance *instance) {
440    // mLock is already held.
441
442    node_id node = (node_id)++mNodeCounter;
443    mNodeIDToInstance.add(node, instance);
444
445    return node;
446}
447
448OMXNodeInstance *OMX::findInstance(node_id node) {
449    Mutex::Autolock autoLock(mLock);
450
451    ssize_t index = mNodeIDToInstance.indexOfKey(node);
452
453    return index < 0 ? NULL : mNodeIDToInstance.valueAt(index);
454}
455
456sp<OMX::CallbackDispatcher> OMX::findDispatcher(node_id node) {
457    Mutex::Autolock autoLock(mLock);
458
459    ssize_t index = mDispatchers.indexOfKey(node);
460
461    return index < 0 ? NULL : mDispatchers.valueAt(index);
462}
463
464void OMX::invalidateNodeID(node_id node) {
465    Mutex::Autolock autoLock(mLock);
466    invalidateNodeID_l(node);
467}
468
469void OMX::invalidateNodeID_l(node_id node) {
470    // mLock is held.
471    mNodeIDToInstance.removeItem(node);
472}
473
474}  // namespace android
475