diff --git a/test/svc_test.cc b/test/svc_test.cc index 3ddd9c145..75659d50d 100644 --- a/test/svc_test.cc +++ b/test/svc_test.cc @@ -234,7 +234,7 @@ TEST_F(SvcTest, FirstFrameHasLayers) { video.Begin(); res = vpx_svc_encode(&svc_, &codec_, video.img(), video.pts(), - video.duration(), VPX_DL_REALTIME); + video.duration(), VPX_DL_GOOD_QUALITY); EXPECT_EQ(VPX_CODEC_OK, res); const vpx_codec_err_t res_dec = decoder_->DecodeFrame( @@ -262,7 +262,7 @@ TEST_F(SvcTest, EncodeThreeFrames) { video.Begin(); // This frame is a keyframe. res = vpx_svc_encode(&svc_, &codec_, video.img(), video.pts(), - video.duration(), VPX_DL_REALTIME); + video.duration(), VPX_DL_GOOD_QUALITY); ASSERT_EQ(VPX_CODEC_OK, res); EXPECT_EQ(1, vpx_svc_is_keyframe(&svc_)); @@ -275,7 +275,7 @@ TEST_F(SvcTest, EncodeThreeFrames) { video.Next(); // This is a P-frame. res = vpx_svc_encode(&svc_, &codec_, video.img(), video.pts(), - video.duration(), VPX_DL_REALTIME); + video.duration(), VPX_DL_GOOD_QUALITY); ASSERT_EQ(VPX_CODEC_OK, res); EXPECT_EQ(0, vpx_svc_is_keyframe(&svc_)); @@ -288,7 +288,7 @@ TEST_F(SvcTest, EncodeThreeFrames) { video.Next(); // This is a P-frame. res = vpx_svc_encode(&svc_, &codec_, video.img(), video.pts(), - video.duration(), VPX_DL_REALTIME); + video.duration(), VPX_DL_GOOD_QUALITY); ASSERT_EQ(VPX_CODEC_OK, res); EXPECT_EQ(0, vpx_svc_is_keyframe(&svc_)); diff --git a/vp9/common/vp9_onyx.h b/vp9/common/vp9_onyx.h index 9df76ded3..564e4195f 100644 --- a/vp9/common/vp9_onyx.h +++ b/vp9/common/vp9_onyx.h @@ -55,6 +55,7 @@ extern "C" { MODE_FIRSTPASS = 0x3, MODE_SECONDPASS = 0x4, MODE_SECONDPASS_BEST = 0x5, + MODE_REALTIME = 0x6, } MODE; typedef enum { diff --git a/vp9/encoder/vp9_encodeframe.c b/vp9/encoder/vp9_encodeframe.c index 6a8a34c21..35aa45fe7 100644 --- a/vp9/encoder/vp9_encodeframe.c +++ b/vp9/encoder/vp9_encodeframe.c @@ -1031,131 +1031,171 @@ static int sb_has_motion(const VP9_COMMON *cm, MODE_INFO **prev_mi_8x8) { } return 0; } - -// TODO(jingning) This currently serves as a test framework for non-RD mode -// decision. To be continued on optimizing the partition type decisions. -static void pick_partition_type(VP9_COMP *cpi, - const TileInfo *const tile, - MODE_INFO **mi_8x8, TOKENEXTRA **tp, - int mi_row, int mi_col, - BLOCK_SIZE bsize, int *rate, int64_t *dist, - int do_recon) { +static void update_state_rt(VP9_COMP *cpi, PICK_MODE_CONTEXT *ctx, + BLOCK_SIZE bsize, int output_enabled) { + int i; VP9_COMMON *const cm = &cpi->common; MACROBLOCK *const x = &cpi->mb; - const int mi_stride = cm->mode_info_stride; - const int num_8x8_subsize = (num_8x8_blocks_wide_lookup[bsize] >> 1); - int i; - PARTITION_TYPE partition = PARTITION_NONE; - BLOCK_SIZE subsize; - BLOCK_SIZE bs_type = mi_8x8[0]->mbmi.sb_type; - int sub_rate[4] = {0}; - int64_t sub_dist[4] = {0}; - int mi_offset; + MACROBLOCKD *const xd = &x->e_mbd; + struct macroblock_plane *const p = x->plane; + struct macroblockd_plane *const pd = xd->plane; + MB_MODE_INFO *const mbmi = &xd->mi_8x8[0]->mbmi; - if (mi_row >= cm->mi_rows || mi_col >= cm->mi_cols) - return; + const int mb_mode_index = ctx->best_mode_index; + int max_plane; - partition = partition_lookup[b_width_log2(bsize)][bs_type]; - subsize = get_subsize(bsize, partition); + max_plane = is_inter_block(mbmi) ? MAX_MB_PLANE : 1; + for (i = 0; i < max_plane; ++i) { + p[i].coeff = ctx->coeff_pbuf[i][1]; + p[i].qcoeff = ctx->qcoeff_pbuf[i][1]; + pd[i].dqcoeff = ctx->dqcoeff_pbuf[i][1]; + p[i].eobs = ctx->eobs_pbuf[i][1]; + } + + for (i = max_plane; i < MAX_MB_PLANE; ++i) { + p[i].coeff = ctx->coeff_pbuf[i][2]; + p[i].qcoeff = ctx->qcoeff_pbuf[i][2]; + pd[i].dqcoeff = ctx->dqcoeff_pbuf[i][2]; + p[i].eobs = ctx->eobs_pbuf[i][2]; + } + + x->skip = ctx->skip; + + if (frame_is_intra_only(cm)) { +#if CONFIG_INTERNAL_STATS + static const int kf_mode_index[] = { + THR_DC /*DC_PRED*/, + THR_V_PRED /*V_PRED*/, + THR_H_PRED /*H_PRED*/, + THR_D45_PRED /*D45_PRED*/, + THR_D135_PRED /*D135_PRED*/, + THR_D117_PRED /*D117_PRED*/, + THR_D153_PRED /*D153_PRED*/, + THR_D207_PRED /*D207_PRED*/, + THR_D63_PRED /*D63_PRED*/, + THR_TM /*TM_PRED*/, + }; + cpi->mode_chosen_counts[kf_mode_index[mi->mbmi.mode]]++; +#endif + } else { + // Note how often each mode chosen as best + cpi->mode_chosen_counts[mb_mode_index]++; + if (is_inter_block(mbmi) && + (mbmi->sb_type < BLOCK_8X8 || mbmi->mode == NEWMV)) { + int_mv best_mv[2]; + for (i = 0; i < 1 + has_second_ref(mbmi); ++i) + best_mv[i].as_int = mbmi->ref_mvs[mbmi->ref_frame[i]][0].as_int; + vp9_update_mv_count(cpi, x, best_mv); + } + + if (cm->interp_filter == SWITCHABLE && is_inter_mode(mbmi->mode)) { + const int ctx = vp9_get_pred_context_switchable_interp(xd); + ++cm->counts.switchable_interp[ctx][mbmi->interp_filter]; + } + } +} + +static void encode_b_rt(VP9_COMP *cpi, const TileInfo *const tile, + TOKENEXTRA **tp, int mi_row, int mi_col, + int output_enabled, BLOCK_SIZE bsize) { + MACROBLOCK *const x = &cpi->mb; if (bsize < BLOCK_8X8) { // When ab_index = 0 all sub-blocks are handled, so for ab_index != 0 // there is nothing to be done. - if (x->ab_index != 0) { - *rate = 0; - *dist = 0; + if (x->ab_index > 0) return; - } - } else { - *(get_sb_partitioning(x, bsize)) = subsize; } + set_offsets(cpi, tile, mi_row, mi_col, bsize); + update_state_rt(cpi, get_block_context(x, bsize), bsize, output_enabled); + + encode_superblock(cpi, tp, output_enabled, mi_row, mi_col, bsize); + update_stats(cpi); + + (*tp)->token = EOSB_TOKEN; + (*tp)++; +} + +static void encode_sb_rt(VP9_COMP *cpi, const TileInfo *const tile, + TOKENEXTRA **tp, int mi_row, int mi_col, + int output_enabled, BLOCK_SIZE bsize) { + VP9_COMMON *const cm = &cpi->common; + MACROBLOCK *const x = &cpi->mb; + const int bsl = b_width_log2(bsize), hbs = (1 << bsl) / 4; + int ctx; + PARTITION_TYPE partition; + BLOCK_SIZE subsize; + + if (mi_row >= cm->mi_rows || mi_col >= cm->mi_cols) + return; + + if (bsize >= BLOCK_8X8) { + MACROBLOCKD *const xd = &cpi->mb.e_mbd; + const int idx_str = xd->mode_info_stride * mi_row + mi_col; + MODE_INFO ** mi_8x8 = cm->mi_grid_visible + idx_str; + ctx = partition_plane_context(cpi->above_seg_context, cpi->left_seg_context, + mi_row, mi_col, bsize); + subsize = mi_8x8[0]->mbmi.sb_type; + + } else { + ctx = 0; + subsize = BLOCK_4X4; + } + + partition = partition_lookup[bsl][subsize]; switch (partition) { case PARTITION_NONE: - rd_pick_sb_modes(cpi, tile, mi_row, mi_col, rate, dist, - bsize, get_block_context(x, bsize), INT64_MAX); - break; - case PARTITION_HORZ: - *get_sb_index(x, subsize) = 0; - rd_pick_sb_modes(cpi, tile, mi_row, mi_col, &sub_rate[0], &sub_dist[0], - subsize, get_block_context(x, subsize), INT64_MAX); - if (bsize >= BLOCK_8X8 && mi_row + num_8x8_subsize < cm->mi_rows) { - update_state(cpi, get_block_context(x, subsize), subsize, 0); - encode_superblock(cpi, tp, 0, mi_row, mi_col, subsize); - *get_sb_index(x, subsize) = 1; - rd_pick_sb_modes(cpi, tile, mi_row + num_8x8_subsize, mi_col, - &sub_rate[1], &sub_dist[1], subsize, - get_block_context(x, subsize), INT64_MAX); - } - *rate = sub_rate[0] + sub_rate[1]; - *dist = sub_dist[0] + sub_dist[1]; + if (output_enabled && bsize >= BLOCK_8X8) + cm->counts.partition[ctx][PARTITION_NONE]++; + encode_b_rt(cpi, tile, tp, mi_row, mi_col, output_enabled, subsize); break; case PARTITION_VERT: + if (output_enabled) + cm->counts.partition[ctx][PARTITION_VERT]++; *get_sb_index(x, subsize) = 0; - rd_pick_sb_modes(cpi, tile, mi_row, mi_col, &sub_rate[0], &sub_dist[0], - subsize, get_block_context(x, subsize), INT64_MAX); - if (bsize >= BLOCK_8X8 && mi_col + num_8x8_subsize < cm->mi_cols) { - update_state(cpi, get_block_context(x, subsize), subsize, 0); - encode_superblock(cpi, tp, 0, mi_row, mi_col, subsize); + encode_b_rt(cpi, tile, tp, mi_row, mi_col, output_enabled, subsize); + if (mi_col + hbs < cm->mi_cols) { *get_sb_index(x, subsize) = 1; - rd_pick_sb_modes(cpi, tile, mi_row, mi_col + num_8x8_subsize, - &sub_rate[1], &sub_dist[1], subsize, - get_block_context(x, subsize), INT64_MAX); + encode_b_rt(cpi, tile, tp, mi_row, mi_col + hbs, output_enabled, + subsize); + } + break; + case PARTITION_HORZ: + if (output_enabled) + cm->counts.partition[ctx][PARTITION_HORZ]++; + *get_sb_index(x, subsize) = 0; + encode_b_rt(cpi, tile, tp, mi_row, mi_col, output_enabled, subsize); + if (mi_row + hbs < cm->mi_rows) { + *get_sb_index(x, subsize) = 1; + encode_b_rt(cpi, tile, tp, mi_row + hbs, mi_col, output_enabled, + subsize); } - *rate = sub_rate[0] + sub_rate[1]; - *dist = sub_dist[1] + sub_dist[1]; break; case PARTITION_SPLIT: + subsize = get_subsize(bsize, PARTITION_SPLIT); + if (output_enabled) + cm->counts.partition[ctx][PARTITION_SPLIT]++; + *get_sb_index(x, subsize) = 0; - pick_partition_type(cpi, tile, mi_8x8, tp, mi_row, mi_col, subsize, - &sub_rate[0], &sub_dist[0], 0); - - if ((mi_col + num_8x8_subsize) < cm->mi_cols) { - *get_sb_index(x, subsize) = 1; - pick_partition_type(cpi, tile, mi_8x8 + num_8x8_subsize, tp, - mi_row, mi_col + num_8x8_subsize, subsize, - &sub_rate[1], &sub_dist[1], 0); - } - - if ((mi_row + num_8x8_subsize) < cm->mi_rows) { - *get_sb_index(x, subsize) = 2; - pick_partition_type(cpi, tile, mi_8x8 + num_8x8_subsize * mi_stride, tp, - mi_row + num_8x8_subsize, mi_col, subsize, - &sub_rate[2], &sub_dist[2], 0); - } - - if ((mi_col + num_8x8_subsize) < cm->mi_cols && - (mi_row + num_8x8_subsize) < cm->mi_rows) { - *get_sb_index(x, subsize) = 3; - mi_offset = num_8x8_subsize * mi_stride + num_8x8_subsize; - pick_partition_type(cpi, tile, mi_8x8 + mi_offset, tp, - mi_row + num_8x8_subsize, mi_col + num_8x8_subsize, - subsize, &sub_rate[3], &sub_dist[3], 0); - } - - for (i = 0; i < 4; ++i) { - *rate += sub_rate[i]; - *dist += sub_dist[i]; - } - + encode_sb_rt(cpi, tile, tp, mi_row, mi_col, output_enabled, subsize); + *get_sb_index(x, subsize) = 1; + encode_sb_rt(cpi, tile, tp, mi_row, mi_col + hbs, output_enabled, + subsize); + *get_sb_index(x, subsize) = 2; + encode_sb_rt(cpi, tile, tp, mi_row + hbs, mi_col, output_enabled, + subsize); + *get_sb_index(x, subsize) = 3; + encode_sb_rt(cpi, tile, tp, mi_row + hbs, mi_col + hbs, output_enabled, + subsize); break; default: - assert(0); + assert("Invalid partition type."); } - if (do_recon) { - int output_enabled = (bsize == BLOCK_64X64); - - // Check the projected output rate for this SB against it's target - // and and if necessary apply a Q delta using segmentation to get - // closer to the target. - if ((cpi->oxcf.aq_mode == COMPLEXITY_AQ) && cm->seg.update_map) { - select_in_frame_q_segment(cpi, mi_row, mi_col, - output_enabled, *rate); - } - - encode_sb(cpi, tile, tp, mi_row, mi_col, output_enabled, bsize); - } + if (partition != PARTITION_SPLIT || bsize == BLOCK_8X8) + update_partition_context(cpi->above_seg_context, cpi->left_seg_context, + mi_row, mi_col, subsize, bsize); } static void rd_use_partition(VP9_COMP *cpi, @@ -2004,34 +2044,6 @@ static void rd_pick_reference_frame(VP9_COMP *cpi, const TileInfo *const tile, restore_context(cpi, mi_row, mi_col, a, l, sa, sl, BLOCK_64X64); } -static void encode_sb_row_rt(VP9_COMP *cpi, const TileInfo *const tile, - int mi_row, TOKENEXTRA **tp) { - VP9_COMMON *const cm = &cpi->common; - int mi_col; - - cpi->sf.always_this_block_size = BLOCK_8X8; - - // Initialize the left context for the new SB row - vpx_memset(&cpi->left_context, 0, sizeof(cpi->left_context)); - vpx_memset(cpi->left_seg_context, 0, sizeof(cpi->left_seg_context)); - - // Code each SB in the row - for (mi_col = tile->mi_col_start; mi_col < tile->mi_col_end; - mi_col += MI_BLOCK_SIZE) { - int dummy_rate; - int64_t dummy_dist; - const int idx_str = cm->mode_info_stride * mi_row + mi_col; - MODE_INFO **mi_8x8 = cm->mi_grid_visible + idx_str; - - vp9_zero(cpi->mb.pred_mv); - - set_offsets(cpi, tile, mi_row, mi_col, BLOCK_64X64); - set_partitioning(cpi, tile, mi_8x8, mi_row, mi_col); - pick_partition_type(cpi, tile, mi_8x8, tp, mi_row, mi_col, BLOCK_64X64, - &dummy_rate, &dummy_dist, 1); - } -} - static void encode_sb_row(VP9_COMP *cpi, const TileInfo *const tile, int mi_row, TOKENEXTRA **tp) { VP9_COMMON *const cm = &cpi->common; @@ -2258,11 +2270,7 @@ static void encode_frame_internal(VP9_COMP *cpi) { vp9_tile_init(&tile, cm, tile_row, tile_col); for (mi_row = tile.mi_row_start; mi_row < tile.mi_row_end; mi_row += 8) -#if 1 encode_sb_row(cpi, &tile, mi_row, &tp); -#else - encode_sb_row_rt(cpi, &tile, mi_row, &tp); -#endif cpi->tok_count[tile_row][tile_col] = (unsigned int)(tp - tp_old); assert(tp - cpi->tok <= get_token_alloc(cm->mb_rows, cm->mb_cols)); @@ -2441,6 +2449,264 @@ static void select_tx_mode(VP9_COMP *cpi) { } } } +// Start RTC Exploration +typedef enum { + BOTH_ZERO = 0, + ZERO_PLUS_PREDICTED = 1, + BOTH_PREDICTED = 2, + NEW_PLUS_NON_INTRA = 3, + BOTH_NEW = 4, + INTRA_PLUS_NON_INTRA = 5, + BOTH_INTRA = 6, + INVALID_CASE = 9 +} motion_vector_context; + +static void set_mode_info(MB_MODE_INFO *mbmi, BLOCK_SIZE bsize, + MB_PREDICTION_MODE mode, int mi_row, int mi_col) { + mbmi->interp_filter = EIGHTTAP; + mbmi->mode = mode; + mbmi->mv[0].as_int = 0; + mbmi->mv[1].as_int = 0; + if (mode < NEARESTMV) { + mbmi->ref_frame[0] = INTRA_FRAME; + } else { + mbmi->ref_frame[0] = LAST_FRAME; + } + + mbmi->ref_frame[1] = INTRA_FRAME; + mbmi->tx_size = max_txsize_lookup[bsize]; + mbmi->uv_mode = mode; + mbmi->skip_coeff = 0; + mbmi->sb_type = bsize; + mbmi->segment_id = 0; +} +static inline int get_block_row(int b32i, int b16i, int b8i) { + return ((b32i >> 1) << 2) + ((b16i >> 1) << 1) + (b8i >> 1); +} +static inline int get_block_col(int b32i, int b16i, int b8i) { + return ((b32i & 1) << 2) + ((b16i & 1) << 1) + (b8i & 1); +} +static void rtc_use_partition(VP9_COMP *cpi, + const TileInfo *const tile, + MODE_INFO **mi_8x8, + TOKENEXTRA **tp, int mi_row, int mi_col, + BLOCK_SIZE bsize, int *rate, int64_t *dist, + int do_recon) { + VP9_COMMON *const cm = &cpi->common; + MACROBLOCK *const x = &cpi->mb; + MACROBLOCKD *const xd = &cpi->mb.e_mbd; + const int mis = cm->mode_info_stride; + int mi_width = num_8x8_blocks_wide_lookup[cpi->sf.always_this_block_size]; + int mi_height = num_8x8_blocks_high_lookup[cpi->sf.always_this_block_size]; + int i, j; + int chosen_rate = INT_MAX; + int64_t chosen_dist = INT_MAX; + MB_PREDICTION_MODE mode = DC_PRED; + int row8x8_remaining = tile->mi_row_end - mi_row; + int col8x8_remaining = tile->mi_col_end - mi_col; + int b32i; + x->fast_ms = 0; + x->subblock_ref = 0; + for (b32i = 0; b32i < 4; b32i++) { + int b16i; + for (b16i = 0; b16i < 4; b16i++) { + int b8i; + int block_row = get_block_row(b32i, b16i, 0); + int block_col = get_block_col(b32i, b16i, 0); + int index = block_row * mis + block_col; + int rate; + int64_t dist; + + int_mv frame_nearest_mv[MAX_REF_FRAMES]; + int_mv frame_near_mv[MAX_REF_FRAMES]; + struct buf_2d yv12_mb[MAX_REF_FRAMES][MAX_MB_PLANE]; + + // Find a partition size that fits + bsize = find_partition_size(cpi->sf.always_this_block_size, + (row8x8_remaining - block_row), + (col8x8_remaining - block_col), + &mi_height, &mi_width); + mi_8x8[index] = mi_8x8[0] + index; + + set_mi_row_col(xd, tile, mi_row + block_row, mi_height, + mi_col + block_col, mi_width, cm->mi_rows, cm->mi_cols); + + xd->mi_8x8 = mi_8x8 + index; + + if (cm->frame_type != KEY_FRAME) { + set_offsets(cpi, tile, mi_row + block_row, mi_col + block_col, bsize); + + vp9_pick_inter_mode(cpi, x, tile, + mi_row + block_row, mi_col + block_col, + &rate, &dist, cpi->sf.always_this_block_size); + } else { + set_mode_info(&mi_8x8[index]->mbmi, bsize, mode, + mi_row + block_row, mi_col + block_col); + vp9_setup_buffer_inter(cpi, x, tile, + LAST_FRAME, cpi->sf.always_this_block_size, + mi_row + block_row, mi_col + block_col, + frame_nearest_mv, frame_near_mv, yv12_mb); + } + + for (j = 0; j < mi_height; j++) + for (i = 0; i < mi_width; i++) + if ((xd->mb_to_right_edge >> (3 + MI_SIZE_LOG2)) + mi_width > i + && (xd->mb_to_bottom_edge >> (3 + MI_SIZE_LOG2)) + mi_height > j) { + mi_8x8[index+ i + j * mis] = mi_8x8[index]; + } + + for (b8i = 0; b8i < 4; b8i++) { + } + } + } + encode_sb_rt(cpi, tile, tp, mi_row, mi_col, 1, BLOCK_64X64); + + *rate = chosen_rate; + *dist = chosen_dist; +} + +static void encode_rtc_sb_row(VP9_COMP *cpi, const TileInfo *const tile, + int mi_row, TOKENEXTRA **tp) { + VP9_COMMON * const cm = &cpi->common; + int mi_col; + + // Initialize the left context for the new SB row + vpx_memset(&cpi->left_context, 0, sizeof(cpi->left_context)); + vpx_memset(cpi->left_seg_context, 0, sizeof(cpi->left_seg_context)); + + // Code each SB in the row + for (mi_col = tile->mi_col_start; mi_col < tile->mi_col_end; + mi_col += MI_BLOCK_SIZE) { + int dummy_rate; + int64_t dummy_dist; + + const int idx_str = cm->mode_info_stride * mi_row + mi_col; + MODE_INFO **mi_8x8 = cm->mi_grid_visible + idx_str; + + cpi->mb.source_variance = UINT_MAX; + set_offsets(cpi, tile, mi_row, mi_col, BLOCK_64X64); + set_partitioning(cpi, tile, mi_8x8, mi_row, mi_col); + rtc_use_partition(cpi, tile, mi_8x8, tp, mi_row, mi_col, BLOCK_64X64, + &dummy_rate, &dummy_dist, 1); + } +} + + +static void encode_rtc_frame_internal(VP9_COMP *cpi) { + int mi_row; + MACROBLOCK * const x = &cpi->mb; + VP9_COMMON * const cm = &cpi->common; + MACROBLOCKD * const xd = &x->e_mbd; + +// fprintf(stderr, "encode_frame_internal frame %d (%d) type %d\n", +// cpi->common.current_video_frame, cpi->common.show_frame, +// cm->frame_type); + +// debug output +#if DBG_PRNT_SEGMAP + { + FILE *statsfile; + statsfile = fopen("segmap2.stt", "a"); + fprintf(statsfile, "\n"); + fclose(statsfile); + } +#endif + + vp9_zero(cm->counts.switchable_interp); + vp9_zero(cpi->tx_stepdown_count); + + xd->mi_8x8 = cm->mi_grid_visible; + // required for vp9_frame_init_quantizer + xd->mi_8x8[0] = cm->mi; + + xd->last_mi = cm->prev_mi; + + vp9_zero(cpi->common.counts.mv); + vp9_zero(cpi->coef_counts); + vp9_zero(cm->counts.eob_branch); + + cpi->mb.e_mbd.lossless = cm->base_qindex == 0 && cm->y_dc_delta_q == 0 + && cm->uv_dc_delta_q == 0 && cm->uv_ac_delta_q == 0; + switch_lossless_mode(cpi, cpi->mb.e_mbd.lossless); + + vp9_frame_init_quantizer(cpi); + + vp9_initialize_rd_consts(cpi); + vp9_initialize_me_consts(cpi, cm->base_qindex); + switch_tx_mode(cpi); + cpi->sf.always_this_block_size = BLOCK_16X16; + + if (cpi->oxcf.tuning == VP8_TUNE_SSIM) { + // Initialize encode frame context. + init_encode_frame_mb_context(cpi); + + // Build a frame level activity map + build_activity_map(cpi); + } + + // Re-initialize encode frame context. + init_encode_frame_mb_context(cpi); + + vp9_zero(cpi->rd_comp_pred_diff); + vp9_zero(cpi->rd_filter_diff); + vp9_zero(cpi->rd_tx_select_diff); + vp9_zero(cpi->rd_tx_select_threshes); + + set_prev_mi(cm); + + { + struct vpx_usec_timer emr_timer; + vpx_usec_timer_start(&emr_timer); + + { + // Take tiles into account and give start/end MB + int tile_col, tile_row; + TOKENEXTRA *tp = cpi->tok; + const int tile_cols = 1 << cm->log2_tile_cols; + const int tile_rows = 1 << cm->log2_tile_rows; + + for (tile_row = 0; tile_row < tile_rows; tile_row++) { + for (tile_col = 0; tile_col < tile_cols; tile_col++) { + TileInfo tile; + TOKENEXTRA *tp_old = tp; + + // For each row of SBs in the frame + vp9_tile_init(&tile, cm, tile_row, tile_col); + for (mi_row = tile.mi_row_start; + mi_row < tile.mi_row_end; mi_row += 8) + encode_rtc_sb_row(cpi, &tile, mi_row, &tp); + + cpi->tok_count[tile_row][tile_col] = (unsigned int)(tp - tp_old); + assert(tp - cpi->tok <= get_token_alloc(cm->mb_rows, cm->mb_cols)); + } + } + } + + vpx_usec_timer_mark(&emr_timer); + cpi->time_encode_sb_row += vpx_usec_timer_elapsed(&emr_timer); + } + + if (cpi->sf.skip_encode_sb) { + int j; + unsigned int intra_count = 0, inter_count = 0; + for (j = 0; j < INTRA_INTER_CONTEXTS; ++j) { + intra_count += cm->counts.intra_inter[j][0]; + inter_count += cm->counts.intra_inter[j][1]; + } + cpi->sf.skip_encode_frame = ((intra_count << 2) < inter_count); + cpi->sf.skip_encode_frame &= (cm->frame_type != KEY_FRAME); + cpi->sf.skip_encode_frame &= cm->show_frame; + } else { + cpi->sf.skip_encode_frame = 0; + } + +#if 0 + // Keep record of the total distortion this time around for future use + cpi->last_frame_distortion = cpi->frame_distortion; +#endif +} +// end RTC play code + void vp9_encode_frame(VP9_COMP *cpi) { VP9_COMMON *const cm = &cpi->common; @@ -2520,7 +2786,11 @@ void vp9_encode_frame(VP9_COMP *cpi) { select_tx_mode(cpi); cm->reference_mode = reference_mode; cm->interp_filter = interp_filter; - encode_frame_internal(cpi); + + if (cpi->compressor_speed == 3) + encode_rtc_frame_internal(cpi); + else + encode_frame_internal(cpi); for (i = 0; i < REFERENCE_MODES; ++i) { const int diff = (int) (cpi->rd_comp_pred_diff[i] / cm->MBs); @@ -2598,7 +2868,7 @@ void vp9_encode_frame(VP9_COMP *cpi) { } } } else { - encode_frame_internal(cpi); + encode_rtc_frame_internal(cpi); } } @@ -2674,7 +2944,8 @@ static void encode_superblock(VP9_COMP *cpi, TOKENEXTRA **t, int output_enabled, const int mi_width = num_8x8_blocks_wide_lookup[bsize]; const int mi_height = num_8x8_blocks_high_lookup[bsize]; x->skip_recode = !x->select_txfm_size && mbmi->sb_type >= BLOCK_8X8 && - (cpi->oxcf.aq_mode != COMPLEXITY_AQ); + (cpi->oxcf.aq_mode != COMPLEXITY_AQ) && + cpi->compressor_speed != 3; x->skip_optimize = ctx->is_coded; ctx->is_coded = 1; x->use_lp32x32fdct = cpi->sf.use_lp32x32fdct; diff --git a/vp9/encoder/vp9_encodemb.c b/vp9/encoder/vp9_encodemb.c index 448818996..8ff23c79a 100644 --- a/vp9/encoder/vp9_encodemb.c +++ b/vp9/encoder/vp9_encodemb.c @@ -338,7 +338,6 @@ static void optimize_init_b(int plane, BLOCK_SIZE bsize, pd->above_context, pd->left_context, num_4x4_w, num_4x4_h); } - void vp9_xform_quant(int plane, int block, BLOCK_SIZE plane_bsize, TX_SIZE tx_size, void *arg) { struct encode_b_args* const args = arg; diff --git a/vp9/encoder/vp9_onyx_if.c b/vp9/encoder/vp9_onyx_if.c index 256ebacd3..0cba03996 100644 --- a/vp9/encoder/vp9_onyx_if.c +++ b/vp9/encoder/vp9_onyx_if.c @@ -1261,6 +1261,11 @@ void vp9_change_config(VP9_PTR ptr, VP9_CONFIG *oxcf) { cpi->pass = 2; cpi->compressor_speed = 0; break; + + case MODE_REALTIME: + cpi->pass = 0; + cpi->compressor_speed = 3; + break; } cpi->oxcf.worst_allowed_q = q_trans[oxcf->worst_allowed_q]; @@ -2544,7 +2549,10 @@ static void loopfilter_frame(VP9_COMP *cpi, VP9_COMMON *cm) { vpx_usec_timer_start(&timer); - vp9_pick_filter_level(cpi->Source, cpi, cpi->sf.use_fast_lpf_pick); + if (cpi->compressor_speed == 3) + lf->filter_level = 4; + else + vp9_pick_filter_level(cpi->Source, cpi, cpi->sf.use_fast_lpf_pick); vpx_usec_timer_mark(&timer); cpi->time_pick_lpf += vpx_usec_timer_elapsed(&timer); @@ -2733,7 +2741,9 @@ static void encode_with_recode_loop(VP9_COMP *cpi, if (cpi->sf.recode_loop != 0) { vp9_save_coding_context(cpi); cpi->dummy_packing = 1; - vp9_pack_bitstream(cpi, dest, size); + if (cpi->compressor_speed != 3) + vp9_pack_bitstream(cpi, dest, size); + cpi->rc.projected_frame_size = (*size) << 3; vp9_restore_coding_context(cpi); @@ -3082,11 +3092,22 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi, &frame_under_shoot_limit, &frame_over_shoot_limit); - // Decide q and q bounds + // Decide q and q bounds. q = vp9_rc_pick_q_and_adjust_q_bounds(cpi, &bottom_index, &top_index); + // JBB : This is realtime mode. In real time mode the first frame + // should be larger. Q of 0 is disabled because we force tx size to be + // 16x16... + if (cpi->compressor_speed == 3) { + if (cpi->common.current_video_frame == 0) + q /= 3; + + if (q == 0) + q++; + } + if (!frame_is_intra_only(cm)) { cm->interp_filter = DEFAULT_INTERP_FILTER; /* TODO: Decide this more intelligently */ diff --git a/vp9/encoder/vp9_pickmode.c b/vp9/encoder/vp9_pickmode.c index 210d15f0d..2b9e31f08 100644 --- a/vp9/encoder/vp9_pickmode.c +++ b/vp9/encoder/vp9_pickmode.c @@ -80,7 +80,7 @@ static int full_pixel_motion_search(VP9_COMP *cpi, MACROBLOCK *x, step_param = 6; further_steps = (cpi->sf.max_step_search_steps - 1) - step_param; - for (i = LAST_FRAME; i <= ALTREF_FRAME && cpi->common.show_frame; ++i) { + for (i = LAST_FRAME; i <= LAST_FRAME && cpi->common.show_frame; ++i) { if ((x->pred_mv_sad[ref] >> 3) > x->pred_mv_sad[i]) { tmp_mv->as_int = INVALID_MV; @@ -142,8 +142,7 @@ int64_t vp9_pick_inter_mode(VP9_COMP *cpi, MACROBLOCK *x, int mi_row, int mi_col, int *returnrate, int64_t *returndistortion, - BLOCK_SIZE bsize, - PICK_MODE_CONTEXT *ctx) { + BLOCK_SIZE bsize) { MACROBLOCKD *xd = &x->e_mbd; MB_MODE_INFO *mbmi = &xd->mi_8x8[0]->mbmi; const BLOCK_SIZE block_size = get_plane_block_size(bsize, &xd->plane[0]); @@ -155,6 +154,7 @@ int64_t vp9_pick_inter_mode(VP9_COMP *cpi, MACROBLOCK *x, VP9_ALT_FLAG }; int64_t best_rd = INT64_MAX; int64_t this_rd; + int64_t cost[4]= { 0, 100, 150, 205 }; x->skip_encode = cpi->sf.skip_encode_frame && x->q_index < QIDX_SKIP_THRESH; @@ -171,7 +171,7 @@ int64_t vp9_pick_inter_mode(VP9_COMP *cpi, MACROBLOCK *x, mbmi->tx_size = MIN(max_txsize_lookup[bsize], tx_mode_to_biggest_tx_size[cpi->common.tx_mode]); - for (ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) { + for (ref_frame = LAST_FRAME; ref_frame <= LAST_FRAME ; ++ref_frame) { x->pred_mv_sad[ref_frame] = INT_MAX; if (cpi->ref_frame_flags & flag_list[ref_frame]) { vp9_setup_buffer_inter(cpi, x, tile, @@ -182,7 +182,7 @@ int64_t vp9_pick_inter_mode(VP9_COMP *cpi, MACROBLOCK *x, frame_mv[ZEROMV][ref_frame].as_int = 0; } - for (ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) { + for (ref_frame = LAST_FRAME; ref_frame <= LAST_FRAME ; ++ref_frame) { int rate_mv = 0; if (!(cpi->ref_frame_flags & flag_list[ref_frame])) @@ -191,29 +191,42 @@ int64_t vp9_pick_inter_mode(VP9_COMP *cpi, MACROBLOCK *x, // Select prediction reference frames. xd->plane[0].pre[0] = yv12_mb[ref_frame][0]; - - x->mode_sad[ref_frame][INTER_OFFSET(NEWMV)] = - full_pixel_motion_search(cpi, x, tile, bsize, mi_row, mi_col, - &frame_mv[NEWMV][ref_frame], &rate_mv); - - if (frame_mv[NEWMV][ref_frame].as_int == INVALID_MV) - continue; - clamp_mv2(&frame_mv[NEARESTMV][ref_frame].as_mv, xd); clamp_mv2(&frame_mv[NEARMV][ref_frame].as_mv, xd); for (this_mode = NEARESTMV; this_mode <= NEWMV; ++this_mode) { - int rate = x->inter_mode_cost[mbmi->mode_context[ref_frame]] - [INTER_OFFSET(this_mode)]; - int64_t dist = x->mode_sad[ref_frame][INTER_OFFSET(this_mode)] * - x->mode_sad[ref_frame][INTER_OFFSET(this_mode)]; - this_rd = RDCOST(x->rdmult, x->rddiv, rate, dist); + int rate = cost[this_mode - NEARESTMV]; + int64_t dist; + + if (this_mode == NEWMV) { + if (this_rd < 300) + continue; + + x->mode_sad[ref_frame][INTER_OFFSET(NEWMV)] = + full_pixel_motion_search(cpi, x, tile, bsize, mi_row, mi_col, + &frame_mv[NEWMV][ref_frame], &rate_mv); + + if (frame_mv[NEWMV][ref_frame].as_int == INVALID_MV) + continue; + } + + dist = x->mode_sad[ref_frame][INTER_OFFSET(this_mode)]; + this_rd = rate + dist; if (this_rd < best_rd) { best_rd = this_rd; mbmi->mode = this_mode; mbmi->ref_frame[0] = ref_frame; mbmi->mv[0].as_int = frame_mv[this_mode][ref_frame].as_int; + xd->mi_8x8[0]->bmi[0].as_mv[0].as_int = mbmi->mv[0].as_int; + mbmi->interp_filter = EIGHTTAP; + + mbmi->ref_frame[1] = INTRA_FRAME; + mbmi->tx_size = max_txsize_lookup[bsize]; + mbmi->uv_mode = this_mode; + mbmi->skip_coeff = 0; + mbmi->sb_type = bsize; + mbmi->segment_id = 0; } } } @@ -223,8 +236,5 @@ int64_t vp9_pick_inter_mode(VP9_COMP *cpi, MACROBLOCK *x, // TODO(jingning) intra prediction search, if the best SAD is above a certain // threshold. - // store mode decisions - ctx->mic = *xd->mi_8x8[0]; - return INT64_MAX; } diff --git a/vp9/encoder/vp9_pickmode.h b/vp9/encoder/vp9_pickmode.h index 82904ae8a..05ff18762 100644 --- a/vp9/encoder/vp9_pickmode.h +++ b/vp9/encoder/vp9_pickmode.h @@ -22,8 +22,7 @@ int64_t vp9_pick_inter_mode(VP9_COMP *cpi, MACROBLOCK *x, int mi_row, int mi_col, int *returnrate, int64_t *returndistortion, - BLOCK_SIZE bsize, - PICK_MODE_CONTEXT *ctx); + BLOCK_SIZE bsize); #ifdef __cplusplus } // extern "C" diff --git a/vp9/encoder/vp9_rdopt.c b/vp9/encoder/vp9_rdopt.c index 24b41a904..f375a88ff 100644 --- a/vp9/encoder/vp9_rdopt.c +++ b/vp9/encoder/vp9_rdopt.c @@ -280,22 +280,24 @@ void vp9_initialize_rd_consts(VP9_COMP *cpi) { fill_token_costs(x->token_costs, cm->fc.coef_probs); - for (i = 0; i < PARTITION_CONTEXTS; i++) - vp9_cost_tokens(x->partition_cost[i], get_partition_probs(cm, i), - vp9_partition_tree); + if (cpi->compressor_speed != 3) { + for (i = 0; i < PARTITION_CONTEXTS; i++) + vp9_cost_tokens(x->partition_cost[i], get_partition_probs(cm, i), + vp9_partition_tree); - fill_mode_costs(cpi); + fill_mode_costs(cpi); - if (!frame_is_intra_only(cm)) { - vp9_build_nmv_cost_table(x->nmvjointcost, - cm->allow_high_precision_mv ? x->nmvcost_hp - : x->nmvcost, - &cm->fc.nmvc, - cm->allow_high_precision_mv, 1, 1); + if (!frame_is_intra_only(cm)) { + vp9_build_nmv_cost_table(x->nmvjointcost, + cm->allow_high_precision_mv ? x->nmvcost_hp + : x->nmvcost, + &cm->fc.nmvc, + cm->allow_high_precision_mv, 1, 1); - for (i = 0; i < INTER_MODE_CONTEXTS; ++i) - vp9_cost_tokens((int *)x->inter_mode_cost[i], - cm->fc.inter_mode_probs[i], vp9_inter_mode_tree); + for (i = 0; i < INTER_MODE_CONTEXTS; ++i) + vp9_cost_tokens((int *)x->inter_mode_cost[i], + cm->fc.inter_mode_probs[i], vp9_inter_mode_tree); + } } } @@ -2478,6 +2480,7 @@ static void single_motion_search(VP9_COMP *cpi, MACROBLOCK *x, for (i = 0; i < MAX_MB_PLANE; i++) xd->plane[i].pre[0] = backup_yv12[i]; } + return; } static void joint_motion_search(VP9_COMP *cpi, MACROBLOCK *x, diff --git a/vp9/vp9_cx_iface.c b/vp9/vp9_cx_iface.c index 897ecd702..6b181710e 100644 --- a/vp9/vp9_cx_iface.c +++ b/vp9/vp9_cx_iface.c @@ -563,10 +563,21 @@ static void pick_quickcompress_mode(vpx_codec_alg_priv_t *ctx, unsigned int new_qc; /* Use best quality mode if no deadline is given. */ - if (deadline) - new_qc = MODE_GOODQUALITY; - else - new_qc = MODE_BESTQUALITY; + new_qc = MODE_BESTQUALITY; + + if (deadline) { + uint64_t duration_us; + + /* Convert duration parameter from stream timebase to microseconds */ + duration_us = (uint64_t)duration * 1000000 + * (uint64_t)ctx->cfg.g_timebase.num + / (uint64_t)ctx->cfg.g_timebase.den; + + /* If the deadline is more that the duration this frame is to be shown, + * use good quality mode. Otherwise use realtime mode. + */ + new_qc = (deadline > duration_us) ? MODE_GOODQUALITY : MODE_REALTIME; + } if (ctx->cfg.g_pass == VPX_RC_FIRST_PASS) new_qc = MODE_FIRSTPASS;