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:
Родитель
08b43fef3a
Коммит
64bcffc1ec
|
@ -42,7 +42,7 @@ extern "C"
|
||||||
void vp9_initialize_dec(void);
|
void vp9_initialize_dec(void);
|
||||||
|
|
||||||
int vp9_receive_compressed_data(VP9D_PTR comp, unsigned long size,
|
int vp9_receive_compressed_data(VP9D_PTR comp, unsigned long size,
|
||||||
const unsigned char *dest,
|
const unsigned char **dest,
|
||||||
int64_t time_stamp);
|
int64_t time_stamp);
|
||||||
|
|
||||||
int vp9_get_raw_frame(VP9D_PTR comp, YV12_BUFFER_CONFIG *sd,
|
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;
|
BOOL_DECODER header_bc, residual_bc;
|
||||||
VP9_COMMON *const pc = &pbi->common;
|
VP9_COMMON *const pc = &pbi->common;
|
||||||
MACROBLOCKD *const xd = &pbi->mb;
|
MACROBLOCKD *const xd = &pbi->mb;
|
||||||
|
@ -1422,5 +1422,12 @@ int vp9_decode_frame(VP9D_COMP *pbi) {
|
||||||
#endif
|
#endif
|
||||||
// printf("Frame %d Done\n", frame_count++);
|
// 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;
|
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,
|
int vp9_receive_compressed_data(VP9D_PTR ptr, unsigned long size,
|
||||||
const unsigned char *source,
|
const unsigned char **psource,
|
||||||
int64_t time_stamp) {
|
int64_t time_stamp) {
|
||||||
#if HAVE_ARMV7
|
#if HAVE_ARMV7
|
||||||
int64_t dx_store_reg[8];
|
int64_t dx_store_reg[8];
|
||||||
#endif
|
#endif
|
||||||
VP9D_COMP *pbi = (VP9D_COMP *) ptr;
|
VP9D_COMP *pbi = (VP9D_COMP *) ptr;
|
||||||
VP9_COMMON *cm = &pbi->common;
|
VP9_COMMON *cm = &pbi->common;
|
||||||
|
const unsigned char *source = *psource;
|
||||||
int retcode = 0;
|
int retcode = 0;
|
||||||
|
|
||||||
/*if(pbi->ready_for_new_data == 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;
|
pbi->common.error.setjmp = 1;
|
||||||
|
|
||||||
retcode = vp9_decode_frame(pbi);
|
retcode = vp9_decode_frame(pbi, psource);
|
||||||
|
|
||||||
if (retcode < 0) {
|
if (retcode < 0) {
|
||||||
#if HAVE_ARMV7
|
#if HAVE_ARMV7
|
||||||
|
|
|
@ -83,7 +83,7 @@ typedef struct VP9Decompressor {
|
||||||
|
|
||||||
} VP9D_COMP;
|
} 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
|
#if CONFIG_DEBUG
|
||||||
|
|
|
@ -77,8 +77,8 @@ struct vpx_codec_alg_priv {
|
||||||
VP9_PTR cpi;
|
VP9_PTR cpi;
|
||||||
unsigned char *cx_data;
|
unsigned char *cx_data;
|
||||||
unsigned int cx_data_sz;
|
unsigned int cx_data_sz;
|
||||||
unsigned char *altref_cx_data;
|
unsigned char *pending_cx_data;
|
||||||
unsigned int altref_size;
|
unsigned int pending_cx_data_sz;
|
||||||
vpx_image_t preview_img;
|
vpx_image_t preview_img;
|
||||||
unsigned int next_frame_flag;
|
unsigned int next_frame_flag;
|
||||||
vp8_postproc_cfg_t preview_ppcfg;
|
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,
|
static vpx_codec_err_t vp8e_encode(vpx_codec_alg_priv_t *ctx,
|
||||||
const vpx_image_t *img,
|
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;
|
ctx->next_frame_flag = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cx_data = ctx->cx_data;
|
||||||
|
cx_data_sz = ctx->cx_data_sz;
|
||||||
lib_flags = 0;
|
lib_flags = 0;
|
||||||
|
|
||||||
if (ctx->altref_size) {
|
/* Any pending invisible frames? */
|
||||||
cx_data = ctx->altref_cx_data + ctx->altref_size;
|
if (ctx->pending_cx_data) {
|
||||||
cx_data_sz = ctx->cx_data_sz - ctx->altref_size;
|
memmove(cx_data, ctx->pending_cx_data, ctx->pending_cx_data_sz);
|
||||||
} else {
|
ctx->pending_cx_data = cx_data;
|
||||||
cx_data = ctx->cx_data;
|
cx_data += ctx->pending_cx_data_sz;
|
||||||
cx_data_sz = ctx->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 &&
|
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;
|
vpx_codec_cx_pkt_t pkt;
|
||||||
VP9_COMP *cpi = (VP9_COMP *)ctx->cpi;
|
VP9_COMP *cpi = (VP9_COMP *)ctx->cpi;
|
||||||
|
|
||||||
/* TODO(jkoleszar): for now we append lengths to all frames, revisit
|
/* Pack invisible frames with the next visisble frame */
|
||||||
* this later to ensure if this is necessary */
|
|
||||||
append_length(cx_data + size, &size);
|
|
||||||
|
|
||||||
if (!cpi->common.show_frame) {
|
if (!cpi->common.show_frame) {
|
||||||
ctx->altref_cx_data = cx_data;
|
if (!ctx->pending_cx_data)
|
||||||
ctx->altref_size = size;
|
ctx->pending_cx_data = cx_data;
|
||||||
|
ctx->pending_cx_data_sz += size;
|
||||||
cx_data += size;
|
cx_data += size;
|
||||||
cx_data_sz -= size;
|
cx_data_sz -= size;
|
||||||
continue;
|
continue;
|
||||||
|
@ -777,14 +772,14 @@ static vpx_codec_err_t vp8e_encode(vpx_codec_alg_priv_t *ctx,
|
||||||
}
|
}
|
||||||
else*/
|
else*/
|
||||||
{
|
{
|
||||||
if (ctx->altref_size) {
|
if (ctx->pending_cx_data) {
|
||||||
pkt.data.frame.sz = ctx->altref_size + size;
|
pkt.data.frame.buf = ctx->pending_cx_data;
|
||||||
pkt.data.frame.buf = ctx->altref_cx_data;
|
pkt.data.frame.sz = ctx->pending_cx_data_sz + size;
|
||||||
ctx->altref_size = 0;
|
ctx->pending_cx_data = NULL;
|
||||||
ctx->altref_cx_data = NULL;
|
ctx->pending_cx_data_sz = 0;
|
||||||
} else {
|
} else {
|
||||||
pkt.data.frame.buf = cx_data;
|
pkt.data.frame.buf = cx_data;
|
||||||
pkt.data.frame.sz = size;
|
pkt.data.frame.sz = size;
|
||||||
}
|
}
|
||||||
pkt.data.frame.partition_id = -1;
|
pkt.data.frame.partition_id = -1;
|
||||||
vpx_codec_pkt_list_add(&ctx->pkt_list.head, &pkt);
|
vpx_codec_pkt_list_add(&ctx->pkt_list.head, &pkt);
|
||||||
|
|
|
@ -303,11 +303,11 @@ static void yuvconfig2image(vpx_image_t *img,
|
||||||
img->self_allocd = 0;
|
img->self_allocd = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static vpx_codec_err_t vp8_decode(vpx_codec_alg_priv_t *ctx,
|
static vpx_codec_err_t decode_one(vpx_codec_alg_priv_t *ctx,
|
||||||
const uint8_t *data,
|
const uint8_t **data,
|
||||||
unsigned int data_sz,
|
unsigned int data_sz,
|
||||||
void *user_priv,
|
void *user_priv,
|
||||||
long deadline) {
|
long deadline) {
|
||||||
vpx_codec_err_t res = VPX_CODEC_OK;
|
vpx_codec_err_t res = VPX_CODEC_OK;
|
||||||
|
|
||||||
ctx->img_avail = 0;
|
ctx->img_avail = 0;
|
||||||
|
@ -317,7 +317,7 @@ static vpx_codec_err_t vp8_decode(vpx_codec_alg_priv_t *ctx,
|
||||||
* of the heap.
|
* of the heap.
|
||||||
*/
|
*/
|
||||||
if (!ctx->si.h)
|
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 */
|
/* Perform deferred allocations, if required */
|
||||||
|
@ -424,6 +424,33 @@ static vpx_codec_err_t vp8_decode(vpx_codec_alg_priv_t *ctx,
|
||||||
return res;
|
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,
|
static vpx_image_t *vp8_get_frame(vpx_codec_alg_priv_t *ctx,
|
||||||
vpx_codec_iter_t *iter) {
|
vpx_codec_iter_t *iter) {
|
||||||
vpx_image_t *img = NULL;
|
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_peek_si, /* vpx_codec_peek_si_fn_t peek_si; */
|
||||||
vp8_get_si, /* vpx_codec_get_si_fn_t get_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; */
|
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);
|
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,
|
vpx_codec_err_t vpx_codec_decode(vpx_codec_ctx_t *ctx,
|
||||||
const uint8_t *data,
|
const uint8_t *data,
|
||||||
|
@ -139,11 +116,6 @@ vpx_codec_err_t vpx_codec_decode(vpx_codec_ctx_t *ctx,
|
||||||
void *user_priv,
|
void *user_priv,
|
||||||
long deadline) {
|
long deadline) {
|
||||||
vpx_codec_err_t res;
|
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 */
|
/* Sanity checks */
|
||||||
/* NULL data ptr allowed if data_sz is 0 too */
|
/* 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)
|
else if (!ctx->iface || !ctx->priv)
|
||||||
res = VPX_CODEC_ERROR;
|
res = VPX_CODEC_ERROR;
|
||||||
else {
|
else {
|
||||||
do {
|
res = ctx->iface->dec.decode(ctx->priv->alg_priv, data, data_sz,
|
||||||
altref_frame = !(*cx_data & 0x10);
|
user_priv, deadline);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return SAVE_STATUS(ctx, res);
|
return SAVE_STATUS(ctx, res);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче