/* * Copyright (c) 2012 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. */ // This is an example demonstrating how to implement a multi-layer VPx// encoding scheme based on temporal scalability for video applications// that benefit from a scalable bitstream. #include <assert.h>#include <math.h>#include <stdio.h>#include <stdlib.h>#include <string.h> #include "./vpx_config.h"#include "./y4minput.h"#include "../vpx_ports/vpx_timer.h"#include "vpx/vp8cx.h"#include "vpx/vpx_encoder.h"#include "vpx_ports/bitops.h" #include "../tools_common.h"#include "../video_writer.h" #define ROI_MAP 0 #define zero(Dest) memset(&(Dest), 0, sizeof(Dest)); static const char *exec_name; void usage_exit(void) { exit(EXIT_FAILURE); } // Denoiser states for vp8, for temporal denoising.enum denoiserStateVp8 { kVp8DenoiserOff, kVp8DenoiserOnYOnly, kVp8DenoiserOnYUV, kVp8DenoiserOnYUVAggressive, kVp8DenoiserOnAdaptive}; // Denoiser states for vp9, for temporal denoising.enum denoiserStateVp9 { kVp9DenoiserOff, kVp9DenoiserOnYOnly, // For SVC: denoise the top two spatial layers. kVp9DenoiserOnYTwoSpatialLayers}; static int mode_to_num_layers[13] = { 1, 2, 2, 3, 3, 3, 3, 5, 2, 3, 3, 3, 3 }; // For rate control encoding stats.struct RateControlMetrics { // Number of input frames per layer. int layer_input_frames[VPX_TS_MAX_LAYERS]; // Total (cumulative) number of encoded frames per layer. int layer_tot_enc_frames[VPX_TS_MAX_LAYERS]; // Number of encoded non-key frames per layer. int layer_enc_frames[VPX_TS_MAX_LAYERS]; // Framerate per layer layer (cumulative). double layer_framerate[VPX_TS_MAX_LAYERS]; // Target average frame size per layer (per-frame-bandwidth per layer). double layer_pfb[VPX_TS_MAX_LAYERS]; // Actual average frame size per layer. double layer_avg_frame_size[VPX_TS_MAX_LAYERS]; // Average rate mismatch per layer (|target - actual| / target). double layer_avg_rate_mismatch[VPX_TS_MAX_LAYERS]; // Actual encoding bitrate per layer (cumulative). double layer_encoding_bitrate[VPX_TS_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-timee encoding bitrate. int window_size; // Number of window measurements. int window_count; int layer_target_bitrate[VPX_MAX_LAYERS];}; // Note: these rate control metrics assume only 1 key frame in the// sequence (i.e., first frame only). So for temporal pattern# 7// (which has key frame for every frame on base layer), the metrics// computation will be off/wrong.// TODO(marpan): Update these metrics to account for multiple key frames// in the stream.static void set_rate_control_metrics(struct RateControlMetrics *rc, vpx_codec_enc_cfg_t *cfg) { int i = 0; // 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; const int ts_number_layers = cfg->ts_number_layers; rc->layer_framerate[0] = framerate / cfg->ts_rate_decimator[0]; rc->layer_pfb[0] = 1000.0 * rc->layer_target_bitrate[0] / rc->layer_framerate[0]; for (i = 0; i < ts_number_layers; ++i) { if (i > 0) { rc->layer_framerate[i] = framerate / cfg->ts_rate_decimator[i]; rc->layer_pfb[i] = 1000.0 * (rc->layer_target_bitrate[i] - rc->layer_target_bitrate[i - 1]) / (rc->layer_framerate[i] - rc->layer_framerate[i - 1]); } rc->layer_input_frames[i] = 0; rc->layer_enc_frames[i] = 0; rc->layer_tot_enc_frames[i] = 0; rc->layer_encoding_bitrate[i] = 0.0; rc->layer_avg_frame_size[i] = 0.0; rc->layer_avg_rate_mismatch[i] = 0.0; } rc->window_count = 0; rc->window_size = 15; rc->avg_st_encoding_bitrate = 0.0; rc->variance_st_encoding_bitrate = 0.0; // Target bandwidth for the whole stream. // Set to layer_target_bitrate for highest layer (total bitrate). cfg->rc_target_bitrate = rc->layer_target_bitrate[ts_number_layers - 1];} static void printout_rate_control_summary(struct RateControlMetrics *rc, vpx_codec_enc_cfg_t *cfg, int frame_cnt) { unsigned int i = 0; 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 %d layer(s):\n\n", cfg->ts_number_layers); for (i = 0; i < cfg->ts_number_layers; ++i) { const int num_dropped = (i > 0) ? (rc->layer_input_frames[i] - rc->layer_enc_frames[i]) : (rc->layer_input_frames[i] - rc->layer_enc_frames[i] - 1); tot_num_frames += rc->layer_input_frames[i]; rc->layer_encoding_bitrate[i] = 0.001 * rc->layer_framerate[i] * rc->layer_encoding_bitrate[i] / tot_num_frames; rc->layer_avg_frame_size[i] = rc->layer_avg_frame_size[i] / rc->layer_enc_frames[i]; rc->layer_avg_rate_mismatch[i] = 100.0 * rc->layer_avg_rate_mismatch[i] / rc->layer_enc_frames[i]; printf("For layer#: %d \n", i); printf("Bitrate (target vs actual): %d %f \n", rc->layer_target_bitrate[i], rc->layer_encoding_bitrate[i]); printf("Average frame size (target vs actual): %f %f \n", rc->layer_pfb[i], rc->layer_avg_frame_size[i]); printf("Average rate_mismatch: %f \n", rc->layer_avg_rate_mismatch[i]); printf( "Number of input frames, encoded (non-key) frames, " "and perc dropped frames: %d %d %f \n", rc->layer_input_frames[i], rc->layer_enc_frames[i], 100.0 * num_dropped / rc->layer_input_frames[i]); 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 - 1) != tot_num_frames) die("Error: Number of input frames not equal to output! \n");} #if ROI_MAPstatic void set_roi_map(const char *enc_name, vpx_codec_enc_cfg_t *cfg, vpx_roi_map_t *roi) { unsigned int i, j; int block_size = 0; uint8_t is_vp8 = strncmp(enc_name, "vp8", 3) == 0 ? 1 : 0; uint8_t is_vp9 = strncmp(enc_name, "vp9", 3) == 0 ? 1 : 0; if (!is_vp8 && !is_vp9) { die("unsupported codec."); } zero(*roi); block_size = is_vp9 && !is_vp8 ? 8 : 16; // ROI is based on the segments (4 for vp8, 8 for vp9), smallest unit for // segment is 16x16 for vp8, 8x8 for vp9. roi->rows = (cfg->g_h + block_size - 1) / block_size; roi->cols = (cfg->g_w + block_size - 1) / block_size; // Applies delta QP on the segment blocks, varies from -63 to 63. // Setting to negative means lower QP (better quality). // Below we set delta_q to the extreme (-63) to show strong effect. // VP8 uses the first 4 segments. VP9 uses all 8 segments. zero(roi->delta_q); roi->delta_q[1] = -63; // Applies delta loopfilter strength on the segment blocks, varies from -63 to // 63. Setting to positive means stronger loopfilter. VP8 uses the first 4 // segments. VP9 uses all 8 segments. zero(roi->delta_lf); if (is_vp8) { // Applies skip encoding threshold on the segment blocks, varies from 0 to // UINT_MAX. Larger value means more skipping of encoding is possible. // This skip threshold only applies on delta frames. zero(roi->static_threshold); } if (is_vp9) { // Apply skip segment. Setting to 1 means this block will be copied from // previous frame. zero(roi->skip); } if (is_vp9) { // Apply ref frame segment. // -1 : Do not apply this segment. // 0 : Froce using intra. // 1 : Force using last. // 2 : Force using golden. // 3 : Force using alfref but not used in non-rd pickmode for 0 lag. memset(roi->ref_frame, -1, sizeof(roi->ref_frame)); roi->ref_frame[1] = 1; } // Use 2 states: 1 is center square, 0 is the rest. roi->roi_map = (uint8_t *)calloc(roi->rows * roi->cols, sizeof(*roi->roi_map)); for (i = 0; i < roi->rows; ++i) { for (j = 0; j < roi->cols; ++j) { if (i > (roi->rows >> 2) && i < ((roi->rows * 3) >> 2) && j > (roi->cols >> 2) && j < ((roi->cols * 3) >> 2)) { roi->roi_map[i * roi->cols + j] = 1; } } }}#endif // Temporal scaling parameters:// NOTE: The 3 prediction frames cannot be used interchangeably due to// differences in the way they are handled throughout the code. The// frames should be allocated to layers in the order LAST, GF, ARF.// Other combinations work, but may produce slightly inferior results.static void set_temporal_layer_pattern(int layering_mode, vpx_codec_enc_cfg_t *cfg, int *layer_flags, int *flag_periodicity) { switch (layering_mode) { case 0: { // 1-layer. int ids[1] = { 0 }; cfg->ts_periodicity = 1; *flag_periodicity = 1; cfg->ts_number_layers = 1; cfg->ts_rate_decimator[0] = 1; memcpy(cfg->ts_layer_id, ids, sizeof(ids)); // Update L only. layer_flags[0] = VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF; break; } case 1: { // 2-layers, 2-frame period. int ids[2] = { 0, 1 }; cfg->ts_periodicity = 2; *flag_periodicity = 2; cfg->ts_number_layers = 2; cfg->ts_rate_decimator[0] = 2; cfg->ts_rate_decimator[1] = 1; memcpy(cfg->ts_layer_id, ids, sizeof(ids));#if 1 // 0=L, 1=GF, Intra-layer prediction enabled. layer_flags[0] = VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF; layer_flags[1] = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_REF_ARF;#else // 0=L, 1=GF, Intra-layer prediction disabled. layer_flags[0] = VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF; layer_flags[1] = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_REF_LAST;#endif break; } case 2: { // 2-layers, 3-frame period. int ids[3] = { 0, 1, 1 }; cfg->ts_periodicity = 3; *flag_periodicity = 3; cfg->ts_number_layers = 2; cfg->ts_rate_decimator[0] = 3; cfg->ts_rate_decimator[1] = 1; memcpy(cfg->ts_layer_id, ids, sizeof(ids)); // 0=L, 1=GF, Intra-layer prediction enabled. layer_flags[0] = VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF; layer_flags[1] = layer_flags[2] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST; break; } case 3: { // 3-layers, 6-frame period. int ids[6] = { 0, 2, 2, 1, 2, 2 }; cfg->ts_periodicity = 6; *flag_periodicity = 6; cfg->ts_number_layers = 3; cfg->ts_rate_decimator[0] = 6; cfg->ts_rate_decimator[1] = 3; cfg->ts_rate_decimator[2] = 1; memcpy(cfg->ts_layer_id, ids, sizeof(ids)); // 0=L, 1=GF, 2=ARF, Intra-layer prediction enabled. layer_flags[0] = VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF; layer_flags[3] = VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST; layer_flags[1] = layer_flags[2] = layer_flags[4] = layer_flags[5] = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_LAST; break; } case 4: { // 3-layers, 4-frame period. int ids[4] = { 0, 2, 1, 2 }; cfg->ts_periodicity = 4; *flag_periodicity = 4; cfg->ts_number_layers = 3; cfg->ts_rate_decimator[0] = 4; cfg->ts_rate_decimator[1] = 2; cfg->ts_rate_decimator[2] = 1; memcpy(cfg->ts_layer_id, ids, sizeof(ids)); // 0=L, 1=GF, 2=ARF, Intra-layer prediction disabled. layer_flags[0] = VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF; layer_flags[2] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST; layer_flags[1] = layer_flags[3] = VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF; break; } case 5: { // 3-layers, 4-frame period. int ids[4] = { 0, 2, 1, 2 }; cfg->ts_periodicity = 4; *flag_periodicity = 4; cfg->ts_number_layers = 3; cfg->ts_rate_decimator[0] = 4; cfg->ts_rate_decimator[1] = 2; cfg->ts_rate_decimator[2] = 1; memcpy(cfg->ts_layer_id, ids, sizeof(ids)); // 0=L, 1=GF, 2=ARF, Intra-layer prediction enabled in layer 1, disabled // in layer 2. layer_flags[0] = VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF; layer_flags[2] = VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_ARF; layer_flags[1] = layer_flags[3] = VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF; break; } case 6: { // 3-layers, 4-frame period. int ids[4] = { 0, 2, 1, 2 }; cfg->ts_periodicity = 4; *flag_periodicity = 4; cfg->ts_number_layers = 3; cfg->ts_rate_decimator[0] = 4; cfg->ts_rate_decimator[1] = 2; cfg->ts_rate_decimator[2] = 1; memcpy(cfg->ts_layer_id, ids, sizeof(ids)); // 0=L, 1=GF, 2=ARF, Intra-layer prediction enabled. layer_flags[0] = VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF; layer_flags[2] = VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_ARF; layer_flags[1] = layer_flags[3] = VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF; break; } case 7: { // NOTE: Probably of academic interest only. // 5-layers, 16-frame period. int ids[16] = { 0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4 }; cfg->ts_periodicity = 16; *flag_periodicity = 16; cfg->ts_number_layers = 5; cfg->ts_rate_decimator[0] = 16; cfg->ts_rate_decimator[1] = 8; cfg->ts_rate_decimator[2] = 4; cfg->ts_rate_decimator[3] = 2; cfg->ts_rate_decimator[4] = 1; memcpy(cfg->ts_layer_id, ids, sizeof(ids)); layer_flags[0] = VPX_EFLAG_FORCE_KF; layer_flags[1] = layer_flags[3] = layer_flags[5] = layer_flags[7] = layer_flags[9] = layer_flags[11] = layer_flags[13] = layer_flags[15] = VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF; layer_flags[2] = layer_flags[6] = layer_flags[10] = layer_flags[14] = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_GF; layer_flags[4] = layer_flags[12] = VP8_EFLAG_NO_REF_LAST | VP8_EFLAG_NO_UPD_ARF; layer_flags[8] = VP8_EFLAG_NO_REF_LAST | VP8_EFLAG_NO_REF_GF; break; } case 8: { // 2-layers, with sync point at first frame of layer 1. int ids[2] = { 0, 1 }; cfg->ts_periodicity = 2; *flag_periodicity = 8; cfg->ts_number_layers = 2; cfg->ts_rate_decimator[0] = 2; cfg->ts_rate_decimator[1] = 1; memcpy(cfg->ts_layer_id, ids, sizeof(ids)); // 0=L, 1=GF. // ARF is used as predictor for all frames, and is only updated on // key frame. Sync point every 8 frames. // Layer 0: predict from L and ARF, update L and G. layer_flags[0] = VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_UPD_ARF; // Layer 1: sync point: predict from L and ARF, and update G. layer_flags[1] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_ARF; // Layer 0, predict from L and ARF, update L. layer_flags[2] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF; // Layer 1: predict from L, G and ARF, and update G. layer_flags[3] = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_ENTROPY; // Layer 0. layer_flags[4] = layer_flags[2]; // Layer 1. layer_flags[5] = layer_flags[3]; // Layer 0. layer_flags[6] = layer_flags[4]; // Layer 1. layer_flags[7] = layer_flags[5]; break; } case 9: { // 3-layers: Sync points for layer 1 and 2 every 8 frames. int ids[4] = { 0, 2, 1, 2 }; cfg->ts_periodicity = 4; *flag_periodicity = 8; cfg->ts_number_layers = 3; cfg->ts_rate_decimator[0] = 4; cfg->ts_rate_decimator[1] = 2; cfg->ts_rate_decimator[2] = 1; memcpy(cfg->ts_layer_id, ids, sizeof(ids)); // 0=L, 1=GF, 2=ARF. layer_flags[0] = VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF; layer_flags[1] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF; layer_flags[2] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_ARF; layer_flags[3] = layer_flags[5] = VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF; layer_flags[4] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF; layer_flags[6] = VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_ARF; layer_flags[7] = VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_ENTROPY; break; } case 10: { // 3-layers structure where ARF is used as predictor for all frames, // and is only updated on key frame. // Sync points for layer 1 and 2 every 8 frames. int ids[4] = { 0, 2, 1, 2 }; cfg->ts_periodicity = 4; *flag_periodicity = 8; cfg->ts_number_layers = 3; cfg->ts_rate_decimator[0] = 4; cfg->ts_rate_decimator[1] = 2; cfg->ts_rate_decimator[2] = 1; memcpy(cfg->ts_layer_id, ids, sizeof(ids)); // 0=L, 1=GF, 2=ARF. // Layer 0: predict from L and ARF; update L and G. layer_flags[0] = VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_REF_GF; // Layer 2: sync point: predict from L and ARF; update none.Lines 1–500 of 986. Load more
/* * Copyright (c) 2012 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. */ // This is an example demonstrating how to implement a multi-layer VPx // encoding scheme based on temporal scalability for video applications // that benefit from a scalable bitstream. #include <assert.h> #include <math.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include "./vpx_config.h" #include "./y4minput.h" #include "../vpx_ports/vpx_timer.h" #include "vpx/vp8cx.h" #include "vpx/vpx_encoder.h" #include "vpx_ports/bitops.h" #include "../tools_common.h" #include "../video_writer.h" #define ROI_MAP 0 #define zero(Dest) memset(&(Dest), 0, sizeof(Dest)); static const char *exec_name; void usage_exit(void) { exit(EXIT_FAILURE); } // Denoiser states for vp8, for temporal denoising. enum denoiserStateVp8 { kVp8DenoiserOff, kVp8DenoiserOnYOnly, kVp8DenoiserOnYUV, kVp8DenoiserOnYUVAggressive, kVp8DenoiserOnAdaptive }; // Denoiser states for vp9, for temporal denoising. enum denoiserStateVp9 { kVp9DenoiserOff, kVp9DenoiserOnYOnly, // For SVC: denoise the top two spatial layers. kVp9DenoiserOnYTwoSpatialLayers }; static int mode_to_num_layers[13] = { 1, 2, 2, 3, 3, 3, 3, 5, 2, 3, 3, 3, 3 }; // For rate control encoding stats. struct RateControlMetrics { // Number of input frames per layer. int layer_input_frames[VPX_TS_MAX_LAYERS]; // Total (cumulative) number of encoded frames per layer. int layer_tot_enc_frames[VPX_TS_MAX_LAYERS]; // Number of encoded non-key frames per layer. int layer_enc_frames[VPX_TS_MAX_LAYERS]; // Framerate per layer layer (cumulative). double layer_framerate[VPX_TS_MAX_LAYERS]; // Target average frame size per layer (per-frame-bandwidth per layer). double layer_pfb[VPX_TS_MAX_LAYERS]; // Actual average frame size per layer. double layer_avg_frame_size[VPX_TS_MAX_LAYERS]; // Average rate mismatch per layer (|target - actual| / target). double layer_avg_rate_mismatch[VPX_TS_MAX_LAYERS]; // Actual encoding bitrate per layer (cumulative). double layer_encoding_bitrate[VPX_TS_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-timee encoding bitrate. int window_size; // Number of window measurements. int window_count; int layer_target_bitrate[VPX_MAX_LAYERS]; }; // Note: these rate control metrics assume only 1 key frame in the // sequence (i.e., first frame only). So for temporal pattern# 7 // (which has key frame for every frame on base layer), the metrics // computation will be off/wrong. // TODO(marpan): Update these metrics to account for multiple key frames // in the stream. static void set_rate_control_metrics(struct RateControlMetrics *rc, vpx_codec_enc_cfg_t *cfg) { int i = 0; // 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; const int ts_number_layers = cfg->ts_number_layers; rc->layer_framerate[0] = framerate / cfg->ts_rate_decimator[0]; rc->layer_pfb[0] = 1000.0 * rc->layer_target_bitrate[0] / rc->layer_framerate[0]; for (i = 0; i < ts_number_layers; ++i) { if (i > 0) { rc->layer_framerate[i] = framerate / cfg->ts_rate_decimator[i]; rc->layer_pfb[i] = 1000.0 * (rc->layer_target_bitrate[i] - rc->layer_target_bitrate[i - 1]) / (rc->layer_framerate[i] - rc->layer_framerate[i - 1]); } rc->layer_input_frames[i] = 0; rc->layer_enc_frames[i] = 0; rc->layer_tot_enc_frames[i] = 0; rc->layer_encoding_bitrate[i] = 0.0; rc->layer_avg_frame_size[i] = 0.0; rc->layer_avg_rate_mismatch[i] = 0.0; } rc->window_count = 0; rc->window_size = 15; rc->avg_st_encoding_bitrate = 0.0; rc->variance_st_encoding_bitrate = 0.0; // Target bandwidth for the whole stream. // Set to layer_target_bitrate for highest layer (total bitrate). cfg->rc_target_bitrate = rc->layer_target_bitrate[ts_number_layers - 1]; } static void printout_rate_control_summary(struct RateControlMetrics *rc, vpx_codec_enc_cfg_t *cfg, int frame_cnt) { unsigned int i = 0; 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 %d layer(s):\n\n", cfg->ts_number_layers); for (i = 0; i < cfg->ts_number_layers; ++i) { const int num_dropped = (i > 0) ? (rc->layer_input_frames[i] - rc->layer_enc_frames[i]) : (rc->layer_input_frames[i] - rc->layer_enc_frames[i] - 1); tot_num_frames += rc->layer_input_frames[i]; rc->layer_encoding_bitrate[i] = 0.001 * rc->layer_framerate[i] * rc->layer_encoding_bitrate[i] / tot_num_frames; rc->layer_avg_frame_size[i] = rc->layer_avg_frame_size[i] / rc->layer_enc_frames[i]; rc->layer_avg_rate_mismatch[i] = 100.0 * rc->layer_avg_rate_mismatch[i] / rc->layer_enc_frames[i]; printf("For layer#: %d \n", i); printf("Bitrate (target vs actual): %d %f \n", rc->layer_target_bitrate[i], rc->layer_encoding_bitrate[i]); printf("Average frame size (target vs actual): %f %f \n", rc->layer_pfb[i], rc->layer_avg_frame_size[i]); printf("Average rate_mismatch: %f \n", rc->layer_avg_rate_mismatch[i]); printf( "Number of input frames, encoded (non-key) frames, " "and perc dropped frames: %d %d %f \n", rc->layer_input_frames[i], rc->layer_enc_frames[i], 100.0 * num_dropped / rc->layer_input_frames[i]); 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 - 1) != tot_num_frames) die("Error: Number of input frames not equal to output! \n"); } #if ROI_MAP static void set_roi_map(const char *enc_name, vpx_codec_enc_cfg_t *cfg, vpx_roi_map_t *roi) { unsigned int i, j; int block_size = 0; uint8_t is_vp8 = strncmp(enc_name, "vp8", 3) == 0 ? 1 : 0; uint8_t is_vp9 = strncmp(enc_name, "vp9", 3) == 0 ? 1 : 0; if (!is_vp8 && !is_vp9) { die("unsupported codec."); } zero(*roi); block_size = is_vp9 && !is_vp8 ? 8 : 16; // ROI is based on the segments (4 for vp8, 8 for vp9), smallest unit for // segment is 16x16 for vp8, 8x8 for vp9. roi->rows = (cfg->g_h + block_size - 1) / block_size; roi->cols = (cfg->g_w + block_size - 1) / block_size; // Applies delta QP on the segment blocks, varies from -63 to 63. // Setting to negative means lower QP (better quality). // Below we set delta_q to the extreme (-63) to show strong effect. // VP8 uses the first 4 segments. VP9 uses all 8 segments. zero(roi->delta_q); roi->delta_q[1] = -63; // Applies delta loopfilter strength on the segment blocks, varies from -63 to // 63. Setting to positive means stronger loopfilter. VP8 uses the first 4 // segments. VP9 uses all 8 segments. zero(roi->delta_lf); if (is_vp8) { // Applies skip encoding threshold on the segment blocks, varies from 0 to // UINT_MAX. Larger value means more skipping of encoding is possible. // This skip threshold only applies on delta frames. zero(roi->static_threshold); } if (is_vp9) { // Apply skip segment. Setting to 1 means this block will be copied from // previous frame. zero(roi->skip); } if (is_vp9) { // Apply ref frame segment. // -1 : Do not apply this segment. // 0 : Froce using intra. // 1 : Force using last. // 2 : Force using golden. // 3 : Force using alfref but not used in non-rd pickmode for 0 lag. memset(roi->ref_frame, -1, sizeof(roi->ref_frame)); roi->ref_frame[1] = 1; } // Use 2 states: 1 is center square, 0 is the rest. roi->roi_map = (uint8_t *)calloc(roi->rows * roi->cols, sizeof(*roi->roi_map)); for (i = 0; i < roi->rows; ++i) { for (j = 0; j < roi->cols; ++j) { if (i > (roi->rows >> 2) && i < ((roi->rows * 3) >> 2) && j > (roi->cols >> 2) && j < ((roi->cols * 3) >> 2)) { roi->roi_map[i * roi->cols + j] = 1; } } } } #endif // Temporal scaling parameters: // NOTE: The 3 prediction frames cannot be used interchangeably due to // differences in the way they are handled throughout the code. The // frames should be allocated to layers in the order LAST, GF, ARF. // Other combinations work, but may produce slightly inferior results. static void set_temporal_layer_pattern(int layering_mode, vpx_codec_enc_cfg_t *cfg, int *layer_flags, int *flag_periodicity) { switch (layering_mode) { case 0: { // 1-layer. int ids[1] = { 0 }; cfg->ts_periodicity = 1; *flag_periodicity = 1; cfg->ts_number_layers = 1; cfg->ts_rate_decimator[0] = 1; memcpy(cfg->ts_layer_id, ids, sizeof(ids)); // Update L only. layer_flags[0] = VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF; break; } case 1: { // 2-layers, 2-frame period. int ids[2] = { 0, 1 }; cfg->ts_periodicity = 2; *flag_periodicity = 2; cfg->ts_number_layers = 2; cfg->ts_rate_decimator[0] = 2; cfg->ts_rate_decimator[1] = 1; memcpy(cfg->ts_layer_id, ids, sizeof(ids)); #if 1 // 0=L, 1=GF, Intra-layer prediction enabled. layer_flags[0] = VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF; layer_flags[1] = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_REF_ARF; #else // 0=L, 1=GF, Intra-layer prediction disabled. layer_flags[0] = VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF; layer_flags[1] = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_REF_LAST; #endif break; } case 2: { // 2-layers, 3-frame period. int ids[3] = { 0, 1, 1 }; cfg->ts_periodicity = 3; *flag_periodicity = 3; cfg->ts_number_layers = 2; cfg->ts_rate_decimator[0] = 3; cfg->ts_rate_decimator[1] = 1; memcpy(cfg->ts_layer_id, ids, sizeof(ids)); // 0=L, 1=GF, Intra-layer prediction enabled. layer_flags[0] = VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF; layer_flags[1] = layer_flags[2] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST; break; } case 3: { // 3-layers, 6-frame period. int ids[6] = { 0, 2, 2, 1, 2, 2 }; cfg->ts_periodicity = 6; *flag_periodicity = 6; cfg->ts_number_layers = 3; cfg->ts_rate_decimator[0] = 6; cfg->ts_rate_decimator[1] = 3; cfg->ts_rate_decimator[2] = 1; memcpy(cfg->ts_layer_id, ids, sizeof(ids)); // 0=L, 1=GF, 2=ARF, Intra-layer prediction enabled. layer_flags[0] = VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF; layer_flags[3] = VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST; layer_flags[1] = layer_flags[2] = layer_flags[4] = layer_flags[5] = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_LAST; break; } case 4: { // 3-layers, 4-frame period. int ids[4] = { 0, 2, 1, 2 }; cfg->ts_periodicity = 4; *flag_periodicity = 4; cfg->ts_number_layers = 3; cfg->ts_rate_decimator[0] = 4; cfg->ts_rate_decimator[1] = 2; cfg->ts_rate_decimator[2] = 1; memcpy(cfg->ts_layer_id, ids, sizeof(ids)); // 0=L, 1=GF, 2=ARF, Intra-layer prediction disabled. layer_flags[0] = VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF; layer_flags[2] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST; layer_flags[1] = layer_flags[3] = VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF; break; } case 5: { // 3-layers, 4-frame period. int ids[4] = { 0, 2, 1, 2 }; cfg->ts_periodicity = 4; *flag_periodicity = 4; cfg->ts_number_layers = 3; cfg->ts_rate_decimator[0] = 4; cfg->ts_rate_decimator[1] = 2; cfg->ts_rate_decimator[2] = 1; memcpy(cfg->ts_layer_id, ids, sizeof(ids)); // 0=L, 1=GF, 2=ARF, Intra-layer prediction enabled in layer 1, disabled // in layer 2. layer_flags[0] = VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF; layer_flags[2] = VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_ARF; layer_flags[1] = layer_flags[3] = VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF; break; } case 6: { // 3-layers, 4-frame period. int ids[4] = { 0, 2, 1, 2 }; cfg->ts_periodicity = 4; *flag_periodicity = 4; cfg->ts_number_layers = 3; cfg->ts_rate_decimator[0] = 4; cfg->ts_rate_decimator[1] = 2; cfg->ts_rate_decimator[2] = 1; memcpy(cfg->ts_layer_id, ids, sizeof(ids)); // 0=L, 1=GF, 2=ARF, Intra-layer prediction enabled. layer_flags[0] = VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF; layer_flags[2] = VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_ARF; layer_flags[1] = layer_flags[3] = VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF; break; } case 7: { // NOTE: Probably of academic interest only. // 5-layers, 16-frame period. int ids[16] = { 0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4 }; cfg->ts_periodicity = 16; *flag_periodicity = 16; cfg->ts_number_layers = 5; cfg->ts_rate_decimator[0] = 16; cfg->ts_rate_decimator[1] = 8; cfg->ts_rate_decimator[2] = 4; cfg->ts_rate_decimator[3] = 2; cfg->ts_rate_decimator[4] = 1; memcpy(cfg->ts_layer_id, ids, sizeof(ids)); layer_flags[0] = VPX_EFLAG_FORCE_KF; layer_flags[1] = layer_flags[3] = layer_flags[5] = layer_flags[7] = layer_flags[9] = layer_flags[11] = layer_flags[13] = layer_flags[15] = VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF; layer_flags[2] = layer_flags[6] = layer_flags[10] = layer_flags[14] = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_GF; layer_flags[4] = layer_flags[12] = VP8_EFLAG_NO_REF_LAST | VP8_EFLAG_NO_UPD_ARF; layer_flags[8] = VP8_EFLAG_NO_REF_LAST | VP8_EFLAG_NO_REF_GF; break; } case 8: { // 2-layers, with sync point at first frame of layer 1. int ids[2] = { 0, 1 }; cfg->ts_periodicity = 2; *flag_periodicity = 8; cfg->ts_number_layers = 2; cfg->ts_rate_decimator[0] = 2; cfg->ts_rate_decimator[1] = 1; memcpy(cfg->ts_layer_id, ids, sizeof(ids)); // 0=L, 1=GF. // ARF is used as predictor for all frames, and is only updated on // key frame. Sync point every 8 frames. // Layer 0: predict from L and ARF, update L and G. layer_flags[0] = VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_UPD_ARF; // Layer 1: sync point: predict from L and ARF, and update G. layer_flags[1] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_ARF; // Layer 0, predict from L and ARF, update L. layer_flags[2] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF; // Layer 1: predict from L, G and ARF, and update G. layer_flags[3] = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_ENTROPY; // Layer 0. layer_flags[4] = layer_flags[2]; // Layer 1. layer_flags[5] = layer_flags[3]; // Layer 0. layer_flags[6] = layer_flags[4]; // Layer 1. layer_flags[7] = layer_flags[5]; break; } case 9: { // 3-layers: Sync points for layer 1 and 2 every 8 frames. int ids[4] = { 0, 2, 1, 2 }; cfg->ts_periodicity = 4; *flag_periodicity = 8; cfg->ts_number_layers = 3; cfg->ts_rate_decimator[0] = 4; cfg->ts_rate_decimator[1] = 2; cfg->ts_rate_decimator[2] = 1; memcpy(cfg->ts_layer_id, ids, sizeof(ids)); // 0=L, 1=GF, 2=ARF. layer_flags[0] = VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF; layer_flags[1] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF; layer_flags[2] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_ARF; layer_flags[3] = layer_flags[5] = VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF; layer_flags[4] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF; layer_flags[6] = VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_ARF; layer_flags[7] = VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_ENTROPY; break; } case 10: { // 3-layers structure where ARF is used as predictor for all frames, // and is only updated on key frame. // Sync points for layer 1 and 2 every 8 frames. int ids[4] = { 0, 2, 1, 2 }; cfg->ts_periodicity = 4; *flag_periodicity = 8; cfg->ts_number_layers = 3; cfg->ts_rate_decimator[0] = 4; cfg->ts_rate_decimator[1] = 2; cfg->ts_rate_decimator[2] = 1; memcpy(cfg->ts_layer_id, ids, sizeof(ids)); // 0=L, 1=GF, 2=ARF. // Layer 0: predict from L and ARF; update L and G. layer_flags[0] = VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_REF_GF; // Layer 2: sync point: predict from L and ARF; update none.