]> git.sesse.net Git - vlc/blob - modules/codec/omxil/iomx.cpp
mediacodec: factorize release_output_buffer
[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 #if ANDROID_API >= 11
35 #define HAS_USE_BUFFER
36 #endif
37
38 using namespace android;
39
40 class IOMXContext {
41 public:
42     IOMXContext() {
43     }
44
45     sp<IOMX> iomx;
46     List<IOMX::ComponentInfo> components;
47 };
48
49 static IOMXContext *ctx;
50
51 class OMXNode;
52
53 class OMXCodecObserver : public BnOMXObserver {
54 public:
55     OMXCodecObserver() {
56         node = NULL;
57     }
58     void setNode(OMXNode* n) {
59         node = n;
60     }
61     void onMessage(const omx_message &msg);
62     void registerBuffers(const sp<IMemoryHeap> &) {
63     }
64 private:
65     OMXNode *node;
66 };
67
68 class OMXNode {
69 public:
70     IOMX::node_id node;
71     sp<OMXCodecObserver> observer;
72     OMX_CALLBACKTYPE callbacks;
73     OMX_PTR app_data;
74     OMX_STATETYPE state;
75     List<OMX_BUFFERHEADERTYPE*> buffers;
76     OMX_HANDLETYPE handle;
77     String8 component_name;
78 };
79
80 class OMXBuffer {
81 public:
82     sp<MemoryDealer> dealer;
83 #ifdef HAS_USE_BUFFER
84     sp<GraphicBuffer> graphicBuffer;
85 #endif
86     IOMX::buffer_id id;
87 };
88
89 void OMXCodecObserver::onMessage(const omx_message &msg)
90 {
91     if (!node)
92         return;
93     switch (msg.type) {
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);
99         break;
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);
105                 break;
106             }
107         }
108         break;
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);
119                 break;
120             }
121         }
122         break;
123     default:
124         break;
125     }
126 }
127
128 static OMX_ERRORTYPE get_error(status_t err)
129 {
130     if (err == OK)
131         return OMX_ErrorNone;
132     return OMX_ErrorUndefined;
133 }
134
135 static OMX_ERRORTYPE iomx_send_command(OMX_HANDLETYPE component, OMX_COMMANDTYPE command, OMX_U32 param1, OMX_PTR)
136 {
137     OMXNode* node = (OMXNode*) ((OMX_COMPONENTTYPE*)component)->pComponentPrivate;
138     return get_error(ctx->iomx->sendCommand(node->node, command, param1));
139 }
140
141 static OMX_ERRORTYPE iomx_get_parameter(OMX_HANDLETYPE component, OMX_INDEXTYPE param_index, OMX_PTR param)
142 {
143     /*
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.
146      */
147     OMX_U32 nSize = *(OMX_U32*)param;
148     OMX_ERRORTYPE error;
149     OMXNode* node = (OMXNode*) ((OMX_COMPONENTTYPE*)component)->pComponentPrivate;
150
151     error = get_error(ctx->iomx->getParameter(node->node, param_index, param, nSize));
152     *(OMX_U32*)param = nSize;
153     return error;
154 }
155
156 static OMX_ERRORTYPE iomx_set_parameter(OMX_HANDLETYPE component, OMX_INDEXTYPE param_index, OMX_PTR param)
157 {
158     OMXNode* node = (OMXNode*) ((OMX_COMPONENTTYPE*)component)->pComponentPrivate;
159     return get_error(ctx->iomx->setParameter(node->node, param_index, param, *(OMX_U32*)param));
160 }
161
162 static OMX_ERRORTYPE iomx_get_state(OMX_HANDLETYPE component, OMX_STATETYPE *ptr) {
163     OMXNode* node = (OMXNode*) ((OMX_COMPONENTTYPE*)component)->pComponentPrivate;
164     *ptr = node->state;
165     return OMX_ErrorNone;
166 }
167
168 static OMX_ERRORTYPE iomx_allocate_buffer(OMX_HANDLETYPE component, OMX_BUFFERHEADERTYPE **bufferptr, OMX_U32 port_index, OMX_PTR app_private, OMX_U32 size)
169 {
170     OMXNode* node = (OMXNode*) ((OMX_COMPONENTTYPE*)component)->pComponentPrivate;
171     OMXBuffer* info = new OMXBuffer;
172 #ifdef HAS_USE_BUFFER
173     info->graphicBuffer = NULL;
174 #endif
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);
178     if (ret != OK)
179         return OMX_ErrorUndefined;
180     OMX_BUFFERHEADERTYPE *buffer = (OMX_BUFFERHEADERTYPE*) calloc(1, sizeof(OMX_BUFFERHEADERTYPE));
181     *bufferptr = buffer;
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;
188 }
189
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)
192 {
193     OMXNode* node = (OMXNode*) ((OMX_COMPONENTTYPE*)component)->pComponentPrivate;
194     OMXBuffer* info = new OMXBuffer;
195     info->dealer = NULL;
196 #if ANDROID_API <= 13
197     info->graphicBuffer = new GraphicBuffer((android_native_buffer_t*) data, false);
198 #else
199     info->graphicBuffer = new GraphicBuffer((ANativeWindowBuffer*) data, false);
200 #endif
201     int ret = ctx->iomx->useGraphicBuffer(node->node, port_index, info->graphicBuffer, &info->id);
202     if (ret != OK)
203         return OMX_ErrorUndefined;
204     OMX_BUFFERHEADERTYPE *buffer = (OMX_BUFFERHEADERTYPE*) calloc(1, sizeof(OMX_BUFFERHEADERTYPE));
205     *bufferptr = buffer;
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;
212 }
213 #endif
214
215 static OMX_ERRORTYPE iomx_free_buffer(OMX_HANDLETYPE component, OMX_U32 port, OMX_BUFFERHEADERTYPE *buffer)
216 {
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++ ) {
221         if (buffer == *it) {
222             node->buffers.erase(it);
223             break;
224         }
225     }
226     free(buffer);
227     delete info;
228     return get_error(ret);
229 }
230
231 static OMX_ERRORTYPE iomx_empty_this_buffer(OMX_HANDLETYPE component, OMX_BUFFERHEADERTYPE *buffer)
232 {
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));
236 }
237
238 static OMX_ERRORTYPE iomx_fill_this_buffer(OMX_HANDLETYPE component, OMX_BUFFERHEADERTYPE *buffer)
239 {
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));
243 }
244
245 static OMX_ERRORTYPE iomx_component_role_enum(OMX_HANDLETYPE component, OMX_U8 *role, OMX_U32 index)
246 {
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;
258         }
259     }
260     return OMX_ErrorInvalidComponentName;
261 }
262
263 static OMX_ERRORTYPE iomx_get_extension_index(OMX_HANDLETYPE component, OMX_STRING parameter, OMX_INDEXTYPE *index)
264 {
265     OMXNode* node = (OMXNode*) ((OMX_COMPONENTTYPE*)component)->pComponentPrivate;
266     return get_error(ctx->iomx->getExtensionIndex(node->node, parameter, index));
267 }
268
269 static OMX_ERRORTYPE iomx_set_config(OMX_HANDLETYPE component, OMX_INDEXTYPE index, OMX_PTR param)
270 {
271     OMXNode* node = (OMXNode*) ((OMX_COMPONENTTYPE*)component)->pComponentPrivate;
272     return get_error(ctx->iomx->setConfig(node->node, index, param, *(OMX_U32*)param));
273 }
274
275 static OMX_ERRORTYPE iomx_get_config(OMX_HANDLETYPE component, OMX_INDEXTYPE index, OMX_PTR param)
276 {
277     OMXNode* node = (OMXNode*) ((OMX_COMPONENTTYPE*)component)->pComponentPrivate;
278     return get_error(ctx->iomx->getConfig(node->node, index, param, *(OMX_U32*)param));
279 }
280
281 extern "C" {
282 OMX_ERRORTYPE PREFIX(OMX_GetHandle)(OMX_HANDLETYPE *handle_ptr, OMX_STRING component_name, OMX_PTR app_data, OMX_CALLBACKTYPE *callbacks)
283 {
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;
291
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;
310 #else
311     component->UseBuffer = NULL;
312 #endif
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;
317
318     *handle_ptr = component;
319     node->handle = component;
320     status_t ret;
321     if ((ret = ctx->iomx->allocateNode( component_name, node->observer, &node->node )) != OK)
322         return OMX_ErrorUndefined;
323     return OMX_ErrorNone;
324 }
325
326 OMX_ERRORTYPE PREFIX(OMX_FreeHandle)(OMX_HANDLETYPE handle)
327 {
328     OMXNode* node = (OMXNode*) ((OMX_COMPONENTTYPE*)handle)->pComponentPrivate;
329     ctx->iomx->freeNode( node->node );
330     node->observer->setNode(NULL);
331     delete node;
332     free(handle);
333     return OMX_ErrorNone;
334 }
335
336 OMX_ERRORTYPE PREFIX(OMX_Init)(void)
337 {
338     OMXClient client;
339     if (client.connect() != OK)
340         return OMX_ErrorUndefined;
341
342     if (!ctx)
343         ctx = new IOMXContext();
344     ctx->iomx = client.interface();
345     ctx->iomx->listNodes(&ctx->components);
346     return OMX_ErrorNone;
347 }
348
349 OMX_ERRORTYPE PREFIX(OMX_Deinit)(void)
350 {
351     ctx->iomx = NULL;
352     delete ctx;
353     ctx = NULL;
354     return OMX_ErrorNone;
355 }
356
357 OMX_ERRORTYPE PREFIX(OMX_ComponentNameEnum)(OMX_STRING component_name, OMX_U32 name_length, OMX_U32 index)
358 {
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++ )
363         it++;
364     strncpy(component_name, it->mName.string(), name_length);
365     component_name[name_length - 1] = '\0';
366     return OMX_ErrorNone;
367 }
368
369 OMX_ERRORTYPE PREFIX(OMX_GetRolesOfComponent)(OMX_STRING component_name, OMX_U32 *num_roles, OMX_U8 **roles)
370 {
371     for( List<IOMX::ComponentInfo>::iterator it = ctx->components.begin(); it != ctx->components.end(); it++ ) {
372         if (!strcmp(component_name, it->mName.string())) {
373             if (!roles) {
374                 *num_roles = it->mRoles.size();
375                 return OMX_ErrorNone;
376             }
377             if (*num_roles < it->mRoles.size())
378                 return OMX_ErrorInsufficientResources;
379             *num_roles = it->mRoles.size();
380             OMX_U32 i = 0;
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';
384             }
385             return OMX_ErrorNone;
386         }
387     }
388     return OMX_ErrorInvalidComponentName;
389 }
390
391 OMX_ERRORTYPE PREFIX(OMX_GetComponentsOfRole)(OMX_STRING role, OMX_U32 *num_comps, OMX_U8 **comp_names)
392 {
393     OMX_U32 i = 0;
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)) {
397                 if (comp_names) {
398                     if (*num_comps < i)
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';
402                 }
403                 i++;
404                 break;
405             }
406         }
407     }
408     *num_comps = i;
409     return OMX_ErrorNone;
410 }
411
412 #ifdef HAS_USE_BUFFER
413 OMX_ERRORTYPE PREFIX(OMXAndroid_EnableGraphicBuffers)(OMX_HANDLETYPE component, OMX_U32 port_index, OMX_BOOL enable)
414 {
415     OMXNode* node = (OMXNode*) ((OMX_COMPONENTTYPE*)component)->pComponentPrivate;
416     int ret = ctx->iomx->enableGraphicBuffers(node->node, port_index, enable);
417     if (ret != OK)
418         return OMX_ErrorUndefined;
419     return OMX_ErrorNone;
420 }
421
422 OMX_ERRORTYPE PREFIX(OMXAndroid_GetGraphicBufferUsage)(OMX_HANDLETYPE component, OMX_U32 port_index, OMX_U32* usage)
423 {
424     OMXNode* node = (OMXNode*) ((OMX_COMPONENTTYPE*)component)->pComponentPrivate;
425     int ret = ctx->iomx->getGraphicBufferUsage(node->node, port_index, usage);
426     if (ret != OK)
427         return OMX_ErrorUndefined;
428     return OMX_ErrorNone;
429 }
430
431 OMX_ERRORTYPE PREFIX(OMXAndroid_GetHalFormat)( const char *comp_name, int* hal_format )
432 {
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
437             break;
438         case OMX_COLOR_FormatYUV420Planar:
439             *hal_format = 0x101; // HAL_PIXEL_FORMAT_YCbCr_420_P
440             break;
441         }
442     }
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" ))
448         *hal_format = 0x108;
449 #endif
450
451     return OMX_ErrorNone;
452 }
453
454 #endif
455 }
456