+#if OUTPUT_RC_STATS
+// For rate control encoding stats.
+struct RateControlStats {
+ // Number of input frames per layer.
+ int layer_input_frames[VPX_MAX_LAYERS];
+ // Total (cumulative) number of encoded frames per layer.
+ int layer_tot_enc_frames[VPX_MAX_LAYERS];
+ // Number of encoded non-key frames per layer.
+ int layer_enc_frames[VPX_MAX_LAYERS];
+ // Framerate per layer (cumulative).
+ double layer_framerate[VPX_MAX_LAYERS];
+ // Target average frame size per layer (per-frame-bandwidth per layer).
+ double layer_pfb[VPX_MAX_LAYERS];
+ // Actual average frame size per layer.
+ double layer_avg_frame_size[VPX_MAX_LAYERS];
+ // Average rate mismatch per layer (|target - actual| / target).
+ double layer_avg_rate_mismatch[VPX_MAX_LAYERS];
+ // Actual encoding bitrate per layer (cumulative).
+ double layer_encoding_bitrate[VPX_MAX_LAYERS];
+ // Average of the short-time encoder actual bitrate.
+ // TODO(marpan): Should we add these short-time stats for each layer?
+ double avg_st_encoding_bitrate;
+ // Variance of the short-time encoder actual bitrate.
+ double variance_st_encoding_bitrate;
+ // Window (number of frames) for computing short-time encoding bitrate.
+ int window_size;
+ // Number of window measurements.
+ int window_count;
+};
+
+// Note: these rate control stats assume only 1 key frame in the
+// sequence (i.e., first frame only).
+static void set_rate_control_stats(struct RateControlStats *rc,
+ vpx_codec_enc_cfg_t *cfg) {
+ unsigned int sl, tl;
+ // Set the layer (cumulative) framerate and the target layer (non-cumulative)
+ // per-frame-bandwidth, for the rate control encoding stats below.
+ const double framerate = cfg->g_timebase.den / cfg->g_timebase.num;
+
+ for (sl = 0; sl < cfg->ss_number_layers; ++sl) {
+ for (tl = 0; tl < cfg->ts_number_layers; ++tl) {
+ const int layer = sl * cfg->ts_number_layers + tl;
+ const int tlayer0 = sl * cfg->ts_number_layers;
+ if (cfg->ts_number_layers == 1)
+ rc->layer_framerate[layer] = framerate;
+ else
+ rc->layer_framerate[layer] = framerate / cfg->ts_rate_decimator[tl];
+ if (tl > 0) {
+ rc->layer_pfb[layer] =
+ 1000.0 * (cfg->layer_target_bitrate[layer] -
+ cfg->layer_target_bitrate[layer - 1]) /
+ (rc->layer_framerate[layer] - rc->layer_framerate[layer - 1]);
+ } else {
+ rc->layer_pfb[tlayer0] = 1000.0 * cfg->layer_target_bitrate[tlayer0] /
+ rc->layer_framerate[tlayer0];
+ }
+ rc->layer_input_frames[layer] = 0;
+ rc->layer_enc_frames[layer] = 0;
+ rc->layer_tot_enc_frames[layer] = 0;
+ rc->layer_encoding_bitrate[layer] = 0.0;
+ rc->layer_avg_frame_size[layer] = 0.0;
+ rc->layer_avg_rate_mismatch[layer] = 0.0;
+ }
+ }
+ rc->window_count = 0;
+ rc->window_size = 15;
+ rc->avg_st_encoding_bitrate = 0.0;
+ rc->variance_st_encoding_bitrate = 0.0;
+}
+
+static void printout_rate_control_summary(struct RateControlStats *rc,
+ vpx_codec_enc_cfg_t *cfg,
+ int frame_cnt) {
+ unsigned int sl, tl;
+ int tot_num_frames = 0;
+ double perc_fluctuation = 0.0;
+ printf("Total number of processed frames: %d\n\n", frame_cnt - 1);
+ printf("Rate control layer stats for sl%d tl%d layer(s):\n\n",
+ cfg->ss_number_layers, cfg->ts_number_layers);
+ for (sl = 0; sl < cfg->ss_number_layers; ++sl) {
+ for (tl = 0; tl < cfg->ts_number_layers; ++tl) {
+ const int layer = sl * cfg->ts_number_layers + tl;
+ const int num_dropped =
+ (tl > 0)
+ ? (rc->layer_input_frames[layer] - rc->layer_enc_frames[layer])
+ : (rc->layer_input_frames[layer] - rc->layer_enc_frames[layer] -
+ 1);
+ if (!sl) tot_num_frames += rc->layer_input_frames[layer];
+ rc->layer_encoding_bitrate[layer] = 0.001 * rc->layer_framerate[layer] *
+ rc->layer_encoding_bitrate[layer] /
+ tot_num_frames;
+ rc->layer_avg_frame_size[layer] =
+ rc->layer_avg_frame_size[layer] / rc->layer_enc_frames[layer];
+ rc->layer_avg_rate_mismatch[layer] = 100.0 *
+ rc->layer_avg_rate_mismatch[layer] /
+ rc->layer_enc_frames[layer];
+ printf("For layer#: sl%d tl%d \n", sl, tl);
+ printf("Bitrate (target vs actual): %d %f.0 kbps\n",
+ cfg->layer_target_bitrate[layer],
+ rc->layer_encoding_bitrate[layer]);
+ printf("Average frame size (target vs actual): %f %f bits\n",
+ rc->layer_pfb[layer], rc->layer_avg_frame_size[layer]);
+ printf("Average rate_mismatch: %f\n", rc->layer_avg_rate_mismatch[layer]);
+ printf(
+ "Number of input frames, encoded (non-key) frames, "
+ "and percent dropped frames: %d %d %f.0 \n",
+ rc->layer_input_frames[layer], rc->layer_enc_frames[layer],
+ 100.0 * num_dropped / rc->layer_input_frames[layer]);
+ printf("\n");
+ }
+ }
+ rc->avg_st_encoding_bitrate = rc->avg_st_encoding_bitrate / rc->window_count;
+ rc->variance_st_encoding_bitrate =
+ rc->variance_st_encoding_bitrate / rc->window_count -
+ (rc->avg_st_encoding_bitrate * rc->avg_st_encoding_bitrate);
+ perc_fluctuation = 100.0 * sqrt(rc->variance_st_encoding_bitrate) /
+ rc->avg_st_encoding_bitrate;
+ printf("Short-time stats, for window of %d frames: \n", rc->window_size);
+ printf("Average, rms-variance, and percent-fluct: %f %f %f \n",
+ rc->avg_st_encoding_bitrate, sqrt(rc->variance_st_encoding_bitrate),
+ perc_fluctuation);
+ if (frame_cnt != tot_num_frames)
+ die("Error: Number of input frames not equal to output encoded frames != "
+ "%d tot_num_frames = %d\n",
+ frame_cnt, tot_num_frames);
+}
+
+vpx_codec_err_t parse_superframe_index(const uint8_t *data, size_t data_sz,
+ uint32_t sizes[8], int *count) {
+ // A chunk ending with a byte matching 0xc0 is an invalid chunk unless
+ // it is a super frame index. If the last byte of real video compression
+ // data is 0xc0 the encoder must add a 0 byte. If we have the marker but
+ // not the associated matching marker byte at the front of the index we have
+ // an invalid bitstream and need to return an error.
+
+ uint8_t marker;
+
+ marker = *(data + data_sz - 1);
+ *count = 0;
+
+ if ((marker & 0xe0) == 0xc0) {
+ const uint32_t frames = (marker & 0x7) + 1;
+ const uint32_t mag = ((marker >> 3) & 0x3) + 1;
+ const size_t index_sz = 2 + mag * frames;
+
+ // This chunk is marked as having a superframe index but doesn't have
+ // enough data for it, thus it's an invalid superframe index.
+ if (data_sz < index_sz) return VPX_CODEC_CORRUPT_FRAME;
+
+ {
+ const uint8_t marker2 = *(data + data_sz - index_sz);
+
+ // This chunk is marked as having a superframe index but doesn't have
+ // the matching marker byte at the front of the index therefore it's an
+ // invalid chunk.
+ if (marker != marker2) return VPX_CODEC_CORRUPT_FRAME;
+ }
+
+ {
+ // Found a valid superframe index.
+ uint32_t i, j;
+ const uint8_t *x = &data[data_sz - index_sz + 1];
+
+ for (i = 0; i < frames; ++i) {
+ uint32_t this_sz = 0;
+
+ for (j = 0; j < mag; ++j) this_sz |= (*x++) << (j * 8);
+ sizes[i] = this_sz;
+ }
+ *count = frames;
+ }
+ }
+ return VPX_CODEC_OK;
+}
+#endif
+
+// Example pattern for spatial layers and 2 temporal layers used in the
+// bypass/flexible mode. The pattern corresponds to the pattern
+// VP9E_TEMPORAL_LAYERING_MODE_0101 (temporal_layering_mode == 2) used in
+// non-flexible mode.
+void set_frame_flags_bypass_mode(int sl, int tl, int num_spatial_layers,
+ int is_key_frame,
+ vpx_svc_ref_frame_config_t *ref_frame_config) {
+ for (sl = 0; sl < num_spatial_layers; ++sl) {
+ if (!tl) {
+ if (!sl) {
+ ref_frame_config->frame_flags[sl] =
+ VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_GF |
+ VP8_EFLAG_NO_UPD_ARF;
+ } else {
+ if (is_key_frame) {
+ ref_frame_config->frame_flags[sl] =
+ VP8_EFLAG_NO_REF_LAST | VP8_EFLAG_NO_REF_ARF |
+ VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF;
+ } else {
+ ref_frame_config->frame_flags[sl] =
+ VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF;
+ }
+ }
+ } else if (tl == 1) {
+ if (!sl) {
+ ref_frame_config->frame_flags[sl] =
+ VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_LAST |
+ VP8_EFLAG_NO_UPD_GF;
+ } else {
+ ref_frame_config->frame_flags[sl] =
+ VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF;
+ }
+ }
+ if (tl == 0) {
+ ref_frame_config->lst_fb_idx[sl] = sl;
+ if (sl)
+ ref_frame_config->gld_fb_idx[sl] = sl - 1;
+ else
+ ref_frame_config->gld_fb_idx[sl] = 0;
+ ref_frame_config->alt_fb_idx[sl] = 0;
+ } else if (tl == 1) {
+ ref_frame_config->lst_fb_idx[sl] = sl;
+ ref_frame_config->gld_fb_idx[sl] = num_spatial_layers + sl - 1;
+ ref_frame_config->alt_fb_idx[sl] = num_spatial_layers + sl;
+ }
+ }
+}
+