From d6a4a5d98fb7d61fd2531e282fe4cfe8548bff2f Mon Sep 17 00:00:00 2001 From: Scott LaVarnway Date: Tue, 22 Jan 2013 10:52:29 -0800 Subject: [PATCH] Bug fix: Handle input data ptr = NULL and size = 0 correctly Issue 517: Issues decoding VPX_CODEC_USE_INPUT_FRAGMENTS http://code.google.com/p/webm/issues/detail?id=517 Change-Id: I030c4cf15b1e1b993433571b6ee77c959a368ff2 --- vp8/common/onyxd.h | 1 - vp8/decoder/onyxd_if.c | 78 ++++++++++++++----------------------------------- vp8/decoder/onyxd_int.h | 8 +++++ vp8/vp8_dx_iface.c | 71 ++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 98 insertions(+), 60 deletions(-) diff --git a/vp8/common/onyxd.h b/vp8/common/onyxd.h index fd7e051..c67910e 100644 --- a/vp8/common/onyxd.h +++ b/vp8/common/onyxd.h @@ -34,7 +34,6 @@ extern "C" int postprocess; int max_threads; int error_concealment; - int input_fragments; } VP8D_CONFIG; typedef enum diff --git a/vp8/decoder/onyxd_if.c b/vp8/decoder/onyxd_if.c index 8d6871b..f05c8c8 100644 --- a/vp8/decoder/onyxd_if.c +++ b/vp8/decoder/onyxd_if.c @@ -91,9 +91,6 @@ struct VP8D_COMP * vp8dx_create_decompressor(VP8D_CONFIG *oxcf) pbi->decoded_key_frame = 0; - pbi->input_fragments = oxcf->input_fragments; - pbi->num_fragments = 0; - /* Independent partitions is activated when a frame updates the * token probability table to have equal probabilities over the * PREV_COEF context. @@ -281,60 +278,13 @@ static int swap_frame_buffers (VP8_COMMON *cm) return err; } -int vp8dx_receive_compressed_data(VP8D_COMP *pbi, size_t size, - const uint8_t *source, - int64_t time_stamp) +int check_fragments_for_errors(VP8D_COMP *pbi) { -#if HAVE_NEON - int64_t dx_store_reg[8]; -#endif - VP8_COMMON *cm = &pbi->common; - int retcode = -1; - - pbi->common.error.error_code = VPX_CODEC_OK; - - if (pbi->num_fragments == 0) - { - /* New frame, reset fragment pointers and sizes */ - vpx_memset((void*)pbi->fragments, 0, sizeof(pbi->fragments)); - vpx_memset(pbi->fragment_sizes, 0, sizeof(pbi->fragment_sizes)); - } - if (pbi->input_fragments && !(source == NULL && size == 0)) - { - /* Store a pointer to this fragment and return. We haven't - * received the complete frame yet, so we will wait with decoding. - */ - assert(pbi->num_fragments < MAX_PARTITIONS); - pbi->fragments[pbi->num_fragments] = source; - pbi->fragment_sizes[pbi->num_fragments] = size; - pbi->num_fragments++; - if (pbi->num_fragments > (1 << EIGHT_PARTITION) + 1) - { - pbi->common.error.error_code = VPX_CODEC_UNSUP_BITSTREAM; - pbi->common.error.setjmp = 0; - pbi->num_fragments = 0; - return -1; - } - return 0; - } - - if (!pbi->input_fragments) - { - pbi->fragments[0] = source; - pbi->fragment_sizes[0] = size; - pbi->num_fragments = 1; - } - assert(pbi->common.multi_token_partition <= EIGHT_PARTITION); - if (pbi->num_fragments == 0) - { - pbi->num_fragments = 1; - pbi->fragments[0] = NULL; - pbi->fragment_sizes[0] = 0; - } - if (!pbi->ec_active && pbi->num_fragments <= 1 && pbi->fragment_sizes[0] == 0) { + VP8_COMMON *cm = &pbi->common; + /* If error concealment is disabled we won't signal missing frames * to the decoder. */ @@ -360,12 +310,29 @@ int vp8dx_receive_compressed_data(VP8D_COMP *pbi, size_t size, /* Signal that we have no frame to show. */ cm->show_frame = 0; - pbi->num_fragments = 0; - /* Nothing more to do. */ return 0; } + return 1; +} + +int vp8dx_receive_compressed_data(VP8D_COMP *pbi, size_t size, + const uint8_t *source, + int64_t time_stamp) +{ +#if HAVE_NEON + int64_t dx_store_reg[8]; +#endif + VP8_COMMON *cm = &pbi->common; + int retcode = -1; + + pbi->common.error.error_code = VPX_CODEC_OK; + + retcode = check_fragments_for_errors(pbi); + if(retcode <= 0) + return retcode; + #if HAVE_NEON #if CONFIG_RUNTIME_CPU_DETECT if (cm->cpu_caps & HAS_NEON) @@ -457,7 +424,6 @@ decode_exit: #endif pbi->common.error.setjmp = 0; - pbi->num_fragments = 0; return retcode; } int vp8dx_get_raw_frame(VP8D_COMP *pbi, YV12_BUFFER_CONFIG *sd, int64_t *time_stamp, int64_t *time_end_stamp, vp8_ppflags_t *flags) diff --git a/vp8/decoder/onyxd_int.h b/vp8/decoder/onyxd_int.h index 0063beb..ff9ef0e 100644 --- a/vp8/decoder/onyxd_int.h +++ b/vp8/decoder/onyxd_int.h @@ -33,6 +33,14 @@ typedef struct MACROBLOCKD mbd; } MB_ROW_DEC; +typedef struct +{ + int enabled; + unsigned int count; + const unsigned char *ptrs[MAX_PARTITIONS]; + unsigned int sizes[MAX_PARTITIONS]; +} FRAGMENT_DATA; + typedef struct VP8D_COMP { DECLARE_ALIGNED(16, MACROBLOCKD, mb); diff --git a/vp8/vp8_dx_iface.c b/vp8/vp8_dx_iface.c index c13d697..ca2245a 100644 --- a/vp8/vp8_dx_iface.c +++ b/vp8/vp8_dx_iface.c @@ -77,6 +77,7 @@ struct vpx_codec_alg_priv vpx_image_t img; int img_setup; void *user_priv; + FRAGMENT_DATA fragments; }; static unsigned long vp8_priv_sz(const vpx_codec_dec_cfg_t *si, vpx_codec_flags_t flags) @@ -215,6 +216,13 @@ static vpx_codec_err_t vp8_init(vpx_codec_ctx_t *ctx, { vp8_init_ctx(ctx, &mmap); + /* initialize number of fragments to zero */ + ctx->priv->alg_priv->fragments.count = 0; + /* is input fragments enabled? */ + ctx->priv->alg_priv->fragments.enabled = + (ctx->priv->alg_priv->base.init_flags & + VPX_CODEC_USE_INPUT_FRAGMENTS); + ctx->priv->alg_priv->defer_alloc = 1; /*post processing level initialized to do nothing */ } @@ -343,6 +351,47 @@ static void yuvconfig2image(vpx_image_t *img, img->self_allocd = 0; } +static int +update_fragments(vpx_codec_alg_priv_t *ctx, + const uint8_t *data, + unsigned int data_sz, + vpx_codec_err_t *res) +{ + *res = VPX_CODEC_OK; + + if (ctx->fragments.count == 0) + { + /* New frame, reset fragment pointers and sizes */ + vpx_memset((void*)ctx->fragments.ptrs, 0, sizeof(ctx->fragments.ptrs)); + vpx_memset(ctx->fragments.sizes, 0, sizeof(ctx->fragments.sizes)); + } + if (ctx->fragments.enabled && !(data == NULL && data_sz == 0)) + { + /* Store a pointer to this fragment and return. We haven't + * received the complete frame yet, so we will wait with decoding. + */ + ctx->fragments.ptrs[ctx->fragments.count] = data; + ctx->fragments.sizes[ctx->fragments.count] = data_sz; + ctx->fragments.count++; + if (ctx->fragments.count > (1 << EIGHT_PARTITION) + 1) + { + ctx->fragments.count = 0; + *res = VPX_CODEC_INVALID_PARAM; + return -1; + } + return 0; + } + + if (!ctx->fragments.enabled) + { + ctx->fragments.ptrs[0] = data; + ctx->fragments.sizes[0] = data_sz; + ctx->fragments.count = 1; + } + + return 1; +} + static vpx_codec_err_t vp8_decode(vpx_codec_alg_priv_t *ctx, const uint8_t *data, unsigned int data_sz, @@ -353,6 +402,11 @@ static vpx_codec_err_t vp8_decode(vpx_codec_alg_priv_t *ctx, unsigned int resolution_change = 0; unsigned int w, h; + + /* Update the input fragment data */ + if(update_fragments(ctx, data, data_sz, &res) <= 0) + return res; + /* Determine the stream parameters. Note that we rely on peek_si to * validate that we have a buffer that does not wrap around the top * of the heap. @@ -360,7 +414,8 @@ static vpx_codec_err_t vp8_decode(vpx_codec_alg_priv_t *ctx, w = ctx->si.w; h = ctx->si.h; - res = ctx->base.iface->dec.peek_si(data, data_sz, &ctx->si); + res = ctx->base.iface->dec.peek_si(ctx->fragments.ptrs[0], + ctx->fragments.sizes[0], &ctx->si); if((res == VPX_CODEC_UNSUP_BITSTREAM) && !ctx->si.is_kf) { @@ -421,8 +476,6 @@ static vpx_codec_err_t vp8_decode(vpx_codec_alg_priv_t *ctx, oxcf.max_threads = ctx->cfg.threads; oxcf.error_concealment = (ctx->base.init_flags & VPX_CODEC_USE_ERROR_CONCEALMENT); - oxcf.input_fragments = - (ctx->base.init_flags & VPX_CODEC_USE_INPUT_FRAGMENTS); optr = vp8dx_create_decompressor(&oxcf); @@ -544,12 +597,24 @@ static vpx_codec_err_t vp8_decode(vpx_codec_alg_priv_t *ctx, ctx->pbi->common.fb_idx_ref_cnt[0] = 0; } + /* update the pbi fragment data */ + ctx->pbi->num_fragments = ctx->fragments.count; + ctx->pbi->input_fragments = ctx->fragments.enabled; + vpx_memcpy(ctx->pbi->fragments, ctx->fragments.ptrs, + sizeof(ctx->fragments.ptrs)); + vpx_memcpy(ctx->pbi->fragment_sizes, ctx->fragments.sizes, + sizeof(ctx->fragments.sizes)); + + ctx->user_priv = user_priv; if (vp8dx_receive_compressed_data(ctx->pbi, data_sz, data, deadline)) { VP8D_COMP *pbi = (VP8D_COMP *)ctx->pbi; res = update_error_state(ctx, &pbi->common.error); } + + /* get ready for the next series of fragments */ + ctx->fragments.count = 0; } return res; -- 2.7.4