Updated encoder to handle intra-only frames
authorAlexander Voronov <avoronov@graphics.cs.msu.ru>
Thu, 3 Oct 2013 16:07:24 +0000 (20:07 +0400)
committerAdrian Grange <agrange@google.com>
Tue, 15 Oct 2013 23:44:02 +0000 (16:44 -0700)
Updated the encoder to handle frames that are coded
intra-only. Intra-only frames must be non-showable,
that is, the "show frame" flag must be set to 0 in
the frame header.

Tested by forcing the ARF frames to be coded intra-
only.

Note: The rate control code will need to be modified
to account for intra-only frames better than they
are currently handled.

Change-Id: I6a9dd5337deddcecc599d3a44a7431909ed21079

vp9/common/vp9_entropy.c
vp9/common/vp9_onyxc_int.h
vp9/decoder/vp9_decodemv.c
vp9/decoder/vp9_decodframe.c
vp9/encoder/vp9_bitstream.c
vp9/encoder/vp9_encodeframe.c
vp9/encoder/vp9_onyx_if.c
vp9/encoder/vp9_rdopt.c
vp9/encoder/vp9_segmentation.c

index 8ebe0e5..7479e7a 100644 (file)
@@ -348,7 +348,7 @@ void vp9_adapt_coef_probs(VP9_COMMON *cm) {
   TX_SIZE t;
   unsigned int count_sat, update_factor;
 
-  if (cm->frame_type == KEY_FRAME || cm->intra_only) {
+  if (frame_is_intra_only(cm)) {
     update_factor = COEF_MAX_UPDATE_FACTOR_KEY;
     count_sat = COEF_COUNT_SAT_KEY;
   } else if (cm->last_frame_type == KEY_FRAME) {
index 953764c..5c8c03e 100644 (file)
@@ -302,4 +302,9 @@ static void set_prev_mi(VP9_COMMON *cm) {
   cm->prev_mi = use_prev_in_find_mv_refs ?
                   cm->prev_mip + cm->mode_info_stride + 1 : NULL;
 }
+
+static INLINE int frame_is_intra_only(const VP9_COMMON *const cm) {
+  return cm->frame_type == KEY_FRAME || cm->intra_only;
+}
+
 #endif  // VP9_COMMON_VP9_ONYXC_INT_H_
index 8c1399d..cc9984a 100644 (file)
@@ -631,7 +631,7 @@ void vp9_prepare_read_mode_info(VP9D_COMP* pbi, vp9_reader *r) {
   for (k = 0; k < MBSKIP_CONTEXTS; ++k)
     vp9_diff_update_prob(r, &cm->fc.mbskip_probs[k]);
 
-  if (cm->frame_type != KEY_FRAME && !cm->intra_only) {
+  if (!frame_is_intra_only(cm)) {
     nmv_context *const nmvc = &pbi->common.fc.nmvc;
     MACROBLOCKD *const xd = &pbi->mb;
     int i, j;
@@ -669,7 +669,7 @@ void vp9_read_mode_info(VP9D_COMP* pbi, int mi_row, int mi_col, vp9_reader *r) {
   const int x_mis = MIN(bw, cm->mi_cols - mi_col);
   int x, y, z;
 
-  if (cm->frame_type == KEY_FRAME || cm->intra_only)
+  if (frame_is_intra_only(cm))
     read_intra_frame_mode_info(pbi, mi, mi_row, mi_col, r);
   else
     read_inter_frame_mode_info(pbi, mi, mi_row, mi_col, r);
index acde390..bc55438 100644 (file)
@@ -894,9 +894,11 @@ static size_t read_uncompressed_header(VP9D_COMP *pbi,
     cm->frame_parallel_decoding_mode = 1;
   }
 
+  // This flag will be overridden by the call to vp9_setup_past_independence
+  // below, forcing the use of context 0 for those frame types.
   cm->frame_context_idx = vp9_rb_read_literal(rb, NUM_FRAME_CONTEXTS_LOG2);
 
-  if (cm->frame_type == KEY_FRAME || cm->error_resilient_mode || cm->intra_only)
+  if (frame_is_intra_only(cm) || cm->error_resilient_mode)
     vp9_setup_past_independence(cm);
 
   setup_loopfilter(&cm->lf, rb);
@@ -1016,7 +1018,7 @@ int vp9_decode_frame(VP9D_COMP *pbi, const uint8_t **p_data_end) {
   if (!cm->error_resilient_mode && !cm->frame_parallel_decoding_mode) {
     vp9_adapt_coef_probs(cm);
 
-    if (!keyframe && !cm->intra_only) {
+    if (!frame_is_intra_only(cm)) {
       vp9_adapt_mode_probs(cm);
       vp9_adapt_mv_probs(cm, xd->allow_high_precision_mv);
     }
index 428ca7e..04752d4 100644 (file)
@@ -580,7 +580,7 @@ static void write_modes_b(VP9_COMP *cpi, MODE_INFO **mi_8x8, vp9_writer *bc,
   set_mi_row_col(&cpi->common, xd,
                  mi_row, num_8x8_blocks_high_lookup[m->mbmi.sb_type],
                  mi_col, num_8x8_blocks_wide_lookup[m->mbmi.sb_type]);
-  if ((cm->frame_type == KEY_FRAME) || cm->intra_only) {
+  if (frame_is_intra_only(cm)) {
     write_mb_modes_kf(cpi, mi_8x8, bc);
 #ifdef ENTROPY_STATS
     active_section = 8;
@@ -1449,7 +1449,7 @@ static size_t write_compressed_header(VP9_COMP *cpi, uint8_t *data) {
 
   vp9_update_skip_probs(cpi, &header_bc);
 
-  if (cm->frame_type != KEY_FRAME) {
+  if (!frame_is_intra_only(cm)) {
     int i;
 #ifdef ENTROPY_STATS
     active_section = 1;
index ead867b..e18bd12 100644 (file)
@@ -397,7 +397,7 @@ static void update_state(VP9_COMP *cpi, PICK_MODE_CONTEXT *ctx,
       cpi->rd_tx_select_diff[i] += ctx->tx_rd_diff[i];
   }
 
-  if (cm->frame_type == KEY_FRAME) {
+  if (frame_is_intra_only(cm)) {
 #if CONFIG_INTERNAL_STATS
     static const int kf_mode_index[] = {
       THR_DC /*DC_PRED*/,
@@ -581,7 +581,7 @@ static void pick_sb_modes(VP9_COMP *cpi, int mi_row, int mi_col,
 
   // Find best coding mode & reconstruct the MB so it is available
   // as a predictor for MBs that follow in the SB
-  if (cm->frame_type == KEY_FRAME) {
+  if (frame_is_intra_only(cm)) {
     vp9_rd_pick_intra_mode_sb(cpi, x, totalrate, totaldist, bsize, ctx,
                               best_rd);
   } else {
@@ -601,7 +601,7 @@ static void update_stats(VP9_COMP *cpi) {
   MODE_INFO *mi = xd->this_mi;
   MB_MODE_INFO *const mbmi = &mi->mbmi;
 
-  if (cm->frame_type != KEY_FRAME) {
+  if (!frame_is_intra_only(cm)) {
     const int seg_ref_active = vp9_segfeature_active(&cm->seg, mbmi->segment_id,
                                                      SEG_LVL_REF_FRAME);
 
@@ -1814,7 +1814,7 @@ static void init_encode_frame_mb_context(VP9_COMP *cpi) {
   xd->mode_info_stride = cm->mode_info_stride;
 
   // reset intra mode contexts
-  if (cm->frame_type == KEY_FRAME)
+  if (frame_is_intra_only(cm))
     vp9_init_mbmode_probs(cm);
 
   // Copy data over into macro block data structures.
@@ -2112,7 +2112,7 @@ static void reset_skip_txfm_size(VP9_COMP *cpi, TX_SIZE txfm_max) {
 
 static int get_frame_type(VP9_COMP *cpi) {
   int frame_type;
-  if (cpi->common.frame_type == KEY_FRAME)
+  if (frame_is_intra_only(&cpi->common))
     frame_type = 0;
   else if (cpi->is_src_frame_alt_ref && cpi->refresh_golden_frame)
     frame_type = 3;
@@ -2160,16 +2160,18 @@ void vp9_encode_frame(VP9_COMP *cpi) {
   // requires further work in the rd loop. For now the only supported encoder
   // side behavior is where the ALT ref buffer has opposite sign bias to
   // the other two.
-  if ((cm->ref_frame_sign_bias[ALTREF_FRAME]
-       == cm->ref_frame_sign_bias[GOLDEN_FRAME])
-      || (cm->ref_frame_sign_bias[ALTREF_FRAME]
-          == cm->ref_frame_sign_bias[LAST_FRAME])) {
-    cm->allow_comp_inter_inter = 0;
-  } else {
-    cm->allow_comp_inter_inter = 1;
-    cm->comp_fixed_ref = ALTREF_FRAME;
-    cm->comp_var_ref[0] = LAST_FRAME;
-    cm->comp_var_ref[1] = GOLDEN_FRAME;
+  if (!frame_is_intra_only(cm)) {
+    if ((cm->ref_frame_sign_bias[ALTREF_FRAME]
+         == cm->ref_frame_sign_bias[GOLDEN_FRAME])
+        || (cm->ref_frame_sign_bias[ALTREF_FRAME]
+            == cm->ref_frame_sign_bias[LAST_FRAME])) {
+      cm->allow_comp_inter_inter = 0;
+    } else {
+      cm->allow_comp_inter_inter = 1;
+      cm->comp_fixed_ref = ALTREF_FRAME;
+      cm->comp_var_ref[0] = LAST_FRAME;
+      cm->comp_var_ref[1] = GOLDEN_FRAME;
+    }
   }
 
   if (cpi->sf.RD) {
index 0afb35f..45d3232 100644 (file)
@@ -772,11 +772,9 @@ void vp9_set_speed_features(VP9_COMP *cpi) {
       sf->recode_loop = (speed < 1);
 
       if (speed == 1) {
-        sf->use_square_partition_only = !(cpi->common.frame_type == KEY_FRAME ||
-                                          cpi->common.intra_only);
+        sf->use_square_partition_only = !frame_is_intra_only(&cpi->common);
         sf->less_rectangular_check  = 1;
-        sf->tx_size_search_method = (cpi->common.frame_type == KEY_FRAME ||
-                                     cpi->common.intra_only)
+        sf->tx_size_search_method = frame_is_intra_only(&cpi->common)
                                      ? USE_FULL_RD : USE_LARGESTALL;
 
         if (MIN(cpi->common.width, cpi->common.height) >= 720)
@@ -795,12 +793,10 @@ void vp9_set_speed_features(VP9_COMP *cpi) {
         sf->intra_uv_mode_mask[TX_16X16] = INTRA_DC_H_V;
       }
       if (speed == 2) {
-        sf->use_square_partition_only = !(cpi->common.frame_type == KEY_FRAME ||
-                                          cpi->common.intra_only);
+        sf->use_square_partition_only = !frame_is_intra_only(&cpi->common);
         sf->less_rectangular_check  = 1;
-        sf->tx_size_search_method = ((cpi->common.frame_type == KEY_FRAME ||
-                                      cpi->common.intra_only)
-                                     ? USE_FULL_RD : USE_LARGESTALL);
+        sf->tx_size_search_method = frame_is_intra_only(&cpi->common)
+                                     ? USE_FULL_RD : USE_LARGESTALL;
 
         if (MIN(cpi->common.width, cpi->common.height) >= 720)
           sf->disable_split_mask = cpi->common.show_frame ?
@@ -911,8 +907,7 @@ void vp9_set_speed_features(VP9_COMP *cpi) {
         sf->comp_inter_joint_search_thresh = BLOCK_SIZES;
         sf->use_one_partition_size_always = 1;
         sf->always_this_block_size = BLOCK_16X16;
-        sf->tx_size_search_method = (cpi->common.frame_type == KEY_FRAME ||
-                                     cpi->common.intra_only) ?
+        sf->tx_size_search_method = frame_is_intra_only(&cpi->common) ?
                                      USE_FULL_RD : USE_LARGESTALL;
         sf->mode_search_skip_flags = FLAG_SKIP_INTRA_DIRMISMATCH |
                                      FLAG_SKIP_INTRA_BESTINTER |
@@ -2626,7 +2621,7 @@ static int pick_q_and_adjust_q_bounds(VP9_COMP *cpi,
   int q = cpi->active_worst_quality;
   VP9_COMMON *const cm = &cpi->common;
 
-  if (cm->frame_type == KEY_FRAME) {
+  if (frame_is_intra_only(cm)) {
 #if !CONFIG_MULTIPLE_ARF
     // Handle the special case for key frames forced when we have75 reached
     // the maximum key frame interval. Here force the Q to a range
@@ -2876,7 +2871,7 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi,
   cpi->mv_step_param = vp9_init_search_range(cpi, max_mv_def);
   // Initialize cpi->max_mv_magnitude and cpi->mv_step_param if appropriate.
   if (sf->auto_mv_step_size) {
-    if ((cpi->common.frame_type == KEY_FRAME) || cpi->common.intra_only) {
+    if (frame_is_intra_only(&cpi->common)) {
       // Initialize max_mv_magnitude for use in the first INTER frame
       // after a key/intra-only frame.
       cpi->max_mv_magnitude = max_mv_def;
@@ -2892,8 +2887,8 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi,
   }
 
   // Set various flags etc to special state if it is a key frame.
-  if (cm->frame_type == KEY_FRAME) {
-    // Reset the loop filter deltas and segmentation map.
+  if (frame_is_intra_only(cm)) {
+    // Reset the loop filter deltas and segmentation map
     setup_features(cm);
 
     // If segmentation is enabled force a map update for key frames.
@@ -2912,6 +2907,9 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi,
       cm->frame_parallel_decoding_mode = 1;
       cm->reset_frame_context = 0;
       cm->refresh_frame_context = 0;
+    } else if (cm->intra_only) {
+      // Only reset the current context.
+      cm->reset_frame_context = 2;
     }
   }
 
@@ -2961,7 +2959,7 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi,
   loop_count = 0;
   vp9_zero(cpi->rd_tx_select_threshes);
 
-  if (cm->frame_type != KEY_FRAME) {
+  if (!frame_is_intra_only(cm)) {
     cm->mcomp_filter_type = DEFAULT_INTERP_FILTER;
     /* TODO: Decide this more intelligently */
     xd->allow_high_precision_mv = q < HIGH_PRECISION_MV_QTHRESH;
@@ -3007,20 +3005,17 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi,
     vp9_set_quantizer(cpi, q);
 
     if (loop_count == 0) {
-      // Set up entropy depending on frame type.
+      // Set up entropy context depending on frame type. The decoder mandates
+      // the use of the default context, index 0, for keyframes and inter
+      // frames where the error_resilient_mode or intra_only flag is set. For
+      // other inter-frames the encoder currently uses only two contexts;
+      // context 1 for ALTREF frames and context 0 for the others.
       if (cm->frame_type == KEY_FRAME) {
-        /* Choose which entropy context to use. When using a forward reference
-         * frame, it immediately follows the keyframe, and thus benefits from
-         * using the same entropy context established by the keyframe.
-         *  Otherwise, use the default context 0.
-         */
-        cm->frame_context_idx = cpi->oxcf.play_alternate;
         vp9_setup_key_frame(cpi);
       } else {
-        /* Choose which entropy context to use. Currently there are only two
-         * contexts used, one for normal frames and one for alt ref frames.
-         */
-        cpi->common.frame_context_idx = cpi->refresh_alt_ref_frame;
+        if (!cm->intra_only && !cm->error_resilient_mode) {
+          cpi->common.frame_context_idx = cpi->refresh_alt_ref_frame;
+        }
         vp9_setup_inter_frame(cpi);
       }
     }
@@ -3239,7 +3234,7 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi,
     vp9_adapt_coef_probs(&cpi->common);
   }
 
-  if (cpi->common.frame_type != KEY_FRAME) {
+  if (!frame_is_intra_only(&cpi->common)) {
     FRAME_COUNTS *counts = &cpi->common.counts;
 
     vp9_copy(counts->y_mode, cpi->y_mode_count);
@@ -3618,7 +3613,6 @@ int vp9_get_compressed_data(VP9_PTR ptr, unsigned int *frame_flags,
       }
 
       cm->show_frame = 0;
-      cm->intra_only = 0;
       cpi->refresh_alt_ref_frame = 1;
       cpi->refresh_golden_frame = 0;
       cpi->refresh_last_frame = 0;
@@ -3640,6 +3634,7 @@ int vp9_get_compressed_data(VP9_PTR ptr, unsigned int *frame_flags,
 #endif
     if ((cpi->source = vp9_lookahead_pop(cpi->lookahead, flush))) {
       cm->show_frame = 1;
+      cm->intra_only = 0;
 
 #if CONFIG_MULTIPLE_ARF
       // Is this frame the ARF overlay.
index eb7ca6b..c8f440c 100644 (file)
@@ -251,7 +251,7 @@ void vp9_initialize_rd_consts(VP9_COMP *cpi, int qindex) {
   /*rough estimate for costing*/
   vp9_init_mode_costs(cpi);
 
-  if (cpi->common.frame_type != KEY_FRAME) {
+  if (!frame_is_intra_only(&cpi->common)) {
     vp9_build_nmv_cost_table(
         cpi->mb.nmvjointcost,
         cpi->mb.e_mbd.allow_high_precision_mv ?
index 874b71a..5137d36 100644 (file)
@@ -253,13 +253,13 @@ void vp9_choose_segmap_coding_method(VP9_COMP *cpi) {
   no_pred_cost = cost_segmap(no_pred_segcounts, no_pred_tree);
 
   // Key frames cannot use temporal prediction
-  if (cm->frame_type != KEY_FRAME) {
+  if (!frame_is_intra_only(cm)) {
     // 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);
     t_pred_cost = cost_segmap(t_unpred_seg_counts, t_pred_tree);
 
-    // Add in the cost of the signalling for each prediction context
+    // Add in the cost of the signaling for each prediction context.
     for (i = 0; i < PREDICTION_PROBS; i++) {
       const int count0 = temporal_predictor_count[i][0];
       const int count1 = temporal_predictor_count[i][1];