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