/* * 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.
// 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
};
// 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. staticvoid 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. constdouble framerate = cfg->g_timebase.den / cfg->g_timebase.num; constint 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];
}
staticvoid printout_rate_control_summary(struct RateControlMetrics *rc,
vpx_codec_enc_cfg_t *cfg, int frame_cnt) { unsignedint 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) { constint 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");
}
// 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;
}
}
}
}
staticvoid set_roi_skip_map(vpx_codec_enc_cfg_t *cfg, vpx_roi_map_t *roi, int *skip_map, int *prev_mask_map, int frame_num) { constint block_size = 8; unsignedint i, j;
roi->rows = (cfg->g_h + block_size - 1) / block_size;
roi->cols = (cfg->g_w + block_size - 1) / block_size;
zero(roi->skip);
zero(roi->delta_q);
zero(roi->delta_lf);
memset(roi->ref_frame, -1, sizeof(roi->ref_frame));
roi->ref_frame[1] = 1; // Use segment 3 for skip.
roi->skip[3] = 1;
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) { constint idx = i * roi->cols + j; // Use segment 3 for skip. // prev_mask_map keeps track of blocks that have been stably on segment 3 // for the past 10 frames. Only skip when the block is on segment 3 in // both current map and prev_mask_map. if (skip_map[idx] == 1 && prev_mask_map[idx] == 1) roi->roi_map[idx] = 3; // Reset it every 10 frames so it doesn't propagate for too many frames. if (frame_num % 10 == 0)
prev_mask_map[idx] = skip_map[idx]; elseif (prev_mask_map[idx] == 1 && skip_map[idx] == 0)
prev_mask_map[idx] = 0;
}
}
} #endif
#if ROI_MAP if (argc != min_args + mode_to_num_layers[layering_mode] + 1) {
die("Invalid number of arguments");
} #else if (argc != min_args + mode_to_num_layers[layering_mode]) {
die("Invalid number of arguments");
} #endif
if (input_ctx.file_type == FILE_TYPE_Y4M) { if (input_ctx.width != cfg.g_w || input_ctx.height != cfg.g_h) {
die("Incorrect width or height: %d x %d", cfg.g_w, cfg.g_h);
} if (input_ctx.framerate.numerator != cfg.g_timebase.den ||
input_ctx.framerate.denominator != cfg.g_timebase.num) {
die("Incorrect framerate: numerator %d denominator %d",
cfg.g_timebase.num, cfg.g_timebase.den);
}
}
framerate = cfg.g_timebase.den / cfg.g_timebase.num; // Open an output file for each stream. for (i = 0; i < cfg.ts_number_layers; ++i) { char file_name[PATH_MAX];
VpxVideoInfo info;
info.codec_fourcc = encoder->fourcc;
info.frame_width = cfg.g_w;
info.frame_height = cfg.g_h;
info.time_base.numerator = cfg.g_timebase.num;
info.time_base.denominator = cfg.g_timebase.den;
snprintf(file_name, sizeof(file_name), "%s_%d.ivf", argv[2], i);
outfile[i] = vpx_video_writer_open(file_name, kContainerIVF, &info); if (!outfile[i]) die("Failed to open %s for writing", file_name);
assert(outfile[i] != NULL);
} // No spatial layers in this encoder.
cfg.ss_number_layers = 1;
// Initialize codec. #if CONFIG_VP9_HIGHBITDEPTH if (vpx_codec_enc_init(
&codec, encoder->codec_interface(), &cfg,
bit_depth == VPX_BITS_8 ? 0 : VPX_CODEC_USE_HIGHBITDEPTH)) #else if (vpx_codec_enc_init(&codec, encoder->codec_interface(), &cfg, 0)) #endif// CONFIG_VP9_HIGHBITDEPTH
die("Failed to initialize encoder");
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.