1 /*
2 * Copyright (c) 2010 The WebM project authors. All Rights Reserved.
3 *
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.
9 */
10
11
12 #include <stdlib.h>
13 #include <string.h>
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/common/vp9_frame_buffers.h"
19 #include "vp9/decoder/vp9_decoder.h"
20 #include "vp9/decoder/vp9_read_bit_buffer.h"
21 #include "vp9/vp9_iface_common.h"
22
23 #define VP9_CAP_POSTPROC (CONFIG_VP9_POSTPROC ? VPX_CODEC_CAP_POSTPROC : 0)
24 typedef vpx_codec_stream_info_t vp9_stream_info_t;
25
26 struct vpx_codec_alg_priv {
27 vpx_codec_priv_t base;
28 vpx_codec_dec_cfg_t cfg;
29 vp9_stream_info_t si;
30 int decoder_init;
31 struct VP9Decompressor *pbi;
32 int postproc_cfg_set;
33 vp8_postproc_cfg_t postproc_cfg;
34 #if CONFIG_POSTPROC_VISUALIZER
35 unsigned int dbg_postproc_flag;
36 int dbg_color_ref_frame_flag;
37 int dbg_color_mb_modes_flag;
38 int dbg_color_b_modes_flag;
39 int dbg_display_mv_flag;
40 #endif
41 vpx_image_t img;
42 int img_setup;
43 int img_avail;
44 int invert_tile_order;
45
46 // External frame buffer info to save for VP9 common.
47 void *ext_priv; // Private data associated with the external frame buffers.
48 vpx_get_frame_buffer_cb_fn_t get_ext_fb_cb;
49 vpx_release_frame_buffer_cb_fn_t release_ext_fb_cb;
50 };
51
vp9_init(vpx_codec_ctx_t * ctx,vpx_codec_priv_enc_mr_cfg_t * data)52 static vpx_codec_err_t vp9_init(vpx_codec_ctx_t *ctx,
53 vpx_codec_priv_enc_mr_cfg_t *data) {
54 // This function only allocates space for the vpx_codec_alg_priv_t
55 // structure. More memory may be required at the time the stream
56 // information becomes known.
57 (void)data;
58 if (!ctx->priv) {
59 void *base = vpx_memalign(32, sizeof(vpx_codec_alg_priv_t));
60 if (base == NULL)
61 return VPX_CODEC_MEM_ERROR;
62
63 memset(base, 0, sizeof(vpx_codec_alg_priv_t));
64 ctx->priv = (vpx_codec_priv_t *)base;
65 ctx->priv->sz = sizeof(*ctx->priv);
66 ctx->priv->iface = ctx->iface;
67 ctx->priv->alg_priv = (vpx_codec_alg_priv_t *)base;
68 ctx->priv->alg_priv->si.sz = sizeof(ctx->priv->alg_priv->si);
69 ctx->priv->init_flags = ctx->init_flags;
70
71 if (ctx->config.dec) {
72 // Update the reference to the config structure to an internal copy.
73 ctx->priv->alg_priv->cfg = *ctx->config.dec;
74 ctx->config.dec = &ctx->priv->alg_priv->cfg;
75 }
76 }
77
78 return VPX_CODEC_OK;
79 }
80
vp9_destroy(vpx_codec_alg_priv_t * ctx)81 static vpx_codec_err_t vp9_destroy(vpx_codec_alg_priv_t *ctx) {
82 if (ctx->pbi)
83 vp9_remove_decompressor(ctx->pbi);
84
85 return VPX_CODEC_OK;
86 }
87
vp9_peek_si(const uint8_t * data,unsigned int data_sz,vpx_codec_stream_info_t * si)88 static vpx_codec_err_t vp9_peek_si(const uint8_t *data, unsigned int data_sz,
89 vpx_codec_stream_info_t *si) {
90 if (data_sz <= 8) return VPX_CODEC_UNSUP_BITSTREAM;
91 if (data + data_sz <= data) return VPX_CODEC_INVALID_PARAM;
92
93 si->is_kf = 0;
94 si->w = si->h = 0;
95
96 {
97 struct vp9_read_bit_buffer rb = { data, data + data_sz, 0, NULL, NULL };
98 const int frame_marker = vp9_rb_read_literal(&rb, 2);
99 const int version = vp9_rb_read_bit(&rb);
100 (void) vp9_rb_read_bit(&rb); // unused version bit
101
102 if (frame_marker != VP9_FRAME_MARKER)
103 return VPX_CODEC_UNSUP_BITSTREAM;
104 if (version > 1) return VPX_CODEC_UNSUP_BITSTREAM;
105
106 if (vp9_rb_read_bit(&rb)) { // show an existing frame
107 return VPX_CODEC_OK;
108 }
109
110 si->is_kf = !vp9_rb_read_bit(&rb);
111 if (si->is_kf) {
112 const int sRGB = 7;
113 int colorspace;
114
115 rb.bit_offset += 1; // show frame
116 rb.bit_offset += 1; // error resilient
117
118 if (vp9_rb_read_literal(&rb, 8) != VP9_SYNC_CODE_0 ||
119 vp9_rb_read_literal(&rb, 8) != VP9_SYNC_CODE_1 ||
120 vp9_rb_read_literal(&rb, 8) != VP9_SYNC_CODE_2) {
121 return VPX_CODEC_UNSUP_BITSTREAM;
122 }
123
124 colorspace = vp9_rb_read_literal(&rb, 3);
125 if (colorspace != sRGB) {
126 rb.bit_offset += 1; // [16,235] (including xvycc) vs [0,255] range
127 if (version == 1) {
128 rb.bit_offset += 2; // subsampling x/y
129 rb.bit_offset += 1; // has extra plane
130 }
131 } else {
132 if (version == 1) {
133 rb.bit_offset += 1; // has extra plane
134 } else {
135 // RGB is only available in version 1
136 return VPX_CODEC_UNSUP_BITSTREAM;
137 }
138 }
139
140 // TODO(jzern): these are available on non-keyframes in intra only mode.
141 si->w = vp9_rb_read_literal(&rb, 16) + 1;
142 si->h = vp9_rb_read_literal(&rb, 16) + 1;
143 }
144 }
145
146 return VPX_CODEC_OK;
147 }
148
vp9_get_si(vpx_codec_alg_priv_t * ctx,vpx_codec_stream_info_t * si)149 static vpx_codec_err_t vp9_get_si(vpx_codec_alg_priv_t *ctx,
150 vpx_codec_stream_info_t *si) {
151 const size_t sz = (si->sz >= sizeof(vp9_stream_info_t))
152 ? sizeof(vp9_stream_info_t)
153 : sizeof(vpx_codec_stream_info_t);
154 memcpy(si, &ctx->si, sz);
155 si->sz = (unsigned int)sz;
156
157 return VPX_CODEC_OK;
158 }
159
160
update_error_state(vpx_codec_alg_priv_t * ctx,const struct vpx_internal_error_info * error)161 static vpx_codec_err_t update_error_state(vpx_codec_alg_priv_t *ctx,
162 const struct vpx_internal_error_info *error) {
163 if (error->error_code)
164 ctx->base.err_detail = error->has_detail ? error->detail : NULL;
165
166 return error->error_code;
167 }
168
decode_one(vpx_codec_alg_priv_t * ctx,const uint8_t ** data,unsigned int data_sz,void * user_priv,int64_t deadline)169 static vpx_codec_err_t decode_one(vpx_codec_alg_priv_t *ctx,
170 const uint8_t **data, unsigned int data_sz,
171 void *user_priv, int64_t deadline) {
172 vpx_codec_err_t res = VPX_CODEC_OK;
173
174 ctx->img_avail = 0;
175
176 // Determine the stream parameters. Note that we rely on peek_si to
177 // validate that we have a buffer that does not wrap around the top
178 // of the heap.
179 if (!ctx->si.h)
180 res = ctx->base.iface->dec.peek_si(*data, data_sz, &ctx->si);
181
182 /* Initialize the decoder instance on the first frame*/
183 if (!res && !ctx->decoder_init) {
184 VP9D_CONFIG oxcf;
185 struct VP9Decompressor *optr;
186
187 vp9_initialize_dec();
188
189 oxcf.width = ctx->si.w;
190 oxcf.height = ctx->si.h;
191 oxcf.version = 9;
192 oxcf.max_threads = ctx->cfg.threads;
193 oxcf.inv_tile_order = ctx->invert_tile_order;
194 optr = vp9_create_decompressor(&oxcf);
195
196 // If postprocessing was enabled by the application and a
197 // configuration has not been provided, default it.
198 if (!ctx->postproc_cfg_set &&
199 (ctx->base.init_flags & VPX_CODEC_USE_POSTPROC)) {
200 ctx->postproc_cfg.post_proc_flag = VP8_DEBLOCK | VP8_DEMACROBLOCK;
201 ctx->postproc_cfg.deblocking_level = 4;
202 ctx->postproc_cfg.noise_level = 0;
203 }
204
205 if (!optr) {
206 res = VPX_CODEC_ERROR;
207 } else {
208 VP9D_COMP *const pbi = (VP9D_COMP*)optr;
209 VP9_COMMON *const cm = &pbi->common;
210
211 // Set index to not initialized.
212 cm->new_fb_idx = -1;
213
214 if (ctx->get_ext_fb_cb != NULL && ctx->release_ext_fb_cb != NULL) {
215 cm->get_fb_cb = ctx->get_ext_fb_cb;
216 cm->release_fb_cb = ctx->release_ext_fb_cb;
217 cm->cb_priv = ctx->ext_priv;
218 } else {
219 cm->get_fb_cb = vp9_get_frame_buffer;
220 cm->release_fb_cb = vp9_release_frame_buffer;
221
222 if (vp9_alloc_internal_frame_buffers(&cm->int_frame_buffers))
223 vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
224 "Failed to initialize internal frame buffers");
225 cm->cb_priv = &cm->int_frame_buffers;
226 }
227
228 ctx->pbi = optr;
229 }
230
231 ctx->decoder_init = 1;
232 }
233
234 if (!res && ctx->pbi) {
235 VP9D_COMP *const pbi = ctx->pbi;
236 VP9_COMMON *const cm = &pbi->common;
237 YV12_BUFFER_CONFIG sd;
238 int64_t time_stamp = 0, time_end_stamp = 0;
239 vp9_ppflags_t flags = {0};
240
241 if (ctx->base.init_flags & VPX_CODEC_USE_POSTPROC) {
242 flags.post_proc_flag =
243 #if CONFIG_POSTPROC_VISUALIZER
244 (ctx->dbg_color_ref_frame_flag ? VP9D_DEBUG_CLR_FRM_REF_BLKS : 0) |
245 (ctx->dbg_color_mb_modes_flag ? VP9D_DEBUG_CLR_BLK_MODES : 0) |
246 (ctx->dbg_color_b_modes_flag ? VP9D_DEBUG_CLR_BLK_MODES : 0) |
247 (ctx->dbg_display_mv_flag ? VP9D_DEBUG_DRAW_MV : 0) |
248 #endif
249 ctx->postproc_cfg.post_proc_flag;
250
251 flags.deblocking_level = ctx->postproc_cfg.deblocking_level;
252 flags.noise_level = ctx->postproc_cfg.noise_level;
253 #if CONFIG_POSTPROC_VISUALIZER
254 flags.display_ref_frame_flag = ctx->dbg_color_ref_frame_flag;
255 flags.display_mb_modes_flag = ctx->dbg_color_mb_modes_flag;
256 flags.display_b_modes_flag = ctx->dbg_color_b_modes_flag;
257 flags.display_mv_flag = ctx->dbg_display_mv_flag;
258 #endif
259 }
260
261 if (vp9_receive_compressed_data(pbi, data_sz, data, deadline))
262 res = update_error_state(ctx, &cm->error);
263
264 if (!res && 0 == vp9_get_raw_frame(pbi, &sd, &time_stamp,
265 &time_end_stamp, &flags)) {
266 yuvconfig2image(&ctx->img, &sd, user_priv);
267
268 ctx->img.fb_priv = cm->frame_bufs[cm->new_fb_idx].raw_frame_buffer.priv;
269 ctx->img_avail = 1;
270 }
271 }
272
273 return res;
274 }
275
parse_superframe_index(const uint8_t * data,size_t data_sz,uint32_t sizes[8],int * count)276 static void parse_superframe_index(const uint8_t *data, size_t data_sz,
277 uint32_t sizes[8], int *count) {
278 uint8_t marker;
279
280 assert(data_sz);
281 marker = data[data_sz - 1];
282 *count = 0;
283
284 if ((marker & 0xe0) == 0xc0) {
285 const uint32_t frames = (marker & 0x7) + 1;
286 const uint32_t mag = ((marker >> 3) & 0x3) + 1;
287 const size_t index_sz = 2 + mag * frames;
288
289 if (data_sz >= index_sz && data[data_sz - index_sz] == marker) {
290 // found a valid superframe index
291 uint32_t i, j;
292 const uint8_t *x = data + data_sz - index_sz + 1;
293
294 for (i = 0; i < frames; i++) {
295 uint32_t this_sz = 0;
296
297 for (j = 0; j < mag; j++)
298 this_sz |= (*x++) << (j * 8);
299 sizes[i] = this_sz;
300 }
301
302 *count = frames;
303 }
304 }
305 }
306
vp9_decode(vpx_codec_alg_priv_t * ctx,const uint8_t * data,unsigned int data_sz,void * user_priv,long deadline)307 static vpx_codec_err_t vp9_decode(vpx_codec_alg_priv_t *ctx,
308 const uint8_t *data,
309 unsigned int data_sz,
310 void *user_priv,
311 long deadline) {
312 const uint8_t *data_start = data;
313 const uint8_t *data_end = data + data_sz;
314 vpx_codec_err_t res = VPX_CODEC_OK;
315 uint32_t sizes[8];
316 int frames_this_pts, frame_count = 0;
317
318 if (data == NULL || data_sz == 0) return VPX_CODEC_INVALID_PARAM;
319
320 parse_superframe_index(data, data_sz, sizes, &frames_this_pts);
321
322 do {
323 // Skip over the superframe index, if present
324 if (data_sz && (*data_start & 0xe0) == 0xc0) {
325 const uint8_t marker = *data_start;
326 const uint32_t frames = (marker & 0x7) + 1;
327 const uint32_t mag = ((marker >> 3) & 0x3) + 1;
328 const uint32_t index_sz = 2 + mag * frames;
329
330 if (data_sz >= index_sz && data_start[index_sz - 1] == marker) {
331 data_start += index_sz;
332 data_sz -= index_sz;
333 if (data_start < data_end)
334 continue;
335 else
336 break;
337 }
338 }
339
340 // Use the correct size for this frame, if an index is present.
341 if (frames_this_pts) {
342 uint32_t this_sz = sizes[frame_count];
343
344 if (data_sz < this_sz) {
345 ctx->base.err_detail = "Invalid frame size in index";
346 return VPX_CODEC_CORRUPT_FRAME;
347 }
348
349 data_sz = this_sz;
350 frame_count++;
351 }
352
353 res = decode_one(ctx, &data_start, data_sz, user_priv, deadline);
354 assert(data_start >= data);
355 assert(data_start <= data_end);
356
357 /* Early exit if there was a decode error */
358 if (res)
359 break;
360
361 /* Account for suboptimal termination by the encoder. */
362 while (data_start < data_end && *data_start == 0)
363 data_start++;
364
365 data_sz = (unsigned int)(data_end - data_start);
366 } while (data_start < data_end);
367 return res;
368 }
369
vp9_get_frame(vpx_codec_alg_priv_t * ctx,vpx_codec_iter_t * iter)370 static vpx_image_t *vp9_get_frame(vpx_codec_alg_priv_t *ctx,
371 vpx_codec_iter_t *iter) {
372 vpx_image_t *img = NULL;
373
374 if (ctx->img_avail) {
375 /* iter acts as a flip flop, so an image is only returned on the first
376 * call to get_frame.
377 */
378 if (!(*iter)) {
379 img = &ctx->img;
380 *iter = img;
381 }
382 }
383 ctx->img_avail = 0;
384
385 return img;
386 }
387
vp9_set_fb_fn(vpx_codec_alg_priv_t * ctx,vpx_get_frame_buffer_cb_fn_t cb_get,vpx_release_frame_buffer_cb_fn_t cb_release,void * cb_priv)388 static vpx_codec_err_t vp9_set_fb_fn(
389 vpx_codec_alg_priv_t *ctx,
390 vpx_get_frame_buffer_cb_fn_t cb_get,
391 vpx_release_frame_buffer_cb_fn_t cb_release, void *cb_priv) {
392 if (cb_get == NULL || cb_release == NULL) {
393 return VPX_CODEC_INVALID_PARAM;
394 } else if (ctx->pbi == NULL) {
395 // If the decoder has already been initialized, do not accept changes to
396 // the frame buffer functions.
397 ctx->get_ext_fb_cb = cb_get;
398 ctx->release_ext_fb_cb = cb_release;
399 ctx->ext_priv = cb_priv;
400 return VPX_CODEC_OK;
401 }
402
403 return VPX_CODEC_ERROR;
404 }
405
set_reference(vpx_codec_alg_priv_t * ctx,int ctr_id,va_list args)406 static vpx_codec_err_t set_reference(vpx_codec_alg_priv_t *ctx, int ctr_id,
407 va_list args) {
408 vpx_ref_frame_t *const data = va_arg(args, vpx_ref_frame_t *);
409 (void)ctr_id;
410 if (data) {
411 vpx_ref_frame_t *const frame = (vpx_ref_frame_t *)data;
412 YV12_BUFFER_CONFIG sd;
413
414 image2yuvconfig(&frame->img, &sd);
415 return vp9_set_reference_dec(&ctx->pbi->common,
416 (VP9_REFFRAME)frame->frame_type, &sd);
417 } else {
418 return VPX_CODEC_INVALID_PARAM;
419 }
420 }
421
copy_reference(vpx_codec_alg_priv_t * ctx,int ctr_id,va_list args)422 static vpx_codec_err_t copy_reference(vpx_codec_alg_priv_t *ctx, int ctr_id,
423 va_list args) {
424 vpx_ref_frame_t *data = va_arg(args, vpx_ref_frame_t *);
425 (void)ctr_id;
426 if (data) {
427 vpx_ref_frame_t *frame = (vpx_ref_frame_t *)data;
428 YV12_BUFFER_CONFIG sd;
429
430 image2yuvconfig(&frame->img, &sd);
431
432 return vp9_copy_reference_dec(ctx->pbi,
433 (VP9_REFFRAME)frame->frame_type, &sd);
434 } else {
435 return VPX_CODEC_INVALID_PARAM;
436 }
437 }
438
get_reference(vpx_codec_alg_priv_t * ctx,int ctr_id,va_list args)439 static vpx_codec_err_t get_reference(vpx_codec_alg_priv_t *ctx, int ctr_id,
440 va_list args) {
441 vp9_ref_frame_t *data = va_arg(args, vp9_ref_frame_t *);
442 (void)ctr_id;
443 if (data) {
444 YV12_BUFFER_CONFIG* fb;
445
446 vp9_get_reference_dec(ctx->pbi, data->idx, &fb);
447 yuvconfig2image(&data->img, fb, NULL);
448 return VPX_CODEC_OK;
449 } else {
450 return VPX_CODEC_INVALID_PARAM;
451 }
452 }
453
set_postproc(vpx_codec_alg_priv_t * ctx,int ctr_id,va_list args)454 static vpx_codec_err_t set_postproc(vpx_codec_alg_priv_t *ctx, int ctr_id,
455 va_list args) {
456 #if CONFIG_VP9_POSTPROC
457 vp8_postproc_cfg_t *data = va_arg(args, vp8_postproc_cfg_t *);
458
459 if (data) {
460 ctx->postproc_cfg_set = 1;
461 ctx->postproc_cfg = *((vp8_postproc_cfg_t *)data);
462 return VPX_CODEC_OK;
463 } else {
464 return VPX_CODEC_INVALID_PARAM;
465 }
466 #else
467 (void)ctr_id;
468 (void)ctx;
469 (void)args;
470 return VPX_CODEC_INCAPABLE;
471 #endif
472 }
473
set_dbg_options(vpx_codec_alg_priv_t * ctx,int ctrl_id,va_list args)474 static vpx_codec_err_t set_dbg_options(vpx_codec_alg_priv_t *ctx, int ctrl_id,
475 va_list args) {
476 #if CONFIG_POSTPROC_VISUALIZER && CONFIG_POSTPROC
477 int data = va_arg(args, int);
478
479 #define MAP(id, var) case id: var = data; break;
480
481 switch (ctrl_id) {
482 MAP(VP8_SET_DBG_COLOR_REF_FRAME, ctx->dbg_color_ref_frame_flag);
483 MAP(VP8_SET_DBG_COLOR_MB_MODES, ctx->dbg_color_mb_modes_flag);
484 MAP(VP8_SET_DBG_COLOR_B_MODES, ctx->dbg_color_b_modes_flag);
485 MAP(VP8_SET_DBG_DISPLAY_MV, ctx->dbg_display_mv_flag);
486 }
487
488 return VPX_CODEC_OK;
489 #else
490 (void)ctrl_id;
491 (void)ctx;
492 (void)args;
493 return VPX_CODEC_INCAPABLE;
494 #endif
495 }
496
get_last_ref_updates(vpx_codec_alg_priv_t * ctx,int ctrl_id,va_list args)497 static vpx_codec_err_t get_last_ref_updates(vpx_codec_alg_priv_t *ctx,
498 int ctrl_id, va_list args) {
499 int *const update_info = va_arg(args, int *);
500
501 (void)ctrl_id;
502 if (update_info) {
503 if (ctx->pbi)
504 *update_info = ctx->pbi->refresh_frame_flags;
505 else
506 return VPX_CODEC_ERROR;
507 return VPX_CODEC_OK;
508 } else {
509 return VPX_CODEC_INVALID_PARAM;
510 }
511 }
512
513
get_frame_corrupted(vpx_codec_alg_priv_t * ctx,int ctrl_id,va_list args)514 static vpx_codec_err_t get_frame_corrupted(vpx_codec_alg_priv_t *ctx,
515 int ctrl_id, va_list args) {
516 int *corrupted = va_arg(args, int *);
517 (void)ctrl_id;
518
519 if (corrupted) {
520 if (ctx->pbi)
521 *corrupted = ctx->pbi->common.frame_to_show->corrupted;
522 else
523 return VPX_CODEC_ERROR;
524 return VPX_CODEC_OK;
525 } else {
526 return VPX_CODEC_INVALID_PARAM;
527 }
528 }
529
get_display_size(vpx_codec_alg_priv_t * ctx,int ctrl_id,va_list args)530 static vpx_codec_err_t get_display_size(vpx_codec_alg_priv_t *ctx,
531 int ctrl_id, va_list args) {
532 int *const display_size = va_arg(args, int *);
533 (void)ctrl_id;
534
535 if (display_size) {
536 if (ctx->pbi) {
537 const VP9_COMMON *const cm = &ctx->pbi->common;
538 display_size[0] = cm->display_width;
539 display_size[1] = cm->display_height;
540 } else {
541 return VPX_CODEC_ERROR;
542 }
543 return VPX_CODEC_OK;
544 } else {
545 return VPX_CODEC_INVALID_PARAM;
546 }
547 }
548
set_invert_tile_order(vpx_codec_alg_priv_t * ctx,int ctrl_id,va_list args)549 static vpx_codec_err_t set_invert_tile_order(vpx_codec_alg_priv_t *ctx,
550 int ctrl_id,
551 va_list args) {
552 (void)ctrl_id;
553 (void)ctx;
554 ctx->invert_tile_order = va_arg(args, int);
555 return VPX_CODEC_OK;
556 }
557
558 static vpx_codec_ctrl_fn_map_t ctf_maps[] = {
559 {VP8_SET_REFERENCE, set_reference},
560 {VP8_COPY_REFERENCE, copy_reference},
561 {VP8_SET_POSTPROC, set_postproc},
562 {VP8_SET_DBG_COLOR_REF_FRAME, set_dbg_options},
563 {VP8_SET_DBG_COLOR_MB_MODES, set_dbg_options},
564 {VP8_SET_DBG_COLOR_B_MODES, set_dbg_options},
565 {VP8_SET_DBG_DISPLAY_MV, set_dbg_options},
566 {VP8D_GET_LAST_REF_UPDATES, get_last_ref_updates},
567 {VP8D_GET_FRAME_CORRUPTED, get_frame_corrupted},
568 {VP9_GET_REFERENCE, get_reference},
569 {VP9D_GET_DISPLAY_SIZE, get_display_size},
570 {VP9_INVERT_TILE_DECODE_ORDER, set_invert_tile_order},
571 { -1, NULL},
572 };
573
574
575 #ifndef VERSION_STRING
576 #define VERSION_STRING
577 #endif
578 CODEC_INTERFACE(vpx_codec_vp9_dx) = {
579 "WebM Project VP9 Decoder" VERSION_STRING,
580 VPX_CODEC_INTERNAL_ABI_VERSION,
581 VPX_CODEC_CAP_DECODER | VP9_CAP_POSTPROC |
582 VPX_CODEC_CAP_EXTERNAL_FRAME_BUFFER,
583 /* vpx_codec_caps_t caps; */
584 vp9_init, /* vpx_codec_init_fn_t init; */
585 vp9_destroy, /* vpx_codec_destroy_fn_t destroy; */
586 ctf_maps, /* vpx_codec_ctrl_fn_map_t *ctrl_maps; */
587 NOT_IMPLEMENTED, /* vpx_codec_get_mmap_fn_t get_mmap; */
588 NOT_IMPLEMENTED, /* vpx_codec_set_mmap_fn_t set_mmap; */
589 { // NOLINT
590 vp9_peek_si, /* vpx_codec_peek_si_fn_t peek_si; */
591 vp9_get_si, /* vpx_codec_get_si_fn_t get_si; */
592 vp9_decode, /* vpx_codec_decode_fn_t decode; */
593 vp9_get_frame, /* vpx_codec_frame_get_fn_t frame_get; */
594 vp9_set_fb_fn, /* vpx_codec_set_fb_fn_t set_fb_fn; */
595 },
596 { // NOLINT
597 /* encoder functions */
598 NOT_IMPLEMENTED,
599 NOT_IMPLEMENTED,
600 NOT_IMPLEMENTED,
601 NOT_IMPLEMENTED,
602 NOT_IMPLEMENTED,
603 NOT_IMPLEMENTED,
604 NOT_IMPLEMENTED
605 }
606 };
607