2 * Copyright (c) 2010 The WebM project authors. All Rights Reserved.
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
14 #include "vpx/vpx_decoder.h"
15 #include "vpx/vp8dx.h"
16 #include "vpx/internal/vpx_codec_internal.h"
17 #include "./vpx_version.h"
18 #include "vp9/decoder/vp9_onyxd.h"
19 #include "vp9/decoder/vp9_onyxd_int.h"
20 #include "vp9/decoder/vp9_read_bit_buffer.h"
21 #include "vp9/vp9_iface_common.h"
23 #define VP9_CAP_POSTPROC (CONFIG_VP9_POSTPROC ? VPX_CODEC_CAP_POSTPROC : 0)
24 typedef vpx_codec_stream_info_t vp9_stream_info_t;
26 /* Structures for handling memory allocations */
28 VP9_SEG_ALG_PRIV = 256,
31 #define NELEMENTS(x) ((int)(sizeof(x)/sizeof(x[0])))
33 static unsigned long priv_sz(const vpx_codec_dec_cfg_t *si,
34 vpx_codec_flags_t flags);
36 static const mem_req_t vp9_mem_req_segs[] = {
37 {VP9_SEG_ALG_PRIV, 0, 8, VPX_CODEC_MEM_ZERO, priv_sz},
38 {VP9_SEG_MAX, 0, 0, 0, NULL}
41 struct vpx_codec_alg_priv {
42 vpx_codec_priv_t base;
43 vpx_codec_mmap_t mmaps[NELEMENTS(vp9_mem_req_segs) - 1];
44 vpx_codec_dec_cfg_t cfg;
50 vp8_postproc_cfg_t postproc_cfg;
51 #if CONFIG_POSTPROC_VISUALIZER
52 unsigned int dbg_postproc_flag;
53 int dbg_color_ref_frame_flag;
54 int dbg_color_mb_modes_flag;
55 int dbg_color_b_modes_flag;
56 int dbg_display_mv_flag;
61 int invert_tile_order;
64 /* External buffer info to save for VP9 common. */
65 vpx_codec_frame_buffer_t *fb_list; // External frame buffers
66 int fb_count; // Total number of frame buffers
67 vpx_realloc_frame_buffer_cb_fn_t realloc_fb_cb;
68 void *user_priv; // Private data associated with the external frame buffers.
71 static unsigned long priv_sz(const vpx_codec_dec_cfg_t *si,
72 vpx_codec_flags_t flags) {
73 /* Although this declaration is constant, we can't use it in the requested
74 * segments list because we want to define the requested segments list
75 * before defining the private type (so that the number of memory maps is
79 return sizeof(vpx_codec_alg_priv_t);
82 static void vp9_init_ctx(vpx_codec_ctx_t *ctx, const vpx_codec_mmap_t *mmap) {
85 ctx->priv = mmap->base;
86 ctx->priv->sz = sizeof(*ctx->priv);
87 ctx->priv->iface = ctx->iface;
88 ctx->priv->alg_priv = mmap->base;
90 for (i = 0; i < NELEMENTS(ctx->priv->alg_priv->mmaps); i++)
91 ctx->priv->alg_priv->mmaps[i].id = vp9_mem_req_segs[i].id;
93 ctx->priv->alg_priv->mmaps[0] = *mmap;
94 ctx->priv->alg_priv->si.sz = sizeof(ctx->priv->alg_priv->si);
95 ctx->priv->init_flags = ctx->init_flags;
97 if (ctx->config.dec) {
98 /* Update the reference to the config structure to an internal copy. */
99 ctx->priv->alg_priv->cfg = *ctx->config.dec;
100 ctx->config.dec = &ctx->priv->alg_priv->cfg;
104 static void vp9_finalize_mmaps(vpx_codec_alg_priv_t *ctx) {
105 /* nothing to clean up */
108 static vpx_codec_err_t vp9_init(vpx_codec_ctx_t *ctx,
109 vpx_codec_priv_enc_mr_cfg_t *data) {
110 vpx_codec_err_t res = VPX_CODEC_OK;
112 /* This function only allocates space for the vpx_codec_alg_priv_t
113 * structure. More memory may be required at the time the stream
114 * information becomes known.
117 vpx_codec_mmap_t mmap;
119 mmap.id = vp9_mem_req_segs[0].id;
120 mmap.sz = sizeof(vpx_codec_alg_priv_t);
121 mmap.align = vp9_mem_req_segs[0].align;
122 mmap.flags = vp9_mem_req_segs[0].flags;
124 res = vpx_mmap_alloc(&mmap);
127 vp9_init_ctx(ctx, &mmap);
129 ctx->priv->alg_priv->defer_alloc = 1;
130 /*post processing level initialized to do nothing */
137 static vpx_codec_err_t vp9_destroy(vpx_codec_alg_priv_t *ctx) {
140 vp9_remove_decompressor(ctx->pbi);
142 for (i = NELEMENTS(ctx->mmaps) - 1; i >= 0; i--) {
143 if (ctx->mmaps[i].dtor)
144 ctx->mmaps[i].dtor(&ctx->mmaps[i]);
150 static vpx_codec_err_t vp9_peek_si(const uint8_t *data,
151 unsigned int data_sz,
152 vpx_codec_stream_info_t *si) {
153 if (data_sz <= 8) return VPX_CODEC_UNSUP_BITSTREAM;
154 if (data + data_sz <= data) return VPX_CODEC_INVALID_PARAM;
160 struct vp9_read_bit_buffer rb = { data, data + data_sz, 0, NULL, NULL };
161 const int frame_marker = vp9_rb_read_literal(&rb, 2);
162 const int version = vp9_rb_read_bit(&rb) | (vp9_rb_read_bit(&rb) << 1);
163 if (frame_marker != 0x2) return VPX_CODEC_UNSUP_BITSTREAM;
165 if (version > 1) return VPX_CODEC_UNSUP_BITSTREAM;
167 if (version != 0) return VPX_CODEC_UNSUP_BITSTREAM;
170 if (vp9_rb_read_bit(&rb)) { // show an existing frame
174 si->is_kf = !vp9_rb_read_bit(&rb);
179 rb.bit_offset += 1; // show frame
180 rb.bit_offset += 1; // error resilient
182 if (vp9_rb_read_literal(&rb, 8) != VP9_SYNC_CODE_0 ||
183 vp9_rb_read_literal(&rb, 8) != VP9_SYNC_CODE_1 ||
184 vp9_rb_read_literal(&rb, 8) != VP9_SYNC_CODE_2) {
185 return VPX_CODEC_UNSUP_BITSTREAM;
188 colorspace = vp9_rb_read_literal(&rb, 3);
189 if (colorspace != sRGB) {
190 rb.bit_offset += 1; // [16,235] (including xvycc) vs [0,255] range
192 rb.bit_offset += 2; // subsampling x/y
193 rb.bit_offset += 1; // has extra plane
197 rb.bit_offset += 1; // has extra plane
199 // RGB is only available in version 1
200 return VPX_CODEC_UNSUP_BITSTREAM;
204 // TODO(jzern): these are available on non-keyframes in intra only mode.
205 si->w = vp9_rb_read_literal(&rb, 16) + 1;
206 si->h = vp9_rb_read_literal(&rb, 16) + 1;
213 static vpx_codec_err_t vp9_get_si(vpx_codec_alg_priv_t *ctx,
214 vpx_codec_stream_info_t *si) {
217 if (si->sz >= sizeof(vp9_stream_info_t))
218 sz = sizeof(vp9_stream_info_t);
220 sz = sizeof(vpx_codec_stream_info_t);
222 memcpy(si, &ctx->si, sz);
229 static vpx_codec_err_t
230 update_error_state(vpx_codec_alg_priv_t *ctx,
231 const struct vpx_internal_error_info *error) {
234 if ((res = error->error_code))
235 ctx->base.err_detail = error->has_detail
242 static vpx_codec_err_t decode_one(vpx_codec_alg_priv_t *ctx,
243 const uint8_t **data,
244 unsigned int data_sz,
247 vpx_codec_err_t res = VPX_CODEC_OK;
251 /* Determine the stream parameters. Note that we rely on peek_si to
252 * validate that we have a buffer that does not wrap around the top
256 res = ctx->base.iface->dec.peek_si(*data, data_sz, &ctx->si);
259 /* Perform deferred allocations, if required */
260 if (!res && ctx->defer_alloc) {
263 for (i = 1; !res && i < NELEMENTS(ctx->mmaps); i++) {
264 vpx_codec_dec_cfg_t cfg;
268 ctx->mmaps[i].id = vp9_mem_req_segs[i].id;
269 ctx->mmaps[i].sz = vp9_mem_req_segs[i].sz;
270 ctx->mmaps[i].align = vp9_mem_req_segs[i].align;
271 ctx->mmaps[i].flags = vp9_mem_req_segs[i].flags;
273 if (!ctx->mmaps[i].sz)
274 ctx->mmaps[i].sz = vp9_mem_req_segs[i].calc_sz(&cfg,
275 ctx->base.init_flags);
277 res = vpx_mmap_alloc(&ctx->mmaps[i]);
281 vp9_finalize_mmaps(ctx);
283 ctx->defer_alloc = 0;
286 /* Initialize the decoder instance on the first frame*/
287 if (!res && !ctx->decoder_init) {
288 res = vpx_validate_mmaps(&ctx->si, ctx->mmaps,
289 vp9_mem_req_segs, NELEMENTS(vp9_mem_req_segs),
290 ctx->base.init_flags);
296 vp9_initialize_dec();
298 oxcf.width = ctx->si.w;
299 oxcf.height = ctx->si.h;
301 oxcf.postprocess = 0;
302 oxcf.max_threads = ctx->cfg.threads;
303 oxcf.inv_tile_order = ctx->invert_tile_order;
304 optr = vp9_create_decompressor(&oxcf);
306 /* If postprocessing was enabled by the application and a
307 * configuration has not been provided, default it.
309 if (!ctx->postproc_cfg_set
310 && (ctx->base.init_flags & VPX_CODEC_USE_POSTPROC)) {
311 ctx->postproc_cfg.post_proc_flag =
312 VP8_DEBLOCK | VP8_DEMACROBLOCK;
313 ctx->postproc_cfg.deblocking_level = 4;
314 ctx->postproc_cfg.noise_level = 0;
318 res = VPX_CODEC_ERROR;
320 VP9D_COMP *const pbi = (VP9D_COMP*)optr;
321 VP9_COMMON *const cm = &pbi->common;
322 if (ctx->fb_list != NULL && ctx->realloc_fb_cb != NULL &&
324 cm->fb_list = ctx->fb_list;
325 cm->fb_count = ctx->fb_count;
326 cm->realloc_fb_cb = ctx->realloc_fb_cb;
327 cm->user_priv = ctx->user_priv;
329 cm->fb_count = FRAME_BUFFERS;
331 cm->fb_lru = ctx->fb_lru;
332 CHECK_MEM_ERROR(cm, cm->yv12_fb,
333 vpx_calloc(cm->fb_count, sizeof(*cm->yv12_fb)));
334 CHECK_MEM_ERROR(cm, cm->fb_idx_ref_cnt,
335 vpx_calloc(cm->fb_count, sizeof(*cm->fb_idx_ref_cnt)));
337 CHECK_MEM_ERROR(cm, cm->fb_idx_ref_lru,
338 vpx_calloc(cm->fb_count,
339 sizeof(*cm->fb_idx_ref_lru)));
345 ctx->decoder_init = 1;
348 if (!res && ctx->pbi) {
349 YV12_BUFFER_CONFIG sd;
350 int64_t time_stamp = 0, time_end_stamp = 0;
351 vp9_ppflags_t flags = {0};
353 if (ctx->base.init_flags & VPX_CODEC_USE_POSTPROC) {
354 flags.post_proc_flag =
355 #if CONFIG_POSTPROC_VISUALIZER
356 ((ctx->dbg_color_ref_frame_flag != 0) ?
357 VP9D_DEBUG_CLR_FRM_REF_BLKS : 0)
358 | ((ctx->dbg_color_mb_modes_flag != 0) ?
359 VP9D_DEBUG_CLR_BLK_MODES : 0)
360 | ((ctx->dbg_color_b_modes_flag != 0) ?
361 VP9D_DEBUG_CLR_BLK_MODES : 0)
362 | ((ctx->dbg_display_mv_flag != 0) ?
363 VP9D_DEBUG_DRAW_MV : 0)
366 ctx->postproc_cfg.post_proc_flag;
368 flags.deblocking_level = ctx->postproc_cfg.deblocking_level;
369 flags.noise_level = ctx->postproc_cfg.noise_level;
370 #if CONFIG_POSTPROC_VISUALIZER
371 flags.display_ref_frame_flag = ctx->dbg_color_ref_frame_flag;
372 flags.display_mb_modes_flag = ctx->dbg_color_mb_modes_flag;
373 flags.display_b_modes_flag = ctx->dbg_color_b_modes_flag;
374 flags.display_mv_flag = ctx->dbg_display_mv_flag;
378 if (vp9_receive_compressed_data(ctx->pbi, data_sz, data, deadline)) {
379 VP9D_COMP *pbi = (VP9D_COMP*)ctx->pbi;
380 res = update_error_state(ctx, &pbi->common.error);
383 if (!res && 0 == vp9_get_raw_frame(ctx->pbi, &sd, &time_stamp,
384 &time_end_stamp, &flags)) {
385 yuvconfig2image(&ctx->img, &sd, user_priv);
393 static void parse_superframe_index(const uint8_t *data,
400 marker = data[data_sz - 1];
403 if ((marker & 0xe0) == 0xc0) {
404 const uint32_t frames = (marker & 0x7) + 1;
405 const uint32_t mag = ((marker >> 3) & 0x3) + 1;
406 const size_t index_sz = 2 + mag * frames;
408 if (data_sz >= index_sz && data[data_sz - index_sz] == marker) {
409 // found a valid superframe index
411 const uint8_t *x = data + data_sz - index_sz + 1;
413 for (i = 0; i < frames; i++) {
414 uint32_t this_sz = 0;
416 for (j = 0; j < mag; j++)
417 this_sz |= (*x++) << (j * 8);
426 static vpx_codec_err_t vp9_decode(vpx_codec_alg_priv_t *ctx,
428 unsigned int data_sz,
431 const uint8_t *data_start = data;
432 const uint8_t *data_end = data + data_sz;
433 vpx_codec_err_t res = 0;
435 int frames_this_pts, frame_count = 0;
437 if (data == NULL || data_sz == 0) return VPX_CODEC_INVALID_PARAM;
439 parse_superframe_index(data, data_sz, sizes, &frames_this_pts);
442 // Skip over the superframe index, if present
443 if (data_sz && (*data_start & 0xe0) == 0xc0) {
444 const uint8_t marker = *data_start;
445 const uint32_t frames = (marker & 0x7) + 1;
446 const uint32_t mag = ((marker >> 3) & 0x3) + 1;
447 const uint32_t index_sz = 2 + mag * frames;
449 if (data_sz >= index_sz && data_start[index_sz - 1] == marker) {
450 data_start += index_sz;
452 if (data_start < data_end)
459 // Use the correct size for this frame, if an index is present.
460 if (frames_this_pts) {
461 uint32_t this_sz = sizes[frame_count];
463 if (data_sz < this_sz) {
464 ctx->base.err_detail = "Invalid frame size in index";
465 return VPX_CODEC_CORRUPT_FRAME;
472 res = decode_one(ctx, &data_start, data_sz, user_priv, deadline);
473 assert(data_start >= data);
474 assert(data_start <= data_end);
476 /* Early exit if there was a decode error */
480 /* Account for suboptimal termination by the encoder. */
481 while (data_start < data_end && *data_start == 0)
484 data_sz = data_end - data_start;
485 } while (data_start < data_end);
489 static vpx_image_t *vp9_get_frame(vpx_codec_alg_priv_t *ctx,
490 vpx_codec_iter_t *iter) {
491 vpx_image_t *img = NULL;
493 if (ctx->img_avail) {
494 /* iter acts as a flip flop, so an image is only returned on the first
507 static vpx_codec_err_t vp9_set_frame_buffers(
508 vpx_codec_alg_priv_t *ctx,
509 vpx_codec_frame_buffer_t *fb_list, int fb_count,
510 vpx_realloc_frame_buffer_cb_fn_t cb, void *user_priv) {
511 if (fb_count < (VP9_MAXIMUM_REF_BUFFERS + VPX_MAXIMUM_WORK_BUFFERS)) {
512 /* The application must pass in at least VP9_MAXIMUM_REF_BUFFERS +
513 * VPX_MAXIMUM_WORK_BUFFERS frame buffers. */
514 return VPX_CODEC_INVALID_PARAM;
515 } else if (!ctx->pbi) {
516 /* If the decoder has already been initialized, do not accept external
519 ctx->fb_list = fb_list;
520 ctx->fb_count = fb_count;
521 ctx->realloc_fb_cb = cb;
522 ctx->user_priv = user_priv;
526 return VPX_CODEC_ERROR;
529 static vpx_codec_err_t vp9_xma_get_mmap(const vpx_codec_ctx_t *ctx,
530 vpx_codec_mmap_t *mmap,
531 vpx_codec_iter_t *iter) {
533 const mem_req_t *seg_iter = *iter;
535 /* Get address of next segment request */
538 seg_iter = vp9_mem_req_segs;
539 else if (seg_iter->id != VP9_SEG_MAX)
542 *iter = (vpx_codec_iter_t)seg_iter;
544 if (seg_iter->id != VP9_SEG_MAX) {
545 mmap->id = seg_iter->id;
546 mmap->sz = seg_iter->sz;
547 mmap->align = seg_iter->align;
548 mmap->flags = seg_iter->flags;
551 mmap->sz = seg_iter->calc_sz(ctx->config.dec, ctx->init_flags);
555 res = VPX_CODEC_LIST_END;
557 } while (!mmap->sz && res != VPX_CODEC_LIST_END);
562 static vpx_codec_err_t vp9_xma_set_mmap(vpx_codec_ctx_t *ctx,
563 const vpx_codec_mmap_t *mmap) {
564 vpx_codec_err_t res = VPX_CODEC_MEM_ERROR;
568 if (mmap->id == VP9_SEG_ALG_PRIV) {
570 vp9_init_ctx(ctx, mmap);
578 if (!res && ctx->priv->alg_priv) {
579 for (i = 0; i < NELEMENTS(ctx->priv->alg_priv->mmaps); i++) {
580 if (ctx->priv->alg_priv->mmaps[i].id == mmap->id)
581 if (!ctx->priv->alg_priv->mmaps[i].base) {
582 ctx->priv->alg_priv->mmaps[i] = *mmap;
586 done &= (ctx->priv->alg_priv->mmaps[i].base != NULL);
591 vp9_finalize_mmaps(ctx->priv->alg_priv);
592 res = ctx->iface->init(ctx, NULL);
598 static vpx_codec_err_t set_reference(vpx_codec_alg_priv_t *ctx,
601 vpx_ref_frame_t *data = va_arg(args, vpx_ref_frame_t *);
604 vpx_ref_frame_t *frame = (vpx_ref_frame_t *)data;
605 YV12_BUFFER_CONFIG sd;
607 image2yuvconfig(&frame->img, &sd);
609 return vp9_set_reference_dec(ctx->pbi,
610 (VP9_REFFRAME)frame->frame_type, &sd);
612 return VPX_CODEC_INVALID_PARAM;
616 static vpx_codec_err_t copy_reference(vpx_codec_alg_priv_t *ctx,
619 vpx_ref_frame_t *data = va_arg(args, vpx_ref_frame_t *);
622 vpx_ref_frame_t *frame = (vpx_ref_frame_t *)data;
623 YV12_BUFFER_CONFIG sd;
625 image2yuvconfig(&frame->img, &sd);
627 return vp9_copy_reference_dec(ctx->pbi,
628 (VP9_REFFRAME)frame->frame_type, &sd);
630 return VPX_CODEC_INVALID_PARAM;
634 static vpx_codec_err_t get_reference(vpx_codec_alg_priv_t *ctx,
637 vp9_ref_frame_t *data = va_arg(args, vp9_ref_frame_t *);
640 YV12_BUFFER_CONFIG* fb;
642 vp9_get_reference_dec(ctx->pbi, data->idx, &fb);
643 yuvconfig2image(&data->img, fb, NULL);
646 return VPX_CODEC_INVALID_PARAM;
650 static vpx_codec_err_t set_postproc(vpx_codec_alg_priv_t *ctx,
653 #if CONFIG_VP9_POSTPROC
654 vp8_postproc_cfg_t *data = va_arg(args, vp8_postproc_cfg_t *);
657 ctx->postproc_cfg_set = 1;
658 ctx->postproc_cfg = *((vp8_postproc_cfg_t *)data);
661 return VPX_CODEC_INVALID_PARAM;
664 return VPX_CODEC_INCAPABLE;
668 static vpx_codec_err_t set_dbg_options(vpx_codec_alg_priv_t *ctx,
671 #if CONFIG_POSTPROC_VISUALIZER && CONFIG_POSTPROC
672 int data = va_arg(args, int);
674 #define MAP(id, var) case id: var = data; break;
677 MAP(VP8_SET_DBG_COLOR_REF_FRAME, ctx->dbg_color_ref_frame_flag);
678 MAP(VP8_SET_DBG_COLOR_MB_MODES, ctx->dbg_color_mb_modes_flag);
679 MAP(VP8_SET_DBG_COLOR_B_MODES, ctx->dbg_color_b_modes_flag);
680 MAP(VP8_SET_DBG_DISPLAY_MV, ctx->dbg_display_mv_flag);
685 return VPX_CODEC_INCAPABLE;
689 static vpx_codec_err_t get_last_ref_updates(vpx_codec_alg_priv_t *ctx,
692 int *update_info = va_arg(args, int *);
693 VP9D_COMP *pbi = (VP9D_COMP*)ctx->pbi;
696 *update_info = pbi->refresh_frame_flags;
700 return VPX_CODEC_INVALID_PARAM;
705 static vpx_codec_err_t get_frame_corrupted(vpx_codec_alg_priv_t *ctx,
708 int *corrupted = va_arg(args, int *);
711 VP9D_COMP *pbi = (VP9D_COMP*)ctx->pbi;
713 *corrupted = pbi->common.frame_to_show->corrupted;
715 return VPX_CODEC_ERROR;
718 return VPX_CODEC_INVALID_PARAM;
722 static vpx_codec_err_t get_display_size(vpx_codec_alg_priv_t *ctx,
725 int *const display_size = va_arg(args, int *);
728 const VP9D_COMP *const pbi = (VP9D_COMP*)ctx->pbi;
730 display_size[0] = pbi->common.display_width;
731 display_size[1] = pbi->common.display_height;
733 return VPX_CODEC_ERROR;
737 return VPX_CODEC_INVALID_PARAM;
741 static vpx_codec_err_t set_invert_tile_order(vpx_codec_alg_priv_t *ctx,
744 ctx->invert_tile_order = va_arg(args, int);
748 static vpx_codec_err_t set_frame_buffer_lru_cache(vpx_codec_alg_priv_t *ctx,
751 VP9D_COMP *const pbi = (VP9D_COMP*)ctx->pbi;
753 // Save for later to pass into vp9 common.
754 ctx->fb_lru = va_arg(args, int);
757 VP9_COMMON *const cm = &pbi->common;
758 cm->fb_lru = ctx->fb_lru;
763 static vpx_codec_ctrl_fn_map_t ctf_maps[] = {
764 {VP8_SET_REFERENCE, set_reference},
765 {VP8_COPY_REFERENCE, copy_reference},
766 {VP8_SET_POSTPROC, set_postproc},
767 {VP8_SET_DBG_COLOR_REF_FRAME, set_dbg_options},
768 {VP8_SET_DBG_COLOR_MB_MODES, set_dbg_options},
769 {VP8_SET_DBG_COLOR_B_MODES, set_dbg_options},
770 {VP8_SET_DBG_DISPLAY_MV, set_dbg_options},
771 {VP8D_GET_LAST_REF_UPDATES, get_last_ref_updates},
772 {VP8D_GET_FRAME_CORRUPTED, get_frame_corrupted},
773 {VP9_GET_REFERENCE, get_reference},
774 {VP9D_GET_DISPLAY_SIZE, get_display_size},
775 {VP9_INVERT_TILE_DECODE_ORDER, set_invert_tile_order},
776 {VP9D_SET_FRAME_BUFFER_LRU_CACHE, set_frame_buffer_lru_cache},
781 #ifndef VERSION_STRING
782 #define VERSION_STRING
784 CODEC_INTERFACE(vpx_codec_vp9_dx) = {
785 "WebM Project VP9 Decoder" VERSION_STRING,
786 VPX_CODEC_INTERNAL_ABI_VERSION,
787 VPX_CODEC_CAP_DECODER | VP9_CAP_POSTPROC |
788 VPX_CODEC_CAP_EXTERNAL_FRAME_BUFFER,
789 /* vpx_codec_caps_t caps; */
790 vp9_init, /* vpx_codec_init_fn_t init; */
791 vp9_destroy, /* vpx_codec_destroy_fn_t destroy; */
792 ctf_maps, /* vpx_codec_ctrl_fn_map_t *ctrl_maps; */
793 vp9_xma_get_mmap, /* vpx_codec_get_mmap_fn_t get_mmap; */
794 vp9_xma_set_mmap, /* vpx_codec_set_mmap_fn_t set_mmap; */
796 vp9_peek_si, /* vpx_codec_peek_si_fn_t peek_si; */
797 vp9_get_si, /* vpx_codec_get_si_fn_t get_si; */
798 vp9_decode, /* vpx_codec_decode_fn_t decode; */
799 vp9_get_frame, /* vpx_codec_frame_get_fn_t frame_get; */
800 vp9_set_frame_buffers, /* vpx_codec_set_frame_buffers_fn_t set_fb; */
803 /* encoder functions */