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