]> git.sesse.net Git - vlc/blob - modules/codec/omxil/iomx.cpp
omxil: Remove an unused struct member
[vlc] / modules / codec / omxil / iomx.cpp
1 /*****************************************************************************
2  * iomx.cpp: OpenMAX interface implementation based on IOMX
3  *****************************************************************************
4  * Copyright (C) 2011 VLC authors and VideoLAN
5  *
6  * Authors: Martin Storsjo <martin@martin.st>
7  *
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.
12  *
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.
17  *
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  *****************************************************************************/
22
23 /*****************************************************************************
24  * Preamble
25  *****************************************************************************/
26
27 #include <media/stagefright/OMXClient.h>
28 #include <media/IOMX.h>
29 #include <binder/MemoryDealer.h>
30 #include <OMX_Component.h>
31
32 #define PREFIX(x) I ## x
33
34 using namespace android;
35
36 class IOMXContext {
37 public:
38     IOMXContext() {
39     }
40
41     sp<IOMX> iomx;
42     List<IOMX::ComponentInfo> components;
43 };
44
45 static IOMXContext *ctx;
46
47 class OMXNode;
48
49 class OMXCodecObserver : public BnOMXObserver {
50 public:
51     OMXCodecObserver() {
52         node = NULL;
53     }
54     void setNode(OMXNode* n) {
55         node = n;
56     }
57     void onMessage(const omx_message &msg);
58     void registerBuffers(const sp<IMemoryHeap> &) {
59     }
60 private:
61     OMXNode *node;
62 };
63
64 class OMXNode {
65 public:
66     IOMX::node_id node;
67     sp<OMXCodecObserver> observer;
68     OMX_CALLBACKTYPE callbacks;
69     OMX_PTR app_data;
70     OMX_STATETYPE state;
71     List<OMX_BUFFERHEADERTYPE*> buffers;
72     OMX_HANDLETYPE handle;
73     String8 component_name;
74 };
75
76 class OMXBuffer {
77 public:
78     sp<MemoryDealer> dealer;
79     IOMX::buffer_id id;
80 };
81
82 void OMXCodecObserver::onMessage(const omx_message &msg)
83 {
84     if (!node)
85         return;
86     switch (msg.type) {
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);
92         break;
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);
98                 break;
99             }
100         }
101         break;
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);
112                 break;
113             }
114         }
115         break;
116     default:
117         break;
118     }
119 }
120
121 static OMX_ERRORTYPE get_error(status_t err)
122 {
123     if (err == OK)
124         return OMX_ErrorNone;
125     return OMX_ErrorUndefined;
126 }
127
128 static int get_param_size(OMX_INDEXTYPE param_index)
129 {
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);
178     default:
179         return 0;
180     }
181 }
182
183 static int get_config_size(OMX_INDEXTYPE param_index)
184 {
185     switch (param_index) {
186     case OMX_IndexConfigCommonOutputCrop:
187         return sizeof(OMX_CONFIG_RECTTYPE);
188     default:
189         /* Dynamically queried config indices could have any size, but
190          * are currently only used with OMX_BOOL. */
191         return sizeof(OMX_BOOL);
192     }
193 }
194
195 static OMX_ERRORTYPE iomx_send_command(OMX_HANDLETYPE component, OMX_COMMANDTYPE command, OMX_U32 param1, OMX_PTR)
196 {
197     OMXNode* node = (OMXNode*) ((OMX_COMPONENTTYPE*)component)->pComponentPrivate;
198     return get_error(ctx->iomx->sendCommand(node->node, command, param1));
199 }
200
201 static OMX_ERRORTYPE iomx_get_parameter(OMX_HANDLETYPE component, OMX_INDEXTYPE param_index, OMX_PTR param)
202 {
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)));
205 }
206
207 static OMX_ERRORTYPE iomx_set_parameter(OMX_HANDLETYPE component, OMX_INDEXTYPE param_index, OMX_PTR param)
208 {
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)));
211 }
212
213 static OMX_ERRORTYPE iomx_get_state(OMX_HANDLETYPE component, OMX_STATETYPE *ptr) {
214     OMXNode* node = (OMXNode*) ((OMX_COMPONENTTYPE*)component)->pComponentPrivate;
215     *ptr = node->state;
216     return OMX_ErrorNone;
217 }
218
219 static OMX_ERRORTYPE iomx_allocate_buffer(OMX_HANDLETYPE component, OMX_BUFFERHEADERTYPE **bufferptr, OMX_U32 port_index, OMX_PTR app_private, OMX_U32 size)
220 {
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);
226     if (ret != OK)
227         return OMX_ErrorUndefined;
228     OMX_BUFFERHEADERTYPE *buffer = (OMX_BUFFERHEADERTYPE*) calloc(1, sizeof(OMX_BUFFERHEADERTYPE));
229     *bufferptr = buffer;
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;
236 }
237
238 static OMX_ERRORTYPE iomx_free_buffer(OMX_HANDLETYPE component, OMX_U32 port, OMX_BUFFERHEADERTYPE *buffer)
239 {
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++ ) {
244         if (buffer == *it) {
245             node->buffers.erase(it);
246             break;
247         }
248     }
249     free(buffer);
250     delete info;
251     return get_error(ret);
252 }
253
254 static OMX_ERRORTYPE iomx_empty_this_buffer(OMX_HANDLETYPE component, OMX_BUFFERHEADERTYPE *buffer)
255 {
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));
259 }
260
261 static OMX_ERRORTYPE iomx_fill_this_buffer(OMX_HANDLETYPE component, OMX_BUFFERHEADERTYPE *buffer)
262 {
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));
266 }
267
268 static OMX_ERRORTYPE iomx_component_role_enum(OMX_HANDLETYPE component, OMX_U8 *role, OMX_U32 index)
269 {
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;
281         }
282     }
283     return OMX_ErrorInvalidComponentName;
284 }
285
286 static OMX_ERRORTYPE iomx_get_extension_index(OMX_HANDLETYPE component, OMX_STRING parameter, OMX_INDEXTYPE *index)
287 {
288     OMXNode* node = (OMXNode*) ((OMX_COMPONENTTYPE*)component)->pComponentPrivate;
289     return get_error(ctx->iomx->getExtensionIndex(node->node, parameter, index));
290 }
291
292 static OMX_ERRORTYPE iomx_set_config(OMX_HANDLETYPE component, OMX_INDEXTYPE index, OMX_PTR param)
293 {
294     OMXNode* node = (OMXNode*) ((OMX_COMPONENTTYPE*)component)->pComponentPrivate;
295     return get_error(ctx->iomx->setConfig(node->node, index, param, get_config_size(index)));
296 }
297
298 static OMX_ERRORTYPE iomx_get_config(OMX_HANDLETYPE component, OMX_INDEXTYPE index, OMX_PTR param)
299 {
300     OMXNode* node = (OMXNode*) ((OMX_COMPONENTTYPE*)component)->pComponentPrivate;
301     return get_error(ctx->iomx->getConfig(node->node, index, param, get_config_size(index)));
302 }
303
304 extern "C" {
305 OMX_ERRORTYPE PREFIX(OMX_GetHandle)(OMX_HANDLETYPE *handle_ptr, OMX_STRING component_name, OMX_PTR app_data, OMX_CALLBACKTYPE *callbacks)
306 {
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;
314
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;
335
336     *handle_ptr = component;
337     node->handle = component;
338     status_t ret;
339     if ((ret = ctx->iomx->allocateNode( component_name, node->observer, &node->node )) != OK)
340         return OMX_ErrorUndefined;
341     return OMX_ErrorNone;
342 }
343
344 OMX_ERRORTYPE PREFIX(OMX_FreeHandle)(OMX_HANDLETYPE handle)
345 {
346     OMXNode* node = (OMXNode*) ((OMX_COMPONENTTYPE*)handle)->pComponentPrivate;
347     ctx->iomx->freeNode( node->node );
348     node->observer->setNode(NULL);
349     delete node;
350     free(handle);
351     return OMX_ErrorNone;
352 }
353
354 OMX_ERRORTYPE PREFIX(OMX_Init)(void)
355 {
356     OMXClient client;
357     if (client.connect() != OK)
358         return OMX_ErrorUndefined;
359
360     if (!ctx)
361         ctx = new IOMXContext();
362     ctx->iomx = client.interface();
363     ctx->iomx->listNodes(&ctx->components);
364     return OMX_ErrorNone;
365 }
366
367 OMX_ERRORTYPE PREFIX(OMX_Deinit)(void)
368 {
369     ctx->iomx = NULL;
370     delete ctx;
371     ctx = NULL;
372     return OMX_ErrorNone;
373 }
374
375 OMX_ERRORTYPE PREFIX(OMX_ComponentNameEnum)(OMX_STRING component_name, OMX_U32 name_length, OMX_U32 index)
376 {
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++ )
381         it++;
382     strncpy(component_name, it->mName.string(), name_length);
383     component_name[name_length - 1] = '\0';
384     return OMX_ErrorNone;
385 }
386
387 OMX_ERRORTYPE PREFIX(OMX_GetRolesOfComponent)(OMX_STRING component_name, OMX_U32 *num_roles, OMX_U8 **roles)
388 {
389     for( List<IOMX::ComponentInfo>::iterator it = ctx->components.begin(); it != ctx->components.end(); it++ ) {
390         if (!strcmp(component_name, it->mName.string())) {
391             if (!roles) {
392                 *num_roles = it->mRoles.size();
393                 return OMX_ErrorNone;
394             }
395             if (*num_roles < it->mRoles.size())
396                 return OMX_ErrorInsufficientResources;
397             *num_roles = it->mRoles.size();
398             OMX_U32 i = 0;
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';
402             }
403             return OMX_ErrorNone;
404         }
405     }
406     return OMX_ErrorInvalidComponentName;
407 }
408
409 OMX_ERRORTYPE PREFIX(OMX_GetComponentsOfRole)(OMX_STRING role, OMX_U32 *num_comps, OMX_U8 **comp_names)
410 {
411     OMX_U32 i = 0;
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)) {
415                 if (comp_names) {
416                     if (*num_comps < i)
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';
420                 }
421                 i++;
422                 break;
423             }
424         }
425     }
426     *num_comps = i;
427     return OMX_ErrorNone;
428 }
429 }
430