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