Refactor firstpass: break the main function to a few functions.

(1). Add two sub functions.
(2). Group a few parameters into a structure for readability.
(3). Add comments for these parameters.

Change-Id: If5e926480e759f6e2b30eb8f1057a991ddd80498
diff --git a/av1/encoder/firstpass.c b/av1/encoder/firstpass.c
index 7e37847..ba2b862 100644
--- a/av1/encoder/firstpass.c
+++ b/av1/encoder/firstpass.c
@@ -295,6 +295,173 @@
   return raw_err_stdev;
 }
 
+// This structure contains several key parameters to be accumulate for this
+// frame.
+typedef struct {
+  // Intra prediction error.
+  int64_t intra_error;
+  // Average wavelet energy computed using Discrete Wavelet Transform (DWT).
+  int64_t frame_avg_wavelet_energy;
+  // Best of intra pred error and inter pred error using last frame as ref.
+  int64_t coded_error;
+  // Best of intra pred error and inter pred error using golden frame as ref.
+  int64_t sr_coded_error;
+  // Best of intra pred error and inter pred error using altref frame as ref.
+  int64_t tr_coded_error;
+  // Count of motion vector.
+  int mv_count;
+  // Count of blocks that pick inter prediction (inter pred error is smaller
+  // than intra pred error).
+  int inter_count;
+  // Count of blocks that pick second ref (golden frame).
+  int second_ref_count;
+  // Count of blocks that pick third ref (altref frame).
+  int third_ref_count;
+  // Count of blocks where the inter and intra are very close and very low.
+  double neutral_count;
+  // Count of blocks where intra error is very small.
+  int intra_skip_count;
+  // Start row.
+  int image_data_start_row;
+  // Count of unique non-zero motion vectors.
+  int new_mv_count;
+  // Sum of inward motion vectors.
+  int sum_in_vectors;
+  // Sum of motion vector row.
+  int sum_mvr;
+  // Sum of motion vector column.
+  int sum_mvc;
+  // Sum of absolute value of motion vector row.
+  int sum_mvr_abs;
+  // Sum of absolute value of motion vector column.
+  int sum_mvc_abs;
+  // Sum of the square of motion vector row.
+  int64_t sum_mvrs;
+  // Sum of the square of motion vector column.
+  int64_t sum_mvcs;
+  // A factor calculated using intra pred error.
+  double intra_factor;
+  // A factor that measures brightness.
+  double brightness_factor;
+} FRAME_STATS;
+
+// Updates the first pass stats of this frame.
+// Input:
+//   cpi: the encoder setting. Only a few params in it will be used.
+//   stats: stats accumulated for this frame.
+//   raw_err_stdev: the statndard deviation for the motion error of all the
+//                  inter blocks of the (0,0) motion using the last source
+//                  frame as the reference.
+//   frame_number: current frame number.
+//   ts_duration: Duration of the frame / collection of frames.
+// Updates:
+//   twopass->total_stats: the accumulated stats.
+//   twopass->stats_buf_ctx->stats_in_end: the pointer to the current stats,
+//                                         update its value and its position
+//                                         in the buffer.
+static void update_firstpass_stats(AV1_COMP *cpi,
+                                   const FRAME_STATS *const stats,
+                                   const double raw_err_stdev,
+                                   const int frame_number,
+                                   const int64_t ts_duration) {
+  TWO_PASS *twopass = &cpi->twopass;
+  AV1_COMMON *const cm = &cpi->common;
+  const CommonModeInfoParams *const mi_params = &cm->mi_params;
+  FIRSTPASS_STATS *this_frame_stats = twopass->stats_buf_ctx->stats_in_end;
+  FIRSTPASS_STATS fps;
+  // The minimum error here insures some bit allocation to frames even
+  // in static regions. The allocation per MB declines for larger formats
+  // where the typical "real" energy per MB also falls.
+  // Initial estimate here uses sqrt(mbs) to define the min_err, where the
+  // number of mbs is proportional to the image area.
+  const int num_mbs = (cpi->oxcf.resize_mode != RESIZE_NONE) ? cpi->initial_mbs
+                                                             : mi_params->MBs;
+  const double min_err = 200 * sqrt(num_mbs);
+
+  fps.weight = stats->intra_factor * stats->brightness_factor;
+  fps.frame = frame_number;
+  fps.coded_error = (double)(stats->coded_error >> 8) + min_err;
+  fps.sr_coded_error = (double)(stats->sr_coded_error >> 8) + min_err;
+  fps.tr_coded_error = (double)(stats->tr_coded_error >> 8) + min_err;
+  fps.intra_error = (double)(stats->intra_error >> 8) + min_err;
+  fps.frame_avg_wavelet_energy = (double)stats->frame_avg_wavelet_energy;
+  fps.count = 1.0;
+  fps.pcnt_inter = (double)stats->inter_count / num_mbs;
+  fps.pcnt_second_ref = (double)stats->second_ref_count / num_mbs;
+  fps.pcnt_third_ref = (double)stats->third_ref_count / num_mbs;
+  fps.pcnt_neutral = (double)stats->neutral_count / num_mbs;
+  fps.intra_skip_pct = (double)stats->intra_skip_count / num_mbs;
+  fps.inactive_zone_rows = (double)stats->image_data_start_row;
+  fps.inactive_zone_cols = (double)0;  // TODO(paulwilkins): fix
+  fps.raw_error_stdev = raw_err_stdev;
+
+  if (stats->mv_count > 0) {
+    fps.MVr = (double)stats->sum_mvr / stats->mv_count;
+    fps.mvr_abs = (double)stats->sum_mvr_abs / stats->mv_count;
+    fps.MVc = (double)stats->sum_mvc / stats->mv_count;
+    fps.mvc_abs = (double)stats->sum_mvc_abs / stats->mv_count;
+    fps.MVrv = ((double)stats->sum_mvrs -
+                ((double)stats->sum_mvr * stats->sum_mvr / stats->mv_count)) /
+               stats->mv_count;
+    fps.MVcv = ((double)stats->sum_mvcs -
+                ((double)stats->sum_mvc * stats->sum_mvc / stats->mv_count)) /
+               stats->mv_count;
+    fps.mv_in_out_count = (double)stats->sum_in_vectors / (stats->mv_count * 2);
+    fps.new_mv_count = stats->new_mv_count;
+    fps.pcnt_motion = (double)stats->mv_count / num_mbs;
+  } else {
+    fps.MVr = 0.0;
+    fps.mvr_abs = 0.0;
+    fps.MVc = 0.0;
+    fps.mvc_abs = 0.0;
+    fps.MVrv = 0.0;
+    fps.MVcv = 0.0;
+    fps.mv_in_out_count = 0.0;
+    fps.new_mv_count = 0.0;
+    fps.pcnt_motion = 0.0;
+  }
+
+  // TODO(paulwilkins):  Handle the case when duration is set to 0, or
+  // something less than the full time between subsequent values of
+  // cpi->source_time_stamp.
+  fps.duration = (double)ts_duration;
+
+  // We will store the stats inside the persistent twopass struct (and NOT the
+  // local variable 'fps'), and then cpi->output_pkt_list will point to it.
+  *this_frame_stats = fps;
+  output_stats(this_frame_stats, cpi->output_pkt_list);
+  if (twopass->total_stats != NULL) {
+    accumulate_stats(twopass->total_stats, &fps);
+  }
+  /*In the case of two pass, first pass uses it as a circular buffer,
+   * when LAP is enabled it is used as a linear buffer*/
+  twopass->stats_buf_ctx->stats_in_end++;
+  if ((cpi->oxcf.pass == 1) && (twopass->stats_buf_ctx->stats_in_end >=
+                                twopass->stats_buf_ctx->stats_in_buf_end)) {
+    twopass->stats_buf_ctx->stats_in_end =
+        twopass->stats_buf_ctx->stats_in_start;
+  }
+}
+
+static void print_reconstruction_frame(
+    const YV12_BUFFER_CONFIG *const last_frame, int frame_number,
+    int do_print) {
+  if (!do_print) return;
+
+  char filename[512];
+  FILE *recon_file;
+  snprintf(filename, sizeof(filename), "enc%04d.yuv", frame_number);
+
+  if (frame_number == 0) {
+    recon_file = fopen(filename, "wb");
+  } else {
+    recon_file = fopen(filename, "ab");
+  }
+
+  fwrite(last_frame->buffer_alloc, last_frame->frame_size, 1, recon_file);
+  fclose(recon_file);
+}
+
 #define UL_INTRA_THRESH 50
 #define INVALID_ROW -1
 #define FIRST_PASS_ALT_REF_DISTANCE 16
@@ -315,29 +482,14 @@
   int i;
 
   int recon_yoffset, src_yoffset, recon_uvoffset;
-  int64_t intra_error = 0;
-  int64_t frame_avg_wavelet_energy = 0;
-  int64_t coded_error = 0;
-  int64_t sr_coded_error = 0;
-  int64_t tr_coded_error = 0;
-
-  int sum_mvr = 0, sum_mvc = 0;
-  int sum_mvr_abs = 0, sum_mvc_abs = 0;
-  int64_t sum_mvrs = 0, sum_mvcs = 0;
-  int mvcount = 0;
-  int intercount = 0;
-  int second_ref_count = 0;
-  int third_ref_count = 0;
   const int intrapenalty = INTRA_MODE_PENALTY;
-  double neutral_count;
-  int intra_skip_count = 0;
-  int image_data_start_row = INVALID_ROW;
-  int new_mv_count = 0;
-  int sum_in_vectors = 0;
   MV lastmv = kZeroMv;
   TWO_PASS *twopass = &cpi->twopass;
   int recon_y_stride, src_y_stride, recon_uv_stride, uv_mb_height;
 
+  FRAME_STATS stats = { 0 };
+  stats.image_data_start_row = INVALID_ROW;
+
   const YV12_BUFFER_CONFIG *const last_frame =
       get_ref_frame_yv12_buf(cm, LAST_FRAME);
   const YV12_BUFFER_CONFIG *golden_frame =
@@ -355,8 +507,6 @@
     }
   }
   YV12_BUFFER_CONFIG *const this_frame = &cm->cur_frame->buf;
-  double intra_factor;
-  double brightness_factor;
   const int qindex = find_fp_qindex(seq_params->bit_depth);
   // First pass coding processes in raster scan with unit size of 16x16.
   const BLOCK_SIZE fp_block_size = BLOCK_16X16;
@@ -379,10 +529,6 @@
   set_mi_offsets(mi_params, xd, 0, 0);
   xd->mi[0]->sb_type = fp_block_size;
 
-  intra_factor = 0.0;
-  brightness_factor = 0.0;
-  neutral_count = 0.0;
-
   // Do not use periodic key frames.
   cpi->rc.frames_to_key = INT_MAX;
 
@@ -476,9 +622,9 @@
       this_intra_error = aom_get_mb_ss(x->plane[0].src_diff);
 
       if (this_intra_error < UL_INTRA_THRESH) {
-        ++intra_skip_count;
-      } else if ((mb_col > 0) && (image_data_start_row == INVALID_ROW)) {
-        image_data_start_row = mb_row;
+        ++stats.intra_skip_count;
+      } else if ((mb_col > 0) && (stats.image_data_start_row == INVALID_ROW)) {
+        stats.image_data_start_row = mb_row;
       }
 
       if (seq_params->use_highbitdepth) {
@@ -497,18 +643,18 @@
       aom_clear_system_state();
       log_intra = log(this_intra_error + 1.0);
       if (log_intra < 10.0)
-        intra_factor += 1.0 + ((10.0 - log_intra) * 0.05);
+        stats.intra_factor += 1.0 + ((10.0 - log_intra) * 0.05);
       else
-        intra_factor += 1.0;
+        stats.intra_factor += 1.0;
 
       if (seq_params->use_highbitdepth)
         level_sample = CONVERT_TO_SHORTPTR(x->plane[0].src.buf)[0];
       else
         level_sample = x->plane[0].src.buf[0];
       if ((level_sample < DARK_THRESH) && (log_intra < 9.0))
-        brightness_factor += 1.0 + (0.01 * (DARK_THRESH - level_sample));
+        stats.brightness_factor += 1.0 + (0.01 * (DARK_THRESH - level_sample));
       else
-        brightness_factor += 1.0;
+        stats.brightness_factor += 1.0;
 
       // Intrapenalty below deals with situations where the intra and inter
       // error scores are very low (e.g. a plain black frame).
@@ -520,14 +666,14 @@
       this_intra_error += intrapenalty;
 
       // Accumulate the intra error.
-      intra_error += (int64_t)this_intra_error;
+      stats.intra_error += (int64_t)this_intra_error;
 
       const int hbd = is_cur_buf_hbd(xd);
       const int stride = x->plane[0].src.stride;
       uint8_t *buf = x->plane[0].src.buf;
       for (int r8 = 0; r8 < 2; ++r8) {
         for (int c8 = 0; c8 < 2; ++c8) {
-          frame_avg_wavelet_energy += av1_haar_ac_sad_8x8_uint8_input(
+          stats.frame_avg_wavelet_energy += av1_haar_ac_sad_8x8_uint8_input(
               buf + c8 * 8 + r8 * 8 * stride, stride, hbd);
         }
       }
@@ -617,7 +763,7 @@
 
             if (gf_motion_error < motion_error &&
                 gf_motion_error < this_intra_error)
-              ++second_ref_count;
+              ++stats.second_ref_count;
 
             // Reset to last frame as reference buffer.
             xd->plane[0].pre[0].buf = last_frame->y_buffer + recon_yoffset;
@@ -629,12 +775,12 @@
             // (just as will be done for) accumulation of "coded_error" for
             // the last frame.
             if (gf_motion_error < this_intra_error)
-              sr_coded_error += gf_motion_error;
+              stats.sr_coded_error += gf_motion_error;
             else
-              sr_coded_error += this_intra_error;
+              stats.sr_coded_error += this_intra_error;
           } else {
             gf_motion_error = motion_error;
-            sr_coded_error += motion_error;
+            stats.sr_coded_error += motion_error;
           }
 
           // Motion search in 3rd reference frame.
@@ -661,7 +807,7 @@
             if (alt_motion_error < motion_error &&
                 alt_motion_error < gf_motion_error &&
                 alt_motion_error < this_intra_error)
-              ++third_ref_count;
+              ++stats.third_ref_count;
 
             // Reset to last frame as reference buffer.
             xd->plane[0].pre[0].buf = last_frame->y_buffer + recon_yoffset;
@@ -671,13 +817,13 @@
             // best of the motion predicted score and the intra coded error
             // (just as will be done for) accumulation of "coded_error" for
             // the last frame.
-            tr_coded_error += AOMMIN(alt_motion_error, this_intra_error);
+            stats.tr_coded_error += AOMMIN(alt_motion_error, this_intra_error);
           } else {
-            tr_coded_error += motion_error;
+            stats.tr_coded_error += motion_error;
           }
         } else {
-          sr_coded_error += motion_error;
-          tr_coded_error += motion_error;
+          stats.sr_coded_error += motion_error;
+          stats.tr_coded_error += motion_error;
         }
 
         // Start by assuming that intra mode is best.
@@ -692,14 +838,15 @@
           // cropped clips with black bars at the sides or top and bottom.
           if (((this_intra_error - intrapenalty) * 9 <= motion_error * 10) &&
               (this_intra_error < (2 * intrapenalty))) {
-            neutral_count += 1.0;
+            stats.neutral_count += 1.0;
             // Also track cases where the intra is not much worse than the inter
             // and use this in limiting the GF/arf group length.
           } else if ((this_intra_error > NCOUNT_INTRA_THRESH) &&
                      (this_intra_error <
                       (NCOUNT_INTRA_FACTOR * motion_error))) {
-            neutral_count += (double)motion_error /
-                             DOUBLE_DIVIDE_CHECK((double)this_intra_error);
+            stats.neutral_count +=
+                (double)motion_error /
+                DOUBLE_DIVIDE_CHECK((double)this_intra_error);
           }
 
           MV best_mv = get_mv_from_fullmv(&mv);
@@ -713,56 +860,55 @@
                                         mb_col * mb_scale, NULL, bsize,
                                         AOM_PLANE_Y, AOM_PLANE_Y);
           av1_encode_sby_pass1(cpi, x, bsize);
-          sum_mvr += best_mv.row;
-          sum_mvr_abs += abs(best_mv.row);
-          sum_mvc += best_mv.col;
-          sum_mvc_abs += abs(best_mv.col);
-          sum_mvrs += best_mv.row * best_mv.row;
-          sum_mvcs += best_mv.col * best_mv.col;
-          ++intercount;
+          stats.sum_mvr += best_mv.row;
+          stats.sum_mvr_abs += abs(best_mv.row);
+          stats.sum_mvc += best_mv.col;
+          stats.sum_mvc_abs += abs(best_mv.col);
+          stats.sum_mvrs += best_mv.row * best_mv.row;
+          stats.sum_mvcs += best_mv.col * best_mv.col;
+          ++stats.inter_count;
 
           best_ref_mv = best_mv;
 
           if (!is_zero_mv(&best_mv)) {
-            ++mvcount;
-
+            ++stats.mv_count;
             // Non-zero vector, was it different from the last non zero vector?
-            if (!is_equal_mv(&best_mv, &lastmv)) ++new_mv_count;
+            if (!is_equal_mv(&best_mv, &lastmv)) ++stats.new_mv_count;
             lastmv = best_mv;
 
             // Does the row vector point inwards or outwards?
             if (mb_row < mi_params->mb_rows / 2) {
               if (mv.row > 0)
-                --sum_in_vectors;
+                --stats.sum_in_vectors;
               else if (mv.row < 0)
-                ++sum_in_vectors;
+                ++stats.sum_in_vectors;
             } else if (mb_row > mi_params->mb_rows / 2) {
               if (mv.row > 0)
-                ++sum_in_vectors;
+                ++stats.sum_in_vectors;
               else if (mv.row < 0)
-                --sum_in_vectors;
+                --stats.sum_in_vectors;
             }
 
             // Does the col vector point inwards or outwards?
             if (mb_col < mi_params->mb_cols / 2) {
               if (mv.col > 0)
-                --sum_in_vectors;
+                --stats.sum_in_vectors;
               else if (mv.col < 0)
-                ++sum_in_vectors;
+                ++stats.sum_in_vectors;
             } else if (mb_col > mi_params->mb_cols / 2) {
               if (mv.col > 0)
-                ++sum_in_vectors;
+                ++stats.sum_in_vectors;
               else if (mv.col < 0)
-                --sum_in_vectors;
+                --stats.sum_in_vectors;
             }
           }
         }
         raw_motion_err_list[raw_motion_err_counts++] = raw_motion_error;
       } else {
-        sr_coded_error += (int64_t)this_intra_error;
-        tr_coded_error += (int64_t)this_intra_error;
+        stats.sr_coded_error += (int64_t)this_intra_error;
+        stats.tr_coded_error += (int64_t)this_intra_error;
       }
-      coded_error += (int64_t)this_intra_error;
+      stats.coded_error += (int64_t)this_intra_error;
 
       // Adjust to the next column of MBs.
       x->plane[0].src.buf += fp_block_size_width;
@@ -790,93 +936,24 @@
 
   // Clamp the image start to rows/2. This number of rows is discarded top
   // and bottom as dead data so rows / 2 means the frame is blank.
-  if ((image_data_start_row > mi_params->mb_rows / 2) ||
-      (image_data_start_row == INVALID_ROW)) {
-    image_data_start_row = mi_params->mb_rows / 2;
+  if ((stats.image_data_start_row > mi_params->mb_rows / 2) ||
+      (stats.image_data_start_row == INVALID_ROW)) {
+    stats.image_data_start_row = mi_params->mb_rows / 2;
   }
   // Exclude any image dead zone
-  if (image_data_start_row > 0) {
-    intra_skip_count = AOMMAX(
-        0, intra_skip_count - (image_data_start_row * mi_params->mb_cols * 2));
+  if (stats.image_data_start_row > 0) {
+    stats.intra_skip_count =
+        AOMMAX(0, stats.intra_skip_count -
+                      (stats.image_data_start_row * mi_params->mb_cols * 2));
   }
 
+  const int num_mbs = (cpi->oxcf.resize_mode != RESIZE_NONE) ? cpi->initial_mbs
+                                                             : mi_params->MBs;
+  stats.intra_factor = stats.intra_factor / (double)num_mbs;
+  stats.brightness_factor = stats.brightness_factor / (double)num_mbs;
   FIRSTPASS_STATS *this_frame_stats = twopass->stats_buf_ctx->stats_in_end;
-  {
-    FIRSTPASS_STATS fps;
-    // The minimum error here insures some bit allocation to frames even
-    // in static regions. The allocation per MB declines for larger formats
-    // where the typical "real" energy per MB also falls.
-    // Initial estimate here uses sqrt(mbs) to define the min_err, where the
-    // number of mbs is proportional to the image area.
-    const int num_mbs = (cpi->oxcf.resize_mode != RESIZE_NONE)
-                            ? cpi->initial_mbs
-                            : mi_params->MBs;
-    const double min_err = 200 * sqrt(num_mbs);
-
-    intra_factor = intra_factor / (double)num_mbs;
-    brightness_factor = brightness_factor / (double)num_mbs;
-    fps.weight = intra_factor * brightness_factor;
-
-    fps.frame = current_frame->frame_number;
-    fps.coded_error = (double)(coded_error >> 8) + min_err;
-    fps.sr_coded_error = (double)(sr_coded_error >> 8) + min_err;
-    fps.tr_coded_error = (double)(tr_coded_error >> 8) + min_err;
-    fps.intra_error = (double)(intra_error >> 8) + min_err;
-    fps.frame_avg_wavelet_energy = (double)frame_avg_wavelet_energy;
-    fps.count = 1.0;
-    fps.pcnt_inter = (double)intercount / num_mbs;
-    fps.pcnt_second_ref = (double)second_ref_count / num_mbs;
-    fps.pcnt_third_ref = (double)third_ref_count / num_mbs;
-    fps.pcnt_neutral = (double)neutral_count / num_mbs;
-    fps.intra_skip_pct = (double)intra_skip_count / num_mbs;
-    fps.inactive_zone_rows = (double)image_data_start_row;
-    fps.inactive_zone_cols = (double)0;  // TODO(paulwilkins): fix
-    fps.raw_error_stdev = raw_err_stdev;
-
-    if (mvcount > 0) {
-      fps.MVr = (double)sum_mvr / mvcount;
-      fps.mvr_abs = (double)sum_mvr_abs / mvcount;
-      fps.MVc = (double)sum_mvc / mvcount;
-      fps.mvc_abs = (double)sum_mvc_abs / mvcount;
-      fps.MVrv =
-          ((double)sum_mvrs - ((double)sum_mvr * sum_mvr / mvcount)) / mvcount;
-      fps.MVcv =
-          ((double)sum_mvcs - ((double)sum_mvc * sum_mvc / mvcount)) / mvcount;
-      fps.mv_in_out_count = (double)sum_in_vectors / (mvcount * 2);
-      fps.new_mv_count = new_mv_count;
-      fps.pcnt_motion = (double)mvcount / num_mbs;
-    } else {
-      fps.MVr = 0.0;
-      fps.mvr_abs = 0.0;
-      fps.MVc = 0.0;
-      fps.mvc_abs = 0.0;
-      fps.MVrv = 0.0;
-      fps.MVcv = 0.0;
-      fps.mv_in_out_count = 0.0;
-      fps.new_mv_count = 0.0;
-      fps.pcnt_motion = 0.0;
-    }
-
-    // TODO(paulwilkins):  Handle the case when duration is set to 0, or
-    // something less than the full time between subsequent values of
-    // cpi->source_time_stamp.
-    fps.duration = (double)ts_duration;
-
-    // We will store the stats inside the persistent twopass struct (and NOT the
-    // local variable 'fps'), and then cpi->output_pkt_list will point to it.
-    *this_frame_stats = fps;
-    output_stats(this_frame_stats, cpi->output_pkt_list);
-    if (twopass->total_stats != NULL)
-      accumulate_stats(twopass->total_stats, &fps);
-    /*In the case of two pass, first pass uses it as a circular buffer,
-     * when LAP is enabled it is used as a linear buffer*/
-    twopass->stats_buf_ctx->stats_in_end++;
-    if ((cpi->oxcf.pass == 1) && (twopass->stats_buf_ctx->stats_in_end >=
-                                  twopass->stats_buf_ctx->stats_in_buf_end)) {
-      twopass->stats_buf_ctx->stats_in_end =
-          twopass->stats_buf_ctx->stats_in_start;
-    }
-  }
+  update_firstpass_stats(cpi, &stats, raw_err_stdev,
+                         current_frame->frame_number, ts_duration);
 
   // Copy the previous Last Frame back into gf buffer if the prediction is good
   // enough... but also don't allow it to lag too far.
@@ -910,22 +987,8 @@
         cm->ref_frame_map[get_ref_frame_map_idx(cm, LAST_FRAME)]);
   }
 
-  // Use this to see what the first pass reconstruction looks like.
-  if (0) {
-    char filename[512];
-    FILE *recon_file;
-    snprintf(filename, sizeof(filename), "enc%04d.yuv",
-             (int)current_frame->frame_number);
-
-    if (current_frame->frame_number == 0)
-      recon_file = fopen(filename, "wb");
-    else
-      recon_file = fopen(filename, "ab");
-
-    (void)fwrite(last_frame->buffer_alloc, last_frame->frame_size, 1,
-                 recon_file);
-    fclose(recon_file);
-  }
+  print_reconstruction_frame(last_frame, current_frame->frame_number,
+                             /*do_print=*/0);
 
   ++current_frame->frame_number;
 }