diff --git a/configure b/configure index f94546e7e..c0e898006 100755 --- a/configure +++ b/configure @@ -263,9 +263,7 @@ ARCH_EXT_LIST=" HAVE_LIST=" ${ARCH_EXT_LIST} vpx_ports - stdint_h pthread_h - sys_mman_h unistd_h " EXPERIMENT_LIST=" @@ -559,16 +557,12 @@ process_detect() { # Specialize windows and POSIX environments. case $toolchain in *-win*-*) - case $header-$toolchain in - stdint*-gcc) true;; - *) false;; - esac && enable_feature $var - ;; + # Don't check for any headers in Windows builds. + false + ;; *) case $header in - stdint.h) true;; pthread.h) true;; - sys/mman.h) true;; unistd.h) true;; *) false;; esac && enable_feature $var @@ -584,9 +578,7 @@ process_detect() { int main(void) {return 0;} EOF # check system headers - check_header stdint.h check_header pthread.h - check_header sys/mman.h check_header unistd.h # for sysconf(3) and friends. check_header vpx/vpx_integer.h -I${source_path} && enable_feature vpx_ports diff --git a/examples/vp8_multi_resolution_encoder.c b/examples/vp8_multi_resolution_encoder.c index 2b032049c..0248edede 100644 --- a/examples/vp8_multi_resolution_encoder.c +++ b/examples/vp8_multi_resolution_encoder.c @@ -29,13 +29,6 @@ #include #include #include -#if USE_POSIX_MMAP -#include -#include -#include -#include -#include -#endif #include "vpx_ports/vpx_timer.h" #include "vpx/vpx_encoder.h" #include "vpx/vp8cx.h" diff --git a/vp10/encoder/aq_complexity.c b/vp10/encoder/aq_complexity.c index 0de044cf9..2506a4e55 100644 --- a/vp10/encoder/aq_complexity.c +++ b/vp10/encoder/aq_complexity.c @@ -51,7 +51,7 @@ void vp10_setup_in_frame_q_adj(VP10_COMP *cpi) { // Make SURE use of floating point in this function is safe. vpx_clear_system_state(); - if (cm->frame_type == KEY_FRAME || + if (frame_is_intra_only(cm) || cm->error_resilient_mode || cpi->refresh_alt_ref_frame || (cpi->refresh_golden_frame && !cpi->rc.is_src_frame_alt_ref)) { int segment; diff --git a/vp10/encoder/aq_variance.c b/vp10/encoder/aq_variance.c index e8e88c3b6..bed5162fb 100644 --- a/vp10/encoder/aq_variance.c +++ b/vp10/encoder/aq_variance.c @@ -47,7 +47,7 @@ void vp10_vaq_frame_setup(VP10_COMP *cpi) { struct segmentation *seg = &cm->seg; int i; - if (cm->frame_type == KEY_FRAME || + if (frame_is_intra_only(cm) || cm->error_resilient_mode || cpi->refresh_alt_ref_frame || (cpi->refresh_golden_frame && !cpi->rc.is_src_frame_alt_ref)) { vp10_enable_segmentation(seg); diff --git a/vp10/encoder/segmentation.c b/vp10/encoder/segmentation.c index e93677573..969b87fa9 100644 --- a/vp10/encoder/segmentation.c +++ b/vp10/encoder/segmentation.c @@ -250,7 +250,7 @@ void vp10_choose_segmap_coding_method(VP10_COMMON *cm, MACROBLOCKD *xd) { no_pred_cost = cost_segmap(no_pred_segcounts, no_pred_tree); // Key frames cannot use temporal prediction - if (!frame_is_intra_only(cm)) { + if (!frame_is_intra_only(cm) && !cm->error_resilient_mode) { // Work out probability tree for coding those segments not // predicted using the temporal method and the cost. calc_segtree_probs(t_unpred_seg_counts, t_pred_tree, segp->tree_probs); @@ -273,6 +273,7 @@ void vp10_choose_segmap_coding_method(VP10_COMMON *cm, MACROBLOCKD *xd) { // Now choose which coding method to use. if (t_pred_cost < no_pred_cost) { + assert(!cm->error_resilient_mode); seg->temporal_update = 1; } else { seg->temporal_update = 0; diff --git a/vp9/common/vp9_entropymv.c b/vp9/common/vp9_entropymv.c index 3acfe1448..566ae91cf 100644 --- a/vp9/common/vp9_entropymv.c +++ b/vp9/common/vp9_entropymv.c @@ -11,9 +11,6 @@ #include "vp9/common/vp9_onyxc_int.h" #include "vp9/common/vp9_entropymv.h" -// Integer pel reference mv threshold for use of high-precision 1/8 mv -#define COMPANDED_MVREF_THRESH 8 - const vpx_tree_index vp9_mv_joint_tree[TREE_SIZE(MV_JOINTS)] = { -MV_JOINT_ZERO, 2, -MV_JOINT_HNZVZ, 4, @@ -127,11 +124,6 @@ MV_CLASS_TYPE vp9_get_mv_class(int z, int *offset) { return c; } -int vp9_use_mv_hp(const MV *ref) { - return (abs(ref->row) >> 3) < COMPANDED_MVREF_THRESH && - (abs(ref->col) >> 3) < COMPANDED_MVREF_THRESH; -} - static void inc_mv_component(int v, nmv_component_counts *comp_counts, int incr, int usehp) { int s, z, c, o, d, e, f; diff --git a/vp9/common/vp9_entropymv.h b/vp9/common/vp9_entropymv.h index 8c817bf7b..2f05ad44b 100644 --- a/vp9/common/vp9_entropymv.h +++ b/vp9/common/vp9_entropymv.h @@ -27,7 +27,14 @@ struct VP9Common; void vp9_init_mv_probs(struct VP9Common *cm); void vp9_adapt_mv_probs(struct VP9Common *cm, int usehp); -int vp9_use_mv_hp(const MV *ref); + +// Integer pel reference mv threshold for use of high-precision 1/8 mv +#define COMPANDED_MVREF_THRESH 8 + +static INLINE int use_mv_hp(const MV *ref) { + return (abs(ref->row) >> 3) < COMPANDED_MVREF_THRESH && + (abs(ref->col) >> 3) < COMPANDED_MVREF_THRESH; +} #define MV_UPDATE_PROB 252 diff --git a/vp9/common/vp9_mvref_common.c b/vp9/common/vp9_mvref_common.c index 77d1ff459..9803ff627 100644 --- a/vp9/common/vp9_mvref_common.c +++ b/vp9/common/vp9_mvref_common.c @@ -11,20 +11,19 @@ #include "vp9/common/vp9_mvref_common.h" -// This function searches the neighbourhood of a given MB/SB +// This function searches the neighborhood of a given MB/SB // to try and find candidate reference vectors. static void find_mv_refs_idx(const VP9_COMMON *cm, const MACROBLOCKD *xd, MODE_INFO *mi, MV_REFERENCE_FRAME ref_frame, int_mv *mv_ref_list, int block, int mi_row, int mi_col, - find_mv_refs_sync sync, void *const data, uint8_t *mode_context) { const int *ref_sign_bias = cm->ref_frame_sign_bias; int i, refmv_count = 0; const POSITION *const mv_ref_search = mv_ref_blocks[mi->mbmi.sb_type]; int different_ref_found = 0; int context_counter = 0; - const MV_REF *const prev_frame_mvs = cm->use_prev_frame_mvs ? + const MV_REF *const prev_frame_mvs = cm->use_prev_frame_mvs ? cm->prev_frame->mvs + mi_row * cm->mi_cols + mi_col : NULL; const TileInfo *const tile = &xd->tile; @@ -59,8 +58,8 @@ static void find_mv_refs_idx(const VP9_COMMON *cm, const MACROBLOCKD *xd, for (; i < MVREF_NEIGHBOURS; ++i) { const POSITION *const mv_ref = &mv_ref_search[i]; if (is_inside(tile, mi_col, mi_row, cm->mi_rows, mv_ref)) { - const MB_MODE_INFO *const candidate = &xd->mi[mv_ref->col + mv_ref->row * - xd->mi_stride]->mbmi; + const MB_MODE_INFO *const candidate = + &xd->mi[mv_ref->col + mv_ref->row * xd->mi_stride]->mbmi; different_ref_found = 1; if (candidate->ref_frame[0] == ref_frame) @@ -70,23 +69,8 @@ static void find_mv_refs_idx(const VP9_COMMON *cm, const MACROBLOCKD *xd, } } - // TODO(hkuang): Remove this sync after fixing pthread_cond_broadcast - // on windows platform. The sync here is unncessary if use_perv_frame_mvs - // is 0. But after removing it, there will be hang in the unit test on windows - // due to several threads waiting for a thread's signal. -#if defined(_WIN32) && !HAVE_PTHREAD_H - if (cm->frame_parallel_decode && sync != NULL) { - sync(data, mi_row); - } -#endif - // Check the last frame's mode and mv info. if (cm->use_prev_frame_mvs) { - // Synchronize here for frame parallel decode if sync function is provided. - if (cm->frame_parallel_decode && sync != NULL) { - sync(data, mi_row); - } - if (prev_frame_mvs->ref_frame[0] == ref_frame) { ADD_MV_REF_LIST(prev_frame_mvs->mv[0], refmv_count, mv_ref_list, Done); } else if (prev_frame_mvs->ref_frame[1] == ref_frame) { @@ -101,8 +85,8 @@ static void find_mv_refs_idx(const VP9_COMMON *cm, const MACROBLOCKD *xd, for (i = 0; i < MVREF_NEIGHBOURS; ++i) { const POSITION *mv_ref = &mv_ref_search[i]; if (is_inside(tile, mi_col, mi_row, cm->mi_rows, mv_ref)) { - const MB_MODE_INFO *const candidate = &xd->mi[mv_ref->col + mv_ref->row - * xd->mi_stride]->mbmi; + const MB_MODE_INFO *const candidate = + &xd->mi[mv_ref->col + mv_ref->row * xd->mi_stride]->mbmi; // If the candidate is INTRA we don't want to consider its mv. IF_DIFF_REF_FRAME_ADD_MV(candidate, ref_frame, ref_sign_bias, @@ -150,20 +134,9 @@ void vp9_find_mv_refs(const VP9_COMMON *cm, const MACROBLOCKD *xd, MODE_INFO *mi, MV_REFERENCE_FRAME ref_frame, int_mv *mv_ref_list, int mi_row, int mi_col, - find_mv_refs_sync sync, void *const data, uint8_t *mode_context) { find_mv_refs_idx(cm, xd, mi, ref_frame, mv_ref_list, -1, - mi_row, mi_col, sync, data, mode_context); -} - -static void lower_mv_precision(MV *mv, int allow_hp) { - const int use_hp = allow_hp && vp9_use_mv_hp(mv); - if (!use_hp) { - if (mv->row & 1) - mv->row += (mv->row > 0 ? -1 : 1); - if (mv->col & 1) - mv->col += (mv->col > 0 ? -1 : 1); - } + mi_row, mi_col, mode_context); } void vp9_find_best_ref_mvs(MACROBLOCKD *xd, int allow_hp, @@ -191,7 +164,7 @@ void vp9_append_sub8x8_mvs_for_idx(VP9_COMMON *cm, MACROBLOCKD *xd, assert(MAX_MV_REF_CANDIDATES == 2); find_mv_refs_idx(cm, xd, mi, mi->mbmi.ref_frame[ref], mv_list, block, - mi_row, mi_col, NULL, NULL, mode_context); + mi_row, mi_col, mode_context); near_mv->as_int = 0; switch (block) { diff --git a/vp9/common/vp9_mvref_common.h b/vp9/common/vp9_mvref_common.h index bd216d433..a6dddd01a 100644 --- a/vp9/common/vp9_mvref_common.h +++ b/vp9/common/vp9_mvref_common.h @@ -157,7 +157,7 @@ static INLINE int_mv scale_mv(const MB_MODE_INFO *mbmi, int ref, // This macro is used to add a motion vector mv_ref list if it isn't // already in the list. If it's the second motion vector it will also -// skip all additional processing and jump to done! +// skip all additional processing and jump to Done! #define ADD_MV_REF_LIST(mv, refmv_count, mv_ref_list, Done) \ do { \ if (refmv_count) { \ @@ -207,11 +207,20 @@ static INLINE void clamp_mv2(MV *mv, const MACROBLOCKD *xd) { xd->mb_to_bottom_edge + RIGHT_BOTTOM_MARGIN); } +static INLINE void lower_mv_precision(MV *mv, int allow_hp) { + const int use_hp = allow_hp && use_mv_hp(mv); + if (!use_hp) { + if (mv->row & 1) + mv->row += (mv->row > 0 ? -1 : 1); + if (mv->col & 1) + mv->col += (mv->col > 0 ? -1 : 1); + } +} + typedef void (*find_mv_refs_sync)(void *const data, int mi_row); void vp9_find_mv_refs(const VP9_COMMON *cm, const MACROBLOCKD *xd, MODE_INFO *mi, MV_REFERENCE_FRAME ref_frame, int_mv *mv_ref_list, int mi_row, int mi_col, - find_mv_refs_sync sync, void *const data, uint8_t *mode_context); // check a list of motion vectors by sad score using a number rows of pixels diff --git a/vp9/decoder/vp9_decodeframe.c b/vp9/decoder/vp9_decodeframe.c index 3fd87cc3a..e27634cdd 100644 --- a/vp9/decoder/vp9_decodeframe.c +++ b/vp9/decoder/vp9_decodeframe.c @@ -719,6 +719,18 @@ static void dec_build_inter_predictors_sb(VP9Decoder *const pbi, const InterpKernel *kernel = vp9_filter_kernels[mi->mbmi.interp_filter]; const BLOCK_SIZE sb_type = mi->mbmi.sb_type; const int is_compound = has_second_ref(&mi->mbmi); + int ref; + + for (ref = 0; ref < 1 + is_compound; ++ref) { + const MV_REFERENCE_FRAME frame = mi->mbmi.ref_frame[ref]; + RefBuffer *ref_buf = &pbi->common.frame_refs[frame - LAST_FRAME]; + + xd->block_refs[ref] = ref_buf; + if (!vp9_is_valid_scale(&ref_buf->sf)) + vpx_internal_error(xd->error_info, VPX_CODEC_UNSUP_BITSTREAM, + "Reference frame has invalid dimensions"); + vp9_setup_pre_planes(xd, ref, ref_buf->buf, mi_row, mi_col, &ref_buf->sf); + } for (plane = 0; plane < MAX_MB_PLANE; ++plane) { struct macroblockd_plane *const pd = &xd->plane[plane]; diff --git a/vp9/decoder/vp9_decodemv.c b/vp9/decoder/vp9_decodemv.c index d3ca7b3fe..bf5d81d86 100644 --- a/vp9/decoder/vp9_decodemv.c +++ b/vp9/decoder/vp9_decodemv.c @@ -289,7 +289,7 @@ static INLINE void read_mv(vpx_reader *r, MV *mv, const MV *ref, nmv_context_counts *counts, int allow_hp) { const MV_JOINT_TYPE joint_type = (MV_JOINT_TYPE)vpx_read_tree(r, vp9_mv_joint_tree, ctx->joints); - const int use_hp = allow_hp && vp9_use_mv_hp(ref); + const int use_hp = allow_hp && use_mv_hp(ref); MV diff = {0, 0}; if (mv_joint_vertical(joint_type)) @@ -476,12 +476,203 @@ static int read_is_inter_block(VP9_COMMON *const cm, MACROBLOCKD *const xd, } } +static void dec_find_best_ref_mvs(MACROBLOCKD *xd, int allow_hp, int_mv *mvlist, + int_mv *nearest_mv, int_mv *near_mv, + int refmv_count) { + int i; + + // Make sure all the candidates are properly clamped etc + for (i = 0; i < refmv_count; ++i) { + lower_mv_precision(&mvlist[i].as_mv, allow_hp); + clamp_mv2(&mvlist[i].as_mv, xd); + } + *nearest_mv = mvlist[0]; + *near_mv = mvlist[1]; +} + static void fpm_sync(void *const data, int mi_row) { VP9Decoder *const pbi = (VP9Decoder *)data; vp9_frameworker_wait(pbi->frame_worker_owner, pbi->common.prev_frame, mi_row << MI_BLOCK_SIZE_LOG2); } +// This macro is used to add a motion vector mv_ref list if it isn't +// already in the list. If it's the second motion vector or early_break +// it will also skip all additional processing and jump to Done! +#define ADD_MV_REF_LIST_EB(mv, refmv_count, mv_ref_list, Done) \ + do { \ + if (refmv_count) { \ + if ((mv).as_int != (mv_ref_list)[0].as_int) { \ + (mv_ref_list)[(refmv_count)] = (mv); \ + refmv_count++; \ + goto Done; \ + } \ + } else { \ + (mv_ref_list)[(refmv_count)++] = (mv); \ + if (early_break) \ + goto Done; \ + } \ + } while (0) + +// If either reference frame is different, not INTRA, and they +// are different from each other scale and add the mv to our list. +#define IF_DIFF_REF_FRAME_ADD_MV_EB(mbmi, ref_frame, ref_sign_bias, \ + refmv_count, mv_ref_list, Done) \ + do { \ + if (is_inter_block(mbmi)) { \ + if ((mbmi)->ref_frame[0] != ref_frame) \ + ADD_MV_REF_LIST_EB(scale_mv((mbmi), 0, ref_frame, ref_sign_bias), \ + refmv_count, mv_ref_list, Done); \ + if (has_second_ref(mbmi) && \ + (mbmi)->ref_frame[1] != ref_frame && \ + (mbmi)->mv[1].as_int != (mbmi)->mv[0].as_int) \ + ADD_MV_REF_LIST_EB(scale_mv((mbmi), 1, ref_frame, ref_sign_bias), \ + refmv_count, mv_ref_list, Done); \ + } \ + } while (0) + +// This function searches the neighborhood of a given MB/SB +// to try and find candidate reference vectors. +static int dec_find_mv_refs(const VP9_COMMON *cm, const MACROBLOCKD *xd, + MODE_INFO *mi, MV_REFERENCE_FRAME ref_frame, + const POSITION *const mv_ref_search, + int_mv *mv_ref_list, + int mi_row, int mi_col, + find_mv_refs_sync sync, void *const data) { + const int *ref_sign_bias = cm->ref_frame_sign_bias; + int i, refmv_count = 0; + int different_ref_found = 0; + const MV_REF *const prev_frame_mvs = cm->use_prev_frame_mvs ? + cm->prev_frame->mvs + mi_row * cm->mi_cols + mi_col : NULL; + const TileInfo *const tile = &xd->tile; + // If mode is nearestmv or newmv (uses nearestmv as a reference) then stop + // searching after the first mv is found. + const int early_break = (mi->mbmi.mode == NEARESTMV) || + (mi->mbmi.mode == NEWMV); + + // Blank the reference vector list + memset(mv_ref_list, 0, sizeof(*mv_ref_list) * MAX_MV_REF_CANDIDATES); + + // Check the rest of the neighbors in much the same way + // as before except we don't need to keep track of sub blocks or + // mode counts. + for (i = 0; i < MVREF_NEIGHBOURS; ++i) { + const POSITION *const mv_ref = &mv_ref_search[i]; + if (is_inside(tile, mi_col, mi_row, cm->mi_rows, mv_ref)) { + const MB_MODE_INFO *const candidate = + &xd->mi[mv_ref->col + mv_ref->row * xd->mi_stride]->mbmi; + different_ref_found = 1; + + if (candidate->ref_frame[0] == ref_frame) + ADD_MV_REF_LIST_EB(candidate->mv[0], refmv_count, mv_ref_list, Done); + else if (candidate->ref_frame[1] == ref_frame) + ADD_MV_REF_LIST_EB(candidate->mv[1], refmv_count, mv_ref_list, Done); + } + } + + // TODO(hkuang): Remove this sync after fixing pthread_cond_broadcast + // on windows platform. The sync here is unnecessary if use_prev_frame_mvs + // is 0. But after removing it, there will be hang in the unit test on windows + // due to several threads waiting for a thread's signal. +#if defined(_WIN32) && !HAVE_PTHREAD_H + if (cm->frame_parallel_decode && sync != NULL) { + sync(data, mi_row); + } +#endif + + // Check the last frame's mode and mv info. + if (prev_frame_mvs) { + // Synchronize here for frame parallel decode if sync function is provided. + if (cm->frame_parallel_decode && sync != NULL) { + sync(data, mi_row); + } + + if (prev_frame_mvs->ref_frame[0] == ref_frame) { + ADD_MV_REF_LIST_EB(prev_frame_mvs->mv[0], refmv_count, mv_ref_list, Done); + } else if (prev_frame_mvs->ref_frame[1] == ref_frame) { + ADD_MV_REF_LIST_EB(prev_frame_mvs->mv[1], refmv_count, mv_ref_list, Done); + } + } + + // Since we couldn't find 2 mvs from the same reference frame + // go back through the neighbors and find motion vectors from + // different reference frames. + if (different_ref_found) { + for (i = 0; i < MVREF_NEIGHBOURS; ++i) { + const POSITION *mv_ref = &mv_ref_search[i]; + if (is_inside(tile, mi_col, mi_row, cm->mi_rows, mv_ref)) { + const MB_MODE_INFO *const candidate = + &xd->mi[mv_ref->col + mv_ref->row * xd->mi_stride]->mbmi; + + // If the candidate is INTRA we don't want to consider its mv. + IF_DIFF_REF_FRAME_ADD_MV_EB(candidate, ref_frame, ref_sign_bias, + refmv_count, mv_ref_list, Done); + } + } + } + + // Since we still don't have a candidate we'll try the last frame. + if (prev_frame_mvs) { + if (prev_frame_mvs->ref_frame[0] != ref_frame && + prev_frame_mvs->ref_frame[0] > INTRA_FRAME) { + int_mv mv = prev_frame_mvs->mv[0]; + if (ref_sign_bias[prev_frame_mvs->ref_frame[0]] != + ref_sign_bias[ref_frame]) { + mv.as_mv.row *= -1; + mv.as_mv.col *= -1; + } + ADD_MV_REF_LIST_EB(mv, refmv_count, mv_ref_list, Done); + } + + if (prev_frame_mvs->ref_frame[1] > INTRA_FRAME && + prev_frame_mvs->ref_frame[1] != ref_frame && + prev_frame_mvs->mv[1].as_int != prev_frame_mvs->mv[0].as_int) { + int_mv mv = prev_frame_mvs->mv[1]; + if (ref_sign_bias[prev_frame_mvs->ref_frame[1]] != + ref_sign_bias[ref_frame]) { + mv.as_mv.row *= -1; + mv.as_mv.col *= -1; + } + ADD_MV_REF_LIST_EB(mv, refmv_count, mv_ref_list, Done); + } + } + + if (mi->mbmi.mode == NEARMV) + refmv_count = MAX_MV_REF_CANDIDATES; + else + // we only care about the nearestmv for the remaining modes + refmv_count = 1; + + Done: + // Clamp vectors + for (i = 0; i < refmv_count; ++i) + clamp_mv_ref(&mv_ref_list[i].as_mv, xd); + + return refmv_count; +} + +static uint8_t get_mode_context(const VP9_COMMON *cm, const MACROBLOCKD *xd, + const POSITION *const mv_ref_search, + int mi_row, int mi_col) { + int i; + int context_counter = 0; + const TileInfo *const tile = &xd->tile; + + // Get mode count from nearest 2 blocks + for (i = 0; i < 2; ++i) { + const POSITION *const mv_ref = &mv_ref_search[i]; + if (is_inside(tile, mi_col, mi_row, cm->mi_rows, mv_ref)) { + const MODE_INFO *const candidate_mi = xd->mi[mv_ref->col + mv_ref->row * + xd->mi_stride]; + const MB_MODE_INFO *const candidate = &candidate_mi->mbmi; + // Keep counts for entropy encoding. + context_counter += mode_2_counter[candidate->mode]; + } + } + + return counter_to_context[context_counter]; +} + static void read_inter_block_mode_info(VP9Decoder *const pbi, MACROBLOCKD *const xd, MODE_INFO *const mi, @@ -491,26 +682,13 @@ static void read_inter_block_mode_info(VP9Decoder *const pbi, const BLOCK_SIZE bsize = mbmi->sb_type; const int allow_hp = cm->allow_high_precision_mv; int_mv nearestmv[2], nearmv[2]; - int_mv ref_mvs[MAX_REF_FRAMES][MAX_MV_REF_CANDIDATES]; int ref, is_compound; - uint8_t inter_mode_ctx[MAX_REF_FRAMES]; + uint8_t inter_mode_ctx; + const POSITION *const mv_ref_search = mv_ref_blocks[bsize]; read_ref_frames(cm, xd, r, mbmi->segment_id, mbmi->ref_frame); is_compound = has_second_ref(mbmi); - - for (ref = 0; ref < 1 + is_compound; ++ref) { - const MV_REFERENCE_FRAME frame = mbmi->ref_frame[ref]; - RefBuffer *ref_buf = &cm->frame_refs[frame - LAST_FRAME]; - - xd->block_refs[ref] = ref_buf; - if ((!vp9_is_valid_scale(&ref_buf->sf))) - vpx_internal_error(xd->error_info, VPX_CODEC_UNSUP_BITSTREAM, - "Reference frame has invalid dimensions"); - vp9_setup_pre_planes(xd, ref, ref_buf->buf, mi_row, mi_col, - &ref_buf->sf); - vp9_find_mv_refs(cm, xd, mi, frame, ref_mvs[frame], - mi_row, mi_col, fpm_sync, (void *)pbi, inter_mode_ctx); - } + inter_mode_ctx = get_mode_context(cm, xd, mv_ref_search, mi_row, mi_col); if (segfeature_active(&cm->seg, mbmi->segment_id, SEG_LVL_SKIP)) { mbmi->mode = ZEROMV; @@ -521,14 +699,27 @@ static void read_inter_block_mode_info(VP9Decoder *const pbi, } } else { if (bsize >= BLOCK_8X8) - mbmi->mode = read_inter_mode(cm, xd, r, - inter_mode_ctx[mbmi->ref_frame[0]]); - } + mbmi->mode = read_inter_mode(cm, xd, r, inter_mode_ctx); + else + // Sub 8x8 blocks use the nearestmv as a ref_mv if the b_mode is NEWMV. + // Setting mode to NEARESTMV forces the search to stop after the nearestmv + // has been found. After b_modes have been read, mode will be overwritten + // by the last b_mode. + mbmi->mode = NEARESTMV; - if (bsize < BLOCK_8X8 || mbmi->mode != ZEROMV) { - for (ref = 0; ref < 1 + is_compound; ++ref) { - vp9_find_best_ref_mvs(xd, allow_hp, ref_mvs[mbmi->ref_frame[ref]], - &nearestmv[ref], &nearmv[ref]); + if (mbmi->mode != ZEROMV) { + for (ref = 0; ref < 1 + is_compound; ++ref) { + int_mv ref_mvs[MAX_MV_REF_CANDIDATES]; + const MV_REFERENCE_FRAME frame = mbmi->ref_frame[ref]; + int refmv_count; + + refmv_count = dec_find_mv_refs(cm, xd, mi, frame, mv_ref_search, + ref_mvs, mi_row, mi_col, fpm_sync, + (void *)pbi); + + dec_find_best_ref_mvs(xd, allow_hp, ref_mvs, &nearestmv[ref], + &nearmv[ref], refmv_count); + } } } @@ -546,7 +737,7 @@ static void read_inter_block_mode_info(VP9Decoder *const pbi, for (idx = 0; idx < 2; idx += num_4x4_w) { int_mv block[2]; const int j = idy * 2 + idx; - b_mode = read_inter_mode(cm, xd, r, inter_mode_ctx[mbmi->ref_frame[0]]); + b_mode = read_inter_mode(cm, xd, r, inter_mode_ctx); if (b_mode == NEARESTMV || b_mode == NEARMV) { uint8_t dummy_mode_ctx[MAX_REF_FRAMES]; diff --git a/vp9/encoder/vp9_aq_360.c b/vp9/encoder/vp9_aq_360.c new file mode 100644 index 000000000..7f937344d --- /dev/null +++ b/vp9/encoder/vp9_aq_360.c @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2013 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include + +#include "vpx_ports/mem.h" +#include "vpx_ports/system_state.h" + +#include "vp9/encoder/vp9_aq_variance.h" + +#include "vp9/common/vp9_seg_common.h" + +#include "vp9/encoder/vp9_ratectrl.h" +#include "vp9/encoder/vp9_rd.h" +#include "vp9/encoder/vp9_segmentation.h" + +#define ENERGY_MIN (-4) +#define ENERGY_MAX (1) +#define ENERGY_SPAN (ENERGY_MAX - ENERGY_MIN + 1) +#define ENERGY_IN_BOUNDS(energy)\ + assert((energy) >= ENERGY_MIN && (energy) <= ENERGY_MAX) + +static const double rate_ratio[MAX_SEGMENTS] = + {1.0, 0.75, 0.6, 0.5, 0.4, 0.3, 0.25}; + +// Sets segment id 0 for the equatorial region, 1 for temperate region +// and 2 for the polar regions +unsigned int vp9_360aq_segment_id(int mi_row, int mi_rows) { + if (mi_row < mi_rows / 8 || mi_row > mi_rows - mi_rows / 8) + return 2; + else if (mi_row < mi_rows / 4 || mi_row > mi_rows - mi_rows / 4) + return 1; + else + return 0; +} + +void vp9_360aq_frame_setup(VP9_COMP *cpi) { + VP9_COMMON *cm = &cpi->common; + struct segmentation *seg = &cm->seg; + int i; + + if (frame_is_intra_only(cm) || cm->error_resilient_mode) { + vp9_enable_segmentation(seg); + vp9_clearall_segfeatures(seg); + + seg->abs_delta = SEGMENT_DELTADATA; + + vpx_clear_system_state(); + + for (i = 0; i < MAX_SEGMENTS; ++i) { + int qindex_delta = + vp9_compute_qdelta_by_rate(&cpi->rc, cm->frame_type, cm->base_qindex, + rate_ratio[i], cm->bit_depth); + + // We don't allow qindex 0 in a segment if the base value is not 0. + // Q index 0 (lossless) implies 4x4 encoding only and in AQ mode a segment + // Q delta is sometimes applied without going back around the rd loop. + // This could lead to an illegal combination of partition size and q. + if ((cm->base_qindex != 0) && ((cm->base_qindex + qindex_delta) == 0)) { + qindex_delta = -cm->base_qindex + 1; + } + + // No need to enable SEG_LVL_ALT_Q for this segment. + if (rate_ratio[i] == 1.0) { + continue; + } + + vp9_set_segdata(seg, i, SEG_LVL_ALT_Q, qindex_delta); + vp9_enable_segfeature(seg, i, SEG_LVL_ALT_Q); + } + } +} diff --git a/vp9/encoder/vp9_aq_360.h b/vp9/encoder/vp9_aq_360.h new file mode 100644 index 000000000..fb861cb05 --- /dev/null +++ b/vp9/encoder/vp9_aq_360.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2013 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#ifndef VP9_ENCODER_VP9_AQ_360_H_ +#define VP9_ENCODER_VP9_AQ_360_H_ + +#include "vp9/encoder/vp9_encoder.h" + +#ifdef __cplusplus +extern "C" { +#endif + +unsigned int vp9_360aq_segment_id(int mi_row, int mi_rows); +void vp9_360aq_frame_setup(VP9_COMP *cpi); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // VP9_ENCODER_VP9_AQ_VARIANCE_H_ diff --git a/vp9/encoder/vp9_encodeframe.c b/vp9/encoder/vp9_encodeframe.c index 7f94e1944..27423f764 100644 --- a/vp9/encoder/vp9_encodeframe.c +++ b/vp9/encoder/vp9_encodeframe.c @@ -33,6 +33,7 @@ #include "vp9/common/vp9_seg_common.h" #include "vp9/common/vp9_tile_common.h" +#include "vp9/encoder/vp9_aq_360.h" #include "vp9/encoder/vp9_aq_complexity.h" #include "vp9/encoder/vp9_aq_cyclicrefresh.h" #include "vp9/encoder/vp9_aq_variance.h" @@ -221,7 +222,8 @@ static void set_offsets(VP9_COMP *cpi, const TileInfo *const tile, // Setup segment ID. if (seg->enabled) { - if (cpi->oxcf.aq_mode != VARIANCE_AQ) { + if (cpi->oxcf.aq_mode != VARIANCE_AQ && + cpi->oxcf.aq_mode != EQUATOR360_AQ) { const uint8_t *const map = seg->update_map ? cpi->segmentation_map : cm->last_frame_seg_map; mbmi->segment_id = get_segment_id(cm, map, bsize, mi_row, mi_col); @@ -1263,6 +1265,15 @@ static void rd_pick_sb_modes(VP9_COMP *cpi, mbmi->segment_id = get_segment_id(cm, map, bsize, mi_row, mi_col); } x->rdmult = set_segment_rdmult(cpi, x, mbmi->segment_id); + } else if (aq_mode == EQUATOR360_AQ) { + if (cm->frame_type == KEY_FRAME) { + mbmi->segment_id = vp9_360aq_segment_id(mi_row, cm->mi_rows); + } else { + const uint8_t *const map = cm->seg.update_map ? cpi->segmentation_map + : cm->last_frame_seg_map; + mbmi->segment_id = get_segment_id(cm, map, bsize, mi_row, mi_col); + } + x->rdmult = set_segment_rdmult(cpi, x, mbmi->segment_id); } else if (aq_mode == COMPLEXITY_AQ) { x->rdmult = set_segment_rdmult(cpi, x, mbmi->segment_id); } else if (aq_mode == CYCLIC_REFRESH_AQ) { @@ -1719,7 +1730,8 @@ static void update_state_rt(VP9_COMP *cpi, ThreadData *td, // For in frame complexity AQ or variance AQ, copy segment_id from // segmentation_map. if (cpi->oxcf.aq_mode == COMPLEXITY_AQ || - cpi->oxcf.aq_mode == VARIANCE_AQ ) { + cpi->oxcf.aq_mode == VARIANCE_AQ || + cpi->oxcf.aq_mode == EQUATOR360_AQ) { const uint8_t *const map = seg->update_map ? cpi->segmentation_map : cm->last_frame_seg_map; mbmi->segment_id = get_segment_id(cm, map, bsize, mi_row, mi_col); diff --git a/vp9/encoder/vp9_encodemv.c b/vp9/encoder/vp9_encodemv.c index e71966343..3bcd6a3b6 100644 --- a/vp9/encoder/vp9_encodemv.c +++ b/vp9/encoder/vp9_encodemv.c @@ -206,7 +206,7 @@ void vp9_encode_mv(VP9_COMP* cpi, vpx_writer* w, const MV diff = {mv->row - ref->row, mv->col - ref->col}; const MV_JOINT_TYPE j = vp9_get_mv_joint(&diff); - usehp = usehp && vp9_use_mv_hp(ref); + usehp = usehp && use_mv_hp(ref); vp9_write_token(w, vp9_mv_joint_tree, mvctx->joints, &mv_joint_encodings[j]); if (mv_joint_vertical(j)) diff --git a/vp9/encoder/vp9_encoder.c b/vp9/encoder/vp9_encoder.c index e4681f601..609344dcd 100644 --- a/vp9/encoder/vp9_encoder.c +++ b/vp9/encoder/vp9_encoder.c @@ -36,6 +36,7 @@ #include "vp9/common/vp9_reconintra.h" #include "vp9/common/vp9_tile_common.h" +#include "vp9/encoder/vp9_aq_360.h" #include "vp9/encoder/vp9_aq_complexity.h" #include "vp9/encoder/vp9_aq_cyclicrefresh.h" #include "vp9/encoder/vp9_aq_variance.h" @@ -3334,6 +3335,8 @@ static void encode_without_recode_loop(VP9_COMP *cpi, // exclusive. if (cpi->oxcf.aq_mode == VARIANCE_AQ) { vp9_vaq_frame_setup(cpi); + } else if (cpi->oxcf.aq_mode == EQUATOR360_AQ) { + vp9_360aq_frame_setup(cpi); } else if (cpi->oxcf.aq_mode == COMPLEXITY_AQ) { vp9_setup_in_frame_q_adj(cpi); } else if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ) { @@ -3464,6 +3467,8 @@ static void encode_with_recode_loop(VP9_COMP *cpi, // exclusive. if (cpi->oxcf.aq_mode == VARIANCE_AQ) { vp9_vaq_frame_setup(cpi); + } else if (cpi->oxcf.aq_mode == EQUATOR360_AQ) { + vp9_360aq_frame_setup(cpi); } else if (cpi->oxcf.aq_mode == COMPLEXITY_AQ) { vp9_setup_in_frame_q_adj(cpi); } diff --git a/vp9/encoder/vp9_encoder.h b/vp9/encoder/vp9_encoder.h index f6d8931fe..76c36f4e5 100644 --- a/vp9/encoder/vp9_encoder.h +++ b/vp9/encoder/vp9_encoder.h @@ -112,6 +112,7 @@ typedef enum { VARIANCE_AQ = 1, COMPLEXITY_AQ = 2, CYCLIC_REFRESH_AQ = 3, + EQUATOR360_AQ = 4, AQ_MODE_COUNT // This should always be the last member of the enum } AQ_MODE; diff --git a/vp9/encoder/vp9_mcomp.c b/vp9/encoder/vp9_mcomp.c index a84202bb4..eab07bccb 100644 --- a/vp9/encoder/vp9_mcomp.c +++ b/vp9/encoder/vp9_mcomp.c @@ -439,7 +439,7 @@ int vp9_find_best_sub_pixel_tree_pruned_evenmore( tr = br; tc = bc; - if (allow_hp && vp9_use_mv_hp(ref_mv) && forced_stop == 0) { + if (allow_hp && use_mv_hp(ref_mv) && forced_stop == 0) { hstep >>= 1; FIRST_LEVEL_CHECKS; if (eighthiters > 1) { @@ -507,7 +507,7 @@ int vp9_find_best_sub_pixel_tree_pruned_more(const MACROBLOCK *x, } } - if (allow_hp && vp9_use_mv_hp(ref_mv) && forced_stop == 0) { + if (allow_hp && use_mv_hp(ref_mv) && forced_stop == 0) { tr = br; tc = bc; hstep >>= 1; @@ -602,7 +602,7 @@ int vp9_find_best_sub_pixel_tree_pruned(const MACROBLOCK *x, tc = bc; } - if (allow_hp && vp9_use_mv_hp(ref_mv) && forced_stop == 0) { + if (allow_hp && use_mv_hp(ref_mv) && forced_stop == 0) { hstep >>= 1; FIRST_LEVEL_CHECKS; if (eighthiters > 1) { @@ -674,7 +674,7 @@ int vp9_find_best_sub_pixel_tree(const MACROBLOCK *x, unsigned int cost_array[5]; int kr, kc; - if (!(allow_hp && vp9_use_mv_hp(ref_mv))) + if (!(allow_hp && use_mv_hp(ref_mv))) if (round == 3) round = 2; diff --git a/vp9/encoder/vp9_pickmode.c b/vp9/encoder/vp9_pickmode.c index 71b8bdba0..4880ff680 100644 --- a/vp9/encoder/vp9_pickmode.c +++ b/vp9/encoder/vp9_pickmode.c @@ -1225,8 +1225,7 @@ void vp9_pick_inter_mode(VP9_COMP *cpi, MACROBLOCK *x, if (cm->use_prev_frame_mvs) vp9_find_mv_refs(cm, xd, xd->mi[0], ref_frame, - candidates, mi_row, mi_col, NULL, NULL, - x->mbmi_ext->mode_context); + candidates, mi_row, mi_col, x->mbmi_ext->mode_context); else const_motion[ref_frame] = mv_refs_rt(cm, x, xd, tile_info, xd->mi[0], @@ -1833,8 +1832,7 @@ void vp9_pick_inter_mode_sub8x8(VP9_COMP *cpi, MACROBLOCK *x, vp9_setup_pred_block(xd, yv12_mb[ref_frame], yv12, mi_row, mi_col, sf, sf); vp9_find_mv_refs(cm, xd, xd->mi[0], ref_frame, - candidates, mi_row, mi_col, NULL, NULL, - mbmi_ext->mode_context); + candidates, mi_row, mi_col, mbmi_ext->mode_context); vp9_find_best_ref_mvs(xd, cm->allow_high_precision_mv, candidates, &dummy_mv[0], &dummy_mv[1]); diff --git a/vp9/encoder/vp9_rdopt.c b/vp9/encoder/vp9_rdopt.c index 973d8f51e..71ee5ee75 100644 --- a/vp9/encoder/vp9_rdopt.c +++ b/vp9/encoder/vp9_rdopt.c @@ -2202,7 +2202,7 @@ static void setup_buffer_inter(VP9_COMP *cpi, MACROBLOCK *x, // Gets an initial list of candidate vectors from neighbours and orders them vp9_find_mv_refs(cm, xd, mi, ref_frame, candidates, mi_row, mi_col, - NULL, NULL, mbmi_ext->mode_context); + mbmi_ext->mode_context); // Candidate refinement carried out at encoder and decoder vp9_find_best_ref_mvs(xd, cm->allow_high_precision_mv, candidates, diff --git a/vp9/vp9cx.mk b/vp9/vp9cx.mk index de688bf48..c7a334d86 100644 --- a/vp9/vp9cx.mk +++ b/vp9/vp9cx.mk @@ -75,6 +75,8 @@ VP9_CX_SRCS-yes += encoder/vp9_tokenize.c VP9_CX_SRCS-yes += encoder/vp9_treewriter.c VP9_CX_SRCS-yes += encoder/vp9_aq_variance.c VP9_CX_SRCS-yes += encoder/vp9_aq_variance.h +VP9_CX_SRCS-yes += encoder/vp9_aq_360.c +VP9_CX_SRCS-yes += encoder/vp9_aq_360.h VP9_CX_SRCS-yes += encoder/vp9_aq_cyclicrefresh.c VP9_CX_SRCS-yes += encoder/vp9_aq_cyclicrefresh.h VP9_CX_SRCS-yes += encoder/vp9_aq_complexity.c diff --git a/vpxenc.c b/vpxenc.c index afbaeac31..db8fcafa1 100644 --- a/vpxenc.c +++ b/vpxenc.c @@ -388,7 +388,7 @@ static const arg_def_t frame_parallel_decoding = ARG_DEF( static const arg_def_t aq_mode = ARG_DEF( NULL, "aq-mode", 1, "Adaptive quantization mode (0: off (default), 1: variance 2: complexity, " - "3: cyclic refresh)"); + "3: cyclic refresh, 4: equator360)"); static const arg_def_t frame_periodic_boost = ARG_DEF( NULL, "frame-boost", 1, "Enable frame periodic boost (0: off (default), 1: on)"); diff --git a/vpxstats.c b/vpxstats.c index 172d8937c..16728ce09 100644 --- a/vpxstats.c +++ b/vpxstats.c @@ -26,17 +26,6 @@ int stats_open_file(stats_io_t *stats, const char *fpf, int pass) { stats->buf.buf = NULL; res = (stats->file != NULL); } else { -#if USE_POSIX_MMAP - struct stat stat_buf; - int fd; - - fd = open(fpf, O_RDONLY); - stats->file = fdopen(fd, "rb"); - fstat(fd, &stat_buf); - stats->buf.sz = stat_buf.st_size; - stats->buf.buf = mmap(NULL, stats->buf.sz, PROT_READ, MAP_PRIVATE, fd, 0); - res = (stats->buf.buf != NULL); -#else size_t nbytes; stats->file = fopen(fpf, "rb"); @@ -58,7 +47,6 @@ int stats_open_file(stats_io_t *stats, const char *fpf, int pass) { nbytes = fread(stats->buf.buf, 1, stats->buf.sz, stats->file); res = (nbytes == stats->buf.sz); -#endif /* USE_POSIX_MMAP */ } return res; @@ -82,11 +70,7 @@ int stats_open_mem(stats_io_t *stats, int pass) { void stats_close(stats_io_t *stats, int last_pass) { if (stats->file) { if (stats->pass == last_pass) { -#if USE_POSIX_MMAP - munmap(stats->buf.buf, stats->buf.sz); -#else free(stats->buf.buf); -#endif /* USE_POSIX_MMAP */ } fclose(stats->file);