diff --git a/vp8/common/onyxc_int.h b/vp8/common/onyxc_int.h index 862307ebbd9c0d2a4c432f1a08555a84f653a8b3..d366b9b1be31eeb6987aaa276e52a7a89ce244cb 100644 --- a/vp8/common/onyxc_int.h +++ b/vp8/common/onyxc_int.h @@ -35,6 +35,8 @@ void vp8_initialize_common(void); #define NUM_YV12_BUFFERS 4 +#define MAX_PARTITIONS 9 + typedef struct frame_contexts { vp8_prob bmode_prob [VP8_BINTRAMODES-1]; diff --git a/vp8/common/onyxd.h b/vp8/common/onyxd.h index cf16a26da1ea95befbce07b771fce4ada67b311e..8a4703a8bae49b042fbcf6b23f23758a30f974f1 100644 --- a/vp8/common/onyxd.h +++ b/vp8/common/onyxd.h @@ -33,6 +33,7 @@ extern "C" int postprocess; int max_threads; int error_concealment; + int input_partition; } VP8D_CONFIG; typedef enum { diff --git a/vp8/decoder/decodframe.c b/vp8/decoder/decodframe.c index 00e001733f5dca1829a12f654727be5641a89a92..7537ec6488aa23218846f52d9b4262c9e7a2679b 100644 --- a/vp8/decoder/decodframe.c +++ b/vp8/decoder/decodframe.c @@ -463,6 +463,40 @@ 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; + + 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) @@ -619,13 +653,19 @@ int vp8_decode_frame(VP8D_COMP *pbi) 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; @@ -841,7 +881,14 @@ int vp8_decode_frame(VP8D_COMP *pbi) } } - 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. */ @@ -930,10 +977,8 @@ int vp8_decode_frame(VP8D_COMP *pbi) 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++) @@ -1021,7 +1066,6 @@ int vp8_decode_frame(VP8D_COMP *pbi) } } - stop_token_decoder(pbi); /* Collect information about decoder corruption. */ diff --git a/vp8/decoder/onyxd_if.c b/vp8/decoder/onyxd_if.c index 9de5ce2c4172e50a722fa11f0a837004d138d3d2..5f81ee6386afb15f6d04e878ebbfe45567d24c22 100644 --- a/vp8/decoder/onyxd_if.c +++ b/vp8/decoder/onyxd_if.c @@ -109,6 +109,8 @@ VP8D_PTR vp8dx_create_decompressor(VP8D_CONFIG *oxcf) pbi->ec_enabled = 0; #endif + pbi->input_partition = oxcf->input_partition; + return (VP8D_PTR) pbi; } @@ -312,68 +314,91 @@ int vp8dx_receive_compressed_data(VP8D_PTR ptr, unsigned long size, const unsign 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); @@ -473,6 +498,10 @@ 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; + if (pbi->input_partition) + pbi->common.multi_token_partition = 0; + pbi->source_sz = 0; #if 0 { diff --git a/vp8/decoder/onyxd_int.h b/vp8/decoder/onyxd_int.h index ea6de3dda30dc472efbf0985a3b2b33ee2d5f59b..be6ffe6bef3181fcd44aef5b5cc2f37c27805e0f 100644 --- a/vp8/decoder/onyxd_int.h +++ b/vp8/decoder/onyxd_int.h @@ -83,6 +83,9 @@ typedef struct VP8Decompressor 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 */ @@ -137,6 +140,7 @@ typedef struct VP8Decompressor unsigned int mvs_corrupt_from_mb; #endif int ec_enabled; + int input_partition; } VP8D_COMP; diff --git a/vp8/encoder/bitstream.c b/vp8/encoder/bitstream.c index 9280b618078811905196d4f02e2e815010dd7942..ac298126314e52a38e52f620048be6fb5683bdb1 100644 --- a/vp8/encoder/bitstream.c +++ b/vp8/encoder/bitstream.c @@ -377,6 +377,7 @@ static void pack_tokens_into_partitions_c(VP8_COMP *cpi, unsigned char *cx_data, 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++) @@ -573,6 +574,9 @@ static void pack_tokens_into_partitions_c(VP8_COMP *cpi, unsigned char *cx_data, 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); @@ -1840,6 +1844,7 @@ void vp8_pack_bitstream(VP8_COMP *cpi, unsigned char *dest, unsigned long *size) } *size = VP8_HEADER_SIZE + extra_bytes_packed + cpi->bc.pos; + cpi->partition_sz[0] = *size; if (pc->multi_token_partition != ONE_PARTITION) { @@ -1865,6 +1870,7 @@ void vp8_pack_bitstream(VP8_COMP *cpi, unsigned char *dest, unsigned long *size) vp8_stop_encode(&cpi->bc2); *size += cpi->bc2.pos; + cpi->partition_sz[1] = cpi->bc2.pos; } } diff --git a/vp8/encoder/onyx_int.h b/vp8/encoder/onyx_int.h index 3ca61a7cd71f6a48ade749bfe54e3680f962681f..d94436bd8dee34f9356a77cd10111ce66c7323ab 100644 --- a/vp8/encoder/onyx_int.h +++ b/vp8/encoder/onyx_int.h @@ -501,6 +501,7 @@ typedef struct VP8_COMP #endif TOKENLIST *tplist; + unsigned int partition_sz[MAX_PARTITIONS]; // end of multithread data @@ -604,6 +605,8 @@ typedef struct VP8_COMP 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; diff --git a/vp8/vp8_cx_iface.c b/vp8/vp8_cx_iface.c index db60bfe4fe1f94d797db26081e37c24d25d62bfb..5e1278a4c647042fdc91f34a46c7be3804b79990 100644 --- a/vp8/vp8_cx_iface.c +++ b/vp8/vp8_cx_iface.c @@ -731,6 +731,9 @@ static vpx_codec_err_t vp8e_encode(vpx_codec_alg_priv_t *ctx, 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; @@ -770,8 +773,6 @@ static vpx_codec_err_t vp8e_encode(vpx_codec_alg_priv_t *ctx, 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; @@ -797,11 +798,35 @@ static vpx_codec_err_t vp8e_encode(vpx_codec_alg_priv_t *ctx, 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; } } } @@ -1121,7 +1146,8 @@ CODEC_INTERFACE(vpx_codec_vp8_cx) = { "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; */ diff --git a/vp8/vp8_dx_iface.c b/vp8/vp8_dx_iface.c index d74dc87bcdc52c685a1832d648e59ad19115e6ce..58dc486dea8430e7538adda09542ffbffbc75ab2 100644 --- a/vp8/vp8_dx_iface.c +++ b/vp8/vp8_dx_iface.c @@ -368,6 +368,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); optr = vp8dx_create_decompressor(&oxcf); @@ -721,7 +723,8 @@ 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_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; */ diff --git a/vpx/vpx_encoder.h b/vpx/vpx_encoder.h index d168d5cfd5ca93cc09ea67175323f8651e776c3e..71153d55f5e820db42c92f308b1a6094e0d3f34f 100644 --- a/vpx/vpx_encoder.h +++ b/vpx/vpx_encoder.h @@ -163,6 +163,13 @@ extern "C" { 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