input: add an input_item_t arg to input_CreateFilename()
[vlc.git] / modules / codec / omxil / mediacodec_ndk.c
blobc8a8680772aaa04151cad2f2b4859714f44aa19e
1 /*****************************************************************************
2 * mediacodec_ndk.c: mc_api implementation using NDK
3 *****************************************************************************
4 * Copyright © 2015 VLC authors and VideoLAN, VideoLabs
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2.1 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19 *****************************************************************************/
21 /*****************************************************************************
22 * Preamble
23 *****************************************************************************/
24 #ifdef HAVE_CONFIG_H
25 # include "config.h"
26 #endif
28 #include <jni.h>
29 #include <dlfcn.h>
30 #include <stdint.h>
31 #include <assert.h>
33 #include <vlc_common.h>
35 #include <OMX_Core.h>
36 #include <OMX_Component.h>
37 #include "omxil_utils.h"
39 #include "mediacodec.h"
41 char* MediaCodec_GetName(vlc_object_t *p_obj, const char *psz_mime,
42 int hxxx_profile, bool *p_adaptive);
44 #define THREAD_NAME "mediacodec_ndk"
46 /* Not in NdkMedia API but we need it since we send config data via input
47 * buffers and not via "csd-*" buffers from AMediaFormat */
48 #define AMEDIACODEC_FLAG_CODEC_CONFIG 2
50 /*****************************************************************************
51 * NdkMediaError.h
52 *****************************************************************************/
54 typedef enum {
55 AMEDIA_OK = 0,
57 AMEDIA_ERROR_BASE = -10000,
58 AMEDIA_ERROR_UNKNOWN = AMEDIA_ERROR_BASE,
59 AMEDIA_ERROR_MALFORMED = AMEDIA_ERROR_BASE - 1,
60 AMEDIA_ERROR_UNSUPPORTED = AMEDIA_ERROR_BASE - 2,
61 AMEDIA_ERROR_INVALID_OBJECT = AMEDIA_ERROR_BASE - 3,
62 AMEDIA_ERROR_INVALID_PARAMETER = AMEDIA_ERROR_BASE - 4,
64 AMEDIA_DRM_ERROR_BASE = -20000,
65 AMEDIA_DRM_NOT_PROVISIONED = AMEDIA_DRM_ERROR_BASE - 1,
66 AMEDIA_DRM_RESOURCE_BUSY = AMEDIA_DRM_ERROR_BASE - 2,
67 AMEDIA_DRM_DEVICE_REVOKED = AMEDIA_DRM_ERROR_BASE - 3,
68 AMEDIA_DRM_SHORT_BUFFER = AMEDIA_DRM_ERROR_BASE - 4,
69 AMEDIA_DRM_SESSION_NOT_OPENED = AMEDIA_DRM_ERROR_BASE - 5,
70 AMEDIA_DRM_TAMPER_DETECTED = AMEDIA_DRM_ERROR_BASE - 6,
71 AMEDIA_DRM_VERIFY_FAILED = AMEDIA_DRM_ERROR_BASE - 7,
72 AMEDIA_DRM_NEED_KEY = AMEDIA_DRM_ERROR_BASE - 8,
73 AMEDIA_DRM_LICENSE_EXPIRED = AMEDIA_DRM_ERROR_BASE - 9,
75 } media_status_t;
77 /*****************************************************************************
78 * NdkMediaCodec.h
79 *****************************************************************************/
81 struct AMediaCodec;
82 typedef struct AMediaCodec AMediaCodec;
84 struct AMediaCodecBufferInfo {
85 int32_t offset;
86 int32_t size;
87 int64_t presentationTimeUs;
88 uint32_t flags;
90 typedef struct AMediaCodecBufferInfo AMediaCodecBufferInfo;
92 enum {
93 AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM = 4,
94 AMEDIACODEC_CONFIGURE_FLAG_ENCODE = 1,
95 AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED = -3,
96 AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED = -2,
97 AMEDIACODEC_INFO_TRY_AGAIN_LATER = -1
100 struct AMediaFormat;
101 typedef struct AMediaFormat AMediaFormat;
103 struct AMediaCrypto;
104 typedef struct AMediaCrypto AMediaCrypto;
106 /*****************************************************************************
107 * Ndk symbols
108 *****************************************************************************/
110 typedef AMediaCodec* (*pf_AMediaCodec_createCodecByName)(const char *name);
112 typedef media_status_t (*pf_AMediaCodec_configure)(AMediaCodec*,
113 const AMediaFormat* format,
114 ANativeWindow* surface,
115 AMediaCrypto *crypto,
116 uint32_t flags);
118 typedef media_status_t (*pf_AMediaCodec_start)(AMediaCodec*);
120 typedef media_status_t (*pf_AMediaCodec_stop)(AMediaCodec*);
122 typedef media_status_t (*pf_AMediaCodec_flush)(AMediaCodec*);
124 typedef media_status_t (*pf_AMediaCodec_delete)(AMediaCodec*);
126 typedef AMediaFormat* (*pf_AMediaCodec_getOutputFormat)(AMediaCodec*);
128 typedef ssize_t (*pf_AMediaCodec_dequeueInputBuffer)(AMediaCodec*,
129 int64_t timeoutUs);
131 typedef uint8_t* (*pf_AMediaCodec_getInputBuffer)(AMediaCodec*,
132 size_t idx, size_t *out_size);
134 typedef media_status_t (*pf_AMediaCodec_queueInputBuffer)(AMediaCodec*,
135 size_t idx, off_t offset, size_t size, uint64_t time, uint32_t flags);
137 typedef ssize_t (*pf_AMediaCodec_dequeueOutputBuffer)(AMediaCodec*,
138 AMediaCodecBufferInfo *info, int64_t timeoutUs);
140 typedef uint8_t* (*pf_AMediaCodec_getOutputBuffer)(AMediaCodec*,
141 size_t idx, size_t *out_size);
143 typedef media_status_t (*pf_AMediaCodec_releaseOutputBuffer)(AMediaCodec*,
144 size_t idx, bool render);
146 typedef media_status_t (*pf_AMediaCodec_releaseOutputBufferAtTime)(AMediaCodec*,
147 size_t idx, int64_t timestampNs);
149 typedef media_status_t (*pf_AMediaCodec_setOutputSurface)(AMediaCodec*,
150 ANativeWindow *surface);
152 typedef AMediaFormat *(*pf_AMediaFormat_new)();
153 typedef media_status_t (*pf_AMediaFormat_delete)(AMediaFormat*);
155 typedef void (*pf_AMediaFormat_setString)(AMediaFormat*,
156 const char* name, const char* value);
158 typedef void (*pf_AMediaFormat_setInt32)(AMediaFormat*,
159 const char* name, int32_t value);
161 typedef bool (*pf_AMediaFormat_getInt32)(AMediaFormat*,
162 const char *name, int32_t *out);
164 struct syms
166 struct {
167 pf_AMediaCodec_createCodecByName createCodecByName;
168 pf_AMediaCodec_configure configure;
169 pf_AMediaCodec_start start;
170 pf_AMediaCodec_stop stop;
171 pf_AMediaCodec_flush flush;
172 pf_AMediaCodec_delete delete;
173 pf_AMediaCodec_getOutputFormat getOutputFormat;
174 pf_AMediaCodec_dequeueInputBuffer dequeueInputBuffer;
175 pf_AMediaCodec_getInputBuffer getInputBuffer;
176 pf_AMediaCodec_queueInputBuffer queueInputBuffer;
177 pf_AMediaCodec_dequeueOutputBuffer dequeueOutputBuffer;
178 pf_AMediaCodec_getOutputBuffer getOutputBuffer;
179 pf_AMediaCodec_releaseOutputBuffer releaseOutputBuffer;
180 pf_AMediaCodec_releaseOutputBufferAtTime releaseOutputBufferAtTime;
181 pf_AMediaCodec_setOutputSurface setOutputSurface;
182 } AMediaCodec;
183 struct {
184 pf_AMediaFormat_new new;
185 pf_AMediaFormat_delete delete;
186 pf_AMediaFormat_setString setString;
187 pf_AMediaFormat_setInt32 setInt32;
188 pf_AMediaFormat_getInt32 getInt32;
189 } AMediaFormat;
191 static struct syms syms;
193 struct members
195 const char *name;
196 int offset;
197 bool critical;
199 static struct members members[] =
201 #define OFF(x) offsetof(struct syms, AMediaCodec.x)
202 { "AMediaCodec_createCodecByName", OFF(createCodecByName), true },
203 { "AMediaCodec_configure", OFF(configure), true },
204 { "AMediaCodec_start", OFF(start), true },
205 { "AMediaCodec_stop", OFF(stop), true },
206 { "AMediaCodec_flush", OFF(flush), true },
207 { "AMediaCodec_delete", OFF(delete), true },
208 { "AMediaCodec_getOutputFormat", OFF(getOutputFormat), true },
209 { "AMediaCodec_dequeueInputBuffer", OFF(dequeueInputBuffer), true },
210 { "AMediaCodec_getInputBuffer", OFF(getInputBuffer), true },
211 { "AMediaCodec_queueInputBuffer", OFF(queueInputBuffer), true },
212 { "AMediaCodec_dequeueOutputBuffer", OFF(dequeueOutputBuffer), true },
213 { "AMediaCodec_getOutputBuffer", OFF(getOutputBuffer), true },
214 { "AMediaCodec_releaseOutputBuffer", OFF(releaseOutputBuffer), true },
215 { "AMediaCodec_releaseOutputBufferAtTime", OFF(releaseOutputBufferAtTime), true },
216 { "AMediaCodec_setOutputSurface", OFF(setOutputSurface), false },
217 #undef OFF
218 #define OFF(x) offsetof(struct syms, AMediaFormat.x)
219 { "AMediaFormat_new", OFF(new), true },
220 { "AMediaFormat_delete", OFF(delete), true },
221 { "AMediaFormat_setString", OFF(setString), true },
222 { "AMediaFormat_setInt32", OFF(setInt32), true },
223 { "AMediaFormat_getInt32", OFF(getInt32), true },
224 #undef OFF
225 { NULL, 0, false }
227 #undef OFF
229 /* Initialize all symbols.
230 * Done only one time during the first initialisation */
231 static bool
232 InitSymbols(mc_api *api)
234 static vlc_mutex_t lock = VLC_STATIC_MUTEX;
235 static int i_init_state = -1;
236 bool ret;
238 vlc_mutex_lock(&lock);
240 if (i_init_state != -1)
241 goto end;
243 i_init_state = 0;
245 void *ndk_handle = dlopen("libmediandk.so", RTLD_NOW);
246 if (!ndk_handle)
247 goto end;
249 for (int i = 0; members[i].name; i++)
251 void *sym = dlsym(ndk_handle, members[i].name);
252 if (!sym && members[i].critical)
254 dlclose(ndk_handle);
255 goto end;
257 *(void **)((uint8_t*)&syms + members[i].offset) = sym;
260 i_init_state = 1;
261 end:
262 ret = i_init_state == 1;
263 if (!ret)
264 msg_Err(api->p_obj, "MediaCodec NDK init failed");
266 vlc_mutex_unlock(&lock);
267 return ret;
270 /****************************************************************************
271 * Local prototypes
272 ****************************************************************************/
274 struct mc_api_sys
276 AMediaCodec* p_codec;
277 AMediaFormat* p_format;
278 AMediaCodecBufferInfo info;
281 /*****************************************************************************
282 * ConfigureDecoder
283 *****************************************************************************/
284 static int ConfigureDecoder(mc_api *api, union mc_api_args *p_args)
286 mc_api_sys *p_sys = api->p_sys;
287 ANativeWindow *p_anw = NULL;
289 assert(api->psz_mime && api->psz_name);
291 p_sys->p_codec = syms.AMediaCodec.createCodecByName(api->psz_name);
292 if (!p_sys->p_codec)
294 msg_Err(api->p_obj, "AMediaCodec.createCodecByName for %s failed",
295 api->psz_name);
296 return MC_API_ERROR;
299 p_sys->p_format = syms.AMediaFormat.new();
300 if (!p_sys->p_format)
302 msg_Err(api->p_obj, "AMediaFormat.new failed");
303 return MC_API_ERROR;
306 syms.AMediaFormat.setInt32(p_sys->p_format, "encoder", 0);
307 syms.AMediaFormat.setString(p_sys->p_format, "mime", api->psz_mime);
308 /* No limits for input size */
309 syms.AMediaFormat.setInt32(p_sys->p_format, "max-input-size", 0);
310 if (api->i_cat == VIDEO_ES)
312 syms.AMediaFormat.setInt32(p_sys->p_format, "width", p_args->video.i_width);
313 syms.AMediaFormat.setInt32(p_sys->p_format, "height", p_args->video.i_height);
314 syms.AMediaFormat.setInt32(p_sys->p_format, "rotation-degrees", p_args->video.i_angle);
315 if (p_args->video.p_surface)
317 p_anw = p_args->video.p_surface;
318 if (p_args->video.b_tunneled_playback)
319 syms.AMediaFormat.setInt32(p_sys->p_format,
320 "feature-tunneled-playback", 1);
321 if (p_args->video.b_adaptive_playback)
322 syms.AMediaFormat.setInt32(p_sys->p_format,
323 "feature-adaptive-playback", 1);
326 else
328 syms.AMediaFormat.setInt32(p_sys->p_format, "sample-rate", p_args->audio.i_sample_rate);
329 syms.AMediaFormat.setInt32(p_sys->p_format, "channel-count", p_args->audio.i_channel_count);
332 if (syms.AMediaCodec.configure(p_sys->p_codec, p_sys->p_format,
333 p_anw, NULL, 0) != AMEDIA_OK)
335 msg_Err(api->p_obj, "AMediaCodec.configure failed");
336 return MC_API_ERROR;
339 api->b_direct_rendering = !!p_anw;
341 return 0;
344 /*****************************************************************************
345 * Stop
346 *****************************************************************************/
347 static int Stop(mc_api *api)
349 mc_api_sys *p_sys = api->p_sys;
351 api->b_direct_rendering = false;
353 if (p_sys->p_codec)
355 if (api->b_started)
357 syms.AMediaCodec.stop(p_sys->p_codec);
358 api->b_started = false;
360 syms.AMediaCodec.delete(p_sys->p_codec);
361 p_sys->p_codec = NULL;
363 if (p_sys->p_format)
365 syms.AMediaFormat.delete(p_sys->p_format);
366 p_sys->p_format = NULL;
369 msg_Dbg(api->p_obj, "MediaCodec via NDK closed");
370 return 0;
373 /*****************************************************************************
374 * Start
375 *****************************************************************************/
376 static int Start(mc_api *api)
378 mc_api_sys *p_sys = api->p_sys;
379 int i_ret = MC_API_ERROR;
381 if (syms.AMediaCodec.start(p_sys->p_codec) != AMEDIA_OK)
383 msg_Err(api->p_obj, "AMediaCodec.start failed");
384 goto error;
387 api->b_started = true;
388 i_ret = 0;
390 msg_Dbg(api->p_obj, "MediaCodec via NDK opened");
391 error:
392 if (i_ret != 0)
393 Stop(api);
394 return i_ret;
397 /*****************************************************************************
398 * Flush
399 *****************************************************************************/
400 static int Flush(mc_api *api)
402 mc_api_sys *p_sys = api->p_sys;
404 if (syms.AMediaCodec.flush(p_sys->p_codec) == AMEDIA_OK)
405 return 0;
406 else
407 return MC_API_ERROR;
410 /*****************************************************************************
411 * DequeueInput
412 *****************************************************************************/
413 static int DequeueInput(mc_api *api, vlc_tick_t i_timeout)
415 mc_api_sys *p_sys = api->p_sys;
416 ssize_t i_index;
418 i_index = syms.AMediaCodec.dequeueInputBuffer(p_sys->p_codec, i_timeout);
419 if (i_index >= 0)
420 return i_index;
421 else if (i_index == AMEDIACODEC_INFO_TRY_AGAIN_LATER)
422 return MC_API_INFO_TRYAGAIN;
423 else
425 msg_Err(api->p_obj, "AMediaCodec.dequeueInputBuffer failed");
426 return MC_API_ERROR;
430 /*****************************************************************************
431 * QueueInput
432 *****************************************************************************/
433 static int QueueInput(mc_api *api, int i_index, const void *p_buf,
434 size_t i_size, vlc_tick_t i_ts, bool b_config)
436 mc_api_sys *p_sys = api->p_sys;
437 uint8_t *p_mc_buf;
438 size_t i_mc_size;
439 int i_flags = (b_config ? AMEDIACODEC_FLAG_CODEC_CONFIG : 0)
440 | (p_buf == NULL ? AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM : 0);
442 assert(i_index >= 0);
444 p_mc_buf = syms.AMediaCodec.getInputBuffer(p_sys->p_codec,
445 i_index, &i_mc_size);
446 if (!p_mc_buf)
447 return MC_API_ERROR;
449 if (i_mc_size > i_size)
450 i_mc_size = i_size;
451 memcpy(p_mc_buf, p_buf, i_mc_size);
453 if (syms.AMediaCodec.queueInputBuffer(p_sys->p_codec, i_index, 0, i_mc_size,
454 i_ts, i_flags) == AMEDIA_OK)
455 return 0;
456 else
458 msg_Err(api->p_obj, "AMediaCodec.queueInputBuffer failed");
459 return MC_API_ERROR;
463 static int32_t GetFormatInteger(AMediaFormat *p_format, const char *psz_name)
465 int32_t i_out = 0;
466 syms.AMediaFormat.getInt32(p_format, psz_name, &i_out);
467 return i_out;
470 /*****************************************************************************
471 * DequeueOutput
472 *****************************************************************************/
473 static int DequeueOutput(mc_api *api, vlc_tick_t i_timeout)
475 mc_api_sys *p_sys = api->p_sys;
476 ssize_t i_index;
478 i_index = syms.AMediaCodec.dequeueOutputBuffer(p_sys->p_codec, &p_sys->info,
479 i_timeout);
481 if (i_index >= 0)
482 return i_index;
483 else if (i_index == AMEDIACODEC_INFO_TRY_AGAIN_LATER)
484 return MC_API_INFO_TRYAGAIN;
485 else if (i_index == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED)
486 return MC_API_INFO_OUTPUT_BUFFERS_CHANGED;
487 else if (i_index == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED)
488 return MC_API_INFO_OUTPUT_FORMAT_CHANGED;
489 else
491 msg_Warn(api->p_obj, "AMediaCodec.dequeueOutputBuffer failed");
492 return MC_API_ERROR;
496 /*****************************************************************************
497 * GetOutput
498 *****************************************************************************/
499 static int GetOutput(mc_api *api, int i_index, mc_api_out *p_out)
501 mc_api_sys *p_sys = api->p_sys;
503 if (i_index >= 0)
505 p_out->type = MC_OUT_TYPE_BUF;
506 p_out->buf.i_index = i_index;
508 p_out->buf.i_ts = p_sys->info.presentationTimeUs;
509 p_out->b_eos = p_sys->info.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM;
511 if (api->b_direct_rendering)
513 p_out->buf.p_ptr = NULL;
514 p_out->buf.i_size = 0;
516 else
518 size_t i_mc_size;
519 uint8_t *p_mc_buf = syms.AMediaCodec.getOutputBuffer(p_sys->p_codec,
520 i_index,
521 &i_mc_size);
522 /* p_mc_buf can be NULL in case of EOS */
523 if (!p_mc_buf && !p_out->b_eos)
525 msg_Err(api->p_obj, "AMediaCodec.getOutputBuffer failed");
526 return MC_API_ERROR;
528 p_out->buf.p_ptr = p_mc_buf + p_sys->info.offset;
529 p_out->buf.i_size = p_sys->info.size;
531 return 1;
533 else if (i_index == MC_API_INFO_OUTPUT_FORMAT_CHANGED)
535 AMediaFormat *format = syms.AMediaCodec.getOutputFormat(p_sys->p_codec);
537 p_out->type = MC_OUT_TYPE_CONF;
538 p_out->b_eos = false;
539 if (api->i_cat == VIDEO_ES)
541 p_out->conf.video.width = GetFormatInteger(format, "width");
542 p_out->conf.video.height = GetFormatInteger(format, "height");
543 p_out->conf.video.stride = GetFormatInteger(format, "stride");
544 p_out->conf.video.slice_height = GetFormatInteger(format, "slice-height");
545 p_out->conf.video.pixel_format = GetFormatInteger(format, "color-format");
546 p_out->conf.video.crop_left = GetFormatInteger(format, "crop-left");
547 p_out->conf.video.crop_top = GetFormatInteger(format, "crop-top");
548 p_out->conf.video.crop_right = GetFormatInteger(format, "crop-right");
549 p_out->conf.video.crop_bottom = GetFormatInteger(format, "crop-bottom");
551 else
553 p_out->conf.audio.channel_count = GetFormatInteger(format, "channel-count");
554 p_out->conf.audio.channel_mask = GetFormatInteger(format, "channel-mask");
555 p_out->conf.audio.sample_rate = GetFormatInteger(format, "sample-rate");
557 return 1;
559 return 0;
562 /*****************************************************************************
563 * ReleaseOutput
564 *****************************************************************************/
565 static int ReleaseOutput(mc_api *api, int i_index, bool b_render)
567 mc_api_sys *p_sys = api->p_sys;
569 assert(i_index >= 0);
570 if (syms.AMediaCodec.releaseOutputBuffer(p_sys->p_codec, i_index, b_render)
571 == AMEDIA_OK)
572 return 0;
573 else
574 return MC_API_ERROR;
577 /*****************************************************************************
578 * ReleaseOutputAtTime
579 *****************************************************************************/
580 static int ReleaseOutputAtTime(mc_api *api, int i_index, int64_t i_ts_ns)
582 mc_api_sys *p_sys = api->p_sys;
584 assert(i_index >= 0);
585 if (syms.AMediaCodec.releaseOutputBufferAtTime(p_sys->p_codec, i_index, i_ts_ns)
586 == AMEDIA_OK)
587 return 0;
588 else
589 return MC_API_ERROR;
592 /*****************************************************************************
593 * SetOutputSurface
594 *****************************************************************************/
595 static int SetOutputSurface(mc_api *api, void *p_surface, void *p_jsurface)
597 (void) p_jsurface;
598 assert(p_surface != NULL);
599 mc_api_sys *p_sys = api->p_sys;
601 return syms.AMediaCodec.setOutputSurface != NULL
602 && syms.AMediaCodec.setOutputSurface(p_sys->p_codec, p_surface)
603 == AMEDIA_OK ? 0 : MC_API_ERROR;
606 /*****************************************************************************
607 * Clean
608 *****************************************************************************/
609 static void Clean(mc_api *api)
611 free(api->psz_name);
612 free(api->p_sys);
615 /*****************************************************************************
616 * Prepare
617 *****************************************************************************/
618 static int Prepare(mc_api * api, int i_profile)
620 free(api->psz_name);
621 bool b_adaptive;
622 api->psz_name = MediaCodec_GetName(api->p_obj, api->psz_mime,
623 i_profile, &b_adaptive);
624 if (!api->psz_name)
625 return MC_API_ERROR;
626 api->i_quirks = OMXCodec_GetQuirks(api->i_cat, api->i_codec, api->psz_name,
627 strlen(api->psz_name));
628 /* Allow interlaced picture after API 21 */
629 api->i_quirks |= MC_API_VIDEO_QUIRKS_SUPPORT_INTERLACED;
630 if (b_adaptive)
631 api->i_quirks |= MC_API_VIDEO_QUIRKS_ADAPTIVE;
632 return 0;
635 /*****************************************************************************
636 * MediaCodecNdk_Init
637 *****************************************************************************/
638 int MediaCodecNdk_Init(mc_api *api)
640 if (!InitSymbols(api))
641 return MC_API_ERROR;
643 api->p_sys = calloc(1, sizeof(mc_api_sys));
644 if (!api->p_sys)
645 return MC_API_ERROR;
647 api->clean = Clean;
648 api->prepare = Prepare;
649 api->configure_decoder = ConfigureDecoder;
650 api->start = Start;
651 api->stop = Stop;
652 api->flush = Flush;
653 api->dequeue_in = DequeueInput;
654 api->queue_in = QueueInput;
655 api->dequeue_out = DequeueOutput;
656 api->get_out = GetOutput;
657 api->release_out = ReleaseOutput;
658 api->release_out_ts = ReleaseOutputAtTime;
659 api->set_output_surface = SetOutputSurface;
661 api->b_support_rotation = true;
662 return 0;