Pack invisible frames without lengths

Modify the decoder to return the ending position of the bool decoder and
use that as the starting position for the next frame.

The constant-space algorithm for parsing the appended frame lengths is
O(n^2), which is a potential DoS concern if n is unbounded. Revisit
the appended lengths for use as partition lengths when multipartition
support is added.

In addition, this allows decoding of raw streams outside of a container
without additional framing information, though it's insufficient to
be able to remux said stream into a container.

Change-Id: I71e801a9c3e37abe559a56a597635b0cbae1934b
This commit is contained in:
John Koleszar 2012-11-15 12:19:07 -08:00
Родитель 08b43fef3a
Коммит 64bcffc1ec
7 изменённых файлов: 77 добавлений и 85 удалений

Просмотреть файл

@ -42,7 +42,7 @@ extern "C"
void vp9_initialize_dec(void);
int vp9_receive_compressed_data(VP9D_PTR comp, unsigned long size,
const unsigned char *dest,
const unsigned char **dest,
int64_t time_stamp);
int vp9_get_raw_frame(VP9D_PTR comp, YV12_BUFFER_CONFIG *sd,

Просмотреть файл

@ -985,7 +985,7 @@ static void read_coef_probs(VP9D_COMP *pbi, BOOL_DECODER* const bc) {
}
}
int vp9_decode_frame(VP9D_COMP *pbi) {
int vp9_decode_frame(VP9D_COMP *pbi, const unsigned char **p_data_end) {
BOOL_DECODER header_bc, residual_bc;
VP9_COMMON *const pc = &pbi->common;
MACROBLOCKD *const xd = &pbi->mb;
@ -1422,5 +1422,12 @@ int vp9_decode_frame(VP9D_COMP *pbi) {
#endif
// printf("Frame %d Done\n", frame_count++);
/* Find the end of the coded buffer */
while (residual_bc.count > CHAR_BIT
&& residual_bc.count < VP9_BD_VALUE_SIZE) {
residual_bc.count -= CHAR_BIT;
residual_bc.user_buffer--;
}
*p_data_end = residual_bc.user_buffer;
return 0;
}

Просмотреть файл

@ -315,13 +315,14 @@ static int swap_frame_buffers(VP9_COMMON *cm) {
}
int vp9_receive_compressed_data(VP9D_PTR ptr, unsigned long size,
const unsigned char *source,
const unsigned char **psource,
int64_t time_stamp) {
#if HAVE_ARMV7
int64_t dx_store_reg[8];
#endif
VP9D_COMP *pbi = (VP9D_COMP *) ptr;
VP9_COMMON *cm = &pbi->common;
const unsigned char *source = *psource;
int retcode = 0;
/*if(pbi->ready_for_new_data == 0)
@ -380,7 +381,7 @@ int vp9_receive_compressed_data(VP9D_PTR ptr, unsigned long size,
pbi->common.error.setjmp = 1;
retcode = vp9_decode_frame(pbi);
retcode = vp9_decode_frame(pbi, psource);
if (retcode < 0) {
#if HAVE_ARMV7

Просмотреть файл

@ -83,7 +83,7 @@ typedef struct VP9Decompressor {
} VP9D_COMP;
int vp9_decode_frame(VP9D_COMP *cpi);
int vp9_decode_frame(VP9D_COMP *cpi, const unsigned char **p_data_end);
#if CONFIG_DEBUG

Просмотреть файл

@ -77,8 +77,8 @@ struct vpx_codec_alg_priv {
VP9_PTR cpi;
unsigned char *cx_data;
unsigned int cx_data_sz;
unsigned char *altref_cx_data;
unsigned int altref_size;
unsigned char *pending_cx_data;
unsigned int pending_cx_data_sz;
vpx_image_t preview_img;
unsigned int next_frame_flag;
vp8_postproc_cfg_t preview_ppcfg;
@ -577,19 +577,6 @@ static void pick_quickcompress_mode(vpx_codec_alg_priv_t *ctx,
}
}
static void append_length(unsigned char* cx_data, unsigned long int *cx_size) {
unsigned char chunk;
unsigned int offset = 0;
unsigned long int size = *cx_size;
do {
chunk = size & 0x7F;
size >>= 7;
chunk |= (offset == 0) << 7;
cx_data[offset] = chunk;
offset++;
} while (size);
*cx_size += offset;
}
static vpx_codec_err_t vp8e_encode(vpx_codec_alg_priv_t *ctx,
const vpx_image_t *img,
@ -693,14 +680,24 @@ static vpx_codec_err_t vp8e_encode(vpx_codec_alg_priv_t *ctx,
ctx->next_frame_flag = 0;
}
lib_flags = 0;
if (ctx->altref_size) {
cx_data = ctx->altref_cx_data + ctx->altref_size;
cx_data_sz = ctx->cx_data_sz - ctx->altref_size;
} else {
cx_data = ctx->cx_data;
cx_data_sz = ctx->cx_data_sz;
lib_flags = 0;
/* Any pending invisible frames? */
if (ctx->pending_cx_data) {
memmove(cx_data, ctx->pending_cx_data, ctx->pending_cx_data_sz);
ctx->pending_cx_data = cx_data;
cx_data += ctx->pending_cx_data_sz;
cx_data_sz -= ctx->pending_cx_data_sz;
/* TODO: this is a minimal check, the underlying codec doesn't respect
* the buffer size anyway.
*/
if (cx_data_sz < ctx->cx_data_sz / 2) {
ctx->base.err_detail = "Compressed data buffer too small";
return VPX_CODEC_ERROR;
}
}
while (cx_data_sz >= ctx->cx_data_sz / 2 &&
@ -712,13 +709,11 @@ static vpx_codec_err_t vp8e_encode(vpx_codec_alg_priv_t *ctx,
vpx_codec_cx_pkt_t pkt;
VP9_COMP *cpi = (VP9_COMP *)ctx->cpi;
/* TODO(jkoleszar): for now we append lengths to all frames, revisit
* this later to ensure if this is necessary */
append_length(cx_data + size, &size);
/* Pack invisible frames with the next visisble frame */
if (!cpi->common.show_frame) {
ctx->altref_cx_data = cx_data;
ctx->altref_size = size;
if (!ctx->pending_cx_data)
ctx->pending_cx_data = cx_data;
ctx->pending_cx_data_sz += size;
cx_data += size;
cx_data_sz -= size;
continue;
@ -777,11 +772,11 @@ static vpx_codec_err_t vp8e_encode(vpx_codec_alg_priv_t *ctx,
}
else*/
{
if (ctx->altref_size) {
pkt.data.frame.sz = ctx->altref_size + size;
pkt.data.frame.buf = ctx->altref_cx_data;
ctx->altref_size = 0;
ctx->altref_cx_data = NULL;
if (ctx->pending_cx_data) {
pkt.data.frame.buf = ctx->pending_cx_data;
pkt.data.frame.sz = ctx->pending_cx_data_sz + size;
ctx->pending_cx_data = NULL;
ctx->pending_cx_data_sz = 0;
} else {
pkt.data.frame.buf = cx_data;
pkt.data.frame.sz = size;

Просмотреть файл

@ -303,8 +303,8 @@ static void yuvconfig2image(vpx_image_t *img,
img->self_allocd = 0;
}
static vpx_codec_err_t vp8_decode(vpx_codec_alg_priv_t *ctx,
const uint8_t *data,
static vpx_codec_err_t decode_one(vpx_codec_alg_priv_t *ctx,
const uint8_t **data,
unsigned int data_sz,
void *user_priv,
long deadline) {
@ -317,7 +317,7 @@ static vpx_codec_err_t vp8_decode(vpx_codec_alg_priv_t *ctx,
* of the heap.
*/
if (!ctx->si.h)
res = ctx->base.iface->dec.peek_si(data, data_sz, &ctx->si);
res = ctx->base.iface->dec.peek_si(*data, data_sz, &ctx->si);
/* Perform deferred allocations, if required */
@ -424,6 +424,33 @@ static vpx_codec_err_t vp8_decode(vpx_codec_alg_priv_t *ctx,
return res;
}
static vpx_codec_err_t vp9_decode(vpx_codec_alg_priv_t *ctx,
const uint8_t *data,
unsigned int data_sz,
void *user_priv,
long deadline) {
const uint8_t *data_start = data;
const uint8_t *data_end = data + data_sz;
vpx_codec_err_t res;
do {
res = decode_one(ctx, &data_start, data_sz, user_priv, deadline);
assert(data_start >= data);
assert(data_start <= data_end);
/* Early exit if there was a decode error */
if (res)
break;
/* Account for suboptimal termination by the encoder. */
while (data_start < data_end && *data_start == 0)
data_start++;
data_sz = data_end - data_start;
} while (data_start < data_end);
return res;
}
static vpx_image_t *vp8_get_frame(vpx_codec_alg_priv_t *ctx,
vpx_codec_iter_t *iter) {
vpx_image_t *img = NULL;
@ -672,7 +699,7 @@ CODEC_INTERFACE(vpx_codec_vp9_dx) = {
{
vp8_peek_si, /* vpx_codec_peek_si_fn_t peek_si; */
vp8_get_si, /* vpx_codec_get_si_fn_t get_si; */
vp8_decode, /* vpx_codec_decode_fn_t decode; */
vp9_decode, /* vpx_codec_decode_fn_t decode; */
vp8_get_frame, /* vpx_codec_frame_get_fn_t frame_get; */
},
{

Просмотреть файл

@ -109,29 +109,6 @@ vpx_codec_err_t vpx_codec_get_stream_info(vpx_codec_ctx_t *ctx,
return SAVE_STATUS(ctx, res);
}
static int read_frame_length(const uint8_t *data, uint64_t size,
uint64_t *frame_length, int *size_length) {
uint64_t value = 0;
*size_length = 0;
do {
uint64_t index;
size -= value + *size_length;
index = size - 1;
value = 0;
do {
if (data + index < data) {
*frame_length = -1;
return -1;
}
value <<= 7;
value |= (data[index] & 0x7F);
} while (!(data[index--] >> 7));
*size_length = size - 1 - index;
} while (value + *size_length < size);
*frame_length = value;
return 0;
}
vpx_codec_err_t vpx_codec_decode(vpx_codec_ctx_t *ctx,
const uint8_t *data,
@ -139,11 +116,6 @@ vpx_codec_err_t vpx_codec_decode(vpx_codec_ctx_t *ctx,
void *user_priv,
long deadline) {
vpx_codec_err_t res;
int offset = 0;
uint64_t length = 0;
unsigned char altref_frame;
unsigned int cx_size = data_sz;
uint8_t *cx_data = data;
/* Sanity checks */
/* NULL data ptr allowed if data_sz is 0 too */
@ -152,18 +124,8 @@ vpx_codec_err_t vpx_codec_decode(vpx_codec_ctx_t *ctx,
else if (!ctx->iface || !ctx->priv)
res = VPX_CODEC_ERROR;
else {
do {
altref_frame = !(*cx_data & 0x10);
res = read_frame_length(cx_data, cx_size, &length, &offset);
if (res != 0)
return SAVE_STATUS(ctx, VPX_CODEC_UNSUP_BITSTREAM);
res = ctx->iface->dec.decode(ctx->priv->alg_priv, cx_data,
length, user_priv, deadline);
if (res != 0)
return SAVE_STATUS(ctx, res);
cx_data += offset + length;
cx_size -= offset + length;
} while (cx_data - data <= data_sz && altref_frame);
res = ctx->iface->dec.decode(ctx->priv->alg_priv, data, data_sz,
user_priv, deadline);
}
return SAVE_STATUS(ctx, res);