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
34 using namespace android;
42 List<IOMX::ComponentInfo> components;
45 static IOMXContext *ctx;
49 class OMXCodecObserver : public BnOMXObserver {
54 void setNode(OMXNode* n) {
57 void onMessage(const omx_message &msg);
58 void registerBuffers(const sp<IMemoryHeap> &) {
67 sp<OMXCodecObserver> observer;
68 OMX_CALLBACKTYPE callbacks;
71 List<OMX_BUFFERHEADERTYPE*> buffers;
72 OMX_HANDLETYPE handle;
73 String8 component_name;
78 sp<MemoryDealer> dealer;
82 void OMXCodecObserver::onMessage(const omx_message &msg)
87 case omx_message::EVENT:
88 // TODO: Needs locking
89 if (msg.u.event_data.event == OMX_EventCmdComplete && msg.u.event_data.data1 == OMX_CommandStateSet)
90 node->state = (OMX_STATETYPE) msg.u.event_data.data2;
91 node->callbacks.EventHandler(node->handle, node->app_data, msg.u.event_data.event, msg.u.event_data.data1, msg.u.event_data.data2, NULL);
93 case omx_message::EMPTY_BUFFER_DONE:
94 for( List<OMX_BUFFERHEADERTYPE*>::iterator it = node->buffers.begin(); it != node->buffers.end(); it++ ) {
95 OMXBuffer* info = (OMXBuffer*) (*it)->pPlatformPrivate;
96 if (msg.u.buffer_data.buffer == info->id) {
97 node->callbacks.EmptyBufferDone(node->handle, node->app_data, *it);
102 case omx_message::FILL_BUFFER_DONE:
103 for( List<OMX_BUFFERHEADERTYPE*>::iterator it = node->buffers.begin(); it != node->buffers.end(); it++ ) {
104 OMXBuffer* info = (OMXBuffer*) (*it)->pPlatformPrivate;
105 if (msg.u.extended_buffer_data.buffer == info->id) {
106 OMX_BUFFERHEADERTYPE *buffer = *it;
107 buffer->nOffset = msg.u.extended_buffer_data.range_offset;
108 buffer->nFilledLen = msg.u.extended_buffer_data.range_length;
109 buffer->nFlags = msg.u.extended_buffer_data.flags;
110 buffer->nTimeStamp = msg.u.extended_buffer_data.timestamp;
111 node->callbacks.FillBufferDone(node->handle, node->app_data, buffer);
121 static OMX_ERRORTYPE get_error(status_t err)
124 return OMX_ErrorNone;
125 return OMX_ErrorUndefined;
128 static int get_param_size(OMX_INDEXTYPE param_index)
130 switch (param_index) {
131 case OMX_IndexParamPortDefinition:
132 return sizeof(OMX_PARAM_PORTDEFINITIONTYPE);
133 case OMX_IndexParamStandardComponentRole:
134 return sizeof(OMX_PARAM_COMPONENTROLETYPE);
135 case OMX_IndexParamVideoInit:
136 case OMX_IndexParamAudioInit:
137 case OMX_IndexParamImageInit:
138 case OMX_IndexParamOtherInit:
139 return sizeof(OMX_PORT_PARAM_TYPE);
140 case OMX_IndexParamNumAvailableStreams:
141 return sizeof(OMX_PARAM_U32TYPE);
142 case OMX_IndexParamAudioPcm:
143 return sizeof(OMX_AUDIO_PARAM_PCMMODETYPE);
144 case OMX_IndexParamAudioAdpcm:
145 return sizeof(OMX_AUDIO_PARAM_AMRTYPE);
146 case OMX_IndexParamAudioAmr:
147 return sizeof(OMX_AUDIO_PARAM_AMRTYPE);
148 case OMX_IndexParamAudioG723:
149 return sizeof(OMX_AUDIO_PARAM_G723TYPE);
150 case OMX_IndexParamAudioG726:
151 return sizeof(OMX_AUDIO_PARAM_G726TYPE);
152 case OMX_IndexParamAudioG729:
153 return sizeof(OMX_AUDIO_PARAM_G729TYPE);
154 case OMX_IndexParamAudioAac:
155 return sizeof(OMX_AUDIO_PARAM_AACPROFILETYPE);
156 case OMX_IndexParamAudioMp3:
157 return sizeof(OMX_AUDIO_PARAM_MP3TYPE);
158 case OMX_IndexParamAudioSbc:
159 return sizeof(OMX_AUDIO_PARAM_SBCTYPE);
160 case OMX_IndexParamAudioVorbis:
161 return sizeof(OMX_AUDIO_PARAM_VORBISTYPE);
162 case OMX_IndexParamAudioWma:
163 return sizeof(OMX_AUDIO_PARAM_WMATYPE);
164 case OMX_IndexParamAudioRa:
165 return sizeof(OMX_AUDIO_PARAM_RATYPE);
166 case OMX_IndexParamVideoPortFormat:
167 return sizeof(OMX_VIDEO_PARAM_PORTFORMATTYPE);
168 case OMX_IndexParamVideoBitrate:
169 return sizeof(OMX_VIDEO_PARAM_BITRATETYPE);
170 case OMX_IndexParamVideoH263:
171 return sizeof(OMX_VIDEO_PARAM_H263TYPE);
172 case OMX_IndexParamVideoMpeg4:
173 return sizeof(OMX_VIDEO_PARAM_MPEG4TYPE);
174 case OMX_IndexParamVideoAvc:
175 return sizeof(OMX_VIDEO_PARAM_AVCTYPE);
176 case OMX_IndexParamVideoWmv:
177 return sizeof(OMX_VIDEO_PARAM_WMVTYPE);
183 static int get_config_size(OMX_INDEXTYPE param_index)
185 switch (param_index) {
186 case OMX_IndexConfigCommonOutputCrop:
187 return sizeof(OMX_CONFIG_RECTTYPE);
189 /* Dynamically queried config indices could have any size, but
190 * are currently only used with OMX_BOOL. */
191 return sizeof(OMX_BOOL);
195 static OMX_ERRORTYPE iomx_send_command(OMX_HANDLETYPE component, OMX_COMMANDTYPE command, OMX_U32 param1, OMX_PTR)
197 OMXNode* node = (OMXNode*) ((OMX_COMPONENTTYPE*)component)->pComponentPrivate;
198 return get_error(ctx->iomx->sendCommand(node->node, command, param1));
201 static OMX_ERRORTYPE iomx_get_parameter(OMX_HANDLETYPE component, OMX_INDEXTYPE param_index, OMX_PTR param)
203 OMXNode* node = (OMXNode*) ((OMX_COMPONENTTYPE*)component)->pComponentPrivate;
204 return get_error(ctx->iomx->getParameter(node->node, param_index, param, get_param_size(param_index)));
207 static OMX_ERRORTYPE iomx_set_parameter(OMX_HANDLETYPE component, OMX_INDEXTYPE param_index, OMX_PTR param)
209 OMXNode* node = (OMXNode*) ((OMX_COMPONENTTYPE*)component)->pComponentPrivate;
210 return get_error(ctx->iomx->setParameter(node->node, param_index, param, get_param_size(param_index)));
213 static OMX_ERRORTYPE iomx_get_state(OMX_HANDLETYPE component, OMX_STATETYPE *ptr) {
214 OMXNode* node = (OMXNode*) ((OMX_COMPONENTTYPE*)component)->pComponentPrivate;
216 return OMX_ErrorNone;
219 static OMX_ERRORTYPE iomx_allocate_buffer(OMX_HANDLETYPE component, OMX_BUFFERHEADERTYPE **bufferptr, OMX_U32 port_index, OMX_PTR app_private, OMX_U32 size)
221 OMXNode* node = (OMXNode*) ((OMX_COMPONENTTYPE*)component)->pComponentPrivate;
222 OMXBuffer* info = new OMXBuffer;
223 info->dealer = new MemoryDealer(size + 4096); // Do we need to keep this around, or is it kept alive via the IMemory that references it?
224 sp<IMemory> mem = info->dealer->allocate(size);
225 int ret = ctx->iomx->allocateBufferWithBackup(node->node, port_index, mem, &info->id);
227 return OMX_ErrorUndefined;
228 OMX_BUFFERHEADERTYPE *buffer = (OMX_BUFFERHEADERTYPE*) calloc(1, sizeof(OMX_BUFFERHEADERTYPE));
230 buffer->pPlatformPrivate = info;
231 buffer->pAppPrivate = app_private;
232 buffer->nAllocLen = size;
233 buffer->pBuffer = (OMX_U8*) mem->pointer();
234 node->buffers.push_back(buffer);
235 return OMX_ErrorNone;
238 static OMX_ERRORTYPE iomx_free_buffer(OMX_HANDLETYPE component, OMX_U32 port, OMX_BUFFERHEADERTYPE *buffer)
240 OMXNode* node = (OMXNode*) ((OMX_COMPONENTTYPE*)component)->pComponentPrivate;
241 OMXBuffer* info = (OMXBuffer*) buffer->pPlatformPrivate;
242 status_t ret = ctx->iomx->freeBuffer(node->node, port, info->id);
243 for( List<OMX_BUFFERHEADERTYPE*>::iterator it = node->buffers.begin(); it != node->buffers.end(); it++ ) {
245 node->buffers.erase(it);
251 return get_error(ret);
254 static OMX_ERRORTYPE iomx_empty_this_buffer(OMX_HANDLETYPE component, OMX_BUFFERHEADERTYPE *buffer)
256 OMXNode* node = (OMXNode*) ((OMX_COMPONENTTYPE*)component)->pComponentPrivate;
257 OMXBuffer* info = (OMXBuffer*) buffer->pPlatformPrivate;
258 return get_error(ctx->iomx->emptyBuffer(node->node, info->id, buffer->nOffset, buffer->nFilledLen, buffer->nFlags, buffer->nTimeStamp));
261 static OMX_ERRORTYPE iomx_fill_this_buffer(OMX_HANDLETYPE component, OMX_BUFFERHEADERTYPE *buffer)
263 OMXNode* node = (OMXNode*) ((OMX_COMPONENTTYPE*)component)->pComponentPrivate;
264 OMXBuffer* info = (OMXBuffer*) buffer->pPlatformPrivate;
265 return get_error(ctx->iomx->fillBuffer(node->node, info->id));
268 static OMX_ERRORTYPE iomx_component_role_enum(OMX_HANDLETYPE component, OMX_U8 *role, OMX_U32 index)
270 OMXNode* node = (OMXNode*) ((OMX_COMPONENTTYPE*)component)->pComponentPrivate;
271 for( List<IOMX::ComponentInfo>::iterator it = ctx->components.begin(); it != ctx->components.end(); it++ ) {
272 if (node->component_name == it->mName) {
273 if (index >= it->mRoles.size())
274 return OMX_ErrorNoMore;
275 List<String8>::iterator it2 = it->mRoles.begin();
276 for( OMX_U32 i = 0; it2 != it->mRoles.end() && i < index; i++, it2++ ) ;
277 strncpy((char*)role, it2->string(), OMX_MAX_STRINGNAME_SIZE);
278 if (it2->length() >= OMX_MAX_STRINGNAME_SIZE)
279 role[OMX_MAX_STRINGNAME_SIZE - 1] = '\0';
280 return OMX_ErrorNone;
283 return OMX_ErrorInvalidComponentName;
286 static OMX_ERRORTYPE iomx_get_extension_index(OMX_HANDLETYPE component, OMX_STRING parameter, OMX_INDEXTYPE *index)
288 OMXNode* node = (OMXNode*) ((OMX_COMPONENTTYPE*)component)->pComponentPrivate;
289 return get_error(ctx->iomx->getExtensionIndex(node->node, parameter, index));
292 static OMX_ERRORTYPE iomx_set_config(OMX_HANDLETYPE component, OMX_INDEXTYPE index, OMX_PTR param)
294 OMXNode* node = (OMXNode*) ((OMX_COMPONENTTYPE*)component)->pComponentPrivate;
295 return get_error(ctx->iomx->setConfig(node->node, index, param, get_config_size(index)));
298 static OMX_ERRORTYPE iomx_get_config(OMX_HANDLETYPE component, OMX_INDEXTYPE index, OMX_PTR param)
300 OMXNode* node = (OMXNode*) ((OMX_COMPONENTTYPE*)component)->pComponentPrivate;
301 return get_error(ctx->iomx->getConfig(node->node, index, param, get_config_size(index)));
305 OMX_ERRORTYPE PREFIX(OMX_GetHandle)(OMX_HANDLETYPE *handle_ptr, OMX_STRING component_name, OMX_PTR app_data, OMX_CALLBACKTYPE *callbacks)
307 OMXNode* node = new OMXNode();
308 node->app_data = app_data;
309 node->callbacks = *callbacks;
310 node->observer = new OMXCodecObserver();
311 node->observer->setNode(node);
312 node->state = OMX_StateLoaded;
313 node->component_name = component_name;
315 OMX_COMPONENTTYPE* component = (OMX_COMPONENTTYPE*) malloc(sizeof(OMX_COMPONENTTYPE));
316 memset(component, 0, sizeof(OMX_COMPONENTTYPE));
317 component->nSize = sizeof(OMX_COMPONENTTYPE);
318 component->nVersion.s.nVersionMajor = 1;
319 component->nVersion.s.nVersionMinor = 1;
320 component->nVersion.s.nRevision = 0;
321 component->nVersion.s.nStep = 0;
322 component->pComponentPrivate = node;
323 component->SendCommand = iomx_send_command;
324 component->GetParameter = iomx_get_parameter;
325 component->SetParameter = iomx_set_parameter;
326 component->FreeBuffer = iomx_free_buffer;
327 component->EmptyThisBuffer = iomx_empty_this_buffer;
328 component->FillThisBuffer = iomx_fill_this_buffer;
329 component->GetState = iomx_get_state;
330 component->AllocateBuffer = iomx_allocate_buffer;
331 component->ComponentRoleEnum = iomx_component_role_enum;
332 component->GetExtensionIndex = iomx_get_extension_index;
333 component->SetConfig = iomx_set_config;
334 component->GetConfig = iomx_get_config;
336 *handle_ptr = component;
337 node->handle = component;
339 if ((ret = ctx->iomx->allocateNode( component_name, node->observer, &node->node )) != OK)
340 return OMX_ErrorUndefined;
341 return OMX_ErrorNone;
344 OMX_ERRORTYPE PREFIX(OMX_FreeHandle)(OMX_HANDLETYPE handle)
346 OMXNode* node = (OMXNode*) ((OMX_COMPONENTTYPE*)handle)->pComponentPrivate;
347 ctx->iomx->freeNode( node->node );
348 node->observer->setNode(NULL);
351 return OMX_ErrorNone;
354 OMX_ERRORTYPE PREFIX(OMX_Init)(void)
357 if (client.connect() != OK)
358 return OMX_ErrorUndefined;
361 ctx = new IOMXContext();
362 ctx->iomx = client.interface();
363 ctx->iomx->listNodes(&ctx->components);
364 return OMX_ErrorNone;
367 OMX_ERRORTYPE PREFIX(OMX_Deinit)(void)
372 return OMX_ErrorNone;
375 OMX_ERRORTYPE PREFIX(OMX_ComponentNameEnum)(OMX_STRING component_name, OMX_U32 name_length, OMX_U32 index)
377 if (index >= ctx->components.size())
378 return OMX_ErrorNoMore;
379 List<IOMX::ComponentInfo>::iterator it = ctx->components.begin();
380 for( OMX_U32 i = 0; i < index; i++ )
382 strncpy(component_name, it->mName.string(), name_length);
383 component_name[name_length - 1] = '\0';
384 return OMX_ErrorNone;
387 OMX_ERRORTYPE PREFIX(OMX_GetRolesOfComponent)(OMX_STRING component_name, OMX_U32 *num_roles, OMX_U8 **roles)
389 for( List<IOMX::ComponentInfo>::iterator it = ctx->components.begin(); it != ctx->components.end(); it++ ) {
390 if (!strcmp(component_name, it->mName.string())) {
392 *num_roles = it->mRoles.size();
393 return OMX_ErrorNone;
395 if (*num_roles < it->mRoles.size())
396 return OMX_ErrorInsufficientResources;
397 *num_roles = it->mRoles.size();
399 for( List<String8>::iterator it2 = it->mRoles.begin(); it2 != it->mRoles.end(); i++, it2++ ) {
400 strncpy((char*)roles[i], it2->string(), OMX_MAX_STRINGNAME_SIZE);
401 roles[i][OMX_MAX_STRINGNAME_SIZE - 1] = '\0';
403 return OMX_ErrorNone;
406 return OMX_ErrorInvalidComponentName;
409 OMX_ERRORTYPE PREFIX(OMX_GetComponentsOfRole)(OMX_STRING role, OMX_U32 *num_comps, OMX_U8 **comp_names)
412 for( List<IOMX::ComponentInfo>::iterator it = ctx->components.begin(); it != ctx->components.end(); it++ ) {
413 for( List<String8>::iterator it2 = it->mRoles.begin(); it2 != it->mRoles.end(); it2++ ) {
414 if (!strcmp(it2->string(), role)) {
417 return OMX_ErrorInsufficientResources;
418 strncpy((char*)comp_names[i], it->mName.string(), OMX_MAX_STRINGNAME_SIZE);
419 comp_names[i][OMX_MAX_STRINGNAME_SIZE - 1] = '\0';
427 return OMX_ErrorNone;