multi-res: force Key frame sychronization
In multi-resolution encoding, frame_type decision for each frame
is made by the lowest-resolution encoder. For all other higher-
resolution encoders, kf_mode is always set to VPX_KF_DISABLED,
and they are forced to use the same frame_type picked by the
lowest-resolution encoder.
Change-Id: Ic4d52ec65bbc012ca9c2d236210e28a295591eaf
diff --git a/vp8/common/blockd.h b/vp8/common/blockd.h
index a4c1d92..1945edb 100644
--- a/vp8/common/blockd.h
+++ b/vp8/common/blockd.h
@@ -168,7 +168,7 @@
} MODE_INFO;
#if CONFIG_MULTI_RES_ENCODING
-/* The information needed to be stored for higher-resolution encoder */
+/* The mb-level information needed to be stored for higher-resolution encoder */
typedef struct
{
MB_PREDICTION_MODE mode;
@@ -176,7 +176,15 @@
int_mv mv;
//union b_mode_info bmi[16];
int dissim; // dissimilarity level of the macroblock
-} LOWER_RES_INFO;
+} LOWER_RES_MB_INFO;
+
+/* The frame-level information needed to be stored for higher-resolution
+ * encoder */
+typedef struct
+{
+ FRAME_TYPE frame_type;
+ LOWER_RES_MB_INFO *mb_info;
+} LOWER_RES_FRAME_INFO;
#endif
typedef struct blockd
diff --git a/vp8/encoder/mr_dissim.c b/vp8/encoder/mr_dissim.c
index 7a62a06..564f963 100644
--- a/vp8/encoder/mr_dissim.c
+++ b/vp8/encoder/mr_dissim.c
@@ -65,14 +65,18 @@
/* Store info for show/no-show frames for supporting alt_ref.
* If parent frame is alt_ref, child has one too.
*/
+ LOWER_RES_FRAME_INFO* store_info
+ = (LOWER_RES_FRAME_INFO*)cpi->oxcf.mr_low_res_mode_info;
+
+ store_info->frame_type = cm->frame_type;
+
if(cm->frame_type != KEY_FRAME)
{
int mb_row;
int mb_col;
/* Point to beginning of allocated MODE_INFO arrays. */
MODE_INFO *tmp = cm->mip + cm->mode_info_stride;
- LOWER_RES_INFO* store_mode_info
- = (LOWER_RES_INFO*)cpi->oxcf.mr_low_res_mode_info;
+ LOWER_RES_MB_INFO* store_mode_info = store_info->mb_info;
for (mb_row = 0; mb_row < cm->mb_rows; mb_row ++)
{
diff --git a/vp8/encoder/onyx_if.c b/vp8/encoder/onyx_if.c
index 8819633..536ae63 100644
--- a/vp8/encoder/onyx_if.c
+++ b/vp8/encoder/onyx_if.c
@@ -3241,6 +3241,17 @@
cm->frame_type = KEY_FRAME;
}
+#if CONFIG_MULTI_RES_ENCODING
+ /* In multi-resolution encoding, frame_type is decided by lowest-resolution
+ * encoder. Same frame_type is adopted while encoding at other resolution.
+ */
+ if (cpi->oxcf.mr_encoder_id)
+ {
+ cm->frame_type =
+ ((LOWER_RES_FRAME_INFO*)cpi->oxcf.mr_low_res_mode_info)->frame_type;
+ }
+#endif
+
// Set default state for segment and mode based loop filter update flags
cpi->mb.e_mbd.update_mb_segmentation_map = 0;
cpi->mb.e_mbd.update_mb_segmentation_data = 0;
diff --git a/vp8/encoder/pickinter.c b/vp8/encoder/pickinter.c
index 618a296..45acb0b 100644
--- a/vp8/encoder/pickinter.c
+++ b/vp8/encoder/pickinter.c
@@ -405,8 +405,8 @@
MB_PREDICTION_MODE *parent_mode,
int_mv *parent_ref_mv, int mb_row, int mb_col)
{
- LOWER_RES_INFO* store_mode_info
- = (LOWER_RES_INFO*)cpi->oxcf.mr_low_res_mode_info;
+ LOWER_RES_MB_INFO* store_mode_info
+ = ((LOWER_RES_FRAME_INFO*)cpi->oxcf.mr_low_res_mode_info)->mb_info;
unsigned int parent_mb_index;
//unsigned int parent_mb_index = map_640x480_to_320x240[mb_row][mb_col];
diff --git a/vp8/vp8_cx_iface.c b/vp8/vp8_cx_iface.c
index f55a420..04d4d86 100644
--- a/vp8/vp8_cx_iface.c
+++ b/vp8/vp8_cx_iface.c
@@ -549,23 +549,28 @@
static vpx_codec_err_t vp8e_mr_alloc_mem(const vpx_codec_enc_cfg_t *cfg,
void **mem_loc)
{
- vpx_codec_err_t res = 0;
-
#if CONFIG_MULTI_RES_ENCODING
+ LOWER_RES_FRAME_INFO *shared_mem_loc;
int mb_rows = ((cfg->g_w + 15) >>4);
int mb_cols = ((cfg->g_h + 15) >>4);
- *mem_loc = calloc(mb_rows*mb_cols, sizeof(LOWER_RES_INFO));
- if(!(*mem_loc))
+ shared_mem_loc = calloc(1, sizeof(LOWER_RES_FRAME_INFO));
+ if(!shared_mem_loc)
{
- free(*mem_loc);
- res = VPX_CODEC_MEM_ERROR;
+ return VPX_CODEC_MEM_ERROR;
+ }
+
+ shared_mem_loc->mb_info = calloc(mb_rows*mb_cols, sizeof(LOWER_RES_MB_INFO));
+ if(!(shared_mem_loc->mb_info))
+ {
+ return VPX_CODEC_MEM_ERROR;
}
else
- res = VPX_CODEC_OK;
+ {
+ *mem_loc = (void *)shared_mem_loc;
+ return VPX_CODEC_OK;
+ }
#endif
-
- return res;
}
static vpx_codec_err_t vp8e_init(vpx_codec_ctx_t *ctx,
@@ -659,7 +664,11 @@
#if CONFIG_MULTI_RES_ENCODING
/* Free multi-encoder shared memory */
if (ctx->oxcf.mr_total_resolutions > 0 && (ctx->oxcf.mr_encoder_id == ctx->oxcf.mr_total_resolutions-1))
+ {
+ LOWER_RES_FRAME_INFO *shared_mem_loc = (LOWER_RES_FRAME_INFO *)ctx->oxcf.mr_low_res_mode_info;
+ free(shared_mem_loc->mb_info);
free(ctx->oxcf.mr_low_res_mode_info);
+ }
#endif
free(ctx->cx_data);
diff --git a/vp8_multi_resolution_encoder.c b/vp8_multi_resolution_encoder.c
index 78f50c2..81e7137 100644
--- a/vp8_multi_resolution_encoder.c
+++ b/vp8_multi_resolution_encoder.c
@@ -288,8 +288,13 @@
cfg[0].g_lag_in_frames = 0;
/* Disable automatic keyframe placement */
+ /* Note: These 3 settings are copied to all levels. But, except the lowest
+ * resolution level, all other levels are set to VPX_KF_DISABLED internally.
+ */
//cfg[0].kf_mode = VPX_KF_DISABLED;
- cfg[0].kf_min_dist = cfg[0].kf_max_dist = 1000;
+ cfg[0].kf_mode = VPX_KF_AUTO;
+ cfg[0].kf_min_dist = 0;
+ cfg[0].kf_max_dist = 150;
cfg[0].rc_target_bitrate = target_bitrate[0]; /* Set target bitrate */
cfg[0].g_timebase.num = 1; /* Set fps */
diff --git a/vpx/src/vpx_encoder.c b/vpx/src/vpx_encoder.c
index 03ddc62..db0120c 100644
--- a/vpx/src/vpx_encoder.c
+++ b/vpx/src/vpx_encoder.c
@@ -117,6 +117,13 @@
mr_cfg.mr_down_sampling_factor.num = dsf->num;
mr_cfg.mr_down_sampling_factor.den = dsf->den;
+ /* Force Key-frame synchronization. Namely, encoder at higher
+ * resolution always use the same frame_type chosen by the
+ * lowest-resolution encoder.
+ */
+ if(mr_cfg.mr_encoder_id)
+ cfg->kf_mode = VPX_KF_DISABLED;
+
ctx->iface = iface;
ctx->name = iface->name;
ctx->priv = NULL;