• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "../include/OMX.h"
22 #include "OMXRenderer.h"
23 
24 #include "pv_omxcore.h"
25 
26 #include "../include/OMXNodeInstance.h"
27 
28 #include <binder/IMemory.h>
29 #include <media/stagefright/MediaDebug.h>
30 #include <media/stagefright/SoftwareRenderer.h>
31 #include <media/stagefright/VideoRenderer.h>
32 
33 #include <OMX_Component.h>
34 
35 namespace android {
36 
37 ////////////////////////////////////////////////////////////////////////////////
38 
39 struct OMX::CallbackDispatcher : public RefBase {
40     CallbackDispatcher(OMX *owner);
41 
42     void post(const omx_message &msg);
43 
44 protected:
45     virtual ~CallbackDispatcher();
46 
47 private:
48     Mutex mLock;
49 
50     OMX *mOwner;
51     bool mDone;
52     Condition mQueueChanged;
53     List<omx_message> mQueue;
54 
55     pthread_t mThread;
56 
57     void dispatch(const omx_message &msg);
58 
59     static void *ThreadWrapper(void *me);
60     void threadEntry();
61 
62     CallbackDispatcher(const CallbackDispatcher &);
63     CallbackDispatcher &operator=(const CallbackDispatcher &);
64 };
65 
CallbackDispatcher(OMX * owner)66 OMX::CallbackDispatcher::CallbackDispatcher(OMX *owner)
67     : mOwner(owner),
68       mDone(false) {
69     pthread_attr_t attr;
70     pthread_attr_init(&attr);
71     pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
72 
73     pthread_create(&mThread, &attr, ThreadWrapper, this);
74 
75     pthread_attr_destroy(&attr);
76 }
77 
~CallbackDispatcher()78 OMX::CallbackDispatcher::~CallbackDispatcher() {
79     {
80         Mutex::Autolock autoLock(mLock);
81 
82         mDone = true;
83         mQueueChanged.signal();
84     }
85 
86     void *dummy;
87     pthread_join(mThread, &dummy);
88 }
89 
post(const omx_message & msg)90 void OMX::CallbackDispatcher::post(const omx_message &msg) {
91     Mutex::Autolock autoLock(mLock);
92     mQueue.push_back(msg);
93     mQueueChanged.signal();
94 }
95 
dispatch(const omx_message & msg)96 void OMX::CallbackDispatcher::dispatch(const omx_message &msg) {
97     OMXNodeInstance *instance = mOwner->findInstance(msg.node);
98     if (instance == NULL) {
99         LOGV("Would have dispatched a message to a node that's already gone.");
100         return;
101     }
102     instance->onMessage(msg);
103 }
104 
105 // static
ThreadWrapper(void * me)106 void *OMX::CallbackDispatcher::ThreadWrapper(void *me) {
107     static_cast<CallbackDispatcher *>(me)->threadEntry();
108 
109     return NULL;
110 }
111 
threadEntry()112 void OMX::CallbackDispatcher::threadEntry() {
113     for (;;) {
114         omx_message msg;
115 
116         {
117             Mutex::Autolock autoLock(mLock);
118             while (!mDone && mQueue.empty()) {
119                 mQueueChanged.wait(mLock);
120             }
121 
122             if (mDone) {
123                 break;
124             }
125 
126             msg = *mQueue.begin();
127             mQueue.erase(mQueue.begin());
128         }
129 
130         dispatch(msg);
131     }
132 }
133 
134 ////////////////////////////////////////////////////////////////////////////////
135 
136 class BufferMeta {
137 public:
BufferMeta(OMX * owner,const sp<IMemory> & mem,bool is_backup=false)138     BufferMeta(OMX *owner, const sp<IMemory> &mem, bool is_backup = false)
139         : mOwner(owner),
140           mMem(mem),
141           mIsBackup(is_backup) {
142     }
143 
BufferMeta(OMX * owner,size_t size)144     BufferMeta(OMX *owner, size_t size)
145         : mOwner(owner),
146           mSize(size),
147           mIsBackup(false) {
148     }
149 
CopyFromOMX(const OMX_BUFFERHEADERTYPE * header)150     void CopyFromOMX(const OMX_BUFFERHEADERTYPE *header) {
151         if (!mIsBackup) {
152             return;
153         }
154 
155         memcpy((OMX_U8 *)mMem->pointer() + header->nOffset,
156                header->pBuffer + header->nOffset,
157                header->nFilledLen);
158     }
159 
CopyToOMX(const OMX_BUFFERHEADERTYPE * header)160     void CopyToOMX(const OMX_BUFFERHEADERTYPE *header) {
161         if (!mIsBackup) {
162             return;
163         }
164 
165         memcpy(header->pBuffer + header->nOffset,
166                (const OMX_U8 *)mMem->pointer() + header->nOffset,
167                header->nFilledLen);
168     }
169 
170 private:
171     OMX *mOwner;
172     sp<IMemory> mMem;
173     size_t mSize;
174     bool mIsBackup;
175 
176     BufferMeta(const BufferMeta &);
177     BufferMeta &operator=(const BufferMeta &);
178 };
179 
OMX()180 OMX::OMX()
181     : mDispatcher(new CallbackDispatcher(this)),
182       mNodeCounter(0) {
183 }
184 
binderDied(const wp<IBinder> & the_late_who)185 void OMX::binderDied(const wp<IBinder> &the_late_who) {
186     OMXNodeInstance *instance;
187 
188     {
189         Mutex::Autolock autoLock(mLock);
190 
191         ssize_t index = mLiveNodes.indexOfKey(the_late_who);
192         CHECK(index >= 0);
193 
194         instance = mLiveNodes.editValueAt(index);
195         mLiveNodes.removeItemsAt(index);
196 
197         invalidateNodeID_l(instance->nodeID());
198     }
199 
200     instance->onObserverDied();
201 }
202 
listNodes(List<String8> * list)203 status_t OMX::listNodes(List<String8> *list) {
204     OMX_MasterInit();  // XXX Put this somewhere else.
205 
206     list->clear();
207 
208     OMX_U32 index = 0;
209     char componentName[256];
210     while (OMX_MasterComponentNameEnum(componentName, sizeof(componentName), index)
211                == OMX_ErrorNone) {
212         list->push_back(String8(componentName));
213 
214         ++index;
215     }
216 
217     return OK;
218 }
219 
allocateNode(const char * name,const sp<IOMXObserver> & observer,node_id * node)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     OMX_MasterInit();  // XXX Put this somewhere else.
227 
228     OMXNodeInstance *instance = new OMXNodeInstance(this, observer);
229 
230     OMX_HANDLETYPE handle;
231     OMX_ERRORTYPE err = OMX_MasterGetHandle(
232             &handle, const_cast<char *>(name), instance,
233             &OMXNodeInstance::kCallbacks);
234 
235     if (err != OMX_ErrorNone) {
236         LOGE("FAILED to allocate omx component '%s'", name);
237 
238         instance->onGetHandleFailed();
239 
240         return UNKNOWN_ERROR;
241     }
242 
243     *node = makeNodeID(instance);
244 
245     instance->setHandle(*node, handle);
246 
247     mLiveNodes.add(observer->asBinder(), instance);
248     observer->asBinder()->linkToDeath(this);
249 
250     return OK;
251 }
252 
freeNode(node_id node)253 status_t OMX::freeNode(node_id node) {
254     OMXNodeInstance *instance = findInstance(node);
255 
256     ssize_t index = mLiveNodes.indexOfKey(instance->observer()->asBinder());
257     CHECK(index >= 0);
258     mLiveNodes.removeItemsAt(index);
259     instance->observer()->asBinder()->unlinkToDeath(this);
260 
261     return instance->freeNode();
262 }
263 
sendCommand(node_id node,OMX_COMMANDTYPE cmd,OMX_S32 param)264 status_t OMX::sendCommand(
265         node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) {
266     return findInstance(node)->sendCommand(cmd, param);
267 }
268 
getParameter(node_id node,OMX_INDEXTYPE index,void * params,size_t size)269 status_t OMX::getParameter(
270         node_id node, OMX_INDEXTYPE index,
271         void *params, size_t size) {
272     return findInstance(node)->getParameter(
273             index, params, size);
274 }
275 
setParameter(node_id node,OMX_INDEXTYPE index,const void * params,size_t size)276 status_t OMX::setParameter(
277         node_id node, OMX_INDEXTYPE index,
278         const void *params, size_t size) {
279     return findInstance(node)->setParameter(
280             index, params, size);
281 }
282 
getConfig(node_id node,OMX_INDEXTYPE index,void * params,size_t size)283 status_t OMX::getConfig(
284         node_id node, OMX_INDEXTYPE index,
285         void *params, size_t size) {
286     return findInstance(node)->getConfig(
287             index, params, size);
288 }
289 
setConfig(node_id node,OMX_INDEXTYPE index,const void * params,size_t size)290 status_t OMX::setConfig(
291         node_id node, OMX_INDEXTYPE index,
292         const void *params, size_t size) {
293     return findInstance(node)->setConfig(
294             index, params, size);
295 }
296 
useBuffer(node_id node,OMX_U32 port_index,const sp<IMemory> & params,buffer_id * buffer)297 status_t OMX::useBuffer(
298         node_id node, OMX_U32 port_index, const sp<IMemory> &params,
299         buffer_id *buffer) {
300     return findInstance(node)->useBuffer(
301             port_index, params, buffer);
302 }
303 
allocateBuffer(node_id node,OMX_U32 port_index,size_t size,buffer_id * buffer)304 status_t OMX::allocateBuffer(
305         node_id node, OMX_U32 port_index, size_t size,
306         buffer_id *buffer) {
307     return findInstance(node)->allocateBuffer(
308             port_index, size, buffer);
309 }
310 
allocateBufferWithBackup(node_id node,OMX_U32 port_index,const sp<IMemory> & params,buffer_id * buffer)311 status_t OMX::allocateBufferWithBackup(
312         node_id node, OMX_U32 port_index, const sp<IMemory> &params,
313         buffer_id *buffer) {
314     return findInstance(node)->allocateBufferWithBackup(
315             port_index, params, buffer);
316 }
317 
freeBuffer(node_id node,OMX_U32 port_index,buffer_id buffer)318 status_t OMX::freeBuffer(node_id node, OMX_U32 port_index, buffer_id buffer) {
319     return findInstance(node)->freeBuffer(
320             port_index, buffer);
321 }
322 
fillBuffer(node_id node,buffer_id buffer)323 status_t OMX::fillBuffer(node_id node, buffer_id buffer) {
324     return findInstance(node)->fillBuffer(buffer);
325 }
326 
emptyBuffer(node_id node,buffer_id buffer,OMX_U32 range_offset,OMX_U32 range_length,OMX_U32 flags,OMX_TICKS timestamp)327 status_t OMX::emptyBuffer(
328         node_id node,
329         buffer_id buffer,
330         OMX_U32 range_offset, OMX_U32 range_length,
331         OMX_U32 flags, OMX_TICKS timestamp) {
332     return findInstance(node)->emptyBuffer(
333             buffer, range_offset, range_length, flags, timestamp);
334 }
335 
getExtensionIndex(node_id node,const char * parameter_name,OMX_INDEXTYPE * index)336 status_t OMX::getExtensionIndex(
337         node_id node,
338         const char *parameter_name,
339         OMX_INDEXTYPE *index) {
340     return findInstance(node)->getExtensionIndex(
341             parameter_name, index);
342 }
343 
OnEvent(node_id node,OMX_IN OMX_EVENTTYPE eEvent,OMX_IN OMX_U32 nData1,OMX_IN OMX_U32 nData2,OMX_IN OMX_PTR pEventData)344 OMX_ERRORTYPE OMX::OnEvent(
345         node_id node,
346         OMX_IN OMX_EVENTTYPE eEvent,
347         OMX_IN OMX_U32 nData1,
348         OMX_IN OMX_U32 nData2,
349         OMX_IN OMX_PTR pEventData) {
350     LOGV("OnEvent(%d, %ld, %ld)", eEvent, nData1, nData2);
351 
352     omx_message msg;
353     msg.type = omx_message::EVENT;
354     msg.node = node;
355     msg.u.event_data.event = eEvent;
356     msg.u.event_data.data1 = nData1;
357     msg.u.event_data.data2 = nData2;
358 
359     mDispatcher->post(msg);
360 
361     return OMX_ErrorNone;
362 }
363 
OnEmptyBufferDone(node_id node,OMX_IN OMX_BUFFERHEADERTYPE * pBuffer)364 OMX_ERRORTYPE OMX::OnEmptyBufferDone(
365         node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) {
366     LOGV("OnEmptyBufferDone buffer=%p", pBuffer);
367 
368     omx_message msg;
369     msg.type = omx_message::EMPTY_BUFFER_DONE;
370     msg.node = node;
371     msg.u.buffer_data.buffer = pBuffer;
372 
373     mDispatcher->post(msg);
374 
375     return OMX_ErrorNone;
376 }
377 
OnFillBufferDone(node_id node,OMX_IN OMX_BUFFERHEADERTYPE * pBuffer)378 OMX_ERRORTYPE OMX::OnFillBufferDone(
379         node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) {
380     LOGV("OnFillBufferDone buffer=%p", pBuffer);
381 
382     omx_message msg;
383     msg.type = omx_message::FILL_BUFFER_DONE;
384     msg.node = node;
385     msg.u.extended_buffer_data.buffer = pBuffer;
386     msg.u.extended_buffer_data.range_offset = pBuffer->nOffset;
387     msg.u.extended_buffer_data.range_length = pBuffer->nFilledLen;
388     msg.u.extended_buffer_data.flags = pBuffer->nFlags;
389     msg.u.extended_buffer_data.timestamp = pBuffer->nTimeStamp;
390     msg.u.extended_buffer_data.platform_private = pBuffer->pPlatformPrivate;
391 
392     mDispatcher->post(msg);
393 
394     return OMX_ErrorNone;
395 }
396 
makeNodeID(OMXNodeInstance * instance)397 OMX::node_id OMX::makeNodeID(OMXNodeInstance *instance) {
398     // mLock is already held.
399 
400     node_id node = (node_id)++mNodeCounter;
401     mNodeIDToInstance.add(node, instance);
402 
403     return node;
404 }
405 
findInstance(node_id node)406 OMXNodeInstance *OMX::findInstance(node_id node) {
407     Mutex::Autolock autoLock(mLock);
408 
409     ssize_t index = mNodeIDToInstance.indexOfKey(node);
410 
411     return index < 0 ? NULL : mNodeIDToInstance.valueAt(index);
412 }
413 
invalidateNodeID(node_id node)414 void OMX::invalidateNodeID(node_id node) {
415     Mutex::Autolock autoLock(mLock);
416     invalidateNodeID_l(node);
417 }
418 
invalidateNodeID_l(node_id node)419 void OMX::invalidateNodeID_l(node_id node) {
420     // mLock is held.
421     mNodeIDToInstance.removeItem(node);
422 }
423 
424 ////////////////////////////////////////////////////////////////////////////////
425 
createRenderer(const sp<ISurface> & surface,const char * componentName,OMX_COLOR_FORMATTYPE colorFormat,size_t encodedWidth,size_t encodedHeight,size_t displayWidth,size_t displayHeight)426 sp<IOMXRenderer> OMX::createRenderer(
427         const sp<ISurface> &surface,
428         const char *componentName,
429         OMX_COLOR_FORMATTYPE colorFormat,
430         size_t encodedWidth, size_t encodedHeight,
431         size_t displayWidth, size_t displayHeight) {
432     Mutex::Autolock autoLock(mLock);
433 
434     VideoRenderer *impl = NULL;
435 
436     static void *libHandle = NULL;
437 
438     if (!libHandle) {
439         libHandle = dlopen("libstagefrighthw.so", RTLD_NOW);
440     }
441 
442     if (libHandle) {
443         typedef VideoRenderer *(*CreateRendererFunc)(
444                 const sp<ISurface> &surface,
445                 const char *componentName,
446                 OMX_COLOR_FORMATTYPE colorFormat,
447                 size_t displayWidth, size_t displayHeight,
448                 size_t decodedWidth, size_t decodedHeight);
449 
450         CreateRendererFunc func =
451             (CreateRendererFunc)dlsym(
452                     libHandle,
453                     "_Z14createRendererRKN7android2spINS_8ISurfaceEEEPKc20"
454                     "OMX_COLOR_FORMATTYPEjjjj");
455 
456         if (func) {
457             impl = (*func)(surface, componentName, colorFormat,
458                     displayWidth, displayHeight, encodedWidth, encodedHeight);
459         }
460     }
461 
462     if (!impl) {
463         LOGW("Using software renderer.");
464         impl = new SoftwareRenderer(
465                 colorFormat,
466                 surface,
467                 displayWidth, displayHeight,
468                 encodedWidth, encodedHeight);
469     }
470 
471     return new OMXRenderer(impl);
472 }
473 
OMXRenderer(VideoRenderer * impl)474 OMXRenderer::OMXRenderer(VideoRenderer *impl)
475     : mImpl(impl) {
476 }
477 
~OMXRenderer()478 OMXRenderer::~OMXRenderer() {
479     delete mImpl;
480     mImpl = NULL;
481 }
482 
render(IOMX::buffer_id buffer)483 void OMXRenderer::render(IOMX::buffer_id buffer) {
484     OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
485 
486     mImpl->render(
487             header->pBuffer + header->nOffset,
488             header->nFilledLen,
489             header->pPlatformPrivate);
490 }
491 
492 }  // namespace android
493 
494