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> ¶ms,
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> ¶ms,
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