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_version.h"
16 #include "vpx/internal/vpx_codec_internal.h"
17 #include "vpx/vp8dx.h"
18 #include "vpx/vpx_decoder.h"
20 #include "vp9/common/vp9_frame_buffers.h"
22 #include "vp9/decoder/vp9_decoder.h"
23 #include "vp9/decoder/vp9_read_bit_buffer.h"
25 #include "vp9/vp9_iface_common.h"
27 #define VP9_CAP_POSTPROC (CONFIG_VP9_POSTPROC ? VPX_CODEC_CAP_POSTPROC : 0)
29 typedef vpx_codec_stream_info_t vp9_stream_info_t;
31 struct vpx_codec_alg_priv {
32 vpx_codec_priv_t base;
33 vpx_codec_dec_cfg_t cfg;
36 struct VP9Decoder *pbi;
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;
46 vpx_decrypt_cb decrypt_cb;
51 int invert_tile_order;
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;
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.
65 vpx_codec_alg_priv_t *alg_priv = vpx_memalign(32, sizeof(*alg_priv));
67 return VPX_CODEC_MEM_ERROR;
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;
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;
88 static vpx_codec_err_t decoder_destroy(vpx_codec_alg_priv_t *ctx) {
90 vp9_decoder_remove(ctx->pbi);
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];
107 return VPX_CODEC_UNSUP_BITSTREAM;
109 if (data + data_sz <= data)
110 return VPX_CODEC_INVALID_PARAM;
116 data_sz = MIN(sizeof(clear_buffer), data_sz);
117 decrypt_cb(decrypt_state, data, clear_buffer, data_sz);
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
127 if (frame_marker != VP9_FRAME_MARKER)
128 return VPX_CODEC_UNSUP_BITSTREAM;
129 if (version > 1) return VPX_CODEC_UNSUP_BITSTREAM;
131 if (vp9_rb_read_bit(&rb)) { // show an existing frame
135 si->is_kf = !vp9_rb_read_bit(&rb);
140 rb.bit_offset += 1; // show frame
141 rb.bit_offset += 1; // error resilient
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;
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
153 rb.bit_offset += 2; // subsampling x/y
154 rb.bit_offset += 1; // has extra plane
158 rb.bit_offset += 1; // has extra plane
160 // RGB is only available in version 1
161 return VPX_CODEC_UNSUP_BITSTREAM;
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;
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);
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;
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;
196 return error->error_code;
199 static void init_buffer_callbacks(vpx_codec_alg_priv_t *ctx) {
200 VP9_COMMON *const cm = &ctx->pbi->common;
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;
209 cm->get_fb_cb = vp9_get_frame_buffer;
210 cm->release_fb_cb = vp9_release_frame_buffer;
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");
216 cm->cb_priv = &cm->int_frame_buffers;
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;
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) |
235 ctx->postproc_cfg.post_proc_flag;
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;
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;
252 oxcf.max_threads = ctx->cfg.threads;
253 oxcf.inv_tile_order = ctx->invert_tile_order;
255 ctx->pbi = vp9_decoder_create(&oxcf);
256 if (ctx->pbi == NULL)
259 vp9_initialize_dec();
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);
267 init_buffer_callbacks(ctx);
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;
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
284 const vpx_codec_err_t res =
285 decoder_peek_si_internal(*data, data_sz, &ctx->si, ctx->decrypt_cb,
287 if (res != VPX_CODEC_OK)
291 // Initialize the decoder instance on the first frame
292 if (!ctx->decoder_init) {
294 if (ctx->pbi == NULL)
295 return VPX_CODEC_ERROR;
297 ctx->decoder_init = 1;
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;
305 cm = &ctx->pbi->common;
307 if (vp9_receive_compressed_data(ctx->pbi, data_sz, data, deadline))
308 return update_error_state(ctx, &cm->error);
310 if (ctx->base.init_flags & VPX_CODEC_USE_POSTPROC)
311 set_ppflags(ctx, &flags);
313 if (vp9_get_raw_frame(ctx->pbi, &sd, &time_stamp, &time_end_stamp, &flags))
314 return update_error_state(ctx, &cm->error);
316 yuvconfig2image(&ctx->img, &sd, user_priv);
317 ctx->img.fb_priv = cm->frame_bufs[cm->new_fb_idx].raw_frame_buffer.priv;
323 static INLINE uint8_t read_marker(vpx_decrypt_cb decrypt_cb,
325 const uint8_t *data) {
328 decrypt_cb(decrypt_state, data, &marker, 1);
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) {
341 marker = read_marker(decrypt_cb, decrypt_state, data + data_sz - 1);
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;
349 uint8_t marker2 = read_marker(decrypt_cb, decrypt_state,
350 data + data_sz - index_sz);
352 if (data_sz >= index_sz && marker2 == marker) {
353 // found a valid superframe index
355 const uint8_t *x = &data[data_sz - index_sz + 1];
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);
361 decrypt_cb(decrypt_state, x, clear_buffer, frames * mag);
365 for (i = 0; i < frames; i++) {
366 uint32_t this_sz = 0;
368 for (j = 0; j < mag; j++)
369 this_sz |= (*x++) << (j * 8);
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;
385 int frames_this_pts, frame_count = 0;
387 if (data == NULL || data_sz == 0)
388 return VPX_CODEC_INVALID_PARAM;
390 parse_superframe_index(data, data_sz, sizes, &frames_this_pts,
391 ctx->decrypt_cb, ctx->decrypt_state);
395 uint8_t marker = read_marker(ctx->decrypt_cb, ctx->decrypt_state,
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;
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;
409 if (data_start < data_end)
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];
422 if (data_sz < this_sz) {
423 ctx->base.err_detail = "Invalid frame size in index";
424 return VPX_CODEC_CORRUPT_FRAME;
431 res = decode_one(ctx, &data_start, data_sz, user_priv, deadline);
432 assert(data_start >= data);
433 assert(data_start <= data_end);
435 // Early exit if there was a decode error
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,
448 data_sz = (unsigned int)(data_end - data_start);
449 } while (data_start < data_end);
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;
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.
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;
486 return VPX_CODEC_ERROR;
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 *);
494 vpx_ref_frame_t *const frame = (vpx_ref_frame_t *)data;
495 YV12_BUFFER_CONFIG sd;
497 image2yuvconfig(&frame->img, &sd);
498 return vp9_set_reference_dec(&ctx->pbi->common,
499 (VP9_REFFRAME)frame->frame_type, &sd);
501 return VPX_CODEC_INVALID_PARAM;
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 *);
510 vpx_ref_frame_t *frame = (vpx_ref_frame_t *)data;
511 YV12_BUFFER_CONFIG sd;
513 image2yuvconfig(&frame->img, &sd);
515 return vp9_copy_reference_dec(ctx->pbi,
516 (VP9_REFFRAME)frame->frame_type, &sd);
518 return VPX_CODEC_INVALID_PARAM;
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 *);
527 YV12_BUFFER_CONFIG* fb;
529 vp9_get_reference_dec(ctx->pbi, data->idx, &fb);
530 yuvconfig2image(&data->img, fb, NULL);
533 return VPX_CODEC_INVALID_PARAM;
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 *);
543 ctx->postproc_cfg_set = 1;
544 ctx->postproc_cfg = *((vp8_postproc_cfg_t *)data);
547 return VPX_CODEC_INVALID_PARAM;
550 return VPX_CODEC_INCAPABLE;
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);
559 #define MAP(id, var) case id: var = data; break;
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);
570 return VPX_CODEC_INCAPABLE;
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 *);
580 *update_info = ctx->pbi->refresh_frame_flags;
582 return VPX_CODEC_ERROR;
585 return VPX_CODEC_INVALID_PARAM;
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 *);
596 *corrupted = ctx->pbi->common.frame_to_show->corrupted;
598 return VPX_CODEC_ERROR;
601 return VPX_CODEC_INVALID_PARAM;
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 *);
611 const VP9_COMMON *const cm = &ctx->pbi->common;
612 display_size[0] = cm->display_width;
613 display_size[1] = cm->display_height;
615 return VPX_CODEC_ERROR;
619 return VPX_CODEC_INVALID_PARAM;
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);
629 static vpx_codec_err_t ctrl_set_decryptor(vpx_codec_alg_priv_t *ctx,
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;
638 static vpx_codec_ctrl_fn_map_t decoder_ctrl_maps[] = {
639 {VP8_COPY_REFERENCE, ctrl_copy_reference},
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},
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},
660 #ifndef VERSION_STRING
661 #define VERSION_STRING
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
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