OSDN Git Service

bc24dbbe9366e3fea0fcd46c32de3be7ada2a12f
[android-x86/frameworks-base.git] / media / libstagefright / omx / OMX.cpp
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
35 namespace android {
36
37 ////////////////////////////////////////////////////////////////////////////////
38
39 // This provides the underlying Thread used by CallbackDispatcher.
40 // Note that deriving CallbackDispatcher from Thread does not work.
41
42 struct OMX::CallbackDispatcherThread : public Thread {
43     CallbackDispatcherThread(CallbackDispatcher *dispatcher)
44         : mDispatcher(dispatcher) {
45     }
46
47 private:
48     CallbackDispatcher *mDispatcher;
49
50     bool threadLoop();
51
52     CallbackDispatcherThread(const CallbackDispatcherThread &);
53     CallbackDispatcherThread &operator=(const CallbackDispatcherThread &);
54 };
55
56 ////////////////////////////////////////////////////////////////////////////////
57
58 struct OMX::CallbackDispatcher : public RefBase {
59     CallbackDispatcher(OMXNodeInstance *owner);
60
61     void post(const omx_message &msg);
62
63     bool loop();
64
65 protected:
66     virtual ~CallbackDispatcher();
67
68 private:
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
84 OMX::CallbackDispatcher::CallbackDispatcher(OMXNodeInstance *owner)
85     : mOwner(owner),
86       mDone(false) {
87     mThread = new CallbackDispatcherThread(this);
88     mThread->run("OMXCallbackDisp", ANDROID_PRIORITY_AUDIO);
89 }
90
91 OMX::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, NO_ERROR);
106     }
107 }
108
109 void OMX::CallbackDispatcher::post(const omx_message &msg) {
110     Mutex::Autolock autoLock(mLock);
111
112     mQueue.push_back(msg);
113     mQueueChanged.signal();
114 }
115
116 void OMX::CallbackDispatcher::dispatch(const omx_message &msg) {
117     if (mOwner == NULL) {
118         LOGV("Would have dispatched a message to a node that's already gone.");
119         return;
120     }
121     mOwner->onMessage(msg);
122 }
123
124 bool 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
150 bool OMX::CallbackDispatcherThread::threadLoop() {
151     return mDispatcher->loop();
152 }
153
154 ////////////////////////////////////////////////////////////////////////////////
155
156 OMX::OMX()
157     : mMaster(new OMXMaster),
158       mNodeCounter(0) {
159 }
160
161 OMX::~OMX() {
162     delete mMaster;
163     mMaster = NULL;
164 }
165
166 void 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
188 bool OMX::livesLocally(pid_t pid) {
189     return pid == getpid();
190 }
191
192 status_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
220 status_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         LOGV("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
252 status_t OMX::freeNode(node_id node) {
253     OMXNodeInstance *instance = findInstance(node);
254
255     ssize_t index = mLiveNodes.indexOfKey(instance->observer()->asBinder());
256     CHECK(index >= 0);
257     mLiveNodes.removeItemsAt(index);
258
259     instance->observer()->asBinder()->unlinkToDeath(this);
260
261     status_t err = instance->freeNode(mMaster);
262
263     {
264         Mutex::Autolock autoLock(mLock);
265         index = mDispatchers.indexOfKey(node);
266         CHECK(index >= 0);
267         mDispatchers.removeItemsAt(index);
268     }
269
270     return err;
271 }
272
273 status_t OMX::sendCommand(
274         node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) {
275     return findInstance(node)->sendCommand(cmd, param);
276 }
277
278 status_t OMX::getParameter(
279         node_id node, OMX_INDEXTYPE index,
280         void *params, size_t size) {
281     return findInstance(node)->getParameter(
282             index, params, size);
283 }
284
285 status_t OMX::setParameter(
286         node_id node, OMX_INDEXTYPE index,
287         const void *params, size_t size) {
288     return findInstance(node)->setParameter(
289             index, params, size);
290 }
291
292 status_t OMX::getConfig(
293         node_id node, OMX_INDEXTYPE index,
294         void *params, size_t size) {
295     return findInstance(node)->getConfig(
296             index, params, size);
297 }
298
299 status_t OMX::setConfig(
300         node_id node, OMX_INDEXTYPE index,
301         const void *params, size_t size) {
302     return findInstance(node)->setConfig(
303             index, params, size);
304 }
305
306 status_t OMX::enableGraphicBuffers(
307         node_id node, OMX_U32 port_index, OMX_BOOL enable) {
308     return findInstance(node)->enableGraphicBuffers(port_index, enable);
309 }
310
311 status_t OMX::getGraphicBufferUsage(
312         node_id node, OMX_U32 port_index, OMX_U32* usage) {
313     return findInstance(node)->getGraphicBufferUsage(port_index, usage);
314 }
315
316 status_t OMX::storeMetaDataInBuffers(
317         node_id node, OMX_U32 port_index, OMX_BOOL enable) {
318     return findInstance(node)->storeMetaDataInBuffers(port_index, enable);
319 }
320
321 status_t OMX::useBuffer(
322         node_id node, OMX_U32 port_index, const sp<IMemory> &params,
323         buffer_id *buffer) {
324     return findInstance(node)->useBuffer(
325             port_index, params, buffer);
326 }
327
328 status_t OMX::useGraphicBuffer(
329         node_id node, OMX_U32 port_index,
330         const sp<GraphicBuffer> &graphicBuffer, buffer_id *buffer) {
331     return findInstance(node)->useGraphicBuffer(
332             port_index, graphicBuffer, buffer);
333 }
334
335 status_t OMX::allocateBuffer(
336         node_id node, OMX_U32 port_index, size_t size,
337         buffer_id *buffer, void **buffer_data) {
338     return findInstance(node)->allocateBuffer(
339             port_index, size, buffer, buffer_data);
340 }
341
342 status_t OMX::allocateBufferWithBackup(
343         node_id node, OMX_U32 port_index, const sp<IMemory> &params,
344         buffer_id *buffer) {
345     return findInstance(node)->allocateBufferWithBackup(
346             port_index, params, buffer);
347 }
348
349 status_t OMX::freeBuffer(node_id node, OMX_U32 port_index, buffer_id buffer) {
350     return findInstance(node)->freeBuffer(
351             port_index, buffer);
352 }
353
354 status_t OMX::fillBuffer(node_id node, buffer_id buffer) {
355     return findInstance(node)->fillBuffer(buffer);
356 }
357
358 status_t OMX::emptyBuffer(
359         node_id node,
360         buffer_id buffer,
361         OMX_U32 range_offset, OMX_U32 range_length,
362         OMX_U32 flags, OMX_TICKS timestamp) {
363     return findInstance(node)->emptyBuffer(
364             buffer, range_offset, range_length, flags, timestamp);
365 }
366
367 status_t OMX::getExtensionIndex(
368         node_id node,
369         const char *parameter_name,
370         OMX_INDEXTYPE *index) {
371     return findInstance(node)->getExtensionIndex(
372             parameter_name, index);
373 }
374
375 OMX_ERRORTYPE OMX::OnEvent(
376         node_id node,
377         OMX_IN OMX_EVENTTYPE eEvent,
378         OMX_IN OMX_U32 nData1,
379         OMX_IN OMX_U32 nData2,
380         OMX_IN OMX_PTR pEventData) {
381     LOGV("OnEvent(%d, %ld, %ld)", eEvent, nData1, nData2);
382
383     omx_message msg;
384     msg.type = omx_message::EVENT;
385     msg.node = node;
386     msg.u.event_data.event = eEvent;
387     msg.u.event_data.data1 = nData1;
388     msg.u.event_data.data2 = nData2;
389
390     findDispatcher(node)->post(msg);
391
392     return OMX_ErrorNone;
393 }
394
395 OMX_ERRORTYPE OMX::OnEmptyBufferDone(
396         node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) {
397     LOGV("OnEmptyBufferDone buffer=%p", pBuffer);
398
399     omx_message msg;
400     msg.type = omx_message::EMPTY_BUFFER_DONE;
401     msg.node = node;
402     msg.u.buffer_data.buffer = pBuffer;
403
404     findDispatcher(node)->post(msg);
405
406     return OMX_ErrorNone;
407 }
408
409 OMX_ERRORTYPE OMX::OnFillBufferDone(
410         node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) {
411     LOGV("OnFillBufferDone buffer=%p", pBuffer);
412
413     omx_message msg;
414     msg.type = omx_message::FILL_BUFFER_DONE;
415     msg.node = node;
416     msg.u.extended_buffer_data.buffer = pBuffer;
417     msg.u.extended_buffer_data.range_offset = pBuffer->nOffset;
418     msg.u.extended_buffer_data.range_length = pBuffer->nFilledLen;
419     msg.u.extended_buffer_data.flags = pBuffer->nFlags;
420     msg.u.extended_buffer_data.timestamp = pBuffer->nTimeStamp;
421     msg.u.extended_buffer_data.platform_private = pBuffer->pPlatformPrivate;
422     msg.u.extended_buffer_data.data_ptr = pBuffer->pBuffer;
423
424     findDispatcher(node)->post(msg);
425
426     return OMX_ErrorNone;
427 }
428
429 OMX::node_id OMX::makeNodeID(OMXNodeInstance *instance) {
430     // mLock is already held.
431
432     node_id node = (node_id)++mNodeCounter;
433     mNodeIDToInstance.add(node, instance);
434
435     return node;
436 }
437
438 OMXNodeInstance *OMX::findInstance(node_id node) {
439     Mutex::Autolock autoLock(mLock);
440
441     ssize_t index = mNodeIDToInstance.indexOfKey(node);
442
443     return index < 0 ? NULL : mNodeIDToInstance.valueAt(index);
444 }
445
446 sp<OMX::CallbackDispatcher> OMX::findDispatcher(node_id node) {
447     Mutex::Autolock autoLock(mLock);
448
449     ssize_t index = mDispatchers.indexOfKey(node);
450
451     return index < 0 ? NULL : mDispatchers.valueAt(index);
452 }
453
454 void OMX::invalidateNodeID(node_id node) {
455     Mutex::Autolock autoLock(mLock);
456     invalidateNodeID_l(node);
457 }
458
459 void OMX::invalidateNodeID_l(node_id node) {
460     // mLock is held.
461     mNodeIDToInstance.removeItem(node);
462 }
463
464 }  // namespace android