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