Implement error tracking in the decoder
A new vpx_codec_control called VP8D_GET_FRAME_CORRUPTED. The output from the function is non-zero if the last decoded frame contains corruption due to packet losses. The decoder is also modified to accept encoded frames of zero length. A zero length frame indicates to the decoder that one or more frames have been completely lost. This will mark the last decoded reference buffer as corrupted. The data pointer can be NULL if the length is zero. Change-Id: Ic5902c785a281c6e05329deea958554b7a6c75ce
This commit is contained in:
Родитель
2a87491fb0
Коммит
67fb3a5155
|
@ -282,6 +282,8 @@ typedef struct
|
|||
|
||||
void *current_bc;
|
||||
|
||||
int corrupted;
|
||||
|
||||
#if CONFIG_RUNTIME_CPU_DETECT
|
||||
struct VP8_COMMON_RTCD *rtcd;
|
||||
#endif
|
||||
|
|
|
@ -206,4 +206,29 @@ static int vp8_decode_value(BOOL_DECODER *br, int bits)
|
|||
|
||||
return z;
|
||||
}
|
||||
|
||||
static int vp8dx_bool_error(BOOL_DECODER *br)
|
||||
{
|
||||
/* Check if we have reached the end of the buffer.
|
||||
*
|
||||
* Variable 'count' stores the number of bits in the 'value' buffer,
|
||||
* minus 8. So if count == 8, there are 16 bits available to be read.
|
||||
* Normally, count is filled with 8 and one byte is filled into the
|
||||
* value buffer. When we reach the end of the buffer, count is instead
|
||||
* filled with VP8_LOTS_OF_BITS, 8 of which represent the last 8 real
|
||||
* bits from the bitstream. So the last bit in the bitstream will be
|
||||
* represented by count == VP8_LOTS_OF_BITS - 16.
|
||||
*/
|
||||
if ((br->count > VP8_BD_VALUE_SIZE)
|
||||
&& (br->count <= VP8_LOTS_OF_BITS - 16))
|
||||
{
|
||||
/* We have tried to decode bits after the end of
|
||||
* stream was encountered.
|
||||
*/
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* No error. */
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -381,6 +381,12 @@ void vp8_decode_mb_row(VP8D_COMP *pbi,
|
|||
xd->pre.u_buffer = pc->yv12_fb[ref_fb_idx].u_buffer + recon_uvoffset;
|
||||
xd->pre.v_buffer = pc->yv12_fb[ref_fb_idx].v_buffer + recon_uvoffset;
|
||||
|
||||
if (xd->mode_info_context->mbmi.ref_frame != INTRA_FRAME)
|
||||
{
|
||||
/* propagate errors from reference frames */
|
||||
xd->corrupted |= pc->yv12_fb[ref_fb_idx].corrupted;
|
||||
}
|
||||
|
||||
vp8_build_uvmvs(xd, pc->full_pixel);
|
||||
|
||||
/*
|
||||
|
@ -391,6 +397,8 @@ void vp8_decode_mb_row(VP8D_COMP *pbi,
|
|||
*/
|
||||
vp8_decode_macroblock(pbi, xd);
|
||||
|
||||
/* check if the boolean decoder has suffered an error */
|
||||
xd->corrupted |= vp8dx_bool_error(xd->current_bc);
|
||||
|
||||
recon_yoffset += 16;
|
||||
recon_uvoffset += 8;
|
||||
|
@ -556,6 +564,7 @@ static void init_frame(VP8D_COMP *pbi)
|
|||
xd->frame_type = pc->frame_type;
|
||||
xd->mode_info_context->mbmi.mode = DC_PRED;
|
||||
xd->mode_info_stride = pc->mode_info_stride;
|
||||
xd->corrupted = 0; /* init without corruption */
|
||||
}
|
||||
|
||||
int vp8_decode_frame(VP8D_COMP *pbi)
|
||||
|
@ -571,6 +580,10 @@ int vp8_decode_frame(VP8D_COMP *pbi)
|
|||
int i, j, k, l;
|
||||
const int *const mb_feature_data_bits = vp8_mb_feature_data_bits;
|
||||
|
||||
/* start with no corruption of current frame */
|
||||
xd->corrupted = 0;
|
||||
pc->yv12_fb[pc->new_fb_idx].corrupted = 0;
|
||||
|
||||
if (data_end - data < 3)
|
||||
vpx_internal_error(&pc->error, VPX_CODEC_CORRUPT_FRAME,
|
||||
"Truncated packet");
|
||||
|
@ -892,6 +905,14 @@ int vp8_decode_frame(VP8D_COMP *pbi)
|
|||
|
||||
stop_token_decoder(pbi);
|
||||
|
||||
/* Collect information about decoder corruption. */
|
||||
/* 1. Check first boolean decoder for errors. */
|
||||
pc->yv12_fb[pc->new_fb_idx].corrupted =
|
||||
vp8dx_bool_error(bc);
|
||||
/* 2. Check the macroblock information */
|
||||
pc->yv12_fb[pc->new_fb_idx].corrupted |=
|
||||
xd->corrupted;
|
||||
|
||||
/* vpx_log("Decoder: Frame Decoded, Size Roughly:%d bytes \n",bc->pos+pbi->bc2.pos); */
|
||||
|
||||
/* If this was a kf or Gf note the Q used */
|
||||
|
|
|
@ -334,6 +334,23 @@ int vp8dx_receive_compressed_data(VP8D_PTR ptr, unsigned long size, const unsign
|
|||
|
||||
pbi->common.error.error_code = VPX_CODEC_OK;
|
||||
|
||||
if (size == 0)
|
||||
{
|
||||
/* This is used to signal that we are missing frames.
|
||||
* We do not know if the missing frame(s) was supposed to update
|
||||
* any of the reference buffers, but we act conservative and
|
||||
* mark only the last buffer as corrupted.
|
||||
*/
|
||||
cm->yv12_fb[cm->lst_fb_idx].corrupted = 1;
|
||||
|
||||
/* Signal that we have no frame to show. */
|
||||
cm->show_frame = 0;
|
||||
|
||||
/* Nothing more to do. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#if HAVE_ARMV7
|
||||
#if CONFIG_RUNTIME_CPU_DETECT
|
||||
if (cm->rtcd.flags & HAS_NEON)
|
||||
|
@ -356,6 +373,13 @@ int vp8dx_receive_compressed_data(VP8D_PTR ptr, unsigned long size, const unsign
|
|||
}
|
||||
#endif
|
||||
pbi->common.error.setjmp = 0;
|
||||
|
||||
/* We do not know if the missing frame(s) was supposed to update
|
||||
* any of the reference buffers, but we act conservative and
|
||||
* mark only the last buffer as corrupted.
|
||||
*/
|
||||
cm->yv12_fb[cm->lst_fb_idx].corrupted = 1;
|
||||
|
||||
if (cm->fb_idx_ref_cnt[cm->new_fb_idx] > 0)
|
||||
cm->fb_idx_ref_cnt[cm->new_fb_idx]--;
|
||||
return -1;
|
||||
|
|
|
@ -893,9 +893,18 @@ void vp8mt_decode_mb_rows( VP8D_COMP *pbi, MACROBLOCKD *xd)
|
|||
xd->pre.u_buffer = pc->yv12_fb[ref_fb_idx].u_buffer + recon_uvoffset;
|
||||
xd->pre.v_buffer = pc->yv12_fb[ref_fb_idx].v_buffer + recon_uvoffset;
|
||||
|
||||
if (xd->mode_info_context->mbmi.ref_frame != INTRA_FRAME)
|
||||
{
|
||||
/* propagate errors from reference frames */
|
||||
xd->corrupted |= pc->yv12_fb[ref_fb_idx].corrupted;
|
||||
}
|
||||
|
||||
vp8_build_uvmvs(xd, pc->full_pixel);
|
||||
vp8mt_decode_macroblock(pbi, xd, mb_row, mb_col);
|
||||
|
||||
/* check if the boolean decoder has suffered an error */
|
||||
xd->corrupted |= vp8dx_bool_error(xd->current_bc);
|
||||
|
||||
if (pbi->common.filter_level)
|
||||
{
|
||||
/* Save decoded MB last row data for next-row decoding */
|
||||
|
|
|
@ -708,6 +708,25 @@ static vpx_codec_err_t vp8_get_last_ref_updates(vpx_codec_alg_priv_t *ctx,
|
|||
}
|
||||
|
||||
|
||||
static vpx_codec_err_t vp8_get_frame_corrupted(vpx_codec_alg_priv_t *ctx,
|
||||
int ctrl_id,
|
||||
va_list args)
|
||||
{
|
||||
|
||||
int *corrupted = va_arg(args, int *);
|
||||
|
||||
if (corrupted)
|
||||
{
|
||||
VP8D_COMP *pbi = (VP8D_COMP *)ctx->pbi;
|
||||
*corrupted = pbi->common.frame_to_show->corrupted;
|
||||
|
||||
return VPX_CODEC_OK;
|
||||
}
|
||||
else
|
||||
return VPX_CODEC_INVALID_PARAM;
|
||||
|
||||
}
|
||||
|
||||
vpx_codec_ctrl_fn_map_t vp8_ctf_maps[] =
|
||||
{
|
||||
{VP8_SET_REFERENCE, vp8_set_reference},
|
||||
|
@ -718,6 +737,7 @@ vpx_codec_ctrl_fn_map_t vp8_ctf_maps[] =
|
|||
{VP8_SET_DBG_COLOR_B_MODES, vp8_set_dbg_options},
|
||||
{VP8_SET_DBG_DISPLAY_MV, vp8_set_dbg_options},
|
||||
{VP8D_GET_LAST_REF_UPDATES, vp8_get_last_ref_updates},
|
||||
{VP8D_GET_FRAME_CORRUPTED, vp8_get_frame_corrupted},
|
||||
{ -1, NULL},
|
||||
};
|
||||
|
||||
|
|
|
@ -118,7 +118,9 @@ vpx_codec_err_t vpx_codec_decode(vpx_codec_ctx_t *ctx,
|
|||
{
|
||||
vpx_codec_err_t res;
|
||||
|
||||
if (!ctx || !data || !data_sz)
|
||||
/* Sanity checks */
|
||||
/* NULL data ptr allowed if data_sz is 0 too */
|
||||
if (!ctx || (!data && data_sz))
|
||||
res = VPX_CODEC_INVALID_PARAM;
|
||||
else if (!ctx->iface || !ctx->priv)
|
||||
res = VPX_CODEC_ERROR;
|
||||
|
|
|
@ -45,6 +45,7 @@ enum vp8d_dec_control_id
|
|||
VP8_DECODER_CTRL_ID_START = 256,
|
||||
VP8D_GET_LAST_REF_UPDATES, /**< control function to get info on which reference frames were updated
|
||||
by the last decode */
|
||||
VP8D_GET_FRAME_CORRUPTED, /**< check if the indicated frame is corrupted */
|
||||
VP8_DECODER_CTRL_ID_MAX
|
||||
} ;
|
||||
|
||||
|
@ -58,6 +59,7 @@ enum vp8d_dec_control_id
|
|||
|
||||
|
||||
VPX_CTRL_USE_TYPE(VP8D_GET_LAST_REF_UPDATES, int *)
|
||||
VPX_CTRL_USE_TYPE(VP8D_GET_FRAME_CORRUPTED, int *)
|
||||
|
||||
|
||||
/*! @} - end defgroup vp8_decoder */
|
||||
|
|
|
@ -81,6 +81,8 @@ vp8_yv12_alloc_frame_buffer(YV12_BUFFER_CONFIG *ybf, int width, int height, int
|
|||
|
||||
ybf->u_buffer = ybf->buffer_alloc + yplane_size + (border / 2 * ybf->uv_stride) + border / 2;
|
||||
ybf->v_buffer = ybf->buffer_alloc + yplane_size + uvplane_size + (border / 2 * ybf->uv_stride) + border / 2;
|
||||
|
||||
ybf->corrupted = 0; /* assume not currupted by errors */
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -57,6 +57,8 @@ extern "C"
|
|||
int border;
|
||||
int frame_size;
|
||||
YUV_TYPE clrtype;
|
||||
|
||||
int corrupted;
|
||||
} YV12_BUFFER_CONFIG;
|
||||
|
||||
int vp8_yv12_alloc_frame_buffer(YV12_BUFFER_CONFIG *ybf, int width, int height, int border);
|
||||
|
|
Загрузка…
Ссылка в новой задаче