#define NUM_YV12_BUFFERS 4
+#define MAX_PARTITIONS 9
+
typedef struct frame_contexts
{
vp8_prob bmode_prob [VP8_BINTRAMODES-1];
int postprocess;
int max_threads;
int error_concealment;
+ int input_partition;
} VP8D_CONFIG;
typedef enum
{
return size;
}
+static void setup_token_decoder_partition_input(VP8D_COMP *pbi)
+{
+ vp8_reader *bool_decoder = &pbi->bc2;
+ int part_idx = 1;
+
+ TOKEN_PARTITION multi_token_partition =
+ (TOKEN_PARTITION)vp8_read_literal(&pbi->bc, 2);
+ 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 void setup_token_decoder(VP8D_COMP *pbi,
const unsigned char *cx_data)
VP8_COMMON *const pc = & pbi->common;
MACROBLOCKD *const xd = & pbi->mb;
const unsigned char *data = (const unsigned char *)pbi->Source;
- const unsigned char *const data_end = data + pbi->source_sz;
+ const unsigned char *data_end = data + pbi->source_sz;
ptrdiff_t first_partition_length_in_bytes;
int mb_row;
int i, j, k, l;
const int *const mb_feature_data_bits = vp8_mb_feature_data_bits;
+ 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;
}
}
- setup_token_decoder(pbi, data + first_partition_length_in_bytes);
+ if (pbi->input_partition)
+ {
+ setup_token_decoder_partition_input(pbi);
+ }
+ else
+ {
+ setup_token_decoder(pbi, data + first_partition_length_in_bytes);
+ }
xd->current_bc = &pbi->bc2;
/* Read the default quantizers. */
fclose(z);
}
-
{
/* read coef probability tree */
-
for (i = 0; i < BLOCK_TYPES; i++)
for (j = 0; j < COEF_BANDS; j++)
for (k = 0; k < PREV_COEF_CONTEXTS; k++)
}
}
-
stop_token_decoder(pbi);
/* Collect information about decoder corruption. */
pbi->ec_enabled = 0;
#endif
+ pbi->input_partition = oxcf->input_partition;
+
return (VP8D_PTR) pbi;
}
pbi->common.error.error_code = VPX_CODEC_OK;
- if (size == 0)
+ if (pbi->input_partition && !(source == NULL && 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;
-
- /* If error concealment is disabled we won't signal missing frames to
- * the decoder.
+ /* Store a pointer to this partition and return. We haven't
+ * received the complete frame yet, so we will wait with decoding.
*/
- if (!pbi->ec_enabled)
+ 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<<pbi->common.multi_token_partition) + 1)
+ pbi->common.multi_token_partition++;
+ if (pbi->common.multi_token_partition > EIGHT_PARTITION)
{
- /* Signal that we have no frame to show. */
- cm->show_frame = 0;
-
- /* Nothing more to do. */
- return 0;
+ pbi->common.error.error_code = VPX_CODEC_UNSUP_BITSTREAM;
+ pbi->common.error.setjmp = 0;
+ return -1;
}
+ return 0;
}
+ else
+ {
+ if (!pbi->input_partition)
+ {
+ pbi->Source = source;
+ pbi->source_sz = size;
+ }
+ 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 error concealment is disabled we won't signal missing frames to
+ * the decoder.
+ */
+ if (!pbi->ec_enabled)
+ {
+ /* 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)
+ if (cm->rtcd.flags & HAS_NEON)
#endif
- {
- vp8_push_neon(dx_store_reg);
- }
+ {
+ vp8_push_neon(dx_store_reg);
+ }
#endif
- cm->new_fb_idx = get_free_fb (cm);
+ cm->new_fb_idx = get_free_fb (cm);
- if (setjmp(pbi->common.error.jmp))
- {
+ if (setjmp(pbi->common.error.jmp))
+ {
#if HAVE_ARMV7
#if CONFIG_RUNTIME_CPU_DETECT
- if (cm->rtcd.flags & HAS_NEON)
+ if (cm->rtcd.flags & HAS_NEON)
#endif
- {
- vp8_pop_neon(dx_store_reg);
- }
+ {
+ 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->common.error.setjmp = 0;
- if (cm->fb_idx_ref_cnt[cm->new_fb_idx] > 0)
- cm->fb_idx_ref_cnt[cm->new_fb_idx]--;
- return -1;
- }
+ /* 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->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;
+ }
- /*cm->current_video_frame++;*/
- pbi->Source = source;
- pbi->source_sz = size;
+ pbi->common.error.setjmp = 1;
+ }
retcode = vp8_decode_frame(pbi);
pbi->ready_for_new_data = 0;
pbi->last_time_stamp = time_stamp;
+ pbi->num_partitions = 0;
+ if (pbi->input_partition)
+ pbi->common.multi_token_partition = 0;
+ pbi->source_sz = 0;
#if 0
{
const unsigned char *Source;
unsigned int source_sz;
+ const unsigned char *partitions[MAX_PARTITIONS];
+ unsigned int partition_sizes[MAX_PARTITIONS];
+ unsigned int num_partitions;
#if CONFIG_MULTITHREAD
/* variable for threading */
unsigned int mvs_corrupt_from_mb;
#endif
int ec_enabled;
+ int input_partition;
} VP8D_COMP;
unsigned int shift;
vp8_writer *w = &cpi->bc2;
*size = 3 * (num_part - 1);
+ cpi->partition_sz[0] += *size;
ptr = cx_data + (*size);
for (i = 0; i < num_part; i++)
vp8_stop_encode(w);
*size += w->pos;
+ /* The first partition size is set earlier */
+ cpi->partition_sz[i + 1] = w->pos;
+
if (i < (num_part - 1))
{
write_partition_size(cx_data, w->pos);
}
*size = VP8_HEADER_SIZE + extra_bytes_packed + cpi->bc.pos;
+ cpi->partition_sz[0] = *size;
if (pc->multi_token_partition != ONE_PARTITION)
{
vp8_stop_encode(&cpi->bc2);
*size += cpi->bc2.pos;
+ cpi->partition_sz[1] = cpi->bc2.pos;
}
}
#endif
TOKENLIST *tplist;
+ unsigned int partition_sz[MAX_PARTITIONS];
// end of multithread data
unsigned char *gf_active_flags;
int gf_active_count;
+ int output_partition;
+
//Store last frame's MV info for next frame MV prediction
int_mv *lfmv;
int *lf_ref_frame_sign_bias;
if (ctx->base.init_flags & VPX_CODEC_USE_PSNR)
((VP8_COMP *)ctx->cpi)->b_calculate_psnr = 1;
+ if (ctx->base.init_flags & VPX_CODEC_USE_OUTPUT_PARTITION)
+ ((VP8_COMP *)ctx->cpi)->output_partition = 1;
+
/* Convert API flags to internal codec lib flags */
lib_flags = (flags & VPX_EFLAG_FORCE_KF) ? FRAMEFLAGS_KEY : 0;
round = 1000000 * ctx->cfg.g_timebase.num / 2 - 1;
delta = (dst_end_time_stamp - dst_time_stamp);
pkt.kind = VPX_CODEC_CX_FRAME_PKT;
- pkt.data.frame.buf = cx_data;
- pkt.data.frame.sz = size;
pkt.data.frame.pts =
(dst_time_stamp * ctx->cfg.g_timebase.den + round)
/ ctx->cfg.g_timebase.num / 10000000;
pkt.data.frame.duration = 0;
}
- vpx_codec_pkt_list_add(&ctx->pkt_list.head, &pkt);
+ if (cpi->output_partition)
+ {
+ int i;
+ const int num_partitions =
+ (1 << cpi->common.multi_token_partition) + 1;
+ for (i = 0; i < num_partitions; ++i)
+ {
+ pkt.data.frame.buf = cx_data;
+ pkt.data.frame.sz = cpi->partition_sz[i];
+ pkt.data.frame.partition_id = i;
+ /* don't set the fragment bit for the last partition */
+ if (i < num_partitions - 1)
+ pkt.data.frame.flags |= VPX_FRAME_IS_FRAGMENT;
+ vpx_codec_pkt_list_add(&ctx->pkt_list.head, &pkt);
+ cx_data += cpi->partition_sz[i];
+ cx_data_sz -= cpi->partition_sz[i];
+ }
+ }
+ else
+ {
+ pkt.data.frame.buf = cx_data;
+ pkt.data.frame.sz = size;
+ pkt.data.frame.partition_id = -1;
+ vpx_codec_pkt_list_add(&ctx->pkt_list.head, &pkt);
+ cx_data += size;
+ cx_data_sz -= size;
+ }
//printf("timestamp: %lld, duration: %d\n", pkt->data.frame.pts, pkt->data.frame.duration);
- cx_data += size;
- cx_data_sz -= size;
}
}
}
{
"WebM Project VP8 Encoder" VERSION_STRING,
VPX_CODEC_INTERNAL_ABI_VERSION,
- VPX_CODEC_CAP_ENCODER | VPX_CODEC_CAP_PSNR,
+ VPX_CODEC_CAP_ENCODER | VPX_CODEC_CAP_PSNR |
+ VPX_CODEC_CAP_OUTPUT_PARTITION,
/* vpx_codec_caps_t caps; */
vp8e_init, /* vpx_codec_init_fn_t init; */
vp8e_destroy, /* vpx_codec_destroy_fn_t destroy; */
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);
optr = vp8dx_create_decompressor(&oxcf);
{
"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_DECODER | VP8_CAP_POSTPROC | VP8_CAP_ERROR_CONCEALMENT |
+ VPX_CODEC_CAP_INPUT_PARTITION,
/* vpx_codec_caps_t caps; */
vp8_init, /* vpx_codec_init_fn_t init; */
vp8_destroy, /* vpx_codec_destroy_fn_t destroy; */
unsigned long duration; /**< duration to show frame
(in timebase units) */
vpx_codec_frame_flags_t flags; /**< flags for this frame */
+ int partition_id; /**< the partition id
+ defines the decoding order
+ of the partitions. Only
+ applicable when "output partition"
+ mode is enabled. First partition
+ has id 0.*/
+
} frame; /**< data for compressed frame packet */
struct vpx_fixed_buf twopass_stats; /**< data for two-pass packet */
struct vpx_psnr_pkt