]> git.sesse.net Git - vlc/blob - modules/codec/omxil/iomx.cpp
omxil: Build the iomx wrapper code as a separate shared library
[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 using namespace android;
33
34 class IOMXContext {
35 public:
36     IOMXContext() {
37     }
38
39     sp<IOMX> iomx;
40     List<IOMX::ComponentInfo> components;
41 };
42
43 static IOMXContext *ctx;
44
45 class OMXNode;
46
47 class OMXCodecObserver : public BnOMXObserver {
48 public:
49     OMXCodecObserver() {
50         node = NULL;
51     }
52     void setNode(OMXNode* n) {
53         node = n;
54     }
55     void onMessage(const omx_message &msg);
56     void registerBuffers(const sp<IMemoryHeap> &) {
57     }
58 private:
59     OMXNode *node;
60 };
61
62 class OMXNode {
63 public:
64     IOMX::node_id node;
65     sp<OMXCodecObserver> observer;
66     OMX_CALLBACKTYPE callbacks;
67     OMX_PTR app_data;
68     OMX_STATETYPE state;
69     List<OMX_BUFFERHEADERTYPE*> buffers;
70     OMX_HANDLETYPE handle;
71     String8 component_name;
72 };
73
74 class OMXBuffer {
75 public:
76     sp<MemoryDealer> dealer;
77     IOMX::buffer_id id;
78 };
79
80 void OMXCodecObserver::onMessage(const omx_message &msg)
81 {
82     if (!node)
83         return;
84     switch (msg.type) {
85     case omx_message::EVENT:
86         // TODO: Needs locking
87         if (msg.u.event_data.event == OMX_EventCmdComplete && msg.u.event_data.data1 == OMX_CommandStateSet)
88             node->state = (OMX_STATETYPE) msg.u.event_data.data2;
89         node->callbacks.EventHandler(node->handle, node->app_data, msg.u.event_data.event, msg.u.event_data.data1, msg.u.event_data.data2, NULL);
90         break;
91     case omx_message::EMPTY_BUFFER_DONE:
92         for( List<OMX_BUFFERHEADERTYPE*>::iterator it = node->buffers.begin(); it != node->buffers.end(); it++ ) {
93             OMXBuffer* info = (OMXBuffer*) (*it)->pPlatformPrivate;
94             if (msg.u.buffer_data.buffer == info->id) {
95                 node->callbacks.EmptyBufferDone(node->handle, node->app_data, *it);
96                 break;
97             }
98         }
99         break;
100     case omx_message::FILL_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.extended_buffer_data.buffer == info->id) {
104                 OMX_BUFFERHEADERTYPE *buffer = *it;
105                 buffer->nOffset = msg.u.extended_buffer_data.range_offset;
106                 buffer->nFilledLen = msg.u.extended_buffer_data.range_length;
107                 buffer->nFlags = msg.u.extended_buffer_data.flags;
108                 buffer->nTimeStamp = msg.u.extended_buffer_data.timestamp;
109                 node->callbacks.FillBufferDone(node->handle, node->app_data, buffer);
110                 break;
111             }
112         }
113         break;
114     default:
115         break;
116     }
117 }
118
119 static OMX_ERRORTYPE get_error(status_t err)
120 {
121     if (err == OK)
122         return OMX_ErrorNone;
123     return OMX_ErrorUndefined;
124 }
125
126 static int get_param_size(OMX_INDEXTYPE param_index)
127 {
128     switch (param_index) {
129     case OMX_IndexParamPortDefinition:
130         return sizeof(OMX_PARAM_PORTDEFINITIONTYPE);
131     case OMX_IndexParamStandardComponentRole:
132         return sizeof(OMX_PARAM_COMPONENTROLETYPE);
133     case OMX_IndexParamVideoInit:
134     case OMX_IndexParamAudioInit:
135     case OMX_IndexParamImageInit:
136     case OMX_IndexParamOtherInit:
137         return sizeof(OMX_PORT_PARAM_TYPE);
138     case OMX_IndexParamNumAvailableStreams:
139         return sizeof(OMX_PARAM_U32TYPE);
140     case OMX_IndexParamAudioPcm:
141         return sizeof(OMX_AUDIO_PARAM_PCMMODETYPE);
142     case OMX_IndexParamAudioAdpcm:
143         return sizeof(OMX_AUDIO_PARAM_AMRTYPE);
144     case OMX_IndexParamAudioAmr:
145         return sizeof(OMX_AUDIO_PARAM_AMRTYPE);
146     case OMX_IndexParamAudioG723:
147         return sizeof(OMX_AUDIO_PARAM_G723TYPE);
148     case OMX_IndexParamAudioG726:
149         return sizeof(OMX_AUDIO_PARAM_G726TYPE);
150     case OMX_IndexParamAudioG729:
151         return sizeof(OMX_AUDIO_PARAM_G729TYPE);
152     case OMX_IndexParamAudioAac:
153         return sizeof(OMX_AUDIO_PARAM_AACPROFILETYPE);
154     case OMX_IndexParamAudioMp3:
155         return sizeof(OMX_AUDIO_PARAM_MP3TYPE);
156     case OMX_IndexParamAudioSbc:
157         return sizeof(OMX_AUDIO_PARAM_SBCTYPE);
158     case OMX_IndexParamAudioVorbis:
159         return sizeof(OMX_AUDIO_PARAM_VORBISTYPE);
160     case OMX_IndexParamAudioWma:
161         return sizeof(OMX_AUDIO_PARAM_WMATYPE);
162     case OMX_IndexParamAudioRa:
163         return sizeof(OMX_AUDIO_PARAM_RATYPE);
164     default:
165         return 0;
166     }
167 }
168
169 static OMX_ERRORTYPE iomx_send_command(OMX_HANDLETYPE component, OMX_COMMANDTYPE command, OMX_U32 param1, OMX_PTR)
170 {
171     OMXNode* node = (OMXNode*) ((OMX_COMPONENTTYPE*)component)->pComponentPrivate;
172     return get_error(ctx->iomx->sendCommand(node->node, command, param1));
173 }
174
175 static OMX_ERRORTYPE iomx_get_parameter(OMX_HANDLETYPE component, OMX_INDEXTYPE param_index, OMX_PTR param)
176 {
177     OMXNode* node = (OMXNode*) ((OMX_COMPONENTTYPE*)component)->pComponentPrivate;
178     return get_error(ctx->iomx->getParameter(node->node, param_index, param, get_param_size(param_index)));
179 }
180
181 static OMX_ERRORTYPE iomx_set_parameter(OMX_HANDLETYPE component, OMX_INDEXTYPE param_index, OMX_PTR param)
182 {
183     OMXNode* node = (OMXNode*) ((OMX_COMPONENTTYPE*)component)->pComponentPrivate;
184     return get_error(ctx->iomx->setParameter(node->node, param_index, param, get_param_size(param_index)));
185 }
186
187 static OMX_ERRORTYPE iomx_get_state(OMX_HANDLETYPE component, OMX_STATETYPE *ptr) {
188     OMXNode* node = (OMXNode*) ((OMX_COMPONENTTYPE*)component)->pComponentPrivate;
189     *ptr = node->state;
190     return OMX_ErrorNone;
191 }
192
193 static OMX_ERRORTYPE iomx_allocate_buffer(OMX_HANDLETYPE component, OMX_BUFFERHEADERTYPE **bufferptr, OMX_U32 port_index, OMX_PTR app_private, OMX_U32 size)
194 {
195     OMXNode* node = (OMXNode*) ((OMX_COMPONENTTYPE*)component)->pComponentPrivate;
196     OMXBuffer* info = new OMXBuffer;
197     info->dealer = new MemoryDealer(size + 4096); // Do we need to keep this around, or is it kept alive via the IMemory that references it?
198     sp<IMemory> mem = info->dealer->allocate(size);
199     int ret = ctx->iomx->allocateBufferWithBackup(node->node, port_index, mem, &info->id);
200     if (ret != OK)
201         return OMX_ErrorUndefined;
202     OMX_BUFFERHEADERTYPE *buffer = (OMX_BUFFERHEADERTYPE*) calloc(1, sizeof(OMX_BUFFERHEADERTYPE));
203     *bufferptr = buffer;
204     buffer->pPlatformPrivate = info;
205     buffer->pAppPrivate = app_private;
206     buffer->nAllocLen = size;
207     buffer->pBuffer = (OMX_U8*) mem->pointer();
208     node->buffers.push_back(buffer);
209     return OMX_ErrorNone;
210 }
211
212 static OMX_ERRORTYPE iomx_free_buffer(OMX_HANDLETYPE component, OMX_U32 port, OMX_BUFFERHEADERTYPE *buffer)
213 {
214     OMXNode* node = (OMXNode*) ((OMX_COMPONENTTYPE*)component)->pComponentPrivate;
215     OMXBuffer* info = (OMXBuffer*) buffer->pPlatformPrivate;
216     status_t ret = ctx->iomx->freeBuffer(node->node, port, info->id);
217     for( List<OMX_BUFFERHEADERTYPE*>::iterator it = node->buffers.begin(); it != node->buffers.end(); it++ ) {
218         if (buffer == *it) {
219             node->buffers.erase(it);
220             break;
221         }
222     }
223     free(buffer);
224     delete info;
225     return get_error(ret);
226 }
227
228 static OMX_ERRORTYPE iomx_empty_this_buffer(OMX_HANDLETYPE component, OMX_BUFFERHEADERTYPE *buffer)
229 {
230     OMXNode* node = (OMXNode*) ((OMX_COMPONENTTYPE*)component)->pComponentPrivate;
231     OMXBuffer* info = (OMXBuffer*) buffer->pPlatformPrivate;
232     return get_error(ctx->iomx->emptyBuffer(node->node, info->id, buffer->nOffset, buffer->nFilledLen, buffer->nFlags, buffer->nTimeStamp));
233 }
234
235 static OMX_ERRORTYPE iomx_fill_this_buffer(OMX_HANDLETYPE component, OMX_BUFFERHEADERTYPE *buffer)
236 {
237     OMXNode* node = (OMXNode*) ((OMX_COMPONENTTYPE*)component)->pComponentPrivate;
238     OMXBuffer* info = (OMXBuffer*) buffer->pPlatformPrivate;
239     return get_error(ctx->iomx->fillBuffer(node->node, info->id));
240 }
241
242 static OMX_ERRORTYPE iomx_component_role_enum(OMX_HANDLETYPE component, OMX_U8 *role, OMX_U32 index)
243 {
244     OMXNode* node = (OMXNode*) ((OMX_COMPONENTTYPE*)component)->pComponentPrivate;
245     for( List<IOMX::ComponentInfo>::iterator it = ctx->components.begin(); it != ctx->components.end(); it++ ) {
246         if (node->component_name == it->mName) {
247             if (index >= it->mRoles.size())
248                 return OMX_ErrorNoMore;
249             List<String8>::iterator it2 = it->mRoles.begin();
250             for( OMX_U32 i = 0; it2 != it->mRoles.end() && i < index; i++, it2++ ) ;
251             strncpy((char*)role, it2->string(), OMX_MAX_STRINGNAME_SIZE);
252             if (it2->length() >= OMX_MAX_STRINGNAME_SIZE)
253                 role[OMX_MAX_STRINGNAME_SIZE - 1] = '\0';
254             return OMX_ErrorNone;
255         }
256     }
257     return OMX_ErrorInvalidComponentName;
258 }
259
260 static OMX_ERRORTYPE iomx_get_extension_index(OMX_HANDLETYPE component, OMX_STRING parameter, OMX_INDEXTYPE *index)
261 {
262     OMXNode* node = (OMXNode*) ((OMX_COMPONENTTYPE*)component)->pComponentPrivate;
263     return get_error(ctx->iomx->getExtensionIndex(node->node, parameter, index));
264 }
265
266 static OMX_ERRORTYPE iomx_set_config(OMX_HANDLETYPE component, OMX_INDEXTYPE index, OMX_PTR param)
267 {
268     OMXNode* node = (OMXNode*) ((OMX_COMPONENTTYPE*)component)->pComponentPrivate;
269     /* TODO: Need a way to map index to param size */
270     return get_error(ctx->iomx->setConfig(node->node, index, param, sizeof(OMX_BOOL)));
271 }
272
273 OMX_ERRORTYPE OMX_GetHandle(OMX_HANDLETYPE *handle_ptr, OMX_STRING component_name, OMX_PTR app_data, OMX_CALLBACKTYPE *callbacks)
274 {
275     OMXNode* node = new OMXNode();
276     node->app_data = app_data;
277     node->callbacks = *callbacks;
278     node->observer = new OMXCodecObserver();
279     node->observer->setNode(node);
280     node->state = OMX_StateLoaded;
281     node->component_name = component_name;
282
283     OMX_COMPONENTTYPE* component = (OMX_COMPONENTTYPE*) malloc(sizeof(OMX_COMPONENTTYPE));
284     memset(component, 0, sizeof(OMX_COMPONENTTYPE));
285     component->nSize = sizeof(OMX_COMPONENTTYPE);
286     component->nVersion.s.nVersionMajor = 1;
287     component->nVersion.s.nVersionMinor = 1;
288     component->nVersion.s.nRevision = 0;
289     component->nVersion.s.nStep = 0;
290     component->pComponentPrivate = node;
291     component->SendCommand = iomx_send_command;
292     component->GetParameter = iomx_get_parameter;
293     component->SetParameter = iomx_set_parameter;
294     component->FreeBuffer = iomx_free_buffer;
295     component->EmptyThisBuffer = iomx_empty_this_buffer;
296     component->FillThisBuffer = iomx_fill_this_buffer;
297     component->GetState = iomx_get_state;
298     component->AllocateBuffer = iomx_allocate_buffer;
299     component->ComponentRoleEnum = iomx_component_role_enum;
300     component->GetExtensionIndex = iomx_get_extension_index;
301     component->SetConfig = iomx_set_config;
302
303     *handle_ptr = component;
304     node->handle = component;
305     status_t ret;
306     if ((ret = ctx->iomx->allocateNode( component_name, node->observer, &node->node )) != OK)
307         return OMX_ErrorUndefined;
308     return OMX_ErrorNone;
309 }
310
311 OMX_ERRORTYPE OMX_FreeHandle(OMX_HANDLETYPE handle)
312 {
313     OMXNode* node = (OMXNode*) ((OMX_COMPONENTTYPE*)handle)->pComponentPrivate;
314     ctx->iomx->freeNode( node->node );
315     node->observer->setNode(NULL);
316     delete node;
317     free(handle);
318     return OMX_ErrorNone;
319 }
320
321 OMX_ERRORTYPE OMX_Init(void)
322 {
323     OMXClient client;
324     if (client.connect() != OK)
325         return OMX_ErrorUndefined;
326
327     if (!ctx)
328         ctx = new IOMXContext();
329     ctx->iomx = client.interface();
330     ctx->iomx->listNodes(&ctx->components);
331     return OMX_ErrorNone;
332 }
333
334 OMX_ERRORTYPE OMX_Deinit(void)
335 {
336     ctx->iomx = NULL;
337     delete ctx;
338     ctx = NULL;
339     return OMX_ErrorNone;
340 }
341
342 OMX_ERRORTYPE OMX_ComponentNameEnum(OMX_STRING component_name, OMX_U32 name_length, OMX_U32 index)
343 {
344     if (index >= ctx->components.size())
345         return OMX_ErrorNoMore;
346     List<IOMX::ComponentInfo>::iterator it = ctx->components.begin();
347     for( OMX_U32 i = 0; i < index; i++ )
348         it++;
349     strncpy(component_name, it->mName.string(), name_length);
350     component_name[name_length - 1] = '\0';
351     return OMX_ErrorNone;
352 }
353
354 OMX_ERRORTYPE OMX_GetRolesOfComponent(OMX_STRING component_name, OMX_U32 *num_roles, OMX_U8 **roles)
355 {
356     for( List<IOMX::ComponentInfo>::iterator it = ctx->components.begin(); it != ctx->components.end(); it++ ) {
357         if (!strcmp(component_name, it->mName.string())) {
358             if (!roles) {
359                 *num_roles = it->mRoles.size();
360                 return OMX_ErrorNone;
361             }
362             if (*num_roles < it->mRoles.size())
363                 return OMX_ErrorInsufficientResources;
364             *num_roles = it->mRoles.size();
365             OMX_U32 i = 0;
366             for( List<String8>::iterator it2 = it->mRoles.begin(); it2 != it->mRoles.end(); i++, it2++ ) {
367                 strncpy((char*)roles[i], it2->string(), OMX_MAX_STRINGNAME_SIZE);
368                 roles[i][OMX_MAX_STRINGNAME_SIZE - 1] = '\0';
369             }
370             return OMX_ErrorNone;
371         }
372     }
373     return OMX_ErrorInvalidComponentName;
374 }
375