OMX.cpp revision 26a48f304a8754d655e554178ffb6d7ba4c5aac3
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#include <inttypes.h>
18
19//#define LOG_NDEBUG 0
20#define LOG_TAG "OMX"
21#include <utils/Log.h>
22
23#include <dlfcn.h>
24
25#include "../include/OMX.h"
26
27#include "../include/OMXNodeInstance.h"
28
29#include <binder/IMemory.h>
30#include <media/stagefright/foundation/ADebug.h>
31#include <utils/threads.h>
32
33#include "OMXMaster.h"
34
35#include <OMX_AsString.h>
36#include <OMX_Component.h>
37
38namespace android {
39
40////////////////////////////////////////////////////////////////////////////////
41
42// This provides the underlying Thread used by CallbackDispatcher.
43// Note that deriving CallbackDispatcher from Thread does not work.
44
45struct OMX::CallbackDispatcherThread : public Thread {
46    CallbackDispatcherThread(CallbackDispatcher *dispatcher)
47        : mDispatcher(dispatcher) {
48    }
49
50private:
51    CallbackDispatcher *mDispatcher;
52
53    bool threadLoop();
54
55    CallbackDispatcherThread(const CallbackDispatcherThread &);
56    CallbackDispatcherThread &operator=(const CallbackDispatcherThread &);
57};
58
59////////////////////////////////////////////////////////////////////////////////
60
61struct OMX::CallbackDispatcher : public RefBase {
62    CallbackDispatcher(OMXNodeInstance *owner);
63
64    // Posts |msg| to the listener's queue. If |realTime| is true, the listener thread is notified
65    // that a new message is available on the queue. Otherwise, the message stays on the queue, but
66    // the listener is not notified of it. It will process this message when a subsequent message
67    // is posted with |realTime| set to true.
68    void post(const omx_message &msg, bool realTime = true);
69
70    bool loop();
71
72protected:
73    virtual ~CallbackDispatcher();
74
75private:
76    Mutex mLock;
77
78    OMXNodeInstance *mOwner;
79    bool mDone;
80    Condition mQueueChanged;
81    std::list<omx_message> mQueue;
82
83    sp<CallbackDispatcherThread> mThread;
84
85    void dispatch(std::list<omx_message> &messages);
86
87    CallbackDispatcher(const CallbackDispatcher &);
88    CallbackDispatcher &operator=(const CallbackDispatcher &);
89};
90
91OMX::CallbackDispatcher::CallbackDispatcher(OMXNodeInstance *owner)
92    : mOwner(owner),
93      mDone(false) {
94    mThread = new CallbackDispatcherThread(this);
95    mThread->run("OMXCallbackDisp", ANDROID_PRIORITY_FOREGROUND);
96}
97
98OMX::CallbackDispatcher::~CallbackDispatcher() {
99    {
100        Mutex::Autolock autoLock(mLock);
101
102        mDone = true;
103        mQueueChanged.signal();
104    }
105
106    // A join on self can happen if the last ref to CallbackDispatcher
107    // is released within the CallbackDispatcherThread loop
108    status_t status = mThread->join();
109    if (status != WOULD_BLOCK) {
110        // Other than join to self, the only other error return codes are
111        // whatever readyToRun() returns, and we don't override that
112        CHECK_EQ(status, (status_t)NO_ERROR);
113    }
114}
115
116void OMX::CallbackDispatcher::post(const omx_message &msg, bool realTime) {
117    Mutex::Autolock autoLock(mLock);
118
119    mQueue.push_back(msg);
120    if (realTime) {
121        mQueueChanged.signal();
122    }
123}
124
125void OMX::CallbackDispatcher::dispatch(std::list<omx_message> &messages) {
126    if (mOwner == NULL) {
127        ALOGV("Would have dispatched a message to a node that's already gone.");
128        return;
129    }
130    mOwner->onMessages(messages);
131}
132
133bool OMX::CallbackDispatcher::loop() {
134    for (;;) {
135        std::list<omx_message> messages;
136
137        {
138            Mutex::Autolock autoLock(mLock);
139            while (!mDone && mQueue.empty()) {
140                mQueueChanged.wait(mLock);
141            }
142
143            if (mDone) {
144                break;
145            }
146
147            messages.swap(mQueue);
148        }
149
150        dispatch(messages);
151    }
152
153    return false;
154}
155
156////////////////////////////////////////////////////////////////////////////////
157
158bool OMX::CallbackDispatcherThread::threadLoop() {
159    return mDispatcher->loop();
160}
161
162////////////////////////////////////////////////////////////////////////////////
163
164OMX::OMX()
165    : mMaster(new OMXMaster),
166      mNodeCounter(0) {
167}
168
169OMX::~OMX() {
170    delete mMaster;
171    mMaster = NULL;
172}
173
174void OMX::binderDied(const wp<IBinder> &the_late_who) {
175    OMXNodeInstance *instance;
176
177    {
178        Mutex::Autolock autoLock(mLock);
179
180        ssize_t index = mLiveNodes.indexOfKey(the_late_who);
181        CHECK(index >= 0);
182
183        instance = mLiveNodes.editValueAt(index);
184        mLiveNodes.removeItemsAt(index);
185
186        index = mDispatchers.indexOfKey(instance->nodeID());
187        CHECK(index >= 0);
188        mDispatchers.removeItemsAt(index);
189
190        invalidateNodeID_l(instance->nodeID());
191    }
192
193    instance->onObserverDied(mMaster);
194}
195
196bool OMX::livesLocally(node_id /* node */, pid_t pid) {
197    return pid == getpid();
198}
199
200status_t OMX::listNodes(List<ComponentInfo> *list) {
201    list->clear();
202
203    OMX_U32 index = 0;
204    char componentName[256];
205    while (mMaster->enumerateComponents(
206                componentName, sizeof(componentName), index) == OMX_ErrorNone) {
207        list->push_back(ComponentInfo());
208        ComponentInfo &info = *--list->end();
209
210        info.mName = componentName;
211
212        Vector<String8> roles;
213        OMX_ERRORTYPE err =
214            mMaster->getRolesOfComponent(componentName, &roles);
215
216        if (err == OMX_ErrorNone) {
217            for (OMX_U32 i = 0; i < roles.size(); ++i) {
218                info.mRoles.push_back(roles[i]);
219            }
220        }
221
222        ++index;
223    }
224
225    return OK;
226}
227
228status_t OMX::allocateNode(
229        const char *name, const sp<IOMXObserver> &observer, node_id *node) {
230    Mutex::Autolock autoLock(mLock);
231
232    *node = 0;
233
234    OMXNodeInstance *instance = new OMXNodeInstance(this, observer, name);
235
236    OMX_COMPONENTTYPE *handle;
237    OMX_ERRORTYPE err = mMaster->makeComponentInstance(
238            name, &OMXNodeInstance::kCallbacks,
239            instance, &handle);
240
241    if (err != OMX_ErrorNone) {
242        ALOGE("FAILED to allocate omx component '%s' err=%s(%#x)", name, asString(err), err);
243
244        instance->onGetHandleFailed();
245
246        return StatusFromOMXError(err);
247    }
248
249    *node = makeNodeID(instance);
250    mDispatchers.add(*node, new CallbackDispatcher(instance));
251
252    instance->setHandle(*node, handle);
253
254    mLiveNodes.add(IInterface::asBinder(observer), instance);
255    IInterface::asBinder(observer)->linkToDeath(this);
256
257    return OK;
258}
259
260status_t OMX::freeNode(node_id node) {
261    OMXNodeInstance *instance = findInstance(node);
262
263    {
264        Mutex::Autolock autoLock(mLock);
265        ssize_t index = mLiveNodes.indexOfKey(IInterface::asBinder(instance->observer()));
266        if (index < 0) {
267            // This could conceivably happen if the observer dies at roughly the
268            // same time that a client attempts to free the node explicitly.
269            return OK;
270        }
271        mLiveNodes.removeItemsAt(index);
272    }
273
274    IInterface::asBinder(instance->observer())->unlinkToDeath(this);
275
276    status_t err = instance->freeNode(mMaster);
277
278    {
279        Mutex::Autolock autoLock(mLock);
280        ssize_t index = mDispatchers.indexOfKey(node);
281        CHECK(index >= 0);
282        mDispatchers.removeItemsAt(index);
283    }
284
285    return err;
286}
287
288status_t OMX::sendCommand(
289        node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) {
290    return findInstance(node)->sendCommand(cmd, param);
291}
292
293status_t OMX::getParameter(
294        node_id node, OMX_INDEXTYPE index,
295        void *params, size_t size) {
296    ALOGV("getParameter(%u %#x %p %zd)", node, index, params, size);
297    return findInstance(node)->getParameter(
298            index, params, size);
299}
300
301status_t OMX::setParameter(
302        node_id node, OMX_INDEXTYPE index,
303        const void *params, size_t size) {
304    ALOGV("setParameter(%u %#x %p %zd)", node, index, params, size);
305    return findInstance(node)->setParameter(
306            index, params, size);
307}
308
309status_t OMX::getConfig(
310        node_id node, OMX_INDEXTYPE index,
311        void *params, size_t size) {
312    return findInstance(node)->getConfig(
313            index, params, size);
314}
315
316status_t OMX::setConfig(
317        node_id node, OMX_INDEXTYPE index,
318        const void *params, size_t size) {
319    return findInstance(node)->setConfig(
320            index, params, size);
321}
322
323status_t OMX::getState(
324        node_id node, OMX_STATETYPE* state) {
325    return findInstance(node)->getState(
326            state);
327}
328
329status_t OMX::enableGraphicBuffers(
330        node_id node, OMX_U32 port_index, OMX_BOOL enable) {
331    return findInstance(node)->enableGraphicBuffers(port_index, enable);
332}
333
334status_t OMX::getGraphicBufferUsage(
335        node_id node, OMX_U32 port_index, OMX_U32* usage) {
336    return findInstance(node)->getGraphicBufferUsage(port_index, usage);
337}
338
339status_t OMX::storeMetaDataInBuffers(
340        node_id node, OMX_U32 port_index, OMX_BOOL enable, MetadataBufferType *type) {
341    return findInstance(node)->storeMetaDataInBuffers(port_index, enable, type);
342}
343
344status_t OMX::prepareForAdaptivePlayback(
345        node_id node, OMX_U32 portIndex, OMX_BOOL enable,
346        OMX_U32 maxFrameWidth, OMX_U32 maxFrameHeight) {
347    return findInstance(node)->prepareForAdaptivePlayback(
348            portIndex, enable, maxFrameWidth, maxFrameHeight);
349}
350
351status_t OMX::configureVideoTunnelMode(
352        node_id node, OMX_U32 portIndex, OMX_BOOL tunneled,
353        OMX_U32 audioHwSync, native_handle_t **sidebandHandle) {
354    return findInstance(node)->configureVideoTunnelMode(
355            portIndex, tunneled, audioHwSync, sidebandHandle);
356}
357
358status_t OMX::useBuffer(
359        node_id node, OMX_U32 port_index, const sp<IMemory> &params,
360        buffer_id *buffer, OMX_U32 allottedSize) {
361    return findInstance(node)->useBuffer(
362            port_index, params, buffer, allottedSize);
363}
364
365status_t OMX::useGraphicBuffer(
366        node_id node, OMX_U32 port_index,
367        const sp<GraphicBuffer> &graphicBuffer, buffer_id *buffer) {
368    return findInstance(node)->useGraphicBuffer(
369            port_index, graphicBuffer, buffer);
370}
371
372status_t OMX::updateGraphicBufferInMeta(
373        node_id node, OMX_U32 port_index,
374        const sp<GraphicBuffer> &graphicBuffer, buffer_id buffer) {
375    return findInstance(node)->updateGraphicBufferInMeta(
376            port_index, graphicBuffer, buffer);
377}
378
379status_t OMX::createInputSurface(
380        node_id node, OMX_U32 port_index,
381        sp<IGraphicBufferProducer> *bufferProducer, MetadataBufferType *type) {
382    return findInstance(node)->createInputSurface(
383            port_index, bufferProducer, type);
384}
385
386status_t OMX::createPersistentInputSurface(
387        sp<IGraphicBufferProducer> *bufferProducer,
388        sp<IGraphicBufferConsumer> *bufferConsumer) {
389    return OMXNodeInstance::createPersistentInputSurface(
390            bufferProducer, bufferConsumer);
391}
392
393status_t OMX::setInputSurface(
394        node_id node, OMX_U32 port_index,
395        const sp<IGraphicBufferConsumer> &bufferConsumer, MetadataBufferType *type) {
396    return findInstance(node)->setInputSurface(port_index, bufferConsumer, type);
397}
398
399
400status_t OMX::signalEndOfInputStream(node_id node) {
401    return findInstance(node)->signalEndOfInputStream();
402}
403
404status_t OMX::allocateBuffer(
405        node_id node, OMX_U32 port_index, size_t size,
406        buffer_id *buffer, void **buffer_data) {
407    return findInstance(node)->allocateBuffer(
408            port_index, size, buffer, buffer_data);
409}
410
411status_t OMX::allocateBufferWithBackup(
412        node_id node, OMX_U32 port_index, const sp<IMemory> &params,
413        buffer_id *buffer, OMX_U32 allottedSize) {
414    return findInstance(node)->allocateBufferWithBackup(
415            port_index, params, buffer, allottedSize);
416}
417
418status_t OMX::freeBuffer(node_id node, OMX_U32 port_index, buffer_id buffer) {
419    return findInstance(node)->freeBuffer(
420            port_index, buffer);
421}
422
423status_t OMX::fillBuffer(node_id node, buffer_id buffer, int fenceFd) {
424    return findInstance(node)->fillBuffer(buffer, fenceFd);
425}
426
427status_t OMX::emptyBuffer(
428        node_id node,
429        buffer_id buffer,
430        OMX_U32 range_offset, OMX_U32 range_length,
431        OMX_U32 flags, OMX_TICKS timestamp, int fenceFd) {
432    return findInstance(node)->emptyBuffer(
433            buffer, range_offset, range_length, flags, timestamp, fenceFd);
434}
435
436status_t OMX::getExtensionIndex(
437        node_id node,
438        const char *parameter_name,
439        OMX_INDEXTYPE *index) {
440    return findInstance(node)->getExtensionIndex(
441            parameter_name, index);
442}
443
444status_t OMX::setInternalOption(
445        node_id node,
446        OMX_U32 port_index,
447        InternalOptionType type,
448        const void *data,
449        size_t size) {
450    return findInstance(node)->setInternalOption(port_index, type, data, size);
451}
452
453OMX_ERRORTYPE OMX::OnEvent(
454        node_id node,
455        OMX_IN OMX_EVENTTYPE eEvent,
456        OMX_IN OMX_U32 nData1,
457        OMX_IN OMX_U32 nData2,
458        OMX_IN OMX_PTR /* pEventData */) {
459    ALOGV("OnEvent(%d, %" PRIu32", %" PRIu32 ")", eEvent, nData1, nData2);
460
461    // Forward to OMXNodeInstance.
462    findInstance(node)->onEvent(eEvent, nData1, nData2);
463
464    omx_message msg;
465    msg.type = omx_message::EVENT;
466    msg.node = node;
467    msg.fenceFd = -1;
468    msg.u.event_data.event = eEvent;
469    msg.u.event_data.data1 = nData1;
470    msg.u.event_data.data2 = nData2;
471
472    findDispatcher(node)->post(msg);
473
474    return OMX_ErrorNone;
475}
476
477OMX_ERRORTYPE OMX::OnEmptyBufferDone(
478        node_id node, buffer_id buffer, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer, int fenceFd) {
479    ALOGV("OnEmptyBufferDone buffer=%p", pBuffer);
480
481    omx_message msg;
482    msg.type = omx_message::EMPTY_BUFFER_DONE;
483    msg.node = node;
484    msg.fenceFd = fenceFd;
485    msg.u.buffer_data.buffer = buffer;
486
487    findDispatcher(node)->post(msg);
488
489    return OMX_ErrorNone;
490}
491
492OMX_ERRORTYPE OMX::OnFillBufferDone(
493        node_id node, buffer_id buffer, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer, int fenceFd) {
494    ALOGV("OnFillBufferDone buffer=%p", pBuffer);
495
496    omx_message msg;
497    msg.type = omx_message::FILL_BUFFER_DONE;
498    msg.node = node;
499    msg.fenceFd = fenceFd;
500    msg.u.extended_buffer_data.buffer = buffer;
501    msg.u.extended_buffer_data.range_offset = pBuffer->nOffset;
502    msg.u.extended_buffer_data.range_length = pBuffer->nFilledLen;
503    msg.u.extended_buffer_data.flags = pBuffer->nFlags;
504    msg.u.extended_buffer_data.timestamp = pBuffer->nTimeStamp;
505
506    findDispatcher(node)->post(msg);
507
508    return OMX_ErrorNone;
509}
510
511OMX::node_id OMX::makeNodeID(OMXNodeInstance *instance) {
512    // mLock is already held.
513
514    node_id node = (node_id)++mNodeCounter;
515    mNodeIDToInstance.add(node, instance);
516
517    return node;
518}
519
520OMXNodeInstance *OMX::findInstance(node_id node) {
521    Mutex::Autolock autoLock(mLock);
522
523    ssize_t index = mNodeIDToInstance.indexOfKey(node);
524
525    return index < 0 ? NULL : mNodeIDToInstance.valueAt(index);
526}
527
528sp<OMX::CallbackDispatcher> OMX::findDispatcher(node_id node) {
529    Mutex::Autolock autoLock(mLock);
530
531    ssize_t index = mDispatchers.indexOfKey(node);
532
533    return index < 0 ? NULL : mDispatchers.valueAt(index);
534}
535
536void OMX::invalidateNodeID(node_id node) {
537    Mutex::Autolock autoLock(mLock);
538    invalidateNodeID_l(node);
539}
540
541void OMX::invalidateNodeID_l(node_id node) {
542    // mLock is held.
543    mNodeIDToInstance.removeItem(node);
544}
545
546}  // namespace android
547