Merge "Changing decoder input partition API to input fragments."

This commit is contained in:
John Koleszar 2011-11-04 09:36:27 -07:00 committed by Gerrit Code Review
commit 7ca6c91732
7 changed files with 221 additions and 232 deletions

View File

@ -33,7 +33,7 @@ extern "C"
int postprocess;
int max_threads;
int error_concealment;
int input_partition;
int input_fragments;
} VP8D_CONFIG;
typedef enum
{

View File

@ -416,49 +416,6 @@ static unsigned int read_partition_size(const unsigned char *cx_size)
return size;
}
static void setup_token_decoder_partition_input(VP8D_COMP *pbi)
{
vp8_reader *bool_decoder = &pbi->bc2;
int part_idx = 1;
int num_token_partitions;
TOKEN_PARTITION multi_token_partition =
(TOKEN_PARTITION)vp8_read_literal(&pbi->bc, 2);
if (!vp8dx_bool_error(&pbi->bc))
pbi->common.multi_token_partition = multi_token_partition;
num_token_partitions = 1 << pbi->common.multi_token_partition;
if (num_token_partitions + 1 > pbi->num_partitions)
vpx_internal_error(&pbi->common.error, VPX_CODEC_CORRUPT_FRAME,
"Partitions missing");
assert(vp8dx_bool_error(&pbi->bc) ||
multi_token_partition == pbi->common.multi_token_partition);
if (pbi->num_partitions > 2)
{
CHECK_MEM_ERROR(pbi->mbc, vpx_malloc((pbi->num_partitions - 1) *
sizeof(vp8_reader)));
bool_decoder = pbi->mbc;
}
for (; part_idx < pbi->num_partitions; ++part_idx)
{
if (vp8dx_start_decode(bool_decoder,
pbi->partitions[part_idx],
pbi->partition_sizes[part_idx]))
vpx_internal_error(&pbi->common.error, VPX_CODEC_MEM_ERROR,
"Failed to allocate bool decoder %d",
part_idx);
bool_decoder++;
}
#if CONFIG_MULTITHREAD
/* Clamp number of decoder threads */
if (pbi->decoding_thread_count > pbi->num_partitions - 1)
pbi->decoding_thread_count = pbi->num_partitions - 1;
#endif
}
static int read_is_valid(const unsigned char *start,
size_t len,
const unsigned char *end)
@ -466,94 +423,146 @@ static int read_is_valid(const unsigned char *start,
return (start + len > start && start + len <= end);
}
static unsigned int read_available_partition_size(
VP8D_COMP *pbi,
const unsigned char *token_part_sizes,
const unsigned char *fragment_start,
const unsigned char *first_fragment_end,
const unsigned char *fragment_end,
int i,
int num_part)
{
VP8_COMMON* pc = &pbi->common;
const unsigned char *partition_size_ptr = token_part_sizes + i * 3;
unsigned int partition_size;
ptrdiff_t bytes_left = fragment_end - fragment_start;
/* Calculate the length of this partition. The last partition
* size is implicit. If the partition size can't be read, then
* either use the remaining data in the buffer (for EC mode)
* or throw an error.
*/
if (i < num_part - 1)
{
if (read_is_valid(partition_size_ptr, 3, first_fragment_end))
partition_size = read_partition_size(partition_size_ptr);
else if (pbi->ec_active)
partition_size = bytes_left;
else
vpx_internal_error(&pc->error, VPX_CODEC_CORRUPT_FRAME,
"Truncated partition size data");
}
else
partition_size = bytes_left;
/* Validate the calculated partition length. If the buffer
* described by the partition can't be fully read, then restrict
* it to the portion that can be (for EC mode) or throw an error.
*/
if (!read_is_valid(fragment_start, partition_size, fragment_end))
{
if (pbi->ec_active)
partition_size = bytes_left;
else
vpx_internal_error(&pc->error, VPX_CODEC_CORRUPT_FRAME,
"Truncated packet or corrupt partition "
"%d length", i + 1);
}
return partition_size;
}
static void setup_token_decoder(VP8D_COMP *pbi,
const unsigned char *cx_data)
const unsigned char* token_part_sizes)
{
int num_part;
int i;
VP8_COMMON *pc = &pbi->common;
const unsigned char *user_data_end = pbi->Source + pbi->source_sz;
vp8_reader *bool_decoder;
const unsigned char *partition;
vp8_reader *bool_decoder = &pbi->bc2;
int fragment_idx, partition_idx;
int num_token_partitions;
const unsigned char *first_fragment_end = pbi->fragments[0] +
pbi->fragment_sizes[0];
/* Parse number of token partitions to use */
const TOKEN_PARTITION multi_token_partition =
TOKEN_PARTITION multi_token_partition =
(TOKEN_PARTITION)vp8_read_literal(&pbi->bc, 2);
/* Only update the multi_token_partition field if we are sure the value
* is correct. */
if (!pbi->ec_active || !vp8dx_bool_error(&pbi->bc))
pc->multi_token_partition = multi_token_partition;
num_part = 1 << pc->multi_token_partition;
/* Set up pointers to the first partition */
partition = cx_data;
bool_decoder = &pbi->bc2;
if (num_part > 1)
if (!vp8dx_bool_error(&pbi->bc))
pbi->common.multi_token_partition = multi_token_partition;
num_token_partitions = 1 << pbi->common.multi_token_partition;
if (num_token_partitions > 1)
{
CHECK_MEM_ERROR(pbi->mbc, vpx_malloc(num_part * sizeof(vp8_reader)));
CHECK_MEM_ERROR(pbi->mbc, vpx_malloc(num_token_partitions *
sizeof(vp8_reader)));
bool_decoder = pbi->mbc;
partition += 3 * (num_part - 1);
}
for (i = 0; i < num_part; i++)
/* Check for partitions within the fragments and unpack the fragments
* so that each fragment pointer points to its corresponding partition. */
for (fragment_idx = 0; fragment_idx < pbi->num_fragments; ++fragment_idx)
{
const unsigned char *partition_size_ptr = cx_data + i * 3;
ptrdiff_t partition_size, bytes_left;
bytes_left = user_data_end - partition;
/* Calculate the length of this partition. The last partition
* size is implicit. If the partition size can't be read, then
* either use the remaining data in the buffer (for EC mode)
* or throw an error.
*/
if (i < num_part - 1)
unsigned int fragment_size = pbi->fragment_sizes[fragment_idx];
const unsigned char *fragment_end = pbi->fragments[fragment_idx] +
fragment_size;
/* Special case for handling the first partition since we have already
* read its size. */
if (fragment_idx == 0)
{
if (read_is_valid(partition_size_ptr, 3, user_data_end))
partition_size = read_partition_size(partition_size_ptr);
else if (pbi->ec_active)
partition_size = bytes_left;
else
vpx_internal_error(&pc->error, VPX_CODEC_CORRUPT_FRAME,
"Truncated partition size data");
/* Size of first partition + token partition sizes element */
ptrdiff_t ext_first_part_size = token_part_sizes -
pbi->fragments[0] + 3 * (num_token_partitions - 1);
fragment_size -= ext_first_part_size;
if (fragment_size > 0)
{
pbi->fragment_sizes[0] = ext_first_part_size;
/* The fragment contains an additional partition. Move to
* next. */
fragment_idx++;
pbi->fragments[fragment_idx] = pbi->fragments[0] +
pbi->fragment_sizes[0];
}
}
else
partition_size = bytes_left;
/* Validate the calculated partition length. If the buffer
* described by the partition can't be fully read, then restrict
* it to the portion that can be (for EC mode) or throw an error.
*/
if (!read_is_valid(partition, partition_size, user_data_end))
/* Split the chunk into partitions read from the bitstream */
while (fragment_size > 0)
{
if (pbi->ec_active)
partition_size = bytes_left;
else
vpx_internal_error(&pc->error, VPX_CODEC_CORRUPT_FRAME,
"Truncated packet or corrupt partition "
"%d length", i + 1);
ptrdiff_t partition_size = read_available_partition_size(
pbi,
token_part_sizes,
pbi->fragments[fragment_idx],
first_fragment_end,
fragment_end,
fragment_idx - 1,
num_token_partitions);
pbi->fragment_sizes[fragment_idx] = partition_size;
fragment_size -= partition_size;
assert(fragment_idx <= num_token_partitions);
if (fragment_size > 0)
{
/* The fragment contains an additional partition.
* Move to next. */
fragment_idx++;
pbi->fragments[fragment_idx] =
pbi->fragments[fragment_idx - 1] + partition_size;
}
}
}
if (vp8dx_start_decode(bool_decoder, partition, partition_size))
vpx_internal_error(&pc->error, VPX_CODEC_MEM_ERROR,
"Failed to allocate bool decoder %d", i + 1);
pbi->num_fragments = num_token_partitions + 1;
for (partition_idx = 1; partition_idx < pbi->num_fragments; ++partition_idx)
{
if (vp8dx_start_decode(bool_decoder,
pbi->fragments[partition_idx],
pbi->fragment_sizes[partition_idx]))
vpx_internal_error(&pbi->common.error, VPX_CODEC_MEM_ERROR,
"Failed to allocate bool decoder %d",
partition_idx);
/* Advance to the next partition */
partition += partition_size;
bool_decoder++;
}
#if CONFIG_MULTITHREAD
/* Clamp number of decoder threads */
if (pbi->decoding_thread_count > num_part - 1)
pbi->decoding_thread_count = num_part - 1;
if (pbi->decoding_thread_count > num_token_partitions - 1)
pbi->decoding_thread_count = num_token_partitions - 1;
#endif
}
static void stop_token_decoder(VP8D_COMP *pbi)
{
VP8_COMMON *pc = &pbi->common;
@ -645,8 +654,8 @@ int vp8_decode_frame(VP8D_COMP *pbi)
vp8_reader *const bc = & pbi->bc;
VP8_COMMON *const pc = & pbi->common;
MACROBLOCKD *const xd = & pbi->mb;
const unsigned char *data = (const unsigned char *)pbi->Source;
const unsigned char *data_end = data + pbi->source_sz;
const unsigned char *data = pbi->fragments[0];
const unsigned char *data_end = data + pbi->fragment_sizes[0];
ptrdiff_t first_partition_length_in_bytes;
int mb_row;
@ -655,12 +664,6 @@ int vp8_decode_frame(VP8D_COMP *pbi)
int corrupt_tokens = 0;
int prev_independent_partitions = pbi->independent_partitions;
if (pbi->input_partition)
{
data = pbi->partitions[0];
data_end = data + pbi->partition_sizes[0];
}
/* start with no corruption of current frame */
xd->corrupted = 0;
pc->yv12_fb[pc->new_fb_idx].corrupted = 0;
@ -877,14 +880,8 @@ int vp8_decode_frame(VP8D_COMP *pbi)
}
}
if (pbi->input_partition)
{
setup_token_decoder_partition_input(pbi);
}
else
{
setup_token_decoder(pbi, data + first_partition_length_in_bytes);
}
setup_token_decoder(pbi, data + first_partition_length_in_bytes);
xd->current_bc = &pbi->bc2;
/* Read the default quantizers. */

View File

@ -108,7 +108,8 @@ VP8D_PTR vp8dx_create_decompressor(VP8D_CONFIG *oxcf)
pbi->decoded_key_frame = 0;
pbi->input_partition = oxcf->input_partition;
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
@ -319,115 +320,107 @@ int vp8dx_receive_compressed_data(VP8D_PTR ptr, unsigned long size, const unsign
pbi->common.error.error_code = VPX_CODEC_OK;
if (pbi->input_partition && !(source == NULL && size == 0))
if (pbi->num_fragments == 0)
{
/* Store a pointer to this partition and return. We haven't
/* New frame, reset fragment pointers and sizes */
vpx_memset(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_partitions < MAX_PARTITIONS);
pbi->partitions[pbi->num_partitions] = source;
pbi->partition_sizes[pbi->num_partitions] = size;
pbi->source_sz += size;
pbi->num_partitions++;
if (pbi->num_partitions > (1 << EIGHT_PARTITION) + 1)
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_partitions = 0;
pbi->num_fragments = 0;
return -1;
}
return 0;
}
else
if (!pbi->input_fragments)
{
if (!pbi->input_partition)
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->num_fragments <= 1 && pbi->fragment_sizes[0] == 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;
/* If error concealment is disabled we won't signal missing frames
* to the decoder.
*/
if (!pbi->ec_active)
{
pbi->Source = source;
pbi->source_sz = size;
}
else
{
assert(pbi->common.multi_token_partition <= EIGHT_PARTITION);
if (pbi->num_partitions == 0)
{
pbi->num_partitions = 1;
pbi->partitions[0] = NULL;
pbi->partition_sizes[0] = 0;
}
while (pbi->num_partitions < (1 << pbi->common.multi_token_partition) + 1)
{
// Reset all missing partitions
pbi->partitions[pbi->num_partitions] =
pbi->partitions[pbi->num_partitions - 1] +
pbi->partition_sizes[pbi->num_partitions - 1];
pbi->partition_sizes[pbi->num_partitions] = 0;
pbi->num_partitions++;
}
/* Signal that we have no frame to show. */
cm->show_frame = 0;
pbi->num_fragments = 0;
/* Nothing more to do. */
return 0;
}
}
if (pbi->source_sz == 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;
#if HAVE_ARMV7
#if CONFIG_RUNTIME_CPU_DETECT
if (cm->rtcd.flags & HAS_NEON)
#endif
{
vp8_push_neon(dx_store_reg);
}
#endif
/* If error concealment is disabled we won't signal missing frames to
* the decoder.
*/
if (!pbi->ec_active)
{
/* Signal that we have no frame to show. */
cm->show_frame = 0;
pbi->num_partitions = 0;
/* Nothing more to do. */
return 0;
}
}
cm->new_fb_idx = get_free_fb (cm);
if (setjmp(pbi->common.error.jmp))
{
#if HAVE_ARMV7
#if CONFIG_RUNTIME_CPU_DETECT
if (cm->rtcd.flags & HAS_NEON)
#endif
{
vp8_push_neon(dx_store_reg);
vp8_pop_neon(dx_store_reg);
}
#endif
pbi->common.error.setjmp = 0;
cm->new_fb_idx = get_free_fb (cm);
pbi->num_fragments = 0;
if (setjmp(pbi->common.error.jmp))
{
#if HAVE_ARMV7
#if CONFIG_RUNTIME_CPU_DETECT
if (cm->rtcd.flags & HAS_NEON)
#endif
{
vp8_pop_neon(dx_store_reg);
}
#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;
pbi->num_partitions = 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;
}
pbi->common.error.setjmp = 1;
if (cm->fb_idx_ref_cnt[cm->new_fb_idx] > 0)
cm->fb_idx_ref_cnt[cm->new_fb_idx]--;
return -1;
}
pbi->common.error.setjmp = 1;
retcode = vp8_decode_frame(pbi);
if (retcode < 0)
@ -442,7 +435,7 @@ int vp8dx_receive_compressed_data(VP8D_PTR ptr, unsigned long size, const unsign
#endif
pbi->common.error.error_code = VPX_CODEC_ERROR;
pbi->common.error.setjmp = 0;
pbi->num_partitions = 0;
pbi->num_fragments = 0;
if (cm->fb_idx_ref_cnt[cm->new_fb_idx] > 0)
cm->fb_idx_ref_cnt[cm->new_fb_idx]--;
return retcode;
@ -463,7 +456,7 @@ int vp8dx_receive_compressed_data(VP8D_PTR ptr, unsigned long size, const unsign
#endif
pbi->common.error.error_code = VPX_CODEC_ERROR;
pbi->common.error.setjmp = 0;
pbi->num_partitions = 0;
pbi->num_fragments = 0;
return -1;
}
} else
@ -481,7 +474,7 @@ int vp8dx_receive_compressed_data(VP8D_PTR ptr, unsigned long size, const unsign
#endif
pbi->common.error.error_code = VPX_CODEC_ERROR;
pbi->common.error.setjmp = 0;
pbi->num_partitions = 0;
pbi->num_fragments = 0;
return -1;
}
@ -500,7 +493,7 @@ int vp8dx_receive_compressed_data(VP8D_PTR ptr, unsigned long size, const unsign
/* swap the mode infos to storage for future error concealment */
if (pbi->ec_enabled && pbi->common.prev_mi)
{
const MODE_INFO* tmp = pbi->common.prev_mi;
MODE_INFO* tmp = pbi->common.prev_mi;
int row, col;
pbi->common.prev_mi = pbi->common.mi;
pbi->common.mi = tmp;
@ -525,8 +518,7 @@ int vp8dx_receive_compressed_data(VP8D_PTR ptr, unsigned long size, const unsign
pbi->ready_for_new_data = 0;
pbi->last_time_stamp = time_stamp;
pbi->num_partitions = 0;
pbi->source_sz = 0;
pbi->num_fragments = 0;
#if 0
{

View File

@ -54,11 +54,9 @@ typedef struct VP8Decompressor
VP8D_CONFIG oxcf;
const unsigned char *Source;
unsigned int source_sz;
const unsigned char *partitions[MAX_PARTITIONS];
unsigned int partition_sizes[MAX_PARTITIONS];
unsigned int num_partitions;
const unsigned char *fragments[MAX_PARTITIONS];
unsigned int fragment_sizes[MAX_PARTITIONS];
unsigned int num_fragments;
#if CONFIG_MULTITHREAD
/* variable for threading */
@ -112,7 +110,7 @@ typedef struct VP8Decompressor
#endif
int ec_enabled;
int ec_active;
int input_partition;
int input_fragments;
int decoded_key_frame;
int independent_partitions;
int frame_corrupt_residual;

View File

@ -398,8 +398,8 @@ 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_partition =
(ctx->base.init_flags & VPX_CODEC_USE_INPUT_PARTITION);
oxcf.input_fragments =
(ctx->base.init_flags & VPX_CODEC_USE_INPUT_FRAGMENTS);
optr = vp8dx_create_decompressor(&oxcf);
@ -741,7 +741,7 @@ CODEC_INTERFACE(vpx_codec_vp8_dx) =
"WebM Project VP8 Decoder" VERSION_STRING,
VPX_CODEC_INTERNAL_ABI_VERSION,
VPX_CODEC_CAP_DECODER | VP8_CAP_POSTPROC | VP8_CAP_ERROR_CONCEALMENT |
VPX_CODEC_CAP_INPUT_PARTITION,
VPX_CODEC_CAP_INPUT_FRAGMENTS,
/* vpx_codec_caps_t caps; */
vp8_init, /* vpx_codec_init_fn_t init; */
vp8_destroy, /* vpx_codec_destroy_fn_t destroy; */

View File

@ -39,8 +39,8 @@ vpx_codec_err_t vpx_codec_dec_init_ver(vpx_codec_ctx_t *ctx,
else if ((flags & VPX_CODEC_USE_ERROR_CONCEALMENT) &&
!(iface->caps & VPX_CODEC_CAP_ERROR_CONCEALMENT))
res = VPX_CODEC_INCAPABLE;
else if ((flags & VPX_CODEC_USE_INPUT_PARTITION) &&
!(iface->caps & VPX_CODEC_CAP_INPUT_PARTITION))
else if ((flags & VPX_CODEC_USE_INPUT_FRAGMENTS) &&
!(iface->caps & VPX_CODEC_CAP_INPUT_FRAGMENTS))
res = VPX_CODEC_INCAPABLE;
else if (!(iface->caps & VPX_CODEC_CAP_DECODER))
res = VPX_CODEC_INCAPABLE;

View File

@ -55,8 +55,8 @@ extern "C" {
#define VPX_CODEC_CAP_POSTPROC 0x40000 /**< Can postprocess decoded frame */
#define VPX_CODEC_CAP_ERROR_CONCEALMENT 0x80000 /**< Can conceal errors due to
packet loss */
#define VPX_CODEC_CAP_INPUT_PARTITION 0x100000 /**< Can receive encoded frames
one partition at a time */
#define VPX_CODEC_CAP_INPUT_FRAGMENTS 0x100000 /**< Can receive encoded frames
one fragment at a time */
/*! \brief Initialization-time Feature Enabling
*
@ -68,9 +68,9 @@ extern "C" {
#define VPX_CODEC_USE_POSTPROC 0x10000 /**< Postprocess decoded frame */
#define VPX_CODEC_USE_ERROR_CONCEALMENT 0x20000 /**< Conceal errors in decoded
frames */
#define VPX_CODEC_USE_INPUT_PARTITION 0x40000 /**< The input frame should be
#define VPX_CODEC_USE_INPUT_FRAGMENTS 0x40000 /**< The input frame should be
passed to the decoder one
partition at a time */
fragment at a time */
/*!\brief Stream properties
*
@ -189,11 +189,13 @@ extern "C" {
* generated, as appropriate. Encoded data \ref MUST be passed in DTS (decode
* time stamp) order. Frames produced will always be in PTS (presentation
* time stamp) order.
* If the decoder is configured with VPX_CODEC_USE_INPUT_PARTITION enabled,
* data and data_sz must contain at most one encoded partition. When no more
* data is available, this function should be called with NULL as data and 0
* as data_sz. The memory passed to this function must be available until
* the frame has been decoded.
* If the decoder is configured with VPX_CODEC_USE_INPUT_FRAGMENTS enabled,
* data and data_sz can contain a fragment of the encoded frame. Fragment #n
* must contain at least partition #n, but can also contain subsequent
* partitions (#n+1 - #n+i), and if so, fragments #n+1, .., #n+i must be
* empty. When no more data is available, this function should be called
* with NULL as data and 0 as data_sz. The memory passed to this function
* must be available until the frame has been decoded.
*
* \param[in] ctx Pointer to this instance's context
* \param[in] data Pointer to this block of new coded data. If