1 /*****************************************************************************
2 * iomx.cpp: OpenMAX interface implementation based on IOMX
3 *****************************************************************************
4 * Copyright (C) 2011 VLC authors and VideoLAN
6 * Authors: Martin Storsjo <martin@martin.st>
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation; either version 2.1 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 *****************************************************************************/
23 /*****************************************************************************
25 *****************************************************************************/
27 #include <media/stagefright/OMXClient.h>
28 #include <media/IOMX.h>
29 #include <binder/MemoryDealer.h>
30 #include <OMX_Component.h>
32 #define PREFIX(x) I ## x
35 #define HAS_USE_BUFFER
38 using namespace android;
46 List<IOMX::ComponentInfo> components;
49 static IOMXContext *ctx;
53 class OMXCodecObserver : public BnOMXObserver {
58 void setNode(OMXNode* n) {
61 void onMessage(const omx_message &msg);
62 void registerBuffers(const sp<IMemoryHeap> &) {
71 sp<OMXCodecObserver> observer;
72 OMX_CALLBACKTYPE callbacks;
75 List<OMX_BUFFERHEADERTYPE*> buffers;
76 OMX_HANDLETYPE handle;
77 String8 component_name;
82 sp<MemoryDealer> dealer;
84 sp<GraphicBuffer> graphicBuffer;
89 void OMXCodecObserver::onMessage(const omx_message &msg)
94 case omx_message::EVENT:
95 // TODO: Needs locking
96 if (msg.u.event_data.event == OMX_EventCmdComplete && msg.u.event_data.data1 == OMX_CommandStateSet)
97 node->state = (OMX_STATETYPE) msg.u.event_data.data2;
98 node->callbacks.EventHandler(node->handle, node->app_data, msg.u.event_data.event, msg.u.event_data.data1, msg.u.event_data.data2, NULL);
100 case omx_message::EMPTY_BUFFER_DONE:
101 for( List<OMX_BUFFERHEADERTYPE*>::iterator it = node->buffers.begin(); it != node->buffers.end(); it++ ) {
102 OMXBuffer* info = (OMXBuffer*) (*it)->pPlatformPrivate;
103 if (msg.u.buffer_data.buffer == info->id) {
104 node->callbacks.EmptyBufferDone(node->handle, node->app_data, *it);
109 case omx_message::FILL_BUFFER_DONE:
110 for( List<OMX_BUFFERHEADERTYPE*>::iterator it = node->buffers.begin(); it != node->buffers.end(); it++ ) {
111 OMXBuffer* info = (OMXBuffer*) (*it)->pPlatformPrivate;
112 if (msg.u.extended_buffer_data.buffer == info->id) {
113 OMX_BUFFERHEADERTYPE *buffer = *it;
114 buffer->nOffset = msg.u.extended_buffer_data.range_offset;
115 buffer->nFilledLen = msg.u.extended_buffer_data.range_length;
116 buffer->nFlags = msg.u.extended_buffer_data.flags;
117 buffer->nTimeStamp = msg.u.extended_buffer_data.timestamp;
118 node->callbacks.FillBufferDone(node->handle, node->app_data, buffer);
128 static OMX_ERRORTYPE get_error(status_t err)
131 return OMX_ErrorNone;
132 return OMX_ErrorUndefined;
135 static OMX_ERRORTYPE iomx_send_command(OMX_HANDLETYPE component, OMX_COMMANDTYPE command, OMX_U32 param1, OMX_PTR)
137 OMXNode* node = (OMXNode*) ((OMX_COMPONENTTYPE*)component)->pComponentPrivate;
138 return get_error(ctx->iomx->sendCommand(node->node, command, param1));
141 static OMX_ERRORTYPE iomx_get_parameter(OMX_HANDLETYPE component, OMX_INDEXTYPE param_index, OMX_PTR param)
144 * Some QCOM OMX_getParameter implementations override the nSize element to
145 * a bad value. So, save the initial nSize in order to restore it after.
147 OMX_U32 nSize = *(OMX_U32*)param;
149 OMXNode* node = (OMXNode*) ((OMX_COMPONENTTYPE*)component)->pComponentPrivate;
151 error = get_error(ctx->iomx->getParameter(node->node, param_index, param, nSize));
152 *(OMX_U32*)param = nSize;
156 static OMX_ERRORTYPE iomx_set_parameter(OMX_HANDLETYPE component, OMX_INDEXTYPE param_index, OMX_PTR param)
158 OMXNode* node = (OMXNode*) ((OMX_COMPONENTTYPE*)component)->pComponentPrivate;
159 return get_error(ctx->iomx->setParameter(node->node, param_index, param, *(OMX_U32*)param));
162 static OMX_ERRORTYPE iomx_get_state(OMX_HANDLETYPE component, OMX_STATETYPE *ptr) {
163 OMXNode* node = (OMXNode*) ((OMX_COMPONENTTYPE*)component)->pComponentPrivate;
165 return OMX_ErrorNone;
168 static OMX_ERRORTYPE iomx_allocate_buffer(OMX_HANDLETYPE component, OMX_BUFFERHEADERTYPE **bufferptr, OMX_U32 port_index, OMX_PTR app_private, OMX_U32 size)
170 OMXNode* node = (OMXNode*) ((OMX_COMPONENTTYPE*)component)->pComponentPrivate;
171 OMXBuffer* info = new OMXBuffer;
172 #ifdef HAS_USE_BUFFER
173 info->graphicBuffer = NULL;
175 info->dealer = new MemoryDealer(size + 4096); // Do we need to keep this around, or is it kept alive via the IMemory that references it?
176 sp<IMemory> mem = info->dealer->allocate(size);
177 int ret = ctx->iomx->allocateBufferWithBackup(node->node, port_index, mem, &info->id);
179 return OMX_ErrorUndefined;
180 OMX_BUFFERHEADERTYPE *buffer = (OMX_BUFFERHEADERTYPE*) calloc(1, sizeof(OMX_BUFFERHEADERTYPE));
182 buffer->pPlatformPrivate = info;
183 buffer->pAppPrivate = app_private;
184 buffer->nAllocLen = size;
185 buffer->pBuffer = (OMX_U8*) mem->pointer();
186 node->buffers.push_back(buffer);
187 return OMX_ErrorNone;
190 #ifdef HAS_USE_BUFFER
191 static OMX_ERRORTYPE iomx_use_buffer(OMX_HANDLETYPE component, OMX_BUFFERHEADERTYPE **bufferptr, OMX_U32 port_index, OMX_PTR app_private, OMX_U32 size, OMX_U8* data)
193 OMXNode* node = (OMXNode*) ((OMX_COMPONENTTYPE*)component)->pComponentPrivate;
194 OMXBuffer* info = new OMXBuffer;
196 #if ANDROID_API <= 13
197 info->graphicBuffer = new GraphicBuffer((android_native_buffer_t*) data, false);
199 info->graphicBuffer = new GraphicBuffer((ANativeWindowBuffer*) data, false);
201 int ret = ctx->iomx->useGraphicBuffer(node->node, port_index, info->graphicBuffer, &info->id);
203 return OMX_ErrorUndefined;
204 OMX_BUFFERHEADERTYPE *buffer = (OMX_BUFFERHEADERTYPE*) calloc(1, sizeof(OMX_BUFFERHEADERTYPE));
206 buffer->pPlatformPrivate = info;
207 buffer->pAppPrivate = app_private;
208 buffer->nAllocLen = size;
209 buffer->pBuffer = data;
210 node->buffers.push_back(buffer);
211 return OMX_ErrorNone;
215 static OMX_ERRORTYPE iomx_free_buffer(OMX_HANDLETYPE component, OMX_U32 port, OMX_BUFFERHEADERTYPE *buffer)
217 OMXNode* node = (OMXNode*) ((OMX_COMPONENTTYPE*)component)->pComponentPrivate;
218 OMXBuffer* info = (OMXBuffer*) buffer->pPlatformPrivate;
219 status_t ret = ctx->iomx->freeBuffer(node->node, port, info->id);
220 for( List<OMX_BUFFERHEADERTYPE*>::iterator it = node->buffers.begin(); it != node->buffers.end(); it++ ) {
222 node->buffers.erase(it);
228 return get_error(ret);
231 static OMX_ERRORTYPE iomx_empty_this_buffer(OMX_HANDLETYPE component, OMX_BUFFERHEADERTYPE *buffer)
233 OMXNode* node = (OMXNode*) ((OMX_COMPONENTTYPE*)component)->pComponentPrivate;
234 OMXBuffer* info = (OMXBuffer*) buffer->pPlatformPrivate;
235 return get_error(ctx->iomx->emptyBuffer(node->node, info->id, buffer->nOffset, buffer->nFilledLen, buffer->nFlags, buffer->nTimeStamp));
238 static OMX_ERRORTYPE iomx_fill_this_buffer(OMX_HANDLETYPE component, OMX_BUFFERHEADERTYPE *buffer)
240 OMXNode* node = (OMXNode*) ((OMX_COMPONENTTYPE*)component)->pComponentPrivate;
241 OMXBuffer* info = (OMXBuffer*) buffer->pPlatformPrivate;
242 return get_error(ctx->iomx->fillBuffer(node->node, info->id));
245 static OMX_ERRORTYPE iomx_component_role_enum(OMX_HANDLETYPE component, OMX_U8 *role, OMX_U32 index)
247 OMXNode* node = (OMXNode*) ((OMX_COMPONENTTYPE*)component)->pComponentPrivate;
248 for( List<IOMX::ComponentInfo>::iterator it = ctx->components.begin(); it != ctx->components.end(); it++ ) {
249 if (node->component_name == it->mName) {
250 if (index >= it->mRoles.size())
251 return OMX_ErrorNoMore;
252 List<String8>::iterator it2 = it->mRoles.begin();
253 for( OMX_U32 i = 0; it2 != it->mRoles.end() && i < index; i++, it2++ ) ;
254 strncpy((char*)role, it2->string(), OMX_MAX_STRINGNAME_SIZE);
255 if (it2->length() >= OMX_MAX_STRINGNAME_SIZE)
256 role[OMX_MAX_STRINGNAME_SIZE - 1] = '\0';
257 return OMX_ErrorNone;
260 return OMX_ErrorInvalidComponentName;
263 static OMX_ERRORTYPE iomx_get_extension_index(OMX_HANDLETYPE component, OMX_STRING parameter, OMX_INDEXTYPE *index)
265 OMXNode* node = (OMXNode*) ((OMX_COMPONENTTYPE*)component)->pComponentPrivate;
266 return get_error(ctx->iomx->getExtensionIndex(node->node, parameter, index));
269 static OMX_ERRORTYPE iomx_set_config(OMX_HANDLETYPE component, OMX_INDEXTYPE index, OMX_PTR param)
271 OMXNode* node = (OMXNode*) ((OMX_COMPONENTTYPE*)component)->pComponentPrivate;
272 return get_error(ctx->iomx->setConfig(node->node, index, param, *(OMX_U32*)param));
275 static OMX_ERRORTYPE iomx_get_config(OMX_HANDLETYPE component, OMX_INDEXTYPE index, OMX_PTR param)
277 OMXNode* node = (OMXNode*) ((OMX_COMPONENTTYPE*)component)->pComponentPrivate;
278 return get_error(ctx->iomx->getConfig(node->node, index, param, *(OMX_U32*)param));
282 OMX_ERRORTYPE PREFIX(OMX_GetHandle)(OMX_HANDLETYPE *handle_ptr, OMX_STRING component_name, OMX_PTR app_data, OMX_CALLBACKTYPE *callbacks)
284 OMXNode* node = new OMXNode();
285 node->app_data = app_data;
286 node->callbacks = *callbacks;
287 node->observer = new OMXCodecObserver();
288 node->observer->setNode(node);
289 node->state = OMX_StateLoaded;
290 node->component_name = component_name;
292 OMX_COMPONENTTYPE* component = (OMX_COMPONENTTYPE*) malloc(sizeof(OMX_COMPONENTTYPE));
293 memset(component, 0, sizeof(OMX_COMPONENTTYPE));
294 component->nSize = sizeof(OMX_COMPONENTTYPE);
295 component->nVersion.s.nVersionMajor = 1;
296 component->nVersion.s.nVersionMinor = 1;
297 component->nVersion.s.nRevision = 0;
298 component->nVersion.s.nStep = 0;
299 component->pComponentPrivate = node;
300 component->SendCommand = iomx_send_command;
301 component->GetParameter = iomx_get_parameter;
302 component->SetParameter = iomx_set_parameter;
303 component->FreeBuffer = iomx_free_buffer;
304 component->EmptyThisBuffer = iomx_empty_this_buffer;
305 component->FillThisBuffer = iomx_fill_this_buffer;
306 component->GetState = iomx_get_state;
307 component->AllocateBuffer = iomx_allocate_buffer;
308 #ifdef HAS_USE_BUFFER
309 component->UseBuffer = iomx_use_buffer;
311 component->UseBuffer = NULL;
313 component->ComponentRoleEnum = iomx_component_role_enum;
314 component->GetExtensionIndex = iomx_get_extension_index;
315 component->SetConfig = iomx_set_config;
316 component->GetConfig = iomx_get_config;
318 *handle_ptr = component;
319 node->handle = component;
321 if ((ret = ctx->iomx->allocateNode( component_name, node->observer, &node->node )) != OK)
322 return OMX_ErrorUndefined;
323 return OMX_ErrorNone;
326 OMX_ERRORTYPE PREFIX(OMX_FreeHandle)(OMX_HANDLETYPE handle)
328 OMXNode* node = (OMXNode*) ((OMX_COMPONENTTYPE*)handle)->pComponentPrivate;
329 ctx->iomx->freeNode( node->node );
330 node->observer->setNode(NULL);
333 return OMX_ErrorNone;
336 OMX_ERRORTYPE PREFIX(OMX_Init)(void)
339 if (client.connect() != OK)
340 return OMX_ErrorUndefined;
343 ctx = new IOMXContext();
344 ctx->iomx = client.interface();
345 ctx->iomx->listNodes(&ctx->components);
346 return OMX_ErrorNone;
349 OMX_ERRORTYPE PREFIX(OMX_Deinit)(void)
354 return OMX_ErrorNone;
357 OMX_ERRORTYPE PREFIX(OMX_ComponentNameEnum)(OMX_STRING component_name, OMX_U32 name_length, OMX_U32 index)
359 if (index >= ctx->components.size())
360 return OMX_ErrorNoMore;
361 List<IOMX::ComponentInfo>::iterator it = ctx->components.begin();
362 for( OMX_U32 i = 0; i < index; i++ )
364 strncpy(component_name, it->mName.string(), name_length);
365 component_name[name_length - 1] = '\0';
366 return OMX_ErrorNone;
369 OMX_ERRORTYPE PREFIX(OMX_GetRolesOfComponent)(OMX_STRING component_name, OMX_U32 *num_roles, OMX_U8 **roles)
371 for( List<IOMX::ComponentInfo>::iterator it = ctx->components.begin(); it != ctx->components.end(); it++ ) {
372 if (!strcmp(component_name, it->mName.string())) {
374 *num_roles = it->mRoles.size();
375 return OMX_ErrorNone;
377 if (*num_roles < it->mRoles.size())
378 return OMX_ErrorInsufficientResources;
379 *num_roles = it->mRoles.size();
381 for( List<String8>::iterator it2 = it->mRoles.begin(); it2 != it->mRoles.end(); i++, it2++ ) {
382 strncpy((char*)roles[i], it2->string(), OMX_MAX_STRINGNAME_SIZE);
383 roles[i][OMX_MAX_STRINGNAME_SIZE - 1] = '\0';
385 return OMX_ErrorNone;
388 return OMX_ErrorInvalidComponentName;
391 OMX_ERRORTYPE PREFIX(OMX_GetComponentsOfRole)(OMX_STRING role, OMX_U32 *num_comps, OMX_U8 **comp_names)
394 for( List<IOMX::ComponentInfo>::iterator it = ctx->components.begin(); it != ctx->components.end(); it++ ) {
395 for( List<String8>::iterator it2 = it->mRoles.begin(); it2 != it->mRoles.end(); it2++ ) {
396 if (!strcmp(it2->string(), role)) {
399 return OMX_ErrorInsufficientResources;
400 strncpy((char*)comp_names[i], it->mName.string(), OMX_MAX_STRINGNAME_SIZE);
401 comp_names[i][OMX_MAX_STRINGNAME_SIZE - 1] = '\0';
409 return OMX_ErrorNone;
412 #ifdef HAS_USE_BUFFER
413 OMX_ERRORTYPE PREFIX(OMXAndroid_EnableGraphicBuffers)(OMX_HANDLETYPE component, OMX_U32 port_index, OMX_BOOL enable)
415 OMXNode* node = (OMXNode*) ((OMX_COMPONENTTYPE*)component)->pComponentPrivate;
416 int ret = ctx->iomx->enableGraphicBuffers(node->node, port_index, enable);
418 return OMX_ErrorUndefined;
419 return OMX_ErrorNone;
422 OMX_ERRORTYPE PREFIX(OMXAndroid_GetGraphicBufferUsage)(OMX_HANDLETYPE component, OMX_U32 port_index, OMX_U32* usage)
424 OMXNode* node = (OMXNode*) ((OMX_COMPONENTTYPE*)component)->pComponentPrivate;
425 int ret = ctx->iomx->getGraphicBufferUsage(node->node, port_index, usage);
427 return OMX_ErrorUndefined;
428 return OMX_ErrorNone;
431 OMX_ERRORTYPE PREFIX(OMXAndroid_GetHalFormat)( const char *comp_name, int* hal_format )
433 if( !strncmp( comp_name, "OMX.SEC.", 8 ) ) {
434 switch( *hal_format ) {
435 case OMX_COLOR_FormatYUV420SemiPlanar:
436 *hal_format = 0x105; // HAL_PIXEL_FORMAT_YCbCr_420_SP
438 case OMX_COLOR_FormatYUV420Planar:
439 *hal_format = 0x101; // HAL_PIXEL_FORMAT_YCbCr_420_P
443 else if( !strcmp( comp_name, "OMX.TI.720P.Decoder" ) ||
444 !strcmp( comp_name, "OMX.TI.Video.Decoder" ) )
445 *hal_format = 0x14; // HAL_PIXEL_FORMAT_YCbCr_422_I
446 #if ANDROID_API <= 13 // Required on msm8660 on 3.2, not required on 4.1
447 else if( !strcmp( comp_name, "OMX.qcom.video.decoder.avc" ))
451 return OMX_ErrorNone;