From cc73e1fcd4723e706b3dc08396a1122ca3b51e3c Mon Sep 17 00:00:00 2001 From: James Zern Date: Mon, 8 Aug 2016 15:09:30 -0700 Subject: [PATCH] remove SVC spatial/temporal scalability are not supported in VP10 currently. + remove the unused vp10/encoder/skin_detection.[hc] this also enables DatarateTestLarge for VP10 which passes with no experiments enabled. these were removed previously when only the SVC tests should have been: 134710a Disable tests not applicable to VP10 Change-Id: I9ee7a0dd5ad3d8cc1e8fd5f0a90260fa43da387c --- configure | 1 - examples.mk | 8 - examples/vpx_temporal_svc_encoder.c | 852 ---------------------------- libs.mk | 6 +- test/datarate_test.cc | 838 +-------------------------- test/encode_test_driver.h | 9 - test/error_resilience_test.cc | 365 +----------- test/spatial_svc_encoder.sh | 72 --- test/svc_test.cc | 803 -------------------------- test/test.mk | 4 - test/vpx_temporal_svc_encoder.sh | 290 ---------- vp10/encoder/encoder.c | 1 - vp10/encoder/skin_detection.c | 104 ---- vp10/encoder/skin_detection.h | 35 -- vp10/vp10_cx_iface.c | 56 +- vp10/vp10cx.mk | 2 - vpx/exports_spatial_svc | 6 - vpx/src/svc_encodeframe.c | 686 ---------------------- vpx/svc_context.h | 123 ---- vpx/vp8cx.h | 142 ----- vpx/vpx_encoder.h | 144 ----- 21 files changed, 37 insertions(+), 4510 deletions(-) delete mode 100644 examples/vpx_temporal_svc_encoder.c delete mode 100644 test/spatial_svc_encoder.sh delete mode 100644 test/svc_test.cc delete mode 100755 test/vpx_temporal_svc_encoder.sh delete mode 100644 vp10/encoder/skin_detection.c delete mode 100644 vp10/encoder/skin_detection.h delete mode 100644 vpx/exports_spatial_svc delete mode 100644 vpx/src/svc_encodeframe.c delete mode 100644 vpx/svc_context.h diff --git a/configure b/configure index a50db7404..2b0722df1 100755 --- a/configure +++ b/configure @@ -250,7 +250,6 @@ HAVE_LIST=" unistd_h " EXPERIMENT_LIST=" - spatial_svc fp_mb_stats emulate_hardware var_tx diff --git a/examples.mk b/examples.mk index 178b2b099..30fade1fe 100644 --- a/examples.mk +++ b/examples.mk @@ -109,14 +109,6 @@ endif vpxenc.GUID = 548DEC74-7A15-4B2B-AFC3-AA102E7C25C1 vpxenc.DESCRIPTION = Full featured encoder -EXAMPLES-$(CONFIG_ENCODERS) += vpx_temporal_svc_encoder.c -vpx_temporal_svc_encoder.SRCS += ivfenc.c ivfenc.h -vpx_temporal_svc_encoder.SRCS += tools_common.c tools_common.h -vpx_temporal_svc_encoder.SRCS += video_common.h -vpx_temporal_svc_encoder.SRCS += video_writer.h video_writer.c -vpx_temporal_svc_encoder.SRCS += vpx_ports/msvc.h -vpx_temporal_svc_encoder.GUID = B18C08F2-A439-4502-A78E-849BE3D60947 -vpx_temporal_svc_encoder.DESCRIPTION = Temporal SVC Encoder EXAMPLES-$(CONFIG_DECODERS) += simple_decoder.c simple_decoder.GUID = D3BBF1E9-2427-450D-BBFF-B2843C1D44CC simple_decoder.SRCS += ivfdec.h ivfdec.c diff --git a/examples/vpx_temporal_svc_encoder.c b/examples/vpx_temporal_svc_encoder.c deleted file mode 100644 index e6c09fb71..000000000 --- a/examples/vpx_temporal_svc_encoder.c +++ /dev/null @@ -1,852 +0,0 @@ -/* - * 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 -#include -#include -#include -#include - -#include "./vpx_config.h" -#include "../vpx_ports/vpx_timer.h" -#include "vpx/vp8cx.h" -#include "vpx/vpx_encoder.h" - -#include "../tools_common.h" -#include "../video_writer.h" - -static const char *exec_name; - -void usage_exit(void) { - exit(EXIT_FAILURE); -} - -// Denoiser states, for temporal denoising. -enum denoiserState { - kDenoiserOff, - kDenoiserOnYOnly, - kDenoiserOnYUV, - kDenoiserOnYUVAggressive, - kDenoiserOnAdaptive -}; - -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) { - unsigned 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; - 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 < cfg->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; -} - -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"); -} - -// 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. - layer_flags[1] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_UPD_GF | - VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST | - VP8_EFLAG_NO_UPD_ENTROPY; - // Layer 1: sync point: predict from L and ARF; update G. - layer_flags[2] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_UPD_ARF | - VP8_EFLAG_NO_UPD_LAST; - // Layer 2: predict from L, G, ARF; update none. - layer_flags[3] = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF | - VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_ENTROPY; - // Layer 0: predict from L and ARF; update L. - layer_flags[4] = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF | - VP8_EFLAG_NO_REF_GF; - // Layer 2: predict from L, G, ARF; update none. - layer_flags[5] = layer_flags[3]; - // Layer 1: predict from L, G, ARF; update G. - layer_flags[6] = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST; - // Layer 2: predict from L, G, ARF; update none. - layer_flags[7] = layer_flags[3]; - break; - } - case 11: { - // 3-layers structure with one reference frame. - // This works same as temporal_layering_mode 3. - // This was added to compare with vp9_spatial_svc_encoder. - - // 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] = 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] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | - VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF; - layer_flags[3] = VP8_EFLAG_NO_REF_LAST | VP8_EFLAG_NO_REF_ARF | - VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF; - break; - } - case 12: - default: { - // 3-layers structure as in case 10, but no sync/refresh points for - // layer 1 and 2. - 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. - layer_flags[0] = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF | - VP8_EFLAG_NO_REF_GF; - layer_flags[4] = layer_flags[0]; - // Layer 1: predict from L, G, ARF; update G. - layer_flags[2] = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST; - layer_flags[6] = layer_flags[2]; - // Layer 2: predict from L, G, ARF; update none. - layer_flags[1] = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF | - VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_ENTROPY; - layer_flags[3] = layer_flags[1]; - layer_flags[5] = layer_flags[1]; - layer_flags[7] = layer_flags[1]; - break; - } - } -} - -int main(int argc, char **argv) { - VpxVideoWriter *outfile[VPX_TS_MAX_LAYERS] = {NULL}; - vpx_codec_ctx_t codec; - vpx_codec_enc_cfg_t cfg; - int frame_cnt = 0; - vpx_image_t raw; - vpx_codec_err_t res; - unsigned int width; - unsigned int height; - int speed; - int frame_avail; - int got_data; - int flags = 0; - unsigned int i; - int pts = 0; // PTS starts at 0. - int frame_duration = 1; // 1 timebase tick per frame. - int layering_mode = 0; - int layer_flags[VPX_TS_MAX_PERIODICITY] = {0}; - int flag_periodicity = 1; -#if VPX_ENCODER_ABI_VERSION > (4 + VPX_CODEC_ABI_VERSION) - vpx_svc_layer_id_t layer_id = {0, 0}; -#else - vpx_svc_layer_id_t layer_id = {0}; -#endif - const VpxInterface *encoder = NULL; - FILE *infile = NULL; - struct RateControlMetrics rc; - int64_t cx_time = 0; - const int min_args_base = 11; -#if CONFIG_VP9_HIGHBITDEPTH - vpx_bit_depth_t bit_depth = VPX_BITS_8; - int input_bit_depth = 8; - const int min_args = min_args_base + 1; -#else - const int min_args = min_args_base; -#endif // CONFIG_VP9_HIGHBITDEPTH - double sum_bitrate = 0.0; - double sum_bitrate2 = 0.0; - double framerate = 30.0; - - exec_name = argv[0]; - // Check usage and arguments. - if (argc < min_args) { -#if CONFIG_VP9_HIGHBITDEPTH - die("Usage: %s " - " " - " ... \n", argv[0]); -#else - die("Usage: %s " - " " - " ... \n", argv[0]); -#endif // CONFIG_VP9_HIGHBITDEPTH - } - - encoder = get_vpx_encoder_by_name(argv[3]); - if (!encoder) - die("Unsupported codec."); - - printf("Using %s\n", vpx_codec_iface_name(encoder->codec_interface())); - - width = strtol(argv[4], NULL, 0); - height = strtol(argv[5], NULL, 0); - if (width < 16 || width % 2 || height < 16 || height % 2) { - die("Invalid resolution: %d x %d", width, height); - } - - layering_mode = strtol(argv[10], NULL, 0); - if (layering_mode < 0 || layering_mode > 13) { - die("Invalid layering mode (0..12) %s", argv[10]); - } - - if (argc != min_args + mode_to_num_layers[layering_mode]) { - die("Invalid number of arguments"); - } - -#if CONFIG_VP9_HIGHBITDEPTH - switch (strtol(argv[argc-1], NULL, 0)) { - case 8: - bit_depth = VPX_BITS_8; - input_bit_depth = 8; - break; - case 10: - bit_depth = VPX_BITS_10; - input_bit_depth = 10; - break; - case 12: - bit_depth = VPX_BITS_12; - input_bit_depth = 12; - break; - default: - die("Invalid bit depth (8, 10, 12) %s", argv[argc-1]); - } - if (!vpx_img_alloc(&raw, - bit_depth == VPX_BITS_8 ? VPX_IMG_FMT_I420 : - VPX_IMG_FMT_I42016, - width, height, 32)) { - die("Failed to allocate image", width, height); - } -#else - if (!vpx_img_alloc(&raw, VPX_IMG_FMT_I420, width, height, 32)) { - die("Failed to allocate image", width, height); - } -#endif // CONFIG_VP9_HIGHBITDEPTH - - // Populate encoder configuration. - res = vpx_codec_enc_config_default(encoder->codec_interface(), &cfg, 0); - if (res) { - printf("Failed to get config: %s\n", vpx_codec_err_to_string(res)); - return EXIT_FAILURE; - } - - // Update the default configuration with our settings. - cfg.g_w = width; - cfg.g_h = height; - -#if CONFIG_VP9_HIGHBITDEPTH - if (bit_depth != VPX_BITS_8) { - cfg.g_bit_depth = bit_depth; - cfg.g_input_bit_depth = input_bit_depth; - cfg.g_profile = 2; - } -#endif // CONFIG_VP9_HIGHBITDEPTH - - // Timebase format e.g. 30fps: numerator=1, demoninator = 30. - cfg.g_timebase.num = strtol(argv[6], NULL, 0); - cfg.g_timebase.den = strtol(argv[7], NULL, 0); - - speed = strtol(argv[8], NULL, 0); - if (speed < 0) { - die("Invalid speed setting: must be positive"); - } - - for (i = min_args_base; - (int)i < min_args_base + mode_to_num_layers[layering_mode]; - ++i) { - rc.layer_target_bitrate[i - 11] = strtol(argv[i], NULL, 0); - if (strncmp(encoder->name, "vp8", 3) == 0) - cfg.ts_target_bitrate[i - 11] = rc.layer_target_bitrate[i - 11]; - else if (strncmp(encoder->name, "vp9", 3) == 0) - cfg.layer_target_bitrate[i - 11] = rc.layer_target_bitrate[i - 11]; - } - - // Real time parameters. - cfg.rc_dropframe_thresh = strtol(argv[9], NULL, 0); - cfg.rc_end_usage = VPX_CBR; - cfg.rc_min_quantizer = 2; - cfg.rc_max_quantizer = 56; - if (strncmp(encoder->name, "vp9", 3) == 0) - cfg.rc_max_quantizer = 52; - cfg.rc_undershoot_pct = 50; - cfg.rc_overshoot_pct = 50; - cfg.rc_buf_initial_sz = 500; - cfg.rc_buf_optimal_sz = 600; - cfg.rc_buf_sz = 1000; - - // Disable dynamic resizing by default. - cfg.rc_resize_allowed = 0; - - // Use 1 thread as default. - cfg.g_threads = 1; - - // Enable error resilient mode. - cfg.g_error_resilient = 1; - cfg.g_lag_in_frames = 0; - cfg.kf_mode = VPX_KF_AUTO; - - // Disable automatic keyframe placement. - cfg.kf_min_dist = cfg.kf_max_dist = 3000; - - cfg.temporal_layering_mode = VP9E_TEMPORAL_LAYERING_MODE_BYPASS; - - set_temporal_layer_pattern(layering_mode, - &cfg, - layer_flags, - &flag_periodicity); - - set_rate_control_metrics(&rc, &cfg); - - // Target bandwidth for the whole stream. - // Set to layer_target_bitrate for highest layer (total bitrate). - cfg.rc_target_bitrate = rc.layer_target_bitrate[cfg.ts_number_layers - 1]; - - // Open input file. - if (!(infile = fopen(argv[1], "rb"))) { - die("Failed to open %s for reading", argv[1]); - } - - 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_codec(&codec, "Failed to initialize encoder"); - - if (strncmp(encoder->name, "vp8", 3) == 0) { - vpx_codec_control(&codec, VP8E_SET_CPUUSED, -speed); - vpx_codec_control(&codec, VP8E_SET_NOISE_SENSITIVITY, kDenoiserOff); - vpx_codec_control(&codec, VP8E_SET_STATIC_THRESHOLD, 1); - } else if (strncmp(encoder->name, "vp9", 3) == 0) { - vpx_svc_extra_cfg_t svc_params; - vpx_codec_control(&codec, VP8E_SET_CPUUSED, speed); - vpx_codec_control(&codec, VP9E_SET_AQ_MODE, 3); - vpx_codec_control(&codec, VP9E_SET_FRAME_PERIODIC_BOOST, 0); - vpx_codec_control(&codec, VP9E_SET_NOISE_SENSITIVITY, kDenoiserOff); - vpx_codec_control(&codec, VP8E_SET_STATIC_THRESHOLD, 1); - vpx_codec_control(&codec, VP9E_SET_TUNE_CONTENT, 0); - vpx_codec_control(&codec, VP9E_SET_TILE_COLUMNS, (cfg.g_threads >> 1)); - if (vpx_codec_control(&codec, VP9E_SET_SVC, layering_mode > 0 ? 1: 0)) - die_codec(&codec, "Failed to set SVC"); - for (i = 0; i < cfg.ts_number_layers; ++i) { - svc_params.max_quantizers[i] = cfg.rc_max_quantizer; - svc_params.min_quantizers[i] = cfg.rc_min_quantizer; - } - svc_params.scaling_factor_num[0] = cfg.g_h; - svc_params.scaling_factor_den[0] = cfg.g_h; - vpx_codec_control(&codec, VP9E_SET_SVC_PARAMETERS, &svc_params); - } - if (strncmp(encoder->name, "vp8", 3) == 0) { - vpx_codec_control(&codec, VP8E_SET_SCREEN_CONTENT_MODE, 0); - } - vpx_codec_control(&codec, VP8E_SET_TOKEN_PARTITIONS, 1); - // This controls the maximum target size of the key frame. - // For generating smaller key frames, use a smaller max_intra_size_pct - // value, like 100 or 200. - { - const int max_intra_size_pct = 900; - vpx_codec_control(&codec, VP8E_SET_MAX_INTRA_BITRATE_PCT, - max_intra_size_pct); - } - - frame_avail = 1; - while (frame_avail || got_data) { - struct vpx_usec_timer timer; - vpx_codec_iter_t iter = NULL; - const vpx_codec_cx_pkt_t *pkt; -#if VPX_ENCODER_ABI_VERSION > (4 + VPX_CODEC_ABI_VERSION) - // Update the temporal layer_id. No spatial layers in this test. - layer_id.spatial_layer_id = 0; -#endif - layer_id.temporal_layer_id = - cfg.ts_layer_id[frame_cnt % cfg.ts_periodicity]; - if (strncmp(encoder->name, "vp9", 3) == 0) { - vpx_codec_control(&codec, VP9E_SET_SVC_LAYER_ID, &layer_id); - } else if (strncmp(encoder->name, "vp8", 3) == 0) { - vpx_codec_control(&codec, VP8E_SET_TEMPORAL_LAYER_ID, - layer_id.temporal_layer_id); - } - flags = layer_flags[frame_cnt % flag_periodicity]; - if (layering_mode == 0) - flags = 0; - frame_avail = vpx_img_read(&raw, infile); - if (frame_avail) - ++rc.layer_input_frames[layer_id.temporal_layer_id]; - vpx_usec_timer_start(&timer); - if (vpx_codec_encode(&codec, frame_avail? &raw : NULL, pts, 1, flags, - VPX_DL_REALTIME)) { - die_codec(&codec, "Failed to encode frame"); - } - vpx_usec_timer_mark(&timer); - cx_time += vpx_usec_timer_elapsed(&timer); - // Reset KF flag. - if (layering_mode != 7) { - layer_flags[0] &= ~VPX_EFLAG_FORCE_KF; - } - got_data = 0; - while ( (pkt = vpx_codec_get_cx_data(&codec, &iter)) ) { - got_data = 1; - switch (pkt->kind) { - case VPX_CODEC_CX_FRAME_PKT: - for (i = cfg.ts_layer_id[frame_cnt % cfg.ts_periodicity]; - i < cfg.ts_number_layers; ++i) { - vpx_video_writer_write_frame(outfile[i], pkt->data.frame.buf, - pkt->data.frame.sz, pts); - ++rc.layer_tot_enc_frames[i]; - rc.layer_encoding_bitrate[i] += 8.0 * pkt->data.frame.sz; - // Keep count of rate control stats per layer (for non-key frames). - if (i == cfg.ts_layer_id[frame_cnt % cfg.ts_periodicity] && - !(pkt->data.frame.flags & VPX_FRAME_IS_KEY)) { - rc.layer_avg_frame_size[i] += 8.0 * pkt->data.frame.sz; - rc.layer_avg_rate_mismatch[i] += - fabs(8.0 * pkt->data.frame.sz - rc.layer_pfb[i]) / - rc.layer_pfb[i]; - ++rc.layer_enc_frames[i]; - } - } - // Update for short-time encoding bitrate states, for moving window - // of size rc->window, shifted by rc->window / 2. - // Ignore first window segment, due to key frame. - if (frame_cnt > rc.window_size) { - sum_bitrate += 0.001 * 8.0 * pkt->data.frame.sz * framerate; - if (frame_cnt % rc.window_size == 0) { - rc.window_count += 1; - rc.avg_st_encoding_bitrate += sum_bitrate / rc.window_size; - rc.variance_st_encoding_bitrate += - (sum_bitrate / rc.window_size) * - (sum_bitrate / rc.window_size); - sum_bitrate = 0.0; - } - } - // Second shifted window. - if (frame_cnt > rc.window_size + rc.window_size / 2) { - sum_bitrate2 += 0.001 * 8.0 * pkt->data.frame.sz * framerate; - if (frame_cnt > 2 * rc.window_size && - frame_cnt % rc.window_size == 0) { - rc.window_count += 1; - rc.avg_st_encoding_bitrate += sum_bitrate2 / rc.window_size; - rc.variance_st_encoding_bitrate += - (sum_bitrate2 / rc.window_size) * - (sum_bitrate2 / rc.window_size); - sum_bitrate2 = 0.0; - } - } - break; - default: - break; - } - } - ++frame_cnt; - pts += frame_duration; - } - fclose(infile); - printout_rate_control_summary(&rc, &cfg, frame_cnt); - printf("\n"); - printf("Frame cnt and encoding time/FPS stats for encoding: %d %f %f \n", - frame_cnt, - 1000 * (float)cx_time / (double)(frame_cnt * 1000000), - 1000000 * (double)frame_cnt / (double)cx_time); - - if (vpx_codec_destroy(&codec)) - die_codec(&codec, "Failed to destroy codec"); - - // Try to rewrite the output file headers with the actual frame count. - for (i = 0; i < cfg.ts_number_layers; ++i) - vpx_video_writer_close(outfile[i]); - - vpx_img_free(&raw); - return EXIT_SUCCESS; -} diff --git a/libs.mk b/libs.mk index 13c33ca3b..b42c62375 100644 --- a/libs.mk +++ b/libs.mk @@ -66,7 +66,6 @@ ifeq ($(CONFIG_VP10_ENCODER),yes) CODEC_EXPORTS-yes += $(addprefix $(VP10_PREFIX),$(VP10_CX_EXPORTS)) CODEC_SRCS-yes += $(VP10_PREFIX)vp10cx.mk vpx/vp8.h vpx/vp8cx.h INSTALL-LIBS-yes += include/vpx/vp8.h include/vpx/vp8cx.h - INSTALL-LIBS-$(CONFIG_SPATIAL_SVC) += include/vpx/svc_context.h INSTALL_MAPS += include/vpx/% $(SRC_PATH_BARE)/$(VP10_PREFIX)/% CODEC_DOC_SRCS += vpx/vp8.h vpx/vp8cx.h CODEC_DOC_SECTIONS += vp9 vp9_encoder @@ -127,9 +126,6 @@ INSTALL-SRCS-$(CONFIG_CODEC_SRCS) += third_party/x86inc/x86inc.asm endif CODEC_EXPORTS-yes += vpx/exports_com CODEC_EXPORTS-$(CONFIG_ENCODERS) += vpx/exports_enc -ifeq ($(CONFIG_SPATIAL_SVC),yes) -CODEC_EXPORTS-$(CONFIG_ENCODERS) += vpx/exports_spatial_svc -endif CODEC_EXPORTS-$(CONFIG_DECODERS) += vpx/exports_dec INSTALL-LIBS-yes += include/vpx/vpx_codec.h @@ -265,7 +261,7 @@ libvpx.def: $(call enabled,CODEC_EXPORTS) $(qexec)echo LIBRARY $(LIBVPX_SO:.dll=) INITINSTANCE TERMINSTANCE > $@ $(qexec)echo "DATA MULTIPLE NONSHARED" >> $@ $(qexec)echo "EXPORTS" >> $@ - $(qexec)awk '!/vpx_svc_*/ {print "_"$$2}' $^ >>$@ + $(qexec)awk '{print "_"$$2}' $^ >>$@ CLEAN-OBJS += libvpx.def libvpx_dll.a: $(LIBVPX_SO) diff --git a/test/datarate_test.cc b/test/datarate_test.cc index 13f12e27f..89761e70f 100644 --- a/test/datarate_test.cc +++ b/test/datarate_test.cc @@ -19,198 +19,13 @@ namespace { class DatarateTestLarge : public ::libvpx_test::EncoderTest, - public ::libvpx_test::CodecTestWithParam { + public ::libvpx_test::CodecTestWith2Params { public: DatarateTestLarge() : EncoderTest(GET_PARAM(0)) {} + protected: virtual ~DatarateTestLarge() {} - protected: - virtual void SetUp() { - InitializeConfig(); - SetMode(GET_PARAM(1)); - ResetModel(); - } - - virtual void ResetModel() { - last_pts_ = 0; - bits_in_buffer_model_ = cfg_.rc_target_bitrate * cfg_.rc_buf_initial_sz; - frame_number_ = 0; - first_drop_ = 0; - bits_total_ = 0; - duration_ = 0.0; - denoiser_offon_test_ = 0; - denoiser_offon_period_ = -1; - } - - virtual void PreEncodeFrameHook(::libvpx_test::VideoSource *video, - ::libvpx_test::Encoder *encoder) { - if (video->frame() == 0) - encoder->Control(VP8E_SET_NOISE_SENSITIVITY, denoiser_on_); - - if (denoiser_offon_test_) { - ASSERT_GT(denoiser_offon_period_, 0) - << "denoiser_offon_period_ is not positive."; - if ((video->frame() + 1) % denoiser_offon_period_ == 0) { - // Flip denoiser_on_ periodically - denoiser_on_ ^= 1; - } - encoder->Control(VP8E_SET_NOISE_SENSITIVITY, denoiser_on_); - } - - const vpx_rational_t tb = video->timebase(); - timebase_ = static_cast(tb.num) / tb.den; - duration_ = 0; - } - - virtual void FramePktHook(const vpx_codec_cx_pkt_t *pkt) { - // Time since last timestamp = duration. - vpx_codec_pts_t duration = pkt->data.frame.pts - last_pts_; - - // TODO(jimbankoski): Remove these lines when the issue: - // http://code.google.com/p/webm/issues/detail?id=496 is fixed. - // For now the codec assumes buffer starts at starting buffer rate - // plus one frame's time. - if (last_pts_ == 0) - duration = 1; - - // Add to the buffer the bits we'd expect from a constant bitrate server. - bits_in_buffer_model_ += static_cast( - duration * timebase_ * cfg_.rc_target_bitrate * 1000); - - /* Test the buffer model here before subtracting the frame. Do so because - * the way the leaky bucket model works in libvpx is to allow the buffer to - * empty - and then stop showing frames until we've got enough bits to - * show one. As noted in comment below (issue 495), this does not currently - * apply to key frames. For now exclude key frames in condition below. */ - const bool key_frame = (pkt->data.frame.flags & VPX_FRAME_IS_KEY) - ? true: false; - if (!key_frame) { - ASSERT_GE(bits_in_buffer_model_, 0) << "Buffer Underrun at frame " - << pkt->data.frame.pts; - } - - const int64_t frame_size_in_bits = pkt->data.frame.sz * 8; - - // Subtract from the buffer the bits associated with a played back frame. - bits_in_buffer_model_ -= frame_size_in_bits; - - // Update the running total of bits for end of test datarate checks. - bits_total_ += frame_size_in_bits; - - // If first drop not set and we have a drop set it to this time. - if (!first_drop_ && duration > 1) - first_drop_ = last_pts_ + 1; - - // Update the most recent pts. - last_pts_ = pkt->data.frame.pts; - - // We update this so that we can calculate the datarate minus the last - // frame encoded in the file. - bits_in_last_frame_ = frame_size_in_bits; - - ++frame_number_; - } - - virtual void EndPassHook(void) { - if (bits_total_) { - const double file_size_in_kb = bits_total_ / 1000.; // bits per kilobit - - duration_ = (last_pts_ + 1) * timebase_; - - // Effective file datarate includes the time spent prebuffering. - effective_datarate_ = (bits_total_ - bits_in_last_frame_) / 1000.0 - / (cfg_.rc_buf_initial_sz / 1000.0 + duration_); - - file_datarate_ = file_size_in_kb / duration_; - } - } - - vpx_codec_pts_t last_pts_; - int64_t bits_in_buffer_model_; - double timebase_; - int frame_number_; - vpx_codec_pts_t first_drop_; - int64_t bits_total_; - double duration_; - double file_datarate_; - double effective_datarate_; - int64_t bits_in_last_frame_; - int denoiser_on_; - int denoiser_offon_test_; - int denoiser_offon_period_; -}; - - -TEST_P(DatarateTestLarge, BasicBufferModel) { - denoiser_on_ = 0; - cfg_.rc_buf_initial_sz = 500; - cfg_.rc_dropframe_thresh = 1; - cfg_.rc_max_quantizer = 56; - cfg_.rc_end_usage = VPX_CBR; - // 2 pass cbr datarate control has a bug hidden by the small # of - // frames selected in this encode. The problem is that even if the buffer is - // negative we produce a keyframe on a cutscene. Ignoring datarate - // constraints - // TODO(jimbankoski): ( Fix when issue - // http://code.google.com/p/webm/issues/detail?id=495 is addressed. ) - ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288, - 30, 1, 0, 140); - - // There is an issue for low bitrates in real-time mode, where the - // effective_datarate slightly overshoots the target bitrate. - // This is same the issue as noted about (#495). - // TODO(jimbankoski/marpan): Update test to run for lower bitrates (< 100), - // when the issue is resolved. - for (int i = 100; i < 800; i += 200) { - cfg_.rc_target_bitrate = i; - ResetModel(); - ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); - ASSERT_GE(cfg_.rc_target_bitrate, effective_datarate_ * 0.95) - << " The datarate for the file exceeds the target!"; - - ASSERT_LE(cfg_.rc_target_bitrate, file_datarate_ * 1.3) - << " The datarate for the file missed the target!"; - } -} - -TEST_P(DatarateTestLarge, ChangingDropFrameThresh) { - denoiser_on_ = 0; - cfg_.rc_buf_initial_sz = 500; - cfg_.rc_max_quantizer = 36; - cfg_.rc_end_usage = VPX_CBR; - cfg_.rc_target_bitrate = 200; - cfg_.kf_mode = VPX_KF_DISABLED; - - const int frame_count = 40; - ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288, - 30, 1, 0, frame_count); - - // Here we check that the first dropped frame gets earlier and earlier - // as the drop frame threshold is increased. - - const int kDropFrameThreshTestStep = 30; - vpx_codec_pts_t last_drop = frame_count; - for (int i = 1; i < 91; i += kDropFrameThreshTestStep) { - cfg_.rc_dropframe_thresh = i; - ResetModel(); - ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); - ASSERT_LE(first_drop_, last_drop) - << " The first dropped frame for drop_thresh " << i - << " > first dropped frame for drop_thresh " - << i - kDropFrameThreshTestStep; - last_drop = first_drop_; - } -} - -class DatarateTestVP9Large : public ::libvpx_test::EncoderTest, - public ::libvpx_test::CodecTestWith2Params { - public: - DatarateTestVP9Large() : EncoderTest(GET_PARAM(0)) {} - - protected: - virtual ~DatarateTestVP9Large() {} - virtual void SetUp() { InitializeConfig(); SetMode(GET_PARAM(1)); @@ -227,77 +42,11 @@ class DatarateTestVP9Large : public ::libvpx_test::EncoderTest, num_drops_ = 0; // Denoiser is off by default. denoiser_on_ = 0; - // For testing up to 3 layers. - for (int i = 0; i < 3; ++i) { - bits_total_[i] = 0; - } + bits_total_ = 0; denoiser_offon_test_ = 0; denoiser_offon_period_ = -1; } - // - // Frame flags and layer id for temporal layers. - // - - // For two layers, test pattern is: - // 1 3 - // 0 2 ..... - // For three layers, test pattern is: - // 1 3 5 7 - // 2 6 - // 0 4 .... - // LAST is always update on base/layer 0, GOLDEN is updated on layer 1. - // For this 3 layer example, the 2nd enhancement layer (layer 2) does not - // update any reference frames. - int SetFrameFlags(int frame_num, int num_temp_layers) { - int frame_flags = 0; - if (num_temp_layers == 2) { - if (frame_num % 2 == 0) { - // Layer 0: predict from L and ARF, update L. - frame_flags = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_UPD_GF | - VP8_EFLAG_NO_UPD_ARF; - } else { - // Layer 1: predict from L, G and ARF, and update G. - frame_flags = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST | - VP8_EFLAG_NO_UPD_ENTROPY; - } - } else if (num_temp_layers == 3) { - if (frame_num % 4 == 0) { - // Layer 0: predict from L and ARF; update L. - frame_flags = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF | - VP8_EFLAG_NO_REF_GF; - } else if ((frame_num - 2) % 4 == 0) { - // Layer 1: predict from L, G, ARF; update G. - frame_flags = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST; - } else if ((frame_num - 1) % 2 == 0) { - // Layer 2: predict from L, G, ARF; update none. - frame_flags = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF | - VP8_EFLAG_NO_UPD_LAST; - } - } - return frame_flags; - } - - int SetLayerId(int frame_num, int num_temp_layers) { - int layer_id = 0; - if (num_temp_layers == 2) { - if (frame_num % 2 == 0) { - layer_id = 0; - } else { - layer_id = 1; - } - } else if (num_temp_layers == 3) { - if (frame_num % 4 == 0) { - layer_id = 0; - } else if ((frame_num - 2) % 4 == 0) { - layer_id = 1; - } else if ((frame_num - 1) % 2 == 0) { - layer_id = 2; - } - } - return layer_id; - } - virtual void PreEncodeFrameHook(::libvpx_test::VideoSource *video, ::libvpx_test::Encoder *encoder) { if (video->frame() == 0) @@ -314,23 +63,11 @@ class DatarateTestVP9Large : public ::libvpx_test::EncoderTest, encoder->Control(VP9E_SET_NOISE_SENSITIVITY, denoiser_on_); - if (cfg_.ts_number_layers > 1) { - if (video->frame() == 0) { - encoder->Control(VP9E_SET_SVC, 1); - } - vpx_svc_layer_id_t layer_id; - layer_id.spatial_layer_id = 0; - frame_flags_ = SetFrameFlags(video->frame(), cfg_.ts_number_layers); - layer_id.temporal_layer_id = SetLayerId(video->frame(), - cfg_.ts_number_layers); - encoder->Control(VP9E_SET_SVC_LAYER_ID, &layer_id); - } const vpx_rational_t tb = video->timebase(); timebase_ = static_cast(tb.num) / tb.den; duration_ = 0; } - virtual void FramePktHook(const vpx_codec_cx_pkt_t *pkt) { // Time since last timestamp = duration. vpx_codec_pts_t duration = pkt->data.frame.pts - last_pts_; @@ -346,8 +83,6 @@ class DatarateTestVP9Large : public ::libvpx_test::EncoderTest, tot_frame_number_ += static_cast(duration - 1); } - int layer = SetLayerId(tot_frame_number_, cfg_.ts_number_layers); - // Add to the buffer the bits we'd expect from a constant bitrate server. bits_in_buffer_model_ += static_cast( duration * timebase_ * cfg_.rc_target_bitrate * 1000); @@ -358,11 +93,8 @@ class DatarateTestVP9Large : public ::libvpx_test::EncoderTest, const size_t frame_size_in_bits = pkt->data.frame.sz * 8; - // Update the total encoded bits. For temporal layers, update the cumulative - // encoded bits per layer. - for (int i = layer; i < static_cast(cfg_.ts_number_layers); ++i) { - bits_total_[i] += frame_size_in_bits; - } + // Update the total encoded bits. + bits_total_ += frame_size_in_bits; // Update the most recent pts. last_pts_ = pkt->data.frame.pts; @@ -371,23 +103,18 @@ class DatarateTestVP9Large : public ::libvpx_test::EncoderTest, } virtual void EndPassHook(void) { - for (int layer = 0; layer < static_cast(cfg_.ts_number_layers); - ++layer) { - duration_ = (last_pts_ + 1) * timebase_; - if (bits_total_[layer]) { - // Effective file datarate: - effective_datarate_[layer] = (bits_total_[layer] / 1000.0) / duration_; - } - } + duration_ = (last_pts_ + 1) * timebase_; + // Effective file datarate: + effective_datarate_ = (bits_total_ / 1000.0) / duration_; } vpx_codec_pts_t last_pts_; double timebase_; int frame_number_; // Counter for number of non-dropped/encoded frames. int tot_frame_number_; // Counter for total number of input frames. - int64_t bits_total_[3]; + int64_t bits_total_; double duration_; - double effective_datarate_[3]; + double effective_datarate_; int set_cpu_used_; int64_t bits_in_buffer_model_; vpx_codec_pts_t first_drop_; @@ -398,7 +125,7 @@ class DatarateTestVP9Large : public ::libvpx_test::EncoderTest, }; // Check basic rate targeting for VBR mode. -TEST_P(DatarateTestVP9Large, BasicRateTargetingVBR) { +TEST_P(DatarateTestLarge, BasicRateTargetingVBR) { cfg_.rc_min_quantizer = 0; cfg_.rc_max_quantizer = 63; cfg_.g_error_resilient = 0; @@ -411,15 +138,15 @@ TEST_P(DatarateTestVP9Large, BasicRateTargetingVBR) { cfg_.rc_target_bitrate = i; ResetModel(); ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); - ASSERT_GE(effective_datarate_[0], cfg_.rc_target_bitrate * 0.75) + ASSERT_GE(effective_datarate_, cfg_.rc_target_bitrate * 0.75) << " The datarate for the file is lower than target by too much!"; - ASSERT_LE(effective_datarate_[0], cfg_.rc_target_bitrate * 1.25) + ASSERT_LE(effective_datarate_, cfg_.rc_target_bitrate * 1.25) << " The datarate for the file is greater than target by too much!"; } } // Check basic rate targeting for CBR, -TEST_P(DatarateTestVP9Large, BasicRateTargeting) { +TEST_P(DatarateTestLarge, BasicRateTargeting) { cfg_.rc_buf_initial_sz = 500; cfg_.rc_buf_optimal_sz = 500; cfg_.rc_buf_sz = 1000; @@ -435,15 +162,15 @@ TEST_P(DatarateTestVP9Large, BasicRateTargeting) { cfg_.rc_target_bitrate = i; ResetModel(); ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); - ASSERT_GE(effective_datarate_[0], cfg_.rc_target_bitrate * 0.85) + ASSERT_GE(effective_datarate_, cfg_.rc_target_bitrate * 0.85) << " The datarate for the file is lower than target by too much!"; - ASSERT_LE(effective_datarate_[0], cfg_.rc_target_bitrate * 1.15) + ASSERT_LE(effective_datarate_, cfg_.rc_target_bitrate * 1.15) << " The datarate for the file is greater than target by too much!"; } } // Check basic rate targeting for CBR. -TEST_P(DatarateTestVP9Large, BasicRateTargeting444) { +TEST_P(DatarateTestLarge, BasicRateTargeting444) { ::libvpx_test::Y4mVideoSource video("rush_hour_444.y4m", 0, 140); cfg_.g_profile = 1; @@ -462,10 +189,10 @@ TEST_P(DatarateTestVP9Large, BasicRateTargeting444) { ResetModel(); ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); ASSERT_GE(static_cast(cfg_.rc_target_bitrate), - effective_datarate_[0] * 0.85) + effective_datarate_ * 0.85) << " The datarate for the file exceeds the target by too much!"; ASSERT_LE(static_cast(cfg_.rc_target_bitrate), - effective_datarate_[0] * 1.15) + effective_datarate_ * 1.15) << " The datarate for the file missed the target!" << cfg_.rc_target_bitrate << " "<< effective_datarate_; } @@ -475,7 +202,7 @@ TEST_P(DatarateTestVP9Large, BasicRateTargeting444) { // as the drop frame threshold is increased, and (2) that the total number of // frame drops does not decrease as we increase frame drop threshold. // Use a lower qp-max to force some frame drops. -TEST_P(DatarateTestVP9Large, ChangingDropFrameThresh) { +TEST_P(DatarateTestLarge, ChangingDropFrameThresh) { cfg_.rc_buf_initial_sz = 500; cfg_.rc_buf_optimal_sz = 500; cfg_.rc_buf_sz = 1000; @@ -501,9 +228,9 @@ TEST_P(DatarateTestVP9Large, ChangingDropFrameThresh) { cfg_.rc_dropframe_thresh = i; ResetModel(); ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); - ASSERT_GE(effective_datarate_[0], cfg_.rc_target_bitrate * 0.85) + ASSERT_GE(effective_datarate_, cfg_.rc_target_bitrate * 0.85) << " The datarate for the file is lower than target by too much!"; - ASSERT_LE(effective_datarate_[0], cfg_.rc_target_bitrate * 1.15) + ASSERT_LE(effective_datarate_, cfg_.rc_target_bitrate * 1.15) << " The datarate for the file is greater than target by too much!"; ASSERT_LE(first_drop_, last_drop) << " The first dropped frame for drop_thresh " << i @@ -518,521 +245,8 @@ TEST_P(DatarateTestVP9Large, ChangingDropFrameThresh) { } } -// Check basic rate targeting for 2 temporal layers. -TEST_P(DatarateTestVP9Large, BasicRateTargeting2TemporalLayers) { - cfg_.rc_buf_initial_sz = 500; - cfg_.rc_buf_optimal_sz = 500; - cfg_.rc_buf_sz = 1000; - cfg_.rc_dropframe_thresh = 1; - cfg_.rc_min_quantizer = 0; - cfg_.rc_max_quantizer = 63; - cfg_.rc_end_usage = VPX_CBR; - cfg_.g_lag_in_frames = 0; - - // 2 Temporal layers, no spatial layers: Framerate decimation (2, 1). - cfg_.ss_number_layers = 1; - cfg_.ts_number_layers = 2; - cfg_.ts_rate_decimator[0] = 2; - cfg_.ts_rate_decimator[1] = 1; - - cfg_.temporal_layering_mode = VP9E_TEMPORAL_LAYERING_MODE_BYPASS; - - if (deadline_ == VPX_DL_REALTIME) - cfg_.g_error_resilient = 1; - - ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288, - 30, 1, 0, 200); - for (int i = 200; i <= 800; i += 200) { - cfg_.rc_target_bitrate = i; - ResetModel(); - // 60-40 bitrate allocation for 2 temporal layers. - cfg_.layer_target_bitrate[0] = 60 * cfg_.rc_target_bitrate / 100; - cfg_.layer_target_bitrate[1] = cfg_.rc_target_bitrate; - ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); - for (int j = 0; j < static_cast(cfg_.ts_number_layers); ++j) { - ASSERT_GE(effective_datarate_[j], cfg_.layer_target_bitrate[j] * 0.85) - << " The datarate for the file is lower than target by too much, " - "for layer: " << j; - ASSERT_LE(effective_datarate_[j], cfg_.layer_target_bitrate[j] * 1.15) - << " The datarate for the file is greater than target by too much, " - "for layer: " << j; - } - } -} - -// Check basic rate targeting for 3 temporal layers. -TEST_P(DatarateTestVP9Large, BasicRateTargeting3TemporalLayers) { - cfg_.rc_buf_initial_sz = 500; - cfg_.rc_buf_optimal_sz = 500; - cfg_.rc_buf_sz = 1000; - cfg_.rc_dropframe_thresh = 1; - cfg_.rc_min_quantizer = 0; - cfg_.rc_max_quantizer = 63; - cfg_.rc_end_usage = VPX_CBR; - cfg_.g_lag_in_frames = 0; - - // 3 Temporal layers, no spatial layers: Framerate decimation (4, 2, 1). - cfg_.ss_number_layers = 1; - cfg_.ts_number_layers = 3; - cfg_.ts_rate_decimator[0] = 4; - cfg_.ts_rate_decimator[1] = 2; - cfg_.ts_rate_decimator[2] = 1; - - cfg_.temporal_layering_mode = VP9E_TEMPORAL_LAYERING_MODE_BYPASS; - - ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288, - 30, 1, 0, 200); - for (int i = 200; i <= 800; i += 200) { - cfg_.rc_target_bitrate = i; - ResetModel(); - // 40-20-40 bitrate allocation for 3 temporal layers. - cfg_.layer_target_bitrate[0] = 40 * cfg_.rc_target_bitrate / 100; - cfg_.layer_target_bitrate[1] = 60 * cfg_.rc_target_bitrate / 100; - cfg_.layer_target_bitrate[2] = cfg_.rc_target_bitrate; - ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); - for (int j = 0; j < static_cast(cfg_.ts_number_layers); ++j) { - // TODO(yaowu): Work out more stable rc control strategy and - // Adjust the thresholds to be tighter than .75. - ASSERT_GE(effective_datarate_[j], cfg_.layer_target_bitrate[j] * 0.75) - << " The datarate for the file is lower than target by too much, " - "for layer: " << j; - // TODO(yaowu): Work out more stable rc control strategy and - // Adjust the thresholds to be tighter than 1.25. - ASSERT_LE(effective_datarate_[j], cfg_.layer_target_bitrate[j] * 1.25) - << " The datarate for the file is greater than target by too much, " - "for layer: " << j; - } - } -} - -// Check basic rate targeting for 3 temporal layers, with frame dropping. -// Only for one (low) bitrate with lower max_quantizer, and somewhat higher -// frame drop threshold, to force frame dropping. -TEST_P(DatarateTestVP9Large, BasicRateTargeting3TemporalLayersFrameDropping) { - cfg_.rc_buf_initial_sz = 500; - cfg_.rc_buf_optimal_sz = 500; - cfg_.rc_buf_sz = 1000; - // Set frame drop threshold and rc_max_quantizer to force some frame drops. - cfg_.rc_dropframe_thresh = 20; - cfg_.rc_max_quantizer = 45; - cfg_.rc_min_quantizer = 0; - cfg_.rc_end_usage = VPX_CBR; - cfg_.g_lag_in_frames = 0; - - // 3 Temporal layers, no spatial layers: Framerate decimation (4, 2, 1). - cfg_.ss_number_layers = 1; - cfg_.ts_number_layers = 3; - cfg_.ts_rate_decimator[0] = 4; - cfg_.ts_rate_decimator[1] = 2; - cfg_.ts_rate_decimator[2] = 1; - - cfg_.temporal_layering_mode = VP9E_TEMPORAL_LAYERING_MODE_BYPASS; - - ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288, - 30, 1, 0, 200); - cfg_.rc_target_bitrate = 200; - ResetModel(); - // 40-20-40 bitrate allocation for 3 temporal layers. - cfg_.layer_target_bitrate[0] = 40 * cfg_.rc_target_bitrate / 100; - cfg_.layer_target_bitrate[1] = 60 * cfg_.rc_target_bitrate / 100; - cfg_.layer_target_bitrate[2] = cfg_.rc_target_bitrate; - ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); - for (int j = 0; j < static_cast(cfg_.ts_number_layers); ++j) { - ASSERT_GE(effective_datarate_[j], cfg_.layer_target_bitrate[j] * 0.85) - << " The datarate for the file is lower than target by too much, " - "for layer: " << j; - ASSERT_LE(effective_datarate_[j], cfg_.layer_target_bitrate[j] * 1.15) - << " The datarate for the file is greater than target by too much, " - "for layer: " << j; - // Expect some frame drops in this test: for this 200 frames test, - // expect at least 10% and not more than 60% drops. - ASSERT_GE(num_drops_, 20); - ASSERT_LE(num_drops_, 130); - } -} - -class DatarateOnePassCbrSvc : public ::libvpx_test::EncoderTest, - public ::libvpx_test::CodecTestWith2Params { - public: - DatarateOnePassCbrSvc() : EncoderTest(GET_PARAM(0)) {} - virtual ~DatarateOnePassCbrSvc() {} - protected: - virtual void SetUp() { - InitializeConfig(); - SetMode(GET_PARAM(1)); - speed_setting_ = GET_PARAM(2); - ResetModel(); - } - virtual void ResetModel() { - last_pts_ = 0; - bits_in_buffer_model_ = cfg_.rc_target_bitrate * cfg_.rc_buf_initial_sz; - frame_number_ = 0; - first_drop_ = 0; - bits_total_ = 0; - duration_ = 0.0; - mismatch_psnr_ = 0.0; - mismatch_nframes_ = 0; - } - virtual void BeginPassHook(unsigned int /*pass*/) { - } - virtual void PreEncodeFrameHook(::libvpx_test::VideoSource *video, - ::libvpx_test::Encoder *encoder) { - if (video->frame() == 0) { - int i; - for (i = 0; i < VPX_MAX_LAYERS; ++i) { - svc_params_.max_quantizers[i] = 63; - svc_params_.min_quantizers[i] = 0; - } - encoder->Control(VP9E_SET_SVC, 1); - encoder->Control(VP9E_SET_SVC_PARAMETERS, &svc_params_); - encoder->Control(VP8E_SET_CPUUSED, speed_setting_); - encoder->Control(VP9E_SET_TILE_COLUMNS, 0); - encoder->Control(VP8E_SET_MAX_INTRA_BITRATE_PCT, 300); - encoder->Control(VP9E_SET_TILE_COLUMNS, (cfg_.g_threads >> 1)); - } - const vpx_rational_t tb = video->timebase(); - timebase_ = static_cast(tb.num) / tb.den; - duration_ = 0; - } - virtual void FramePktHook(const vpx_codec_cx_pkt_t *pkt) { - vpx_codec_pts_t duration = pkt->data.frame.pts - last_pts_; - if (last_pts_ == 0) - duration = 1; - bits_in_buffer_model_ += static_cast( - duration * timebase_ * cfg_.rc_target_bitrate * 1000); - const bool key_frame = (pkt->data.frame.flags & VPX_FRAME_IS_KEY) - ? true: false; - if (!key_frame) { - ASSERT_GE(bits_in_buffer_model_, 0) << "Buffer Underrun at frame " - << pkt->data.frame.pts; - } - const size_t frame_size_in_bits = pkt->data.frame.sz * 8; - bits_in_buffer_model_ -= frame_size_in_bits; - bits_total_ += frame_size_in_bits; - if (!first_drop_ && duration > 1) - first_drop_ = last_pts_ + 1; - last_pts_ = pkt->data.frame.pts; - bits_in_last_frame_ = frame_size_in_bits; - ++frame_number_; - } - virtual void EndPassHook(void) { - if (bits_total_) { - const double file_size_in_kb = bits_total_ / 1000.; // bits per kilobit - duration_ = (last_pts_ + 1) * timebase_; - file_datarate_ = file_size_in_kb / duration_; - } - } - - virtual void MismatchHook(const vpx_image_t *img1, - const vpx_image_t *img2) { - double mismatch_psnr = compute_psnr(img1, img2); - mismatch_psnr_ += mismatch_psnr; - ++mismatch_nframes_; - } - - unsigned int GetMismatchFrames() { - return mismatch_nframes_; - } - - vpx_codec_pts_t last_pts_; - int64_t bits_in_buffer_model_; - double timebase_; - int frame_number_; - vpx_codec_pts_t first_drop_; - int64_t bits_total_; - double duration_; - double file_datarate_; - size_t bits_in_last_frame_; - vpx_svc_extra_cfg_t svc_params_; - int speed_setting_; - double mismatch_psnr_; - int mismatch_nframes_; -}; -static void assign_layer_bitrates(vpx_codec_enc_cfg_t *const enc_cfg, - const vpx_svc_extra_cfg_t *svc_params, - int spatial_layers, - int temporal_layers, - int temporal_layering_mode) { - int sl, spatial_layer_target; - float total = 0; - float alloc_ratio[VPX_MAX_LAYERS] = {0}; - for (sl = 0; sl < spatial_layers; ++sl) { - if (svc_params->scaling_factor_den[sl] > 0) { - alloc_ratio[sl] = (float)(svc_params->scaling_factor_num[sl] * - 1.0 / svc_params->scaling_factor_den[sl]); - total += alloc_ratio[sl]; - } - } - for (sl = 0; sl < spatial_layers; ++sl) { - enc_cfg->ss_target_bitrate[sl] = spatial_layer_target = - (unsigned int)(enc_cfg->rc_target_bitrate * - alloc_ratio[sl] / total); - const int index = sl * temporal_layers; - if (temporal_layering_mode == 3) { - enc_cfg->layer_target_bitrate[index] = - spatial_layer_target >> 1; - enc_cfg->layer_target_bitrate[index + 1] = - (spatial_layer_target >> 1) + (spatial_layer_target >> 2); - enc_cfg->layer_target_bitrate[index + 2] = - spatial_layer_target; - } else if (temporal_layering_mode == 2) { - enc_cfg->layer_target_bitrate[index] = - spatial_layer_target * 2 / 3; - enc_cfg->layer_target_bitrate[index + 1] = - spatial_layer_target; - } - } -} - -// Check basic rate targeting for 1 pass CBR SVC: 2 spatial layers and -// 3 temporal layers. Run CIF clip with 1 thread. -TEST_P(DatarateOnePassCbrSvc, OnePassCbrSvc2SpatialLayers) { - cfg_.rc_buf_initial_sz = 500; - cfg_.rc_buf_optimal_sz = 500; - cfg_.rc_buf_sz = 1000; - cfg_.rc_min_quantizer = 0; - cfg_.rc_max_quantizer = 63; - cfg_.rc_end_usage = VPX_CBR; - cfg_.g_lag_in_frames = 0; - cfg_.ss_number_layers = 2; - cfg_.ts_number_layers = 3; - cfg_.ts_rate_decimator[0] = 4; - cfg_.ts_rate_decimator[1] = 2; - cfg_.ts_rate_decimator[2] = 1; - cfg_.g_error_resilient = 1; - cfg_.g_threads = 1; - cfg_.temporal_layering_mode = 3; - svc_params_.scaling_factor_num[0] = 144; - svc_params_.scaling_factor_den[0] = 288; - svc_params_.scaling_factor_num[1] = 288; - svc_params_.scaling_factor_den[1] = 288; - cfg_.rc_dropframe_thresh = 10; - cfg_.kf_max_dist = 9999; - ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288, - 30, 1, 0, 200); - // TODO(wonkap/marpan): Check that effective_datarate for each layer hits the - // layer target_bitrate. - for (int i = 200; i <= 800; i += 200) { - cfg_.rc_target_bitrate = i; - ResetModel(); - assign_layer_bitrates(&cfg_, &svc_params_, cfg_.ss_number_layers, - cfg_.ts_number_layers, cfg_.temporal_layering_mode); - ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); - ASSERT_GE(cfg_.rc_target_bitrate, file_datarate_ * 0.85) - << " The datarate for the file exceeds the target by too much!"; - ASSERT_LE(cfg_.rc_target_bitrate, file_datarate_ * 1.15) - << " The datarate for the file is lower than the target by too much!"; - EXPECT_EQ(static_cast(0), GetMismatchFrames()); - } -} - -// Check basic rate targeting for 1 pass CBR SVC: 2 spatial layers and 3 -// temporal layers. Run CIF clip with 1 thread, and few short key frame periods. -TEST_P(DatarateOnePassCbrSvc, OnePassCbrSvc2SpatialLayersSmallKf) { - cfg_.rc_buf_initial_sz = 500; - cfg_.rc_buf_optimal_sz = 500; - cfg_.rc_buf_sz = 1000; - cfg_.rc_min_quantizer = 0; - cfg_.rc_max_quantizer = 63; - cfg_.rc_end_usage = VPX_CBR; - cfg_.g_lag_in_frames = 0; - cfg_.ss_number_layers = 2; - cfg_.ts_number_layers = 3; - cfg_.ts_rate_decimator[0] = 4; - cfg_.ts_rate_decimator[1] = 2; - cfg_.ts_rate_decimator[2] = 1; - cfg_.g_error_resilient = 1; - cfg_.g_threads = 1; - cfg_.temporal_layering_mode = 3; - svc_params_.scaling_factor_num[0] = 144; - svc_params_.scaling_factor_den[0] = 288; - svc_params_.scaling_factor_num[1] = 288; - svc_params_.scaling_factor_den[1] = 288; - cfg_.rc_dropframe_thresh = 10; - ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288, - 30, 1, 0, 200); - cfg_.rc_target_bitrate = 400; - // For this 3 temporal layer case, pattern repeats every 4 frames, so choose - // 4 key neighboring key frame periods (so key frame will land on 0-2-1-2). - for (int j = 64; j <= 67; j++) { - cfg_.kf_max_dist = j; - ResetModel(); - assign_layer_bitrates(&cfg_, &svc_params_, cfg_.ss_number_layers, - cfg_.ts_number_layers, cfg_.temporal_layering_mode); - ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); - ASSERT_GE(cfg_.rc_target_bitrate, file_datarate_ * 0.85) - << " The datarate for the file exceeds the target by too much!"; - ASSERT_LE(cfg_.rc_target_bitrate, file_datarate_ * 1.15) - << " The datarate for the file is lower than the target by too much!"; - EXPECT_EQ(static_cast(0), GetMismatchFrames()); - } -} - -// Check basic rate targeting for 1 pass CBR SVC: 2 spatial layers and -// 3 temporal layers. Run HD clip with 4 threads. -TEST_P(DatarateOnePassCbrSvc, OnePassCbrSvc2SpatialLayers4threads) { - cfg_.rc_buf_initial_sz = 500; - cfg_.rc_buf_optimal_sz = 500; - cfg_.rc_buf_sz = 1000; - cfg_.rc_min_quantizer = 0; - cfg_.rc_max_quantizer = 63; - cfg_.rc_end_usage = VPX_CBR; - cfg_.g_lag_in_frames = 0; - cfg_.ss_number_layers = 2; - cfg_.ts_number_layers = 3; - cfg_.ts_rate_decimator[0] = 4; - cfg_.ts_rate_decimator[1] = 2; - cfg_.ts_rate_decimator[2] = 1; - cfg_.g_error_resilient = 1; - cfg_.g_threads = 4; - cfg_.temporal_layering_mode = 3; - svc_params_.scaling_factor_num[0] = 144; - svc_params_.scaling_factor_den[0] = 288; - svc_params_.scaling_factor_num[1] = 288; - svc_params_.scaling_factor_den[1] = 288; - cfg_.rc_dropframe_thresh = 10; - cfg_.kf_max_dist = 9999; - ::libvpx_test::I420VideoSource video("niklas_1280_720_30.y4m", 1280, 720, - 30, 1, 0, 300); - cfg_.rc_target_bitrate = 800; - ResetModel(); - assign_layer_bitrates(&cfg_, &svc_params_, cfg_.ss_number_layers, - cfg_.ts_number_layers, cfg_.temporal_layering_mode); - ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); - ASSERT_GE(cfg_.rc_target_bitrate, file_datarate_ * 0.85) - << " The datarate for the file exceeds the target by too much!"; - ASSERT_LE(cfg_.rc_target_bitrate, file_datarate_ * 1.15) - << " The datarate for the file is lower than the target by too much!"; - EXPECT_EQ(static_cast(0), GetMismatchFrames()); -} - -// Check basic rate targeting for 1 pass CBR SVC: 3 spatial layers and -// 3 temporal layers. Run CIF clip with 1 thread. -TEST_P(DatarateOnePassCbrSvc, OnePassCbrSvc3SpatialLayers) { - cfg_.rc_buf_initial_sz = 500; - cfg_.rc_buf_optimal_sz = 500; - cfg_.rc_buf_sz = 1000; - cfg_.rc_min_quantizer = 0; - cfg_.rc_max_quantizer = 63; - cfg_.rc_end_usage = VPX_CBR; - cfg_.g_lag_in_frames = 0; - cfg_.ss_number_layers = 3; - cfg_.ts_number_layers = 3; - cfg_.ts_rate_decimator[0] = 4; - cfg_.ts_rate_decimator[1] = 2; - cfg_.ts_rate_decimator[2] = 1; - cfg_.g_error_resilient = 1; - cfg_.g_threads = 1; - cfg_.temporal_layering_mode = 3; - svc_params_.scaling_factor_num[0] = 72; - svc_params_.scaling_factor_den[0] = 288; - svc_params_.scaling_factor_num[1] = 144; - svc_params_.scaling_factor_den[1] = 288; - svc_params_.scaling_factor_num[2] = 288; - svc_params_.scaling_factor_den[2] = 288; - cfg_.rc_dropframe_thresh = 10; - cfg_.kf_max_dist = 9999; - ::libvpx_test::I420VideoSource video("niklas_1280_720_30.y4m", 1280, 720, - 30, 1, 0, 300); - cfg_.rc_target_bitrate = 800; - ResetModel(); - assign_layer_bitrates(&cfg_, &svc_params_, cfg_.ss_number_layers, - cfg_.ts_number_layers, cfg_.temporal_layering_mode); - ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); - ASSERT_GE(cfg_.rc_target_bitrate, file_datarate_ * 0.85) - << " The datarate for the file exceeds the target by too much!"; - ASSERT_LE(cfg_.rc_target_bitrate, file_datarate_ * 1.22) - << " The datarate for the file is lower than the target by too much!"; - EXPECT_EQ(static_cast(0), GetMismatchFrames()); -} - -// Check basic rate targeting for 1 pass CBR SVC: 3 spatial layers and 3 -// temporal layers. Run CIF clip with 1 thread, and few short key frame periods. -TEST_P(DatarateOnePassCbrSvc, OnePassCbrSvc3SpatialLayersSmallKf) { - cfg_.rc_buf_initial_sz = 500; - cfg_.rc_buf_optimal_sz = 500; - cfg_.rc_buf_sz = 1000; - cfg_.rc_min_quantizer = 0; - cfg_.rc_max_quantizer = 63; - cfg_.rc_end_usage = VPX_CBR; - cfg_.g_lag_in_frames = 0; - cfg_.ss_number_layers = 3; - cfg_.ts_number_layers = 3; - cfg_.ts_rate_decimator[0] = 4; - cfg_.ts_rate_decimator[1] = 2; - cfg_.ts_rate_decimator[2] = 1; - cfg_.g_error_resilient = 1; - cfg_.g_threads = 1; - cfg_.temporal_layering_mode = 3; - svc_params_.scaling_factor_num[0] = 72; - svc_params_.scaling_factor_den[0] = 288; - svc_params_.scaling_factor_num[1] = 144; - svc_params_.scaling_factor_den[1] = 288; - svc_params_.scaling_factor_num[2] = 288; - svc_params_.scaling_factor_den[2] = 288; - cfg_.rc_dropframe_thresh = 10; - ::libvpx_test::I420VideoSource video("niklas_1280_720_30.y4m", 1280, 720, - 30, 1, 0, 300); - cfg_.rc_target_bitrate = 800; - // For this 3 temporal layer case, pattern repeats every 4 frames, so choose - // 4 key neighboring key frame periods (so key frame will land on 0-2-1-2). - for (int j = 32; j <= 35; j++) { - cfg_.kf_max_dist = j; - ResetModel(); - assign_layer_bitrates(&cfg_, &svc_params_, cfg_.ss_number_layers, - cfg_.ts_number_layers, cfg_.temporal_layering_mode); - ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); - ASSERT_GE(cfg_.rc_target_bitrate, file_datarate_ * 0.85) - << " The datarate for the file exceeds the target by too much!"; - ASSERT_LE(cfg_.rc_target_bitrate, file_datarate_ * 1.30) - << " The datarate for the file is lower than the target by too much!"; - EXPECT_EQ(static_cast(0), GetMismatchFrames()); - } -} - -// Check basic rate targeting for 1 pass CBR SVC: 3 spatial layers and -// 3 temporal layers. Run HD clip with 4 threads. -TEST_P(DatarateOnePassCbrSvc, OnePassCbrSvc3SpatialLayers4threads) { - cfg_.rc_buf_initial_sz = 500; - cfg_.rc_buf_optimal_sz = 500; - cfg_.rc_buf_sz = 1000; - cfg_.rc_min_quantizer = 0; - cfg_.rc_max_quantizer = 63; - cfg_.rc_end_usage = VPX_CBR; - cfg_.g_lag_in_frames = 0; - cfg_.ss_number_layers = 3; - cfg_.ts_number_layers = 3; - cfg_.ts_rate_decimator[0] = 4; - cfg_.ts_rate_decimator[1] = 2; - cfg_.ts_rate_decimator[2] = 1; - cfg_.g_error_resilient = 1; - cfg_.g_threads = 4; - cfg_.temporal_layering_mode = 3; - svc_params_.scaling_factor_num[0] = 72; - svc_params_.scaling_factor_den[0] = 288; - svc_params_.scaling_factor_num[1] = 144; - svc_params_.scaling_factor_den[1] = 288; - svc_params_.scaling_factor_num[2] = 288; - svc_params_.scaling_factor_den[2] = 288; - cfg_.rc_dropframe_thresh = 10; - cfg_.kf_max_dist = 9999; - ::libvpx_test::I420VideoSource video("niklas_1280_720_30.y4m", 1280, 720, - 30, 1, 0, 300); - cfg_.rc_target_bitrate = 800; - ResetModel(); - assign_layer_bitrates(&cfg_, &svc_params_, cfg_.ss_number_layers, - cfg_.ts_number_layers, cfg_.temporal_layering_mode); - ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); - ASSERT_GE(cfg_.rc_target_bitrate, file_datarate_ * 0.85) - << " The datarate for the file exceeds the target by too much!"; - ASSERT_LE(cfg_.rc_target_bitrate, file_datarate_ * 1.22) - << " The datarate for the file is lower than the target by too much!"; - EXPECT_EQ(static_cast(0), GetMismatchFrames()); -} - -/* VP10 does not support multiple layers yet. -VP10_INSTANTIATE_TEST_CASE(DatarateOnePassCbrSvc, - ::testing::Values(::libvpx_test::kRealTime), - ::testing::Range(5, 8)); - */ +VP10_INSTANTIATE_TEST_CASE(DatarateTestLarge, + ::testing::Values(::libvpx_test::kOnePassGood, + ::libvpx_test::kRealTime), + ::testing::Range(2, 9)); } // namespace diff --git a/test/encode_test_driver.h b/test/encode_test_driver.h index e444a9291..720ec84ff 100644 --- a/test/encode_test_driver.h +++ b/test/encode_test_driver.h @@ -134,15 +134,6 @@ class Encoder { ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError(); } - void Control(int ctrl_id, struct vpx_svc_layer_id *arg) { - const vpx_codec_err_t res = vpx_codec_control_(&encoder_, ctrl_id, arg); - ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError(); - } - - void Control(int ctrl_id, struct vpx_svc_parameters *arg) { - const vpx_codec_err_t res = vpx_codec_control_(&encoder_, ctrl_id, arg); - ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError(); - } #if CONFIG_VP10_ENCODER void Control(int ctrl_id, vpx_active_map_t *arg) { const vpx_codec_err_t res = vpx_codec_control_(&encoder_, ctrl_id, arg); diff --git a/test/error_resilience_test.cc b/test/error_resilience_test.cc index d6deb759c..99419ad6d 100644 --- a/test/error_resilience_test.cc +++ b/test/error_resilience_test.cc @@ -20,11 +20,10 @@ const int kMaxErrorFrames = 12; const int kMaxDroppableFrames = 12; class ErrorResilienceTestLarge : public ::libvpx_test::EncoderTest, - public ::libvpx_test::CodecTestWith2Params { + public ::libvpx_test::CodecTestWithParam { protected: ErrorResilienceTestLarge() : EncoderTest(GET_PARAM(0)), - svc_support_(GET_PARAM(2)), psnr_(0.0), nframes_(0), mismatch_psnr_(0.0), @@ -58,77 +57,23 @@ class ErrorResilienceTestLarge : public ::libvpx_test::EncoderTest, nframes_++; } - // - // Frame flags and layer id for temporal layers. - // For two layers, test pattern is: - // 1 3 - // 0 2 ..... - // LAST is updated on base/layer 0, GOLDEN updated on layer 1. - // Non-zero pattern_switch parameter means pattern will switch to - // not using LAST for frame_num >= pattern_switch. - int SetFrameFlags(int frame_num, - int num_temp_layers, - int pattern_switch) { - int frame_flags = 0; - if (num_temp_layers == 2) { - if (frame_num % 2 == 0) { - if (frame_num < pattern_switch || pattern_switch == 0) { - // Layer 0: predict from LAST and ARF, update LAST. - frame_flags = VP8_EFLAG_NO_REF_GF | - VP8_EFLAG_NO_UPD_GF | - VP8_EFLAG_NO_UPD_ARF; - } else { - // Layer 0: predict from GF and ARF, update GF. - frame_flags = VP8_EFLAG_NO_REF_LAST | - VP8_EFLAG_NO_UPD_LAST | - VP8_EFLAG_NO_UPD_ARF; - } - } else { - if (frame_num < pattern_switch || pattern_switch == 0) { - // Layer 1: predict from L, GF, and ARF, update GF. - frame_flags = VP8_EFLAG_NO_UPD_ARF | - VP8_EFLAG_NO_UPD_LAST; - } else { - // Layer 1: predict from GF and ARF, update GF. - frame_flags = VP8_EFLAG_NO_REF_LAST | - VP8_EFLAG_NO_UPD_LAST | - VP8_EFLAG_NO_UPD_ARF; - } - } - } - return frame_flags; - } - virtual void PreEncodeFrameHook(libvpx_test::VideoSource *video, ::libvpx_test::Encoder * /*encoder*/) { frame_flags_ &= ~(VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF); - // For temporal layer case. - if (cfg_.ts_number_layers > 1) { - frame_flags_ = SetFrameFlags(video->frame(), - cfg_.ts_number_layers, - pattern_switch_); + if (droppable_nframes_ > 0 && + (cfg_.g_pass == VPX_RC_LAST_PASS || cfg_.g_pass == VPX_RC_ONE_PASS)) { for (unsigned int i = 0; i < droppable_nframes_; ++i) { if (droppable_frames_[i] == video->frame()) { std::cout << "Encoding droppable frame: " << droppable_frames_[i] << "\n"; + frame_flags_ |= (VP8_EFLAG_NO_UPD_LAST | + VP8_EFLAG_NO_UPD_GF | + VP8_EFLAG_NO_UPD_ARF); + return; } } - } else { - if (droppable_nframes_ > 0 && - (cfg_.g_pass == VPX_RC_LAST_PASS || cfg_.g_pass == VPX_RC_ONE_PASS)) { - for (unsigned int i = 0; i < droppable_nframes_; ++i) { - if (droppable_frames_[i] == video->frame()) { - std::cout << "Encoding droppable frame: " - << droppable_frames_[i] << "\n"; - frame_flags_ |= (VP8_EFLAG_NO_UPD_LAST | - VP8_EFLAG_NO_UPD_GF | - VP8_EFLAG_NO_UPD_ARF); - return; - } - } - } } } @@ -195,8 +140,6 @@ class ErrorResilienceTestLarge : public ::libvpx_test::EncoderTest, pattern_switch_ = frame_switch; } - bool svc_support_; - private: double psnr_; unsigned int nframes_; @@ -301,297 +244,5 @@ TEST_P(ErrorResilienceTestLarge, DropFramesWithoutRecovery) { #endif } -// Check for successful decoding and no encoder/decoder mismatch -// if we lose (i.e., drop before decoding) the enhancement layer frames for a -// two layer temporal pattern. The base layer does not predict from the top -// layer, so successful decoding is expected. -TEST_P(ErrorResilienceTestLarge, 2LayersDropEnhancement) { - // This test doesn't run if SVC is not supported. - if (!svc_support_) - return; - - const vpx_rational timebase = { 33333333, 1000000000 }; - cfg_.g_timebase = timebase; - cfg_.rc_target_bitrate = 500; - cfg_.g_lag_in_frames = 0; - - cfg_.rc_end_usage = VPX_CBR; - // 2 Temporal layers, no spatial layers, CBR mode. - cfg_.ss_number_layers = 1; - cfg_.ts_number_layers = 2; - cfg_.ts_rate_decimator[0] = 2; - cfg_.ts_rate_decimator[1] = 1; - cfg_.ts_periodicity = 2; - cfg_.ts_target_bitrate[0] = 60 * cfg_.rc_target_bitrate / 100; - cfg_.ts_target_bitrate[1] = cfg_.rc_target_bitrate; - - init_flags_ = VPX_CODEC_USE_PSNR; - - libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288, - timebase.den, timebase.num, 0, 40); - - // Error resilient mode ON. - cfg_.g_error_resilient = 1; - cfg_.kf_mode = VPX_KF_DISABLED; - SetPatternSwitch(0); - - // The odd frames are the enhancement layer for 2 layer pattern, so set - // those frames as droppable. Drop the last 7 frames. - unsigned int num_droppable_frames = 7; - unsigned int droppable_frame_list[] = {27, 29, 31, 33, 35, 37, 39}; - SetDroppableFrames(num_droppable_frames, droppable_frame_list); - SetErrorFrames(num_droppable_frames, droppable_frame_list); - ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); - // Test that no mismatches have been found - std::cout << " Mismatch frames: " - << GetMismatchFrames() << "\n"; - EXPECT_EQ(GetMismatchFrames(), (unsigned int) 0); - - // Reset previously set of error/droppable frames. - Reset(); -} - -// Check for successful decoding and no encoder/decoder mismatch -// for a two layer temporal pattern, where at some point in the -// sequence, the LAST ref is not used anymore. -TEST_P(ErrorResilienceTestLarge, 2LayersNoRefLast) { - // This test doesn't run if SVC is not supported. - if (!svc_support_) - return; - - const vpx_rational timebase = { 33333333, 1000000000 }; - cfg_.g_timebase = timebase; - cfg_.rc_target_bitrate = 500; - cfg_.g_lag_in_frames = 0; - - cfg_.rc_end_usage = VPX_CBR; - // 2 Temporal layers, no spatial layers, CBR mode. - cfg_.ss_number_layers = 1; - cfg_.ts_number_layers = 2; - cfg_.ts_rate_decimator[0] = 2; - cfg_.ts_rate_decimator[1] = 1; - cfg_.ts_periodicity = 2; - cfg_.ts_target_bitrate[0] = 60 * cfg_.rc_target_bitrate / 100; - cfg_.ts_target_bitrate[1] = cfg_.rc_target_bitrate; - - init_flags_ = VPX_CODEC_USE_PSNR; - - libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288, - timebase.den, timebase.num, 0, 100); - - // Error resilient mode ON. - cfg_.g_error_resilient = 1; - cfg_.kf_mode = VPX_KF_DISABLED; - SetPatternSwitch(60); - - ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); - // Test that no mismatches have been found - std::cout << " Mismatch frames: " - << GetMismatchFrames() << "\n"; - EXPECT_EQ(GetMismatchFrames(), (unsigned int) 0); - - // Reset previously set of error/droppable frames. - Reset(); -} - -class ErrorResilienceTestLargeCodecControls : public ::libvpx_test::EncoderTest, - public ::libvpx_test::CodecTestWithParam { - protected: - ErrorResilienceTestLargeCodecControls() - : EncoderTest(GET_PARAM(0)), - encoding_mode_(GET_PARAM(1)) { - Reset(); - } - - virtual ~ErrorResilienceTestLargeCodecControls() {} - - void Reset() { - last_pts_ = 0; - tot_frame_number_ = 0; - // For testing up to 3 layers. - for (int i = 0; i < 3; ++i) { - bits_total_[i] = 0; - } - duration_ = 0.0; - } - - virtual void SetUp() { - InitializeConfig(); - SetMode(encoding_mode_); - } - - // - // Frame flags and layer id for temporal layers. - // - - // For two layers, test pattern is: - // 1 3 - // 0 2 ..... - // For three layers, test pattern is: - // 1 3 5 7 - // 2 6 - // 0 4 .... - // LAST is always update on base/layer 0, GOLDEN is updated on layer 1, - // and ALTREF is updated on top layer for 3 layer pattern. - int SetFrameFlags(int frame_num, int num_temp_layers) { - int frame_flags = 0; - if (num_temp_layers == 2) { - if (frame_num % 2 == 0) { - // Layer 0: predict from L and ARF, update L. - frame_flags = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_UPD_GF | - VP8_EFLAG_NO_UPD_ARF; - } else { - // Layer 1: predict from L, G and ARF, and update G. - frame_flags = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST | - VP8_EFLAG_NO_UPD_ENTROPY; - } - } else if (num_temp_layers == 3) { - if (frame_num % 4 == 0) { - // Layer 0: predict from L, update L. - frame_flags = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF | - VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF; - } else if ((frame_num - 2) % 4 == 0) { - // Layer 1: predict from L, G, update G. - frame_flags = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST | - VP8_EFLAG_NO_REF_ARF; - } else if ((frame_num - 1) % 2 == 0) { - // Layer 2: predict from L, G, ARF; update ARG. - frame_flags = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_LAST; - } - } - return frame_flags; - } - - int SetLayerId(int frame_num, int num_temp_layers) { - int layer_id = 0; - if (num_temp_layers == 2) { - if (frame_num % 2 == 0) { - layer_id = 0; - } else { - layer_id = 1; - } - } else if (num_temp_layers == 3) { - if (frame_num % 4 == 0) { - layer_id = 0; - } else if ((frame_num - 2) % 4 == 0) { - layer_id = 1; - } else if ((frame_num - 1) % 2 == 0) { - layer_id = 2; - } - } - return layer_id; - } - - virtual void PreEncodeFrameHook(libvpx_test::VideoSource *video, - libvpx_test::Encoder *encoder) { - if (cfg_.ts_number_layers > 1) { - int layer_id = SetLayerId(video->frame(), cfg_.ts_number_layers); - int frame_flags = SetFrameFlags(video->frame(), cfg_.ts_number_layers); - if (video->frame() > 0) { - encoder->Control(VP8E_SET_TEMPORAL_LAYER_ID, layer_id); - encoder->Control(VP8E_SET_FRAME_FLAGS, frame_flags); - } - const vpx_rational_t tb = video->timebase(); - timebase_ = static_cast(tb.num) / tb.den; - duration_ = 0; - return; - } - } - - virtual void FramePktHook(const vpx_codec_cx_pkt_t *pkt) { - // Time since last timestamp = duration. - vpx_codec_pts_t duration = pkt->data.frame.pts - last_pts_; - if (duration > 1) { - // Update counter for total number of frames (#frames input to encoder). - // Needed for setting the proper layer_id below. - tot_frame_number_ += static_cast(duration - 1); - } - int layer = SetLayerId(tot_frame_number_, cfg_.ts_number_layers); - const size_t frame_size_in_bits = pkt->data.frame.sz * 8; - // Update the total encoded bits. For temporal layers, update the cumulative - // encoded bits per layer. - for (int i = layer; i < static_cast(cfg_.ts_number_layers); ++i) { - bits_total_[i] += frame_size_in_bits; - } - // Update the most recent pts. - last_pts_ = pkt->data.frame.pts; - ++tot_frame_number_; - } - - virtual void EndPassHook(void) { - duration_ = (last_pts_ + 1) * timebase_; - if (cfg_.ts_number_layers > 1) { - for (int layer = 0; layer < static_cast(cfg_.ts_number_layers); - ++layer) { - if (bits_total_[layer]) { - // Effective file datarate: - effective_datarate_[layer] = (bits_total_[layer] / 1000.0) / duration_; - } - } - } - } - - double effective_datarate_[3]; - private: - libvpx_test::TestMode encoding_mode_; - vpx_codec_pts_t last_pts_; - double timebase_; - int64_t bits_total_[3]; - double duration_; - int tot_frame_number_; - }; - -// Check two codec controls used for: -// (1) for setting temporal layer id, and (2) for settings encoder flags. -// This test invokes those controls for each frame, and verifies encoder/decoder -// mismatch and basic rate control response. -// TODO(marpan): Maybe move this test to datarate_test.cc. -TEST_P(ErrorResilienceTestLargeCodecControls, CodecControl3TemporalLayers) { - cfg_.rc_buf_initial_sz = 500; - cfg_.rc_buf_optimal_sz = 500; - cfg_.rc_buf_sz = 1000; - cfg_.rc_dropframe_thresh = 1; - cfg_.rc_min_quantizer = 2; - cfg_.rc_max_quantizer = 56; - cfg_.rc_end_usage = VPX_CBR; - cfg_.rc_dropframe_thresh = 1; - cfg_.g_lag_in_frames = 0; - cfg_.kf_mode = VPX_KF_DISABLED; - cfg_.g_error_resilient = 1; - - // 3 Temporal layers. Framerate decimation (4, 2, 1). - cfg_.ts_number_layers = 3; - cfg_.ts_rate_decimator[0] = 4; - cfg_.ts_rate_decimator[1] = 2; - cfg_.ts_rate_decimator[2] = 1; - cfg_.ts_periodicity = 4; - cfg_.ts_layer_id[0] = 0; - cfg_.ts_layer_id[1] = 2; - cfg_.ts_layer_id[2] = 1; - cfg_.ts_layer_id[3] = 2; - - ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288, - 30, 1, 0, 200); - for (int i = 200; i <= 800; i += 200) { - cfg_.rc_target_bitrate = i; - Reset(); - // 40-20-40 bitrate allocation for 3 temporal layers. - cfg_.ts_target_bitrate[0] = 40 * cfg_.rc_target_bitrate / 100; - cfg_.ts_target_bitrate[1] = 60 * cfg_.rc_target_bitrate / 100; - cfg_.ts_target_bitrate[2] = cfg_.rc_target_bitrate; - ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); - for (int j = 0; j < static_cast(cfg_.ts_number_layers); ++j) { - ASSERT_GE(effective_datarate_[j], cfg_.ts_target_bitrate[j] * 0.75) - << " The datarate for the file is lower than target by too much, " - "for layer: " << j; - ASSERT_LE(effective_datarate_[j], cfg_.ts_target_bitrate[j] * 1.25) - << " The datarate for the file is greater than target by too much, " - "for layer: " << j; - } - } -} - -// SVC-related tests don't run for VP10 since SVC is not supported. -VP10_INSTANTIATE_TEST_CASE(ErrorResilienceTestLarge, ONE_PASS_TEST_MODES, - ::testing::Values(false)); +VP10_INSTANTIATE_TEST_CASE(ErrorResilienceTestLarge, ONE_PASS_TEST_MODES); } // namespace diff --git a/test/spatial_svc_encoder.sh b/test/spatial_svc_encoder.sh deleted file mode 100644 index 65031073f..000000000 --- a/test/spatial_svc_encoder.sh +++ /dev/null @@ -1,72 +0,0 @@ -#!/bin/sh -## -## Copyright (c) 2014 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 file tests the libvpx vp9_spatial_svc_encoder example. To add new -## tests to to this file, do the following: -## 1. Write a shell function (this is your test). -## 2. Add the function to vp9_spatial_svc_tests (on a new line). -## -. $(dirname $0)/tools_common.sh - -# Environment check: $YUV_RAW_INPUT is required. -vp9_spatial_svc_encoder_verify_environment() { - if [ ! -e "${YUV_RAW_INPUT}" ]; then - echo "Libvpx test data must exist in LIBVPX_TEST_DATA_PATH." - return 1 - fi -} - -# Runs vp9_spatial_svc_encoder. $1 is the test name. -vp9_spatial_svc_encoder() { - local readonly \ - encoder="${LIBVPX_BIN_PATH}/vp9_spatial_svc_encoder${VPX_TEST_EXE_SUFFIX}" - local readonly test_name="$1" - local readonly \ - output_file="${VPX_TEST_OUTPUT_DIR}/vp9_ssvc_encoder${test_name}.ivf" - local readonly frames_to_encode=10 - local readonly max_kf=9999 - - shift - - if [ ! -x "${encoder}" ]; then - elog "${encoder} does not exist or is not executable." - return 1 - fi - - eval "${VPX_TEST_PREFIX}" "${encoder}" -w "${YUV_RAW_INPUT_WIDTH}" \ - -h "${YUV_RAW_INPUT_HEIGHT}" -k "${max_kf}" -f "${frames_to_encode}" \ - "$@" "${YUV_RAW_INPUT}" "${output_file}" ${devnull} - - [ -e "${output_file}" ] || return 1 -} - -# Each test is run with layer count 1-$vp9_ssvc_test_layers. -vp9_ssvc_test_layers=5 - -vp9_spatial_svc() { - if [ "$(vp9_encode_available)" = "yes" ]; then - local readonly test_name="vp9_spatial_svc" - for layers in $(seq 1 ${vp9_ssvc_test_layers}); do - vp9_spatial_svc_encoder "${test_name}" -sl ${layers} - done - fi -} - -readonly vp9_spatial_svc_tests="DISABLED_vp9_spatial_svc_mode_i - DISABLED_vp9_spatial_svc_mode_altip - DISABLED_vp9_spatial_svc_mode_ip - DISABLED_vp9_spatial_svc_mode_gf - vp9_spatial_svc" - -if [ "$(vpx_config_option_enabled CONFIG_SPATIAL_SVC)" = "yes" ]; then - run_tests \ - vp9_spatial_svc_encoder_verify_environment \ - "${vp9_spatial_svc_tests}" -fi diff --git a/test/svc_test.cc b/test/svc_test.cc deleted file mode 100644 index 1ad17be86..000000000 --- a/test/svc_test.cc +++ /dev/null @@ -1,803 +0,0 @@ -/* - * Copyright (c) 2013 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. - */ - -#include -#include "third_party/googletest/src/include/gtest/gtest.h" -#include "test/codec_factory.h" -#include "test/decode_test_driver.h" -#include "test/i420_video_source.h" - -#include "vp9/decoder/vp9_decoder.h" - -#include "vpx/svc_context.h" -#include "vpx/vp8cx.h" -#include "vpx/vpx_encoder.h" - -namespace { - -using libvpx_test::CodecFactory; -using libvpx_test::Decoder; -using libvpx_test::DxDataIterator; -using libvpx_test::VP9CodecFactory; - -class SvcTest : public ::testing::Test { - protected: - static const uint32_t kWidth = 352; - static const uint32_t kHeight = 288; - - SvcTest() - : codec_iface_(0), - test_file_name_("hantro_collage_w352h288.yuv"), - codec_initialized_(false), - decoder_(0) { - memset(&svc_, 0, sizeof(svc_)); - memset(&codec_, 0, sizeof(codec_)); - memset(&codec_enc_, 0, sizeof(codec_enc_)); - } - - virtual ~SvcTest() {} - - virtual void SetUp() { - svc_.log_level = SVC_LOG_DEBUG; - svc_.log_print = 0; - - codec_iface_ = vpx_codec_vp9_cx(); - const vpx_codec_err_t res = - vpx_codec_enc_config_default(codec_iface_, &codec_enc_, 0); - EXPECT_EQ(VPX_CODEC_OK, res); - - codec_enc_.g_w = kWidth; - codec_enc_.g_h = kHeight; - codec_enc_.g_timebase.num = 1; - codec_enc_.g_timebase.den = 60; - codec_enc_.kf_min_dist = 100; - codec_enc_.kf_max_dist = 100; - - vpx_codec_dec_cfg_t dec_cfg = vpx_codec_dec_cfg_t(); - VP9CodecFactory codec_factory; - decoder_ = codec_factory.CreateDecoder(dec_cfg, 0); -#if CONFIG_VP10 && CONFIG_EXT_TILE - if (decoder_->IsVP10()) { - decoder_->Control(VP10_SET_DECODE_TILE_ROW, -1); - decoder_->Control(VP10_SET_DECODE_TILE_COL, -1); - } -#endif - - tile_columns_ = 0; - tile_rows_ = 0; - } - - virtual void TearDown() { - ReleaseEncoder(); - delete(decoder_); - } - - void InitializeEncoder() { - const vpx_codec_err_t res = - vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_); - EXPECT_EQ(VPX_CODEC_OK, res); - vpx_codec_control(&codec_, VP8E_SET_CPUUSED, 4); // Make the test faster - vpx_codec_control(&codec_, VP9E_SET_TILE_COLUMNS, tile_columns_); - vpx_codec_control(&codec_, VP9E_SET_TILE_ROWS, tile_rows_); - codec_initialized_ = true; - } - - void ReleaseEncoder() { - vpx_svc_release(&svc_); - if (codec_initialized_) vpx_codec_destroy(&codec_); - codec_initialized_ = false; - } - - void GetStatsData(std::string *const stats_buf) { - vpx_codec_iter_t iter = NULL; - const vpx_codec_cx_pkt_t *cx_pkt; - - while ((cx_pkt = vpx_codec_get_cx_data(&codec_, &iter)) != NULL) { - if (cx_pkt->kind == VPX_CODEC_STATS_PKT) { - EXPECT_GT(cx_pkt->data.twopass_stats.sz, 0U); - ASSERT_TRUE(cx_pkt->data.twopass_stats.buf != NULL); - stats_buf->append(static_cast(cx_pkt->data.twopass_stats.buf), - cx_pkt->data.twopass_stats.sz); - } - } - } - - void Pass1EncodeNFrames(const int n, const int layers, - std::string *const stats_buf) { - vpx_codec_err_t res; - - ASSERT_GT(n, 0); - ASSERT_GT(layers, 0); - svc_.spatial_layers = layers; - codec_enc_.g_pass = VPX_RC_FIRST_PASS; - InitializeEncoder(); - - libvpx_test::I420VideoSource video(test_file_name_, - codec_enc_.g_w, codec_enc_.g_h, - codec_enc_.g_timebase.den, - codec_enc_.g_timebase.num, 0, 30); - video.Begin(); - - for (int i = 0; i < n; ++i) { - res = vpx_svc_encode(&svc_, &codec_, video.img(), video.pts(), - video.duration(), VPX_DL_GOOD_QUALITY); - ASSERT_EQ(VPX_CODEC_OK, res); - GetStatsData(stats_buf); - video.Next(); - } - - // Flush encoder and test EOS packet. - res = vpx_svc_encode(&svc_, &codec_, NULL, video.pts(), - video.duration(), VPX_DL_GOOD_QUALITY); - ASSERT_EQ(VPX_CODEC_OK, res); - GetStatsData(stats_buf); - - ReleaseEncoder(); - } - - void StoreFrames(const size_t max_frame_received, - struct vpx_fixed_buf *const outputs, - size_t *const frame_received) { - vpx_codec_iter_t iter = NULL; - const vpx_codec_cx_pkt_t *cx_pkt; - - while ((cx_pkt = vpx_codec_get_cx_data(&codec_, &iter)) != NULL) { - if (cx_pkt->kind == VPX_CODEC_CX_FRAME_PKT) { - const size_t frame_size = cx_pkt->data.frame.sz; - - EXPECT_GT(frame_size, 0U); - ASSERT_TRUE(cx_pkt->data.frame.buf != NULL); - ASSERT_LT(*frame_received, max_frame_received); - - if (*frame_received == 0) - EXPECT_EQ(1, !!(cx_pkt->data.frame.flags & VPX_FRAME_IS_KEY)); - - outputs[*frame_received].buf = malloc(frame_size + 16); - ASSERT_TRUE(outputs[*frame_received].buf != NULL); - memcpy(outputs[*frame_received].buf, cx_pkt->data.frame.buf, - frame_size); - outputs[*frame_received].sz = frame_size; - ++(*frame_received); - } - } - } - - void Pass2EncodeNFrames(std::string *const stats_buf, - const int n, const int layers, - struct vpx_fixed_buf *const outputs) { - vpx_codec_err_t res; - size_t frame_received = 0; - - ASSERT_TRUE(outputs != NULL); - ASSERT_GT(n, 0); - ASSERT_GT(layers, 0); - svc_.spatial_layers = layers; - codec_enc_.rc_target_bitrate = 500; - if (codec_enc_.g_pass == VPX_RC_LAST_PASS) { - ASSERT_TRUE(stats_buf != NULL); - ASSERT_GT(stats_buf->size(), 0U); - codec_enc_.rc_twopass_stats_in.buf = &(*stats_buf)[0]; - codec_enc_.rc_twopass_stats_in.sz = stats_buf->size(); - } - InitializeEncoder(); - - libvpx_test::I420VideoSource video(test_file_name_, - codec_enc_.g_w, codec_enc_.g_h, - codec_enc_.g_timebase.den, - codec_enc_.g_timebase.num, 0, 30); - video.Begin(); - - for (int i = 0; i < n; ++i) { - res = vpx_svc_encode(&svc_, &codec_, video.img(), video.pts(), - video.duration(), VPX_DL_GOOD_QUALITY); - ASSERT_EQ(VPX_CODEC_OK, res); - StoreFrames(n, outputs, &frame_received); - video.Next(); - } - - // Flush encoder. - res = vpx_svc_encode(&svc_, &codec_, NULL, 0, - video.duration(), VPX_DL_GOOD_QUALITY); - EXPECT_EQ(VPX_CODEC_OK, res); - StoreFrames(n, outputs, &frame_received); - - EXPECT_EQ(frame_received, static_cast(n)); - - ReleaseEncoder(); - } - - void DecodeNFrames(const struct vpx_fixed_buf *const inputs, const int n) { - int decoded_frames = 0; - int received_frames = 0; - - ASSERT_TRUE(inputs != NULL); - ASSERT_GT(n, 0); - - for (int i = 0; i < n; ++i) { - ASSERT_TRUE(inputs[i].buf != NULL); - ASSERT_GT(inputs[i].sz, 0U); - const vpx_codec_err_t res_dec = - decoder_->DecodeFrame(static_cast(inputs[i].buf), - inputs[i].sz); - ASSERT_EQ(VPX_CODEC_OK, res_dec) << decoder_->DecodeError(); - ++decoded_frames; - - DxDataIterator dec_iter = decoder_->GetDxData(); - while (dec_iter.Next() != NULL) { - ++received_frames; - } - } - EXPECT_EQ(decoded_frames, n); - EXPECT_EQ(received_frames, n); - } - - void DropEnhancementLayers(struct vpx_fixed_buf *const inputs, - const int num_super_frames, - const int remained_spatial_layers) { - ASSERT_TRUE(inputs != NULL); - ASSERT_GT(num_super_frames, 0); - ASSERT_GT(remained_spatial_layers, 0); - - for (int i = 0; i < num_super_frames; ++i) { - uint32_t frame_sizes[8] = {0}; - int frame_count = 0; - int frames_found = 0; - int frame; - ASSERT_TRUE(inputs[i].buf != NULL); - ASSERT_GT(inputs[i].sz, 0U); - - vpx_codec_err_t res = - vp9_parse_superframe_index(static_cast(inputs[i].buf), - inputs[i].sz, frame_sizes, &frame_count, - NULL, NULL); - ASSERT_EQ(VPX_CODEC_OK, res); - - if (frame_count == 0) { - // There's no super frame but only a single frame. - ASSERT_EQ(1, remained_spatial_layers); - } else { - // Found a super frame. - uint8_t *frame_data = static_cast(inputs[i].buf); - uint8_t *frame_start = frame_data; - for (frame = 0; frame < frame_count; ++frame) { - // Looking for a visible frame. - if (frame_data[0] & 0x02) { - ++frames_found; - if (frames_found == remained_spatial_layers) - break; - } - frame_data += frame_sizes[frame]; - } - ASSERT_LT(frame, frame_count) << "Couldn't find a visible frame. " - << "remained_spatial_layers: " << remained_spatial_layers - << " super_frame: " << i; - if (frame == frame_count - 1) - continue; - - frame_data += frame_sizes[frame]; - - // We need to add one more frame for multiple frame contexts. - uint8_t marker = - static_cast(inputs[i].buf)[inputs[i].sz - 1]; - const uint32_t mag = ((marker >> 3) & 0x3) + 1; - const size_t index_sz = 2 + mag * frame_count; - const size_t new_index_sz = 2 + mag * (frame + 1); - marker &= 0x0f8; - marker |= frame; - - // Copy existing frame sizes. - memmove(frame_data + 1, frame_start + inputs[i].sz - index_sz + 1, - new_index_sz - 2); - // New marker. - frame_data[0] = marker; - frame_data += (mag * (frame + 1) + 1); - - *frame_data++ = marker; - inputs[i].sz = frame_data - frame_start; - } - } - } - - void FreeBitstreamBuffers(struct vpx_fixed_buf *const inputs, const int n) { - ASSERT_TRUE(inputs != NULL); - ASSERT_GT(n, 0); - - for (int i = 0; i < n; ++i) { - free(inputs[i].buf); - inputs[i].buf = NULL; - inputs[i].sz = 0; - } - } - - SvcContext svc_; - vpx_codec_ctx_t codec_; - struct vpx_codec_enc_cfg codec_enc_; - vpx_codec_iface_t *codec_iface_; - std::string test_file_name_; - bool codec_initialized_; - Decoder *decoder_; - int tile_columns_; - int tile_rows_; -}; - -TEST_F(SvcTest, SvcInit) { - // test missing parameters - vpx_codec_err_t res = vpx_svc_init(NULL, &codec_, codec_iface_, &codec_enc_); - EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res); - res = vpx_svc_init(&svc_, NULL, codec_iface_, &codec_enc_); - EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res); - res = vpx_svc_init(&svc_, &codec_, NULL, &codec_enc_); - EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res); - - res = vpx_svc_init(&svc_, &codec_, codec_iface_, NULL); - EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res); - - svc_.spatial_layers = 6; // too many layers - res = vpx_svc_init(&svc_, &codec_, codec_iface_, &codec_enc_); - EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res); - - svc_.spatial_layers = 0; // use default layers - InitializeEncoder(); - EXPECT_EQ(VPX_SS_DEFAULT_LAYERS, svc_.spatial_layers); -} - -TEST_F(SvcTest, InitTwoLayers) { - svc_.spatial_layers = 2; - InitializeEncoder(); -} - -TEST_F(SvcTest, InvalidOptions) { - vpx_codec_err_t res = vpx_svc_set_options(&svc_, NULL); - EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res); - - res = vpx_svc_set_options(&svc_, "not-an-option=1"); - EXPECT_EQ(VPX_CODEC_OK, res); - res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_); - EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res); -} - -TEST_F(SvcTest, SetLayersOption) { - vpx_codec_err_t res = vpx_svc_set_options(&svc_, "spatial-layers=3"); - EXPECT_EQ(VPX_CODEC_OK, res); - InitializeEncoder(); - EXPECT_EQ(3, svc_.spatial_layers); -} - -TEST_F(SvcTest, SetMultipleOptions) { - vpx_codec_err_t res = - vpx_svc_set_options(&svc_, "spatial-layers=2 scale-factors=1/3,2/3"); - EXPECT_EQ(VPX_CODEC_OK, res); - InitializeEncoder(); - EXPECT_EQ(2, svc_.spatial_layers); -} - -TEST_F(SvcTest, SetScaleFactorsOption) { - svc_.spatial_layers = 2; - vpx_codec_err_t res = - vpx_svc_set_options(&svc_, "scale-factors=not-scale-factors"); - EXPECT_EQ(VPX_CODEC_OK, res); - res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_); - EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res); - - res = vpx_svc_set_options(&svc_, "scale-factors=1/3, 3*3"); - EXPECT_EQ(VPX_CODEC_OK, res); - res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_); - EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res); - - res = vpx_svc_set_options(&svc_, "scale-factors=1/3"); - EXPECT_EQ(VPX_CODEC_OK, res); - res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_); - EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res); - - res = vpx_svc_set_options(&svc_, "scale-factors=1/3,2/3"); - EXPECT_EQ(VPX_CODEC_OK, res); - InitializeEncoder(); -} - -TEST_F(SvcTest, SetQuantizersOption) { - svc_.spatial_layers = 2; - vpx_codec_err_t res = vpx_svc_set_options(&svc_, "max-quantizers=nothing"); - EXPECT_EQ(VPX_CODEC_OK, res); - res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_); - EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res); - - res = vpx_svc_set_options(&svc_, "min-quantizers=nothing"); - EXPECT_EQ(VPX_CODEC_OK, res); - res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_); - EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res); - - res = vpx_svc_set_options(&svc_, "max-quantizers=40"); - EXPECT_EQ(VPX_CODEC_OK, res); - res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_); - EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res); - - res = vpx_svc_set_options(&svc_, "min-quantizers=40"); - EXPECT_EQ(VPX_CODEC_OK, res); - res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_); - EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res); - - res = vpx_svc_set_options(&svc_, "max-quantizers=30,30 min-quantizers=40,40"); - EXPECT_EQ(VPX_CODEC_OK, res); - res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_); - EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res); - - res = vpx_svc_set_options(&svc_, "max-quantizers=40,40 min-quantizers=30,30"); - InitializeEncoder(); -} - -TEST_F(SvcTest, SetAutoAltRefOption) { - svc_.spatial_layers = 5; - vpx_codec_err_t res = vpx_svc_set_options(&svc_, "auto-alt-refs=none"); - EXPECT_EQ(VPX_CODEC_OK, res); - res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_); - EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res); - - res = vpx_svc_set_options(&svc_, "auto-alt-refs=1,1,1,1,0"); - EXPECT_EQ(VPX_CODEC_OK, res); - res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_); - EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res); - - vpx_svc_set_options(&svc_, "auto-alt-refs=0,1,1,1,0"); - InitializeEncoder(); -} - -// Test that decoder can handle an SVC frame as the first frame in a sequence. -TEST_F(SvcTest, OnePassEncodeOneFrame) { - codec_enc_.g_pass = VPX_RC_ONE_PASS; - vpx_fixed_buf output = {0}; - Pass2EncodeNFrames(NULL, 1, 2, &output); - DecodeNFrames(&output, 1); - FreeBitstreamBuffers(&output, 1); -} - -TEST_F(SvcTest, OnePassEncodeThreeFrames) { - codec_enc_.g_pass = VPX_RC_ONE_PASS; - codec_enc_.g_lag_in_frames = 0; - vpx_fixed_buf outputs[3]; - memset(&outputs[0], 0, sizeof(outputs)); - Pass2EncodeNFrames(NULL, 3, 2, &outputs[0]); - DecodeNFrames(&outputs[0], 3); - FreeBitstreamBuffers(&outputs[0], 3); -} - -TEST_F(SvcTest, TwoPassEncode10Frames) { - // First pass encode - std::string stats_buf; - Pass1EncodeNFrames(10, 2, &stats_buf); - - // Second pass encode - codec_enc_.g_pass = VPX_RC_LAST_PASS; - vpx_fixed_buf outputs[10]; - memset(&outputs[0], 0, sizeof(outputs)); - Pass2EncodeNFrames(&stats_buf, 10, 2, &outputs[0]); - DecodeNFrames(&outputs[0], 10); - FreeBitstreamBuffers(&outputs[0], 10); -} - -TEST_F(SvcTest, TwoPassEncode20FramesWithAltRef) { - // First pass encode - std::string stats_buf; - Pass1EncodeNFrames(20, 2, &stats_buf); - - // Second pass encode - codec_enc_.g_pass = VPX_RC_LAST_PASS; - vpx_svc_set_options(&svc_, "auto-alt-refs=1,1"); - vpx_fixed_buf outputs[20]; - memset(&outputs[0], 0, sizeof(outputs)); - Pass2EncodeNFrames(&stats_buf, 20, 2, &outputs[0]); - DecodeNFrames(&outputs[0], 20); - FreeBitstreamBuffers(&outputs[0], 20); -} - -TEST_F(SvcTest, TwoPassEncode2SpatialLayersDecodeBaseLayerOnly) { - // First pass encode - std::string stats_buf; - Pass1EncodeNFrames(10, 2, &stats_buf); - - // Second pass encode - codec_enc_.g_pass = VPX_RC_LAST_PASS; - vpx_svc_set_options(&svc_, "auto-alt-refs=1,1"); - vpx_fixed_buf outputs[10]; - memset(&outputs[0], 0, sizeof(outputs)); - Pass2EncodeNFrames(&stats_buf, 10, 2, &outputs[0]); - DropEnhancementLayers(&outputs[0], 10, 1); - DecodeNFrames(&outputs[0], 10); - FreeBitstreamBuffers(&outputs[0], 10); -} - -TEST_F(SvcTest, TwoPassEncode5SpatialLayersDecode54321Layers) { - // First pass encode - std::string stats_buf; - Pass1EncodeNFrames(10, 5, &stats_buf); - - // Second pass encode - codec_enc_.g_pass = VPX_RC_LAST_PASS; - vpx_svc_set_options(&svc_, "auto-alt-refs=0,1,1,1,0"); - vpx_fixed_buf outputs[10]; - memset(&outputs[0], 0, sizeof(outputs)); - Pass2EncodeNFrames(&stats_buf, 10, 5, &outputs[0]); - - DecodeNFrames(&outputs[0], 10); - DropEnhancementLayers(&outputs[0], 10, 4); - DecodeNFrames(&outputs[0], 10); - DropEnhancementLayers(&outputs[0], 10, 3); - DecodeNFrames(&outputs[0], 10); - DropEnhancementLayers(&outputs[0], 10, 2); - DecodeNFrames(&outputs[0], 10); - DropEnhancementLayers(&outputs[0], 10, 1); - DecodeNFrames(&outputs[0], 10); - - FreeBitstreamBuffers(&outputs[0], 10); -} - -TEST_F(SvcTest, TwoPassEncode2SNRLayers) { - // First pass encode - std::string stats_buf; - vpx_svc_set_options(&svc_, "scale-factors=1/1,1/1"); - Pass1EncodeNFrames(20, 2, &stats_buf); - - // Second pass encode - codec_enc_.g_pass = VPX_RC_LAST_PASS; - vpx_svc_set_options(&svc_, - "auto-alt-refs=1,1 scale-factors=1/1,1/1"); - vpx_fixed_buf outputs[20]; - memset(&outputs[0], 0, sizeof(outputs)); - Pass2EncodeNFrames(&stats_buf, 20, 2, &outputs[0]); - DecodeNFrames(&outputs[0], 20); - FreeBitstreamBuffers(&outputs[0], 20); -} - -TEST_F(SvcTest, TwoPassEncode3SNRLayersDecode321Layers) { - // First pass encode - std::string stats_buf; - vpx_svc_set_options(&svc_, "scale-factors=1/1,1/1,1/1"); - Pass1EncodeNFrames(20, 3, &stats_buf); - - // Second pass encode - codec_enc_.g_pass = VPX_RC_LAST_PASS; - vpx_svc_set_options(&svc_, - "auto-alt-refs=1,1,1 scale-factors=1/1,1/1,1/1"); - vpx_fixed_buf outputs[20]; - memset(&outputs[0], 0, sizeof(outputs)); - Pass2EncodeNFrames(&stats_buf, 20, 3, &outputs[0]); - DecodeNFrames(&outputs[0], 20); - DropEnhancementLayers(&outputs[0], 20, 2); - DecodeNFrames(&outputs[0], 20); - DropEnhancementLayers(&outputs[0], 20, 1); - DecodeNFrames(&outputs[0], 20); - - FreeBitstreamBuffers(&outputs[0], 20); -} - -TEST_F(SvcTest, SetMultipleFrameContextsOption) { - svc_.spatial_layers = 5; - vpx_codec_err_t res = - vpx_svc_set_options(&svc_, "multi-frame-contexts=1"); - EXPECT_EQ(VPX_CODEC_OK, res); - res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_); - EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res); - - svc_.spatial_layers = 2; - res = vpx_svc_set_options(&svc_, "multi-frame-contexts=1"); - InitializeEncoder(); -} - -TEST_F(SvcTest, TwoPassEncode2SpatialLayersWithMultipleFrameContexts) { - // First pass encode - std::string stats_buf; - Pass1EncodeNFrames(10, 2, &stats_buf); - - // Second pass encode - codec_enc_.g_pass = VPX_RC_LAST_PASS; - codec_enc_.g_error_resilient = 0; - vpx_svc_set_options(&svc_, "auto-alt-refs=1,1 multi-frame-contexts=1"); - vpx_fixed_buf outputs[10]; - memset(&outputs[0], 0, sizeof(outputs)); - Pass2EncodeNFrames(&stats_buf, 10, 2, &outputs[0]); - DecodeNFrames(&outputs[0], 10); - FreeBitstreamBuffers(&outputs[0], 10); -} - -TEST_F(SvcTest, - TwoPassEncode2SpatialLayersWithMultipleFrameContextsDecodeBaselayer) { - // First pass encode - std::string stats_buf; - Pass1EncodeNFrames(10, 2, &stats_buf); - - // Second pass encode - codec_enc_.g_pass = VPX_RC_LAST_PASS; - codec_enc_.g_error_resilient = 0; - vpx_svc_set_options(&svc_, "auto-alt-refs=1,1 multi-frame-contexts=1"); - vpx_fixed_buf outputs[10]; - memset(&outputs[0], 0, sizeof(outputs)); - Pass2EncodeNFrames(&stats_buf, 10, 2, &outputs[0]); - DropEnhancementLayers(&outputs[0], 10, 1); - DecodeNFrames(&outputs[0], 10); - FreeBitstreamBuffers(&outputs[0], 10); -} - -TEST_F(SvcTest, TwoPassEncode2SNRLayersWithMultipleFrameContexts) { - // First pass encode - std::string stats_buf; - vpx_svc_set_options(&svc_, "scale-factors=1/1,1/1"); - Pass1EncodeNFrames(10, 2, &stats_buf); - - // Second pass encode - codec_enc_.g_pass = VPX_RC_LAST_PASS; - codec_enc_.g_error_resilient = 0; - vpx_svc_set_options(&svc_, "auto-alt-refs=1,1 scale-factors=1/1,1/1 " - "multi-frame-contexts=1"); - vpx_fixed_buf outputs[10]; - memset(&outputs[0], 0, sizeof(outputs)); - Pass2EncodeNFrames(&stats_buf, 10, 2, &outputs[0]); - DecodeNFrames(&outputs[0], 10); - FreeBitstreamBuffers(&outputs[0], 10); -} - -TEST_F(SvcTest, - TwoPassEncode3SNRLayersWithMultipleFrameContextsDecode321Layer) { - // First pass encode - std::string stats_buf; - vpx_svc_set_options(&svc_, "scale-factors=1/1,1/1,1/1"); - Pass1EncodeNFrames(10, 3, &stats_buf); - - // Second pass encode - codec_enc_.g_pass = VPX_RC_LAST_PASS; - codec_enc_.g_error_resilient = 0; - vpx_svc_set_options(&svc_, "auto-alt-refs=1,1,1 scale-factors=1/1,1/1,1/1 " - "multi-frame-contexts=1"); - vpx_fixed_buf outputs[10]; - memset(&outputs[0], 0, sizeof(outputs)); - Pass2EncodeNFrames(&stats_buf, 10, 3, &outputs[0]); - - DecodeNFrames(&outputs[0], 10); - DropEnhancementLayers(&outputs[0], 10, 2); - DecodeNFrames(&outputs[0], 10); - DropEnhancementLayers(&outputs[0], 10, 1); - DecodeNFrames(&outputs[0], 10); - - FreeBitstreamBuffers(&outputs[0], 10); -} - -TEST_F(SvcTest, TwoPassEncode2TemporalLayers) { - // First pass encode - std::string stats_buf; - vpx_svc_set_options(&svc_, "scale-factors=1/1"); - svc_.temporal_layers = 2; - Pass1EncodeNFrames(10, 1, &stats_buf); - - // Second pass encode - codec_enc_.g_pass = VPX_RC_LAST_PASS; - svc_.temporal_layers = 2; - vpx_svc_set_options(&svc_, "auto-alt-refs=1 scale-factors=1/1"); - vpx_fixed_buf outputs[10]; - memset(&outputs[0], 0, sizeof(outputs)); - Pass2EncodeNFrames(&stats_buf, 10, 1, &outputs[0]); - DecodeNFrames(&outputs[0], 10); - FreeBitstreamBuffers(&outputs[0], 10); -} - -TEST_F(SvcTest, TwoPassEncode2TemporalLayersWithMultipleFrameContexts) { - // First pass encode - std::string stats_buf; - vpx_svc_set_options(&svc_, "scale-factors=1/1"); - svc_.temporal_layers = 2; - Pass1EncodeNFrames(10, 1, &stats_buf); - - // Second pass encode - codec_enc_.g_pass = VPX_RC_LAST_PASS; - svc_.temporal_layers = 2; - codec_enc_.g_error_resilient = 0; - vpx_svc_set_options(&svc_, "auto-alt-refs=1 scale-factors=1/1 " - "multi-frame-contexts=1"); - vpx_fixed_buf outputs[10]; - memset(&outputs[0], 0, sizeof(outputs)); - Pass2EncodeNFrames(&stats_buf, 10, 1, &outputs[0]); - DecodeNFrames(&outputs[0], 10); - FreeBitstreamBuffers(&outputs[0], 10); -} - -TEST_F(SvcTest, TwoPassEncode2TemporalLayersDecodeBaseLayer) { - // First pass encode - std::string stats_buf; - vpx_svc_set_options(&svc_, "scale-factors=1/1"); - svc_.temporal_layers = 2; - Pass1EncodeNFrames(10, 1, &stats_buf); - - // Second pass encode - codec_enc_.g_pass = VPX_RC_LAST_PASS; - svc_.temporal_layers = 2; - vpx_svc_set_options(&svc_, "auto-alt-refs=1 scale-factors=1/1"); - vpx_fixed_buf outputs[10]; - memset(&outputs[0], 0, sizeof(outputs)); - Pass2EncodeNFrames(&stats_buf, 10, 1, &outputs[0]); - - vpx_fixed_buf base_layer[5]; - for (int i = 0; i < 5; ++i) - base_layer[i] = outputs[i * 2]; - - DecodeNFrames(&base_layer[0], 5); - FreeBitstreamBuffers(&outputs[0], 10); -} - -TEST_F(SvcTest, - TwoPassEncode2TemporalLayersWithMultipleFrameContextsDecodeBaseLayer) { - // First pass encode - std::string stats_buf; - vpx_svc_set_options(&svc_, "scale-factors=1/1"); - svc_.temporal_layers = 2; - Pass1EncodeNFrames(10, 1, &stats_buf); - - // Second pass encode - codec_enc_.g_pass = VPX_RC_LAST_PASS; - svc_.temporal_layers = 2; - codec_enc_.g_error_resilient = 0; - vpx_svc_set_options(&svc_, "auto-alt-refs=1 scale-factors=1/1 " - "multi-frame-contexts=1"); - vpx_fixed_buf outputs[10]; - memset(&outputs[0], 0, sizeof(outputs)); - Pass2EncodeNFrames(&stats_buf, 10, 1, &outputs[0]); - - vpx_fixed_buf base_layer[5]; - for (int i = 0; i < 5; ++i) - base_layer[i] = outputs[i * 2]; - - DecodeNFrames(&base_layer[0], 5); - FreeBitstreamBuffers(&outputs[0], 10); -} - -TEST_F(SvcTest, TwoPassEncode2TemporalLayersWithTiles) { - // First pass encode - std::string stats_buf; - vpx_svc_set_options(&svc_, "scale-factors=1/1"); - svc_.temporal_layers = 2; - Pass1EncodeNFrames(10, 1, &stats_buf); - - // Second pass encode - codec_enc_.g_pass = VPX_RC_LAST_PASS; - svc_.temporal_layers = 2; - vpx_svc_set_options(&svc_, "auto-alt-refs=1 scale-factors=1/1"); - codec_enc_.g_w = 704; - codec_enc_.g_h = 144; - tile_columns_ = 1; - tile_rows_ = 1; - vpx_fixed_buf outputs[10]; - memset(&outputs[0], 0, sizeof(outputs)); - Pass2EncodeNFrames(&stats_buf, 10, 1, &outputs[0]); - DecodeNFrames(&outputs[0], 10); - FreeBitstreamBuffers(&outputs[0], 10); -} - -TEST_F(SvcTest, - TwoPassEncode2TemporalLayersWithMultipleFrameContextsAndTiles) { - // First pass encode - std::string stats_buf; - vpx_svc_set_options(&svc_, "scale-factors=1/1"); - svc_.temporal_layers = 2; - Pass1EncodeNFrames(10, 1, &stats_buf); - - // Second pass encode - codec_enc_.g_pass = VPX_RC_LAST_PASS; - svc_.temporal_layers = 2; - codec_enc_.g_error_resilient = 0; - codec_enc_.g_w = 704; - codec_enc_.g_h = 144; - tile_columns_ = 1; - tile_rows_ = 1; - vpx_svc_set_options(&svc_, "auto-alt-refs=1 scale-factors=1/1 " - "multi-frame-contexts=1"); - vpx_fixed_buf outputs[10]; - memset(&outputs[0], 0, sizeof(outputs)); - Pass2EncodeNFrames(&stats_buf, 10, 1, &outputs[0]); - DecodeNFrames(&outputs[0], 10); - FreeBitstreamBuffers(&outputs[0], 10); -} - -} // namespace diff --git a/test/test.mk b/test/test.mk index 346a9babd..bc8424c9c 100644 --- a/test/test.mk +++ b/test/test.mk @@ -120,10 +120,6 @@ LIBVPX_TEST_SRCS-$(CONFIG_VP10_ENCODER) += error_block_test.cc #LIBVPX_TEST_SRCS-$(CONFIG_VP10_ENCODER) += vp9_quantize_test.cc LIBVPX_TEST_SRCS-$(CONFIG_VP10_ENCODER) += subtract_test.cc -ifeq ($(CONFIG_VP10_ENCODER),yes) -LIBVPX_TEST_SRCS-$(CONFIG_SPATIAL_SVC) += svc_test.cc -endif - ifeq ($(CONFIG_VP10_ENCODER)$(CONFIG_VP10_TEMPORAL_DENOISING),yesyes) LIBVPX_TEST_SRCS-$(HAVE_SSE2) += denoiser_sse2_test.cc endif diff --git a/test/vpx_temporal_svc_encoder.sh b/test/vpx_temporal_svc_encoder.sh deleted file mode 100755 index fcc8cb4ff..000000000 --- a/test/vpx_temporal_svc_encoder.sh +++ /dev/null @@ -1,290 +0,0 @@ -#!/bin/sh -## -## Copyright (c) 2014 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 file tests the libvpx vpx_temporal_svc_encoder example. To add new -## tests to this file, do the following: -## 1. Write a shell function (this is your test). -## 2. Add the function to vpx_tsvc_encoder_tests (on a new line). -## -. $(dirname $0)/tools_common.sh - -# Environment check: $YUV_RAW_INPUT is required. -vpx_tsvc_encoder_verify_environment() { - if [ ! -e "${YUV_RAW_INPUT}" ]; then - echo "Libvpx test data must exist in LIBVPX_TEST_DATA_PATH." - return 1 - fi - if [ "$(vpx_config_option_enabled CONFIG_TEMPORAL_DENOISING)" != "yes" ]; then - elog "Warning: Temporal denoising is disabled! Spatial denoising will be " \ - "used instead, which is probably not what you want for this test." - fi -} - -# Runs vpx_temporal_svc_encoder using the codec specified by $1 and output file -# name by $2. Additional positional parameters are passed directly to -# vpx_temporal_svc_encoder. -vpx_tsvc_encoder() { - local encoder="${LIBVPX_BIN_PATH}/vpx_temporal_svc_encoder" - encoder="${encoder}${VPX_TEST_EXE_SUFFIX}" - local codec="$1" - local output_file_base="$2" - local output_file="${VPX_TEST_OUTPUT_DIR}/${output_file_base}" - local timebase_num="1" - local timebase_den="1000" - local speed="6" - local frame_drop_thresh="30" - - shift 2 - - if [ ! -x "${encoder}" ]; then - elog "${encoder} does not exist or is not executable." - return 1 - fi - - eval "${VPX_TEST_PREFIX}" "${encoder}" "${YUV_RAW_INPUT}" "${output_file}" \ - "${codec}" "${YUV_RAW_INPUT_WIDTH}" "${YUV_RAW_INPUT_HEIGHT}" \ - "${timebase_num}" "${timebase_den}" "${speed}" "${frame_drop_thresh}" \ - "$@" \ - ${devnull} -} - -# Confirms that all expected output files exist given the output file name -# passed to vpx_temporal_svc_encoder. -# The file name passed to vpx_temporal_svc_encoder is joined with the stream -# number and the extension .ivf to produce per stream output files. Here $1 is -# file name, and $2 is expected number of files. -files_exist() { - local file_name="${VPX_TEST_OUTPUT_DIR}/$1" - local num_files="$(($2 - 1))" - for stream_num in $(seq 0 ${num_files}); do - [ -e "${file_name}_${stream_num}.ivf" ] || return 1 - done -} - -# Run vpx_temporal_svc_encoder in all supported modes for vp8 and vp9. - -vpx_tsvc_encoder_vp8_mode_0() { - if [ "$(vp8_encode_available)" = "yes" ]; then - vpx_tsvc_encoder vp8 "${FUNCNAME}" 0 200 || return 1 - # Mode 0 produces 1 stream - files_exist "${FUNCNAME}" 1 || return 1 - fi -} - -vpx_tsvc_encoder_vp8_mode_1() { - if [ "$(vp8_encode_available)" = "yes" ]; then - vpx_tsvc_encoder vp8 "${FUNCNAME}" 1 200 400 || return 1 - # Mode 1 produces 2 streams - files_exist "${FUNCNAME}" 2 || return 1 - fi -} - -vpx_tsvc_encoder_vp8_mode_2() { - if [ "$(vp8_encode_available)" = "yes" ]; then - vpx_tsvc_encoder vp8 "${FUNCNAME}" 2 200 400 || return 1 - # Mode 2 produces 2 streams - files_exist "${FUNCNAME}" 2 || return 1 - fi -} - -vpx_tsvc_encoder_vp8_mode_3() { - if [ "$(vp8_encode_available)" = "yes" ]; then - vpx_tsvc_encoder vp8 "${FUNCNAME}" 3 200 400 600 || return 1 - # Mode 3 produces 3 streams - files_exist "${FUNCNAME}" 3 || return 1 - fi -} - -vpx_tsvc_encoder_vp8_mode_4() { - if [ "$(vp8_encode_available)" = "yes" ]; then - vpx_tsvc_encoder vp8 "${FUNCNAME}" 4 200 400 600 || return 1 - # Mode 4 produces 3 streams - files_exist "${FUNCNAME}" 3 || return 1 - fi -} - -vpx_tsvc_encoder_vp8_mode_5() { - if [ "$(vp8_encode_available)" = "yes" ]; then - vpx_tsvc_encoder vp8 "${FUNCNAME}" 5 200 400 600 || return 1 - # Mode 5 produces 3 streams - files_exist "${FUNCNAME}" 3 || return 1 - fi -} - -vpx_tsvc_encoder_vp8_mode_6() { - if [ "$(vp8_encode_available)" = "yes" ]; then - vpx_tsvc_encoder vp8 "${FUNCNAME}" 6 200 400 600 || return 1 - # Mode 6 produces 3 streams - files_exist "${FUNCNAME}" 3 || return 1 - fi -} - -vpx_tsvc_encoder_vp8_mode_7() { - if [ "$(vp8_encode_available)" = "yes" ]; then - vpx_tsvc_encoder vp8 "${FUNCNAME}" 7 200 400 600 800 1000 || return 1 - # Mode 7 produces 5 streams - files_exist "${FUNCNAME}" 5 || return 1 - fi -} - -vpx_tsvc_encoder_vp8_mode_8() { - if [ "$(vp8_encode_available)" = "yes" ]; then - vpx_tsvc_encoder vp8 "${FUNCNAME}" 8 200 400 || return 1 - # Mode 8 produces 2 streams - files_exist "${FUNCNAME}" 2 || return 1 - fi -} - -vpx_tsvc_encoder_vp8_mode_9() { - if [ "$(vp8_encode_available)" = "yes" ]; then - vpx_tsvc_encoder vp8 "${FUNCNAME}" 9 200 400 600 || return 1 - # Mode 9 produces 3 streams - files_exist "${FUNCNAME}" 3 || return 1 - fi -} - -vpx_tsvc_encoder_vp8_mode_10() { - if [ "$(vp8_encode_available)" = "yes" ]; then - vpx_tsvc_encoder vp8 "${FUNCNAME}" 10 200 400 600 || return 1 - # Mode 10 produces 3 streams - files_exist "${FUNCNAME}" 3 || return 1 - fi -} - -vpx_tsvc_encoder_vp8_mode_11() { - if [ "$(vp8_encode_available)" = "yes" ]; then - vpx_tsvc_encoder vp8 "${FUNCNAME}" 11 200 400 600 || return 1 - # Mode 11 produces 3 streams - files_exist "${FUNCNAME}" 3 || return 1 - fi -} - -vpx_tsvc_encoder_vp9_mode_0() { - if [ "$(vp9_encode_available)" = "yes" ]; then - vpx_tsvc_encoder vp9 "${FUNCNAME}" 0 200 || return 1 - # Mode 0 produces 1 stream - files_exist "${FUNCNAME}" 1 || return 1 - fi -} - -vpx_tsvc_encoder_vp9_mode_1() { - if [ "$(vp9_encode_available)" = "yes" ]; then - vpx_tsvc_encoder vp9 "${FUNCNAME}" 1 200 400 || return 1 - # Mode 1 produces 2 streams - files_exist "${FUNCNAME}" 2 || return 1 - fi -} - -vpx_tsvc_encoder_vp9_mode_2() { - if [ "$(vp9_encode_available)" = "yes" ]; then - vpx_tsvc_encoder vp9 "${FUNCNAME}" 2 200 400 || return 1 - # Mode 2 produces 2 streams - files_exist "${FUNCNAME}" 2 || return 1 - fi -} - -vpx_tsvc_encoder_vp9_mode_3() { - if [ "$(vp9_encode_available)" = "yes" ]; then - vpx_tsvc_encoder vp9 "${FUNCNAME}" 3 200 400 600 || return 1 - # Mode 3 produces 3 streams - files_exist "${FUNCNAME}" 3 || return 1 - fi -} - -vpx_tsvc_encoder_vp9_mode_4() { - if [ "$(vp9_encode_available)" = "yes" ]; then - vpx_tsvc_encoder vp9 "${FUNCNAME}" 4 200 400 600 || return 1 - # Mode 4 produces 3 streams - files_exist "${FUNCNAME}" 3 || return 1 - fi -} - -vpx_tsvc_encoder_vp9_mode_5() { - if [ "$(vp9_encode_available)" = "yes" ]; then - vpx_tsvc_encoder vp9 "${FUNCNAME}" 5 200 400 600 || return 1 - # Mode 5 produces 3 streams - files_exist "${FUNCNAME}" 3 || return 1 - fi -} - -vpx_tsvc_encoder_vp9_mode_6() { - if [ "$(vp9_encode_available)" = "yes" ]; then - vpx_tsvc_encoder vp9 "${FUNCNAME}" 6 200 400 600 || return 1 - # Mode 6 produces 3 streams - files_exist "${FUNCNAME}" 3 || return 1 - fi -} - -vpx_tsvc_encoder_vp9_mode_7() { - if [ "$(vp9_encode_available)" = "yes" ]; then - vpx_tsvc_encoder vp9 "${FUNCNAME}" 7 200 400 600 800 1000 || return 1 - # Mode 7 produces 5 streams - files_exist "${FUNCNAME}" 5 || return 1 - fi -} - -vpx_tsvc_encoder_vp9_mode_8() { - if [ "$(vp9_encode_available)" = "yes" ]; then - vpx_tsvc_encoder vp9 "${FUNCNAME}" 8 200 400 || return 1 - # Mode 8 produces 2 streams - files_exist "${FUNCNAME}" 2 || return 1 - fi -} - -vpx_tsvc_encoder_vp9_mode_9() { - if [ "$(vp9_encode_available)" = "yes" ]; then - vpx_tsvc_encoder vp9 "${FUNCNAME}" 9 200 400 600 || return 1 - # Mode 9 produces 3 streams - files_exist "${FUNCNAME}" 3 || return 1 - fi -} - -vpx_tsvc_encoder_vp9_mode_10() { - if [ "$(vp9_encode_available)" = "yes" ]; then - vpx_tsvc_encoder vp9 "${FUNCNAME}" 10 200 400 600 || return 1 - # Mode 10 produces 3 streams - files_exist "${FUNCNAME}" 3 || return 1 - fi -} - -vpx_tsvc_encoder_vp9_mode_11() { - if [ "$(vp9_encode_available)" = "yes" ]; then - vpx_tsvc_encoder vp9 "${FUNCNAME}" 11 200 400 600 || return 1 - # Mode 11 produces 3 streams - files_exist "${FUNCNAME}" 3 || return 1 - fi -} - -vpx_tsvc_encoder_tests="vpx_tsvc_encoder_vp8_mode_0 - vpx_tsvc_encoder_vp8_mode_1 - vpx_tsvc_encoder_vp8_mode_2 - vpx_tsvc_encoder_vp8_mode_3 - vpx_tsvc_encoder_vp8_mode_4 - vpx_tsvc_encoder_vp8_mode_5 - vpx_tsvc_encoder_vp8_mode_6 - vpx_tsvc_encoder_vp8_mode_7 - vpx_tsvc_encoder_vp8_mode_8 - vpx_tsvc_encoder_vp8_mode_9 - vpx_tsvc_encoder_vp8_mode_10 - vpx_tsvc_encoder_vp8_mode_11 - vpx_tsvc_encoder_vp9_mode_0 - vpx_tsvc_encoder_vp9_mode_1 - vpx_tsvc_encoder_vp9_mode_2 - vpx_tsvc_encoder_vp9_mode_3 - vpx_tsvc_encoder_vp9_mode_4 - vpx_tsvc_encoder_vp9_mode_5 - vpx_tsvc_encoder_vp9_mode_6 - vpx_tsvc_encoder_vp9_mode_7 - vpx_tsvc_encoder_vp9_mode_8 - vpx_tsvc_encoder_vp9_mode_9 - vpx_tsvc_encoder_vp9_mode_10 - vpx_tsvc_encoder_vp9_mode_11" - -run_tests vpx_tsvc_encoder_verify_environment "${vpx_tsvc_encoder_tests}" diff --git a/vp10/encoder/encoder.c b/vp10/encoder/encoder.c index efb042ad9..646e43274 100644 --- a/vp10/encoder/encoder.c +++ b/vp10/encoder/encoder.c @@ -43,7 +43,6 @@ #include "vp10/encoder/rd.h" #include "vp10/encoder/resize.h" #include "vp10/encoder/segmentation.h" -#include "vp10/encoder/skin_detection.h" #include "vp10/encoder/speed_features.h" #include "vp10/encoder/temporal_filter.h" diff --git a/vp10/encoder/skin_detection.c b/vp10/encoder/skin_detection.c deleted file mode 100644 index 1714cd34d..000000000 --- a/vp10/encoder/skin_detection.c +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (c) 2015 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. - */ - -#include -#include - -#include "vp10/common/blockd.h" -#include "vp10/encoder/encoder.h" -#include "vp10/encoder/skin_detection.h" - -// Fixed-point skin color model parameters. -static const int skin_mean[2] = {7463, 9614}; // q6 -static const int skin_inv_cov[4] = {4107, 1663, 1663, 2157}; // q16 -static const int skin_threshold = 1570636; // q18 - -// Thresholds on luminance. -static const int y_low = 20; -static const int y_high = 220; - -// Evaluates the Mahalanobis distance measure for the input CbCr values. -static int evaluate_skin_color_difference(int cb, int cr) { - const int cb_q6 = cb << 6; - const int cr_q6 = cr << 6; - const int cb_diff_q12 = (cb_q6 - skin_mean[0]) * (cb_q6 - skin_mean[0]); - const int cbcr_diff_q12 = (cb_q6 - skin_mean[0]) * (cr_q6 - skin_mean[1]); - const int cr_diff_q12 = (cr_q6 - skin_mean[1]) * (cr_q6 - skin_mean[1]); - const int cb_diff_q2 = (cb_diff_q12 + (1 << 9)) >> 10; - const int cbcr_diff_q2 = (cbcr_diff_q12 + (1 << 9)) >> 10; - const int cr_diff_q2 = (cr_diff_q12 + (1 << 9)) >> 10; - const int skin_diff = skin_inv_cov[0] * cb_diff_q2 + - skin_inv_cov[1] * cbcr_diff_q2 + - skin_inv_cov[2] * cbcr_diff_q2 + - skin_inv_cov[3] * cr_diff_q2; - return skin_diff; -} - -int vp10_skin_pixel(const uint8_t y, const uint8_t cb, const uint8_t cr) { - if (y < y_low || y > y_high) - return 0; - else - return (evaluate_skin_color_difference(cb, cr) < skin_threshold); -} - -#ifdef OUTPUT_YUV_SKINMAP -// For viewing skin map on input source. -void vp10_compute_skin_map(VP10_COMP *const cpi, FILE *yuv_skinmap_file) { - int i, j, mi_row, mi_col; - VP10_COMMON *const cm = &cpi->common; - uint8_t *y; - const uint8_t *src_y = cpi->Source->y_buffer; - const uint8_t *src_u = cpi->Source->u_buffer; - const uint8_t *src_v = cpi->Source->v_buffer; - const int src_ystride = cpi->Source->y_stride; - const int src_uvstride = cpi->Source->uv_stride; - YV12_BUFFER_CONFIG skinmap; - memset(&skinmap, 0, sizeof(YV12_BUFFER_CONFIG)); - if (vpx_alloc_frame_buffer(&skinmap, cm->width, cm->height, - cm->subsampling_x, cm->subsampling_y, - VPX_ENC_BORDER_IN_PIXELS, cm->byte_alignment)) { - vpx_free_frame_buffer(&skinmap); - return; - } - memset(skinmap.buffer_alloc, 128, skinmap.frame_size); - y = skinmap.y_buffer; - // Loop through 8x8 blocks and set skin map based on center pixel of block. - // Set y to white for skin block, otherwise set to source with gray scale. - // Ignore rightmost/bottom boundary blocks. - for (mi_row = 0; mi_row < cm->mi_rows - 1; ++mi_row) { - for (mi_col = 0; mi_col < cm->mi_cols - 1; ++mi_col) { - // Use middle pixel for each 8x8 block for skin detection. - // If middle pixel is skin, assign whole 8x8 block to skin. - const uint8_t ysource = src_y[4 * src_ystride + 4]; - const uint8_t usource = src_u[2 * src_uvstride + 2]; - const uint8_t vsource = src_v[2 * src_uvstride + 2]; - const int is_skin = vp10_skin_pixel(ysource, usource, vsource); - for (i = 0; i < 8; i++) { - for (j = 0; j < 8; j++) { - if (is_skin) - y[i * src_ystride + j] = 255; - else - y[i * src_ystride + j] = src_y[i * src_ystride + j]; - } - } - y += 8; - src_y += 8; - src_u += 4; - src_v += 4; - } - y += (src_ystride << 3) - ((cm->mi_cols - 1) << 3); - src_y += (src_ystride << 3) - ((cm->mi_cols - 1) << 3); - src_u += (src_uvstride << 2) - ((cm->mi_cols - 1) << 2); - src_v += (src_uvstride << 2) - ((cm->mi_cols - 1) << 2); - } - vp10_write_yuv_frame_420(&skinmap, yuv_skinmap_file); - vpx_free_frame_buffer(&skinmap); -} -#endif diff --git a/vp10/encoder/skin_detection.h b/vp10/encoder/skin_detection.h deleted file mode 100644 index 26b7d5e7c..000000000 --- a/vp10/encoder/skin_detection.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2015 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. - */ - -#ifndef VP10_ENCODER_SKIN_MAP_H_ -#define VP10_ENCODER_SKIN_MAP_H_ - -#include "vp10/common/blockd.h" - -#ifdef __cplusplus -extern "C" { -#endif - -struct VP10_COMP; - -// #define OUTPUT_YUV_SKINMAP - -int vp10_skin_pixel(const uint8_t y, const uint8_t cb, const uint8_t cr); - -#ifdef OUTPUT_YUV_SKINMAP -// For viewing skin map on input source. -void vp10_compute_skin_map(VP10_COMP *const cpi, FILE *yuv_skinmap_file); -#endif - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // VP10_ENCODER_SKIN_MAP_H_ diff --git a/vp10/vp10_cx_iface.c b/vp10/vp10_cx_iface.c index 4b6f75f41..6a9b9e40a 100644 --- a/vp10/vp10_cx_iface.c +++ b/vp10/vp10_cx_iface.c @@ -110,7 +110,6 @@ struct vpx_codec_alg_priv { vp8_postproc_cfg_t preview_ppcfg; vpx_codec_pkt_list_decl(256) pkt_list; unsigned int fixed_kf_cntr; - vpx_codec_priv_output_cx_pkt_cb_pair_t output_cx_pkt_cb; // BufferPool that holds all reference frames. BufferPool *buffer_pool; }; @@ -192,10 +191,6 @@ static vpx_codec_err_t validate_config(vpx_codec_alg_priv_t *ctx, RANGE_CHECK(cfg, rc_scaled_height, 0, cfg->g_h); } - // Spatial/temporal scalability are not yet supported in VP10. - // Only accept the default value for range checking. - RANGE_CHECK(cfg, ss_number_layers, 1, 1); - RANGE_CHECK(cfg, ts_number_layers, 1, 1); // VP9 does not support a lower bound on the keyframe interval in // automatic keyframe placement mode. if (cfg->kf_mode != VPX_KF_DISABLED && @@ -1054,22 +1049,6 @@ static vpx_codec_err_t encoder_encode(vpx_codec_alg_priv_t *ctx, cx_data += size; cx_data_sz -= size; - if (ctx->output_cx_pkt_cb.output_cx_pkt) { - pkt.kind = VPX_CODEC_CX_FRAME_PKT; - pkt.data.frame.pts = ticks_to_timebase_units(timebase, - dst_time_stamp); - pkt.data.frame.duration = - (unsigned long)ticks_to_timebase_units(timebase, - dst_end_time_stamp - dst_time_stamp); - pkt.data.frame.flags = get_frame_pkt_flags(cpi, lib_flags); - pkt.data.frame.buf = ctx->pending_cx_data; - pkt.data.frame.sz = size; - ctx->pending_cx_data = NULL; - ctx->pending_cx_data_sz = 0; - ctx->pending_frame_count = 0; - ctx->output_cx_pkt_cb.output_cx_pkt( - &pkt, ctx->output_cx_pkt_cb.user_priv); - } continue; } @@ -1084,9 +1063,7 @@ static vpx_codec_err_t encoder_encode(vpx_codec_alg_priv_t *ctx, if (ctx->pending_cx_data) { ctx->pending_frame_sizes[ctx->pending_frame_count++] = size; ctx->pending_cx_data_sz += size; - // write the superframe only for the case when - if (!ctx->output_cx_pkt_cb.output_cx_pkt) - size += write_superframe_index(ctx); + size += write_superframe_index(ctx); pkt.data.frame.buf = ctx->pending_cx_data; pkt.data.frame.sz = ctx->pending_cx_data_sz; ctx->pending_cx_data = NULL; @@ -1098,11 +1075,7 @@ static vpx_codec_err_t encoder_encode(vpx_codec_alg_priv_t *ctx, } pkt.data.frame.partition_id = -1; - if(ctx->output_cx_pkt_cb.output_cx_pkt) - ctx->output_cx_pkt_cb.output_cx_pkt(&pkt, - ctx->output_cx_pkt_cb.user_priv); - else - vpx_codec_pkt_list_add(&ctx->pkt_list.head, &pkt); + vpx_codec_pkt_list_add(&ctx->pkt_list.head, &pkt); cx_data += size; cx_data_sz -= size; @@ -1265,16 +1238,6 @@ static vpx_codec_err_t ctrl_set_scale_mode(vpx_codec_alg_priv_t *ctx, } } -static vpx_codec_err_t ctrl_register_cx_callback(vpx_codec_alg_priv_t *ctx, - va_list args) { - vpx_codec_priv_output_cx_pkt_cb_pair_t *cbp = - (vpx_codec_priv_output_cx_pkt_cb_pair_t *)va_arg(args, void *); - ctx->output_cx_pkt_cb.output_cx_pkt = cbp->output_cx_pkt; - ctx->output_cx_pkt_cb.user_priv = cbp->user_priv; - - return VPX_CODEC_OK; -} - static vpx_codec_err_t ctrl_set_tune_content(vpx_codec_alg_priv_t *ctx, va_list args) { struct vp10_extracfg extra_cfg = ctx->extra_cfg; @@ -1343,7 +1306,6 @@ static vpx_codec_ctrl_fn_map_t encoder_ctrl_maps[] = { {VP9E_SET_FRAME_PARALLEL_DECODING, ctrl_set_frame_parallel_decoding_mode}, {VP9E_SET_AQ_MODE, ctrl_set_aq_mode}, {VP9E_SET_FRAME_PERIODIC_BOOST, ctrl_set_frame_periodic_boost}, - {VP9E_REGISTER_CX_CALLBACK, ctrl_register_cx_callback}, {VP9E_SET_TUNE_CONTENT, ctrl_set_tune_content}, {VP9E_SET_COLOR_SPACE, ctrl_set_color_space}, {VP9E_SET_COLOR_RANGE, ctrl_set_color_range}, @@ -1412,20 +1374,6 @@ static vpx_codec_enc_cfg_map_t encoder_usage_cfg_map[] = { VPX_KF_AUTO, // g_kfmode 0, // kf_min_dist 9999, // kf_max_dist - - // TODO(yunqingwang): Spatial/temporal scalability are not supported - // in VP10. The following 10 parameters are not used, which should - // be removed later. - 1, // ss_number_layers - {0}, - {0}, // ss_target_bitrate - 1, // ts_number_layers - {0}, // ts_target_bitrate - {0}, // ts_rate_decimator - 0, // ts_periodicity - {0}, // ts_layer_id - {0}, // layer_taget_bitrate - 0 // temporal_layering_mode } }, }; diff --git a/vp10/vp10cx.mk b/vp10/vp10cx.mk index 735ec5b6c..0bf476f30 100644 --- a/vp10/vp10cx.mk +++ b/vp10/vp10cx.mk @@ -84,8 +84,6 @@ VP10_CX_SRCS-yes += encoder/aq_cyclicrefresh.c VP10_CX_SRCS-yes += encoder/aq_cyclicrefresh.h VP10_CX_SRCS-yes += encoder/aq_complexity.c VP10_CX_SRCS-yes += encoder/aq_complexity.h -VP10_CX_SRCS-yes += encoder/skin_detection.c -VP10_CX_SRCS-yes += encoder/skin_detection.h VP10_CX_SRCS-yes += encoder/temporal_filter.c VP10_CX_SRCS-yes += encoder/temporal_filter.h VP10_CX_SRCS-yes += encoder/mbgraph.c diff --git a/vpx/exports_spatial_svc b/vpx/exports_spatial_svc deleted file mode 100644 index d258a1d61..000000000 --- a/vpx/exports_spatial_svc +++ /dev/null @@ -1,6 +0,0 @@ -text vpx_svc_dump_statistics -text vpx_svc_encode -text vpx_svc_get_message -text vpx_svc_init -text vpx_svc_release -text vpx_svc_set_options diff --git a/vpx/src/svc_encodeframe.c b/vpx/src/svc_encodeframe.c deleted file mode 100644 index ef9b3528a..000000000 --- a/vpx/src/svc_encodeframe.c +++ /dev/null @@ -1,686 +0,0 @@ -/* - * Copyright (c) 2013 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. - */ - -/** - * @file - * VP9 SVC encoding support via libvpx - */ - -#include -#include -#include -#include -#include -#include -#include -#define VPX_DISABLE_CTRL_TYPECHECKS 1 -#include "./vpx_config.h" -#include "vpx/svc_context.h" -#include "vpx/vp8cx.h" -#include "vpx/vpx_encoder.h" -#include "vpx_mem/vpx_mem.h" -#include "vp9/common/vp9_onyxc_int.h" - -#ifdef __MINGW32__ -#define strtok_r strtok_s -#ifndef MINGW_HAS_SECURE_API -// proto from /usr/x86_64-w64-mingw32/include/sec_api/string_s.h -_CRTIMP char *__cdecl strtok_s(char *str, const char *delim, char **context); -#endif /* MINGW_HAS_SECURE_API */ -#endif /* __MINGW32__ */ - -#ifdef _MSC_VER -#define strdup _strdup -#define strtok_r strtok_s -#endif - -#define SVC_REFERENCE_FRAMES 8 -#define SUPERFRAME_SLOTS (8) -#define SUPERFRAME_BUFFER_SIZE (SUPERFRAME_SLOTS * sizeof(uint32_t) + 2) - -#define MAX_QUANTIZER 63 - -static const int DEFAULT_SCALE_FACTORS_NUM[VPX_SS_MAX_LAYERS] = { - 4, 5, 7, 11, 16 -}; - -static const int DEFAULT_SCALE_FACTORS_DEN[VPX_SS_MAX_LAYERS] = { - 16, 16, 16, 16, 16 -}; - -typedef enum { - QUANTIZER = 0, - BITRATE, - SCALE_FACTOR, - AUTO_ALT_REF, - ALL_OPTION_TYPES -} LAYER_OPTION_TYPE; - -static const int option_max_values[ALL_OPTION_TYPES] = { - 63, INT_MAX, INT_MAX, 1 -}; - -static const int option_min_values[ALL_OPTION_TYPES] = { - 0, 0, 1, 0 -}; - -// One encoded frame -typedef struct FrameData { - void *buf; // compressed data buffer - size_t size; // length of compressed data - vpx_codec_frame_flags_t flags; /**< flags for this frame */ - struct FrameData *next; -} FrameData; - -static SvcInternal_t *get_svc_internal(SvcContext *svc_ctx) { - if (svc_ctx == NULL) return NULL; - if (svc_ctx->internal == NULL) { - SvcInternal_t *const si = (SvcInternal_t *)malloc(sizeof(*si)); - if (si != NULL) { - memset(si, 0, sizeof(*si)); - } - svc_ctx->internal = si; - } - return (SvcInternal_t *)svc_ctx->internal; -} - -static const SvcInternal_t *get_const_svc_internal( - const SvcContext *svc_ctx) { - if (svc_ctx == NULL) return NULL; - return (const SvcInternal_t *)svc_ctx->internal; -} - -static void svc_log_reset(SvcContext *svc_ctx) { - SvcInternal_t *const si = (SvcInternal_t *)svc_ctx->internal; - si->message_buffer[0] = '\0'; -} - -static int svc_log(SvcContext *svc_ctx, SVC_LOG_LEVEL level, - const char *fmt, ...) { - char buf[512]; - int retval = 0; - va_list ap; - SvcInternal_t *const si = get_svc_internal(svc_ctx); - - if (level > svc_ctx->log_level) { - return retval; - } - - va_start(ap, fmt); - retval = vsnprintf(buf, sizeof(buf), fmt, ap); - va_end(ap); - - if (svc_ctx->log_print) { - printf("%s", buf); - } else { - strncat(si->message_buffer, buf, - sizeof(si->message_buffer) - strlen(si->message_buffer) - 1); - } - - if (level == SVC_LOG_ERROR) { - si->codec_ctx->err_detail = si->message_buffer; - } - return retval; -} - -static vpx_codec_err_t extract_option(LAYER_OPTION_TYPE type, - char *input, - int *value0, - int *value1) { - if (type == SCALE_FACTOR) { - *value0 = strtol(input, &input, 10); - if (*input++ != '/') - return VPX_CODEC_INVALID_PARAM; - *value1 = strtol(input, &input, 10); - - if (*value0 < option_min_values[SCALE_FACTOR] || - *value1 < option_min_values[SCALE_FACTOR] || - *value0 > option_max_values[SCALE_FACTOR] || - *value1 > option_max_values[SCALE_FACTOR] || - *value0 > *value1) // num shouldn't be greater than den - return VPX_CODEC_INVALID_PARAM; - } else { - *value0 = atoi(input); - if (*value0 < option_min_values[type] || - *value0 > option_max_values[type]) - return VPX_CODEC_INVALID_PARAM; - } - return VPX_CODEC_OK; -} - -static vpx_codec_err_t parse_layer_options_from_string(SvcContext *svc_ctx, - LAYER_OPTION_TYPE type, - const char *input, - int *option0, - int *option1) { - int i; - vpx_codec_err_t res = VPX_CODEC_OK; - char *input_string; - char *token; - const char *delim = ","; - char *save_ptr; - - if (input == NULL || option0 == NULL || - (option1 == NULL && type == SCALE_FACTOR)) - return VPX_CODEC_INVALID_PARAM; - - input_string = strdup(input); - token = strtok_r(input_string, delim, &save_ptr); - for (i = 0; i < svc_ctx->spatial_layers; ++i) { - if (token != NULL) { - res = extract_option(type, token, option0 + i, option1 + i); - if (res != VPX_CODEC_OK) - break; - token = strtok_r(NULL, delim, &save_ptr); - } else { - break; - } - } - if (res == VPX_CODEC_OK && i != svc_ctx->spatial_layers) { - svc_log(svc_ctx, SVC_LOG_ERROR, - "svc: layer params type: %d %d values required, " - "but only %d specified\n", type, svc_ctx->spatial_layers, i); - res = VPX_CODEC_INVALID_PARAM; - } - free(input_string); - return res; -} - -/** - * Parse SVC encoding options - * Format: encoding-mode=,layers= - * scale-factors=/,/,... - * quantizers=,,... - * svc_mode = [i|ip|alt_ip|gf] - */ -static vpx_codec_err_t parse_options(SvcContext *svc_ctx, const char *options) { - char *input_string; - char *option_name; - char *option_value; - char *input_ptr; - SvcInternal_t *const si = get_svc_internal(svc_ctx); - vpx_codec_err_t res = VPX_CODEC_OK; - int i, alt_ref_enabled = 0; - - if (options == NULL) return VPX_CODEC_OK; - input_string = strdup(options); - - // parse option name - option_name = strtok_r(input_string, "=", &input_ptr); - while (option_name != NULL) { - // parse option value - option_value = strtok_r(NULL, " ", &input_ptr); - if (option_value == NULL) { - svc_log(svc_ctx, SVC_LOG_ERROR, "option missing value: %s\n", - option_name); - res = VPX_CODEC_INVALID_PARAM; - break; - } - if (strcmp("spatial-layers", option_name) == 0) { - svc_ctx->spatial_layers = atoi(option_value); - } else if (strcmp("temporal-layers", option_name) == 0) { - svc_ctx->temporal_layers = atoi(option_value); - } else if (strcmp("scale-factors", option_name) == 0) { - res = parse_layer_options_from_string(svc_ctx, SCALE_FACTOR, option_value, - si->svc_params.scaling_factor_num, - si->svc_params.scaling_factor_den); - if (res != VPX_CODEC_OK) break; - } else if (strcmp("max-quantizers", option_name) == 0) { - res = parse_layer_options_from_string(svc_ctx, QUANTIZER, option_value, - si->svc_params.max_quantizers, - NULL); - if (res != VPX_CODEC_OK) break; - } else if (strcmp("min-quantizers", option_name) == 0) { - res = parse_layer_options_from_string(svc_ctx, QUANTIZER, option_value, - si->svc_params.min_quantizers, - NULL); - if (res != VPX_CODEC_OK) break; - } else if (strcmp("auto-alt-refs", option_name) == 0) { - res = parse_layer_options_from_string(svc_ctx, AUTO_ALT_REF, option_value, - si->enable_auto_alt_ref, NULL); - if (res != VPX_CODEC_OK) break; - } else if (strcmp("bitrates", option_name) == 0) { - res = parse_layer_options_from_string(svc_ctx, BITRATE, option_value, - si->bitrates, NULL); - if (res != VPX_CODEC_OK) break; - } else if (strcmp("multi-frame-contexts", option_name) == 0) { - si->use_multiple_frame_contexts = atoi(option_value); - } else { - svc_log(svc_ctx, SVC_LOG_ERROR, "invalid option: %s\n", option_name); - res = VPX_CODEC_INVALID_PARAM; - break; - } - option_name = strtok_r(NULL, "=", &input_ptr); - } - free(input_string); - - for (i = 0; i < svc_ctx->spatial_layers; ++i) { - if (si->svc_params.max_quantizers[i] > MAX_QUANTIZER || - si->svc_params.max_quantizers[i] < 0 || - si->svc_params.min_quantizers[i] > si->svc_params.max_quantizers[i] || - si->svc_params.min_quantizers[i] < 0) - res = VPX_CODEC_INVALID_PARAM; - } - - if (si->use_multiple_frame_contexts && - (svc_ctx->spatial_layers > 3 || - svc_ctx->spatial_layers * svc_ctx->temporal_layers > 4)) - res = VPX_CODEC_INVALID_PARAM; - - for (i = 0; i < svc_ctx->spatial_layers; ++i) - alt_ref_enabled += si->enable_auto_alt_ref[i]; - if (alt_ref_enabled > REF_FRAMES - svc_ctx->spatial_layers) { - svc_log(svc_ctx, SVC_LOG_ERROR, - "svc: auto alt ref: Maxinum %d(REF_FRAMES - layers) layers could" - "enabled auto alt reference frame, but % layers are enabled\n", - REF_FRAMES - svc_ctx->spatial_layers, alt_ref_enabled); - res = VPX_CODEC_INVALID_PARAM; - } - - return res; -} - -vpx_codec_err_t vpx_svc_set_options(SvcContext *svc_ctx, - const char *options) { - SvcInternal_t *const si = get_svc_internal(svc_ctx); - if (svc_ctx == NULL || options == NULL || si == NULL) { - return VPX_CODEC_INVALID_PARAM; - } - strncpy(si->options, options, sizeof(si->options)); - si->options[sizeof(si->options) - 1] = '\0'; - return VPX_CODEC_OK; -} - -void assign_layer_bitrates(const SvcContext *svc_ctx, - vpx_codec_enc_cfg_t *const enc_cfg) { - int i; - const SvcInternal_t *const si = get_const_svc_internal(svc_ctx); - int sl, tl, spatial_layer_target; - - if (svc_ctx->temporal_layering_mode != 0) { - if (si->bitrates[0] != 0) { - enc_cfg->rc_target_bitrate = 0; - for (sl = 0; sl < svc_ctx->spatial_layers; ++sl) { - enc_cfg->ss_target_bitrate[sl*svc_ctx->temporal_layers] = 0; - for (tl = 0; tl < svc_ctx->temporal_layers; ++tl) { - enc_cfg->ss_target_bitrate[sl*svc_ctx->temporal_layers] - += (unsigned int)si->bitrates[sl * svc_ctx->temporal_layers + tl]; - enc_cfg->layer_target_bitrate[sl*svc_ctx->temporal_layers + tl] - = si->bitrates[sl * svc_ctx->temporal_layers + tl]; - } - } - } else { - float total = 0; - float alloc_ratio[VPX_MAX_LAYERS] = {0}; - - for (sl = 0; sl < svc_ctx->spatial_layers; ++sl) { - if (si->svc_params.scaling_factor_den[sl] > 0) { - alloc_ratio[sl] = (float)( pow(2, sl) ); - total += alloc_ratio[sl]; - } - } - - for (sl = 0; sl < svc_ctx->spatial_layers; ++sl) { - enc_cfg->ss_target_bitrate[sl] = spatial_layer_target = - (unsigned int)(enc_cfg->rc_target_bitrate * - alloc_ratio[sl] / total); - if (svc_ctx->temporal_layering_mode == 3) { - enc_cfg->layer_target_bitrate[sl * svc_ctx->temporal_layers] = - (spatial_layer_target*6)/10; // 60% - enc_cfg->layer_target_bitrate[sl * svc_ctx->temporal_layers + 1] = - (spatial_layer_target*8)/10; // 80% - enc_cfg->layer_target_bitrate[sl * svc_ctx->temporal_layers + 2] = - spatial_layer_target; - } else if (svc_ctx->temporal_layering_mode == 2 || - svc_ctx->temporal_layering_mode == 1) { - enc_cfg->layer_target_bitrate[sl * svc_ctx->temporal_layers] = - spatial_layer_target * 2 / 3; - enc_cfg->layer_target_bitrate[sl * svc_ctx->temporal_layers + 1] = - spatial_layer_target; - } else { - // User should explicitly assign bitrates in this case. - assert(0); - } - } - } - } else { - if (si->bitrates[0] != 0) { - enc_cfg->rc_target_bitrate = 0; - for (i = 0; i < svc_ctx->spatial_layers; ++i) { - enc_cfg->ss_target_bitrate[i] = (unsigned int)si->bitrates[i]; - enc_cfg->rc_target_bitrate += si->bitrates[i]; - } - } else { - float total = 0; - float alloc_ratio[VPX_MAX_LAYERS] = {0}; - - for (i = 0; i < svc_ctx->spatial_layers; ++i) { - if (si->svc_params.scaling_factor_den[i] > 0) { - alloc_ratio[i] = (float)(si->svc_params.scaling_factor_num[i] * 1.0 / - si->svc_params.scaling_factor_den[i]); - - alloc_ratio[i] *= alloc_ratio[i]; - total += alloc_ratio[i]; - } - } - for (i = 0; i < VPX_SS_MAX_LAYERS; ++i) { - if (total > 0) { - enc_cfg->layer_target_bitrate[i] = (unsigned int) - (enc_cfg->rc_target_bitrate * alloc_ratio[i] / total); - } - } - } - } -} - -vpx_codec_err_t vpx_svc_init(SvcContext *svc_ctx, vpx_codec_ctx_t *codec_ctx, - vpx_codec_iface_t *iface, - vpx_codec_enc_cfg_t *enc_cfg) { - vpx_codec_err_t res; - int i, sl , tl; - SvcInternal_t *const si = get_svc_internal(svc_ctx); - if (svc_ctx == NULL || codec_ctx == NULL || iface == NULL || - enc_cfg == NULL) { - return VPX_CODEC_INVALID_PARAM; - } - if (si == NULL) return VPX_CODEC_MEM_ERROR; - - si->codec_ctx = codec_ctx; - - si->width = enc_cfg->g_w; - si->height = enc_cfg->g_h; - - si->kf_dist = enc_cfg->kf_max_dist; - - if (svc_ctx->spatial_layers == 0) - svc_ctx->spatial_layers = VPX_SS_DEFAULT_LAYERS; - if (svc_ctx->spatial_layers < 1 || - svc_ctx->spatial_layers > VPX_SS_MAX_LAYERS) { - svc_log(svc_ctx, SVC_LOG_ERROR, "spatial layers: invalid value: %d\n", - svc_ctx->spatial_layers); - return VPX_CODEC_INVALID_PARAM; - } - - // Note: temporal_layering_mode only applies to one-pass CBR - // si->svc_params.temporal_layering_mode = svc_ctx->temporal_layering_mode; - if (svc_ctx->temporal_layering_mode == 3) { - svc_ctx->temporal_layers = 3; - } else if (svc_ctx->temporal_layering_mode == 2 || - svc_ctx->temporal_layering_mode == 1) { - svc_ctx->temporal_layers = 2; - } - - for (sl = 0; sl < VPX_SS_MAX_LAYERS; ++sl) { - si->svc_params.scaling_factor_num[sl] = DEFAULT_SCALE_FACTORS_NUM[sl]; - si->svc_params.scaling_factor_den[sl] = DEFAULT_SCALE_FACTORS_DEN[sl]; - } - for (tl = 0; tl < svc_ctx->temporal_layers; ++tl) { - for (sl = 0; sl < svc_ctx->spatial_layers; ++sl) { - i = sl * svc_ctx->temporal_layers + tl; - si->svc_params.max_quantizers[i] = MAX_QUANTIZER; - si->svc_params.min_quantizers[i] = 0; - } - } - - // Parse aggregate command line options. Options must start with - // "layers=xx" then followed by other options - res = parse_options(svc_ctx, si->options); - if (res != VPX_CODEC_OK) return res; - - if (svc_ctx->spatial_layers < 1) - svc_ctx->spatial_layers = 1; - if (svc_ctx->spatial_layers > VPX_SS_MAX_LAYERS) - svc_ctx->spatial_layers = VPX_SS_MAX_LAYERS; - - if (svc_ctx->temporal_layers < 1) - svc_ctx->temporal_layers = 1; - if (svc_ctx->temporal_layers > VPX_TS_MAX_LAYERS) - svc_ctx->temporal_layers = VPX_TS_MAX_LAYERS; - - if (svc_ctx->temporal_layers * svc_ctx->spatial_layers > VPX_MAX_LAYERS) { - svc_log(svc_ctx, SVC_LOG_ERROR, - "spatial layers * temporal layers exceeds the maximum number of " - "allowed layers of %d\n", - svc_ctx->spatial_layers * svc_ctx->temporal_layers, - (int) VPX_MAX_LAYERS); - return VPX_CODEC_INVALID_PARAM; - } - assign_layer_bitrates(svc_ctx, enc_cfg); - -#if CONFIG_SPATIAL_SVC - for (i = 0; i < svc_ctx->spatial_layers; ++i) - enc_cfg->ss_enable_auto_alt_ref[i] = si->enable_auto_alt_ref[i]; -#endif - - if (svc_ctx->temporal_layers > 1) { - int i; - for (i = 0; i < svc_ctx->temporal_layers; ++i) { - enc_cfg->ts_target_bitrate[i] = enc_cfg->rc_target_bitrate / - svc_ctx->temporal_layers; - enc_cfg->ts_rate_decimator[i] = 1 << (svc_ctx->temporal_layers - 1 - i); - } - } - - if (svc_ctx->threads) - enc_cfg->g_threads = svc_ctx->threads; - - // Modify encoder configuration - enc_cfg->ss_number_layers = svc_ctx->spatial_layers; - enc_cfg->ts_number_layers = svc_ctx->temporal_layers; - - if (enc_cfg->rc_end_usage == VPX_CBR) { - enc_cfg->rc_resize_allowed = 0; - enc_cfg->rc_min_quantizer = 2; - enc_cfg->rc_max_quantizer = 56; - enc_cfg->rc_undershoot_pct = 50; - enc_cfg->rc_overshoot_pct = 50; - enc_cfg->rc_buf_initial_sz = 500; - enc_cfg->rc_buf_optimal_sz = 600; - enc_cfg->rc_buf_sz = 1000; - enc_cfg->rc_dropframe_thresh = 0; - } - - if (enc_cfg->g_error_resilient == 0 && si->use_multiple_frame_contexts == 0) - enc_cfg->g_error_resilient = 1; - - // Initialize codec - res = vpx_codec_enc_init(codec_ctx, iface, enc_cfg, VPX_CODEC_USE_PSNR); - if (res != VPX_CODEC_OK) { - svc_log(svc_ctx, SVC_LOG_ERROR, "svc_enc_init error\n"); - return res; - } - if (svc_ctx->spatial_layers > 1 || svc_ctx->temporal_layers > 1) { - vpx_codec_control(codec_ctx, VP9E_SET_SVC, 1); - vpx_codec_control(codec_ctx, VP9E_SET_SVC_PARAMETERS, &si->svc_params); - } - return VPX_CODEC_OK; -} - -/** - * Encode a frame into multiple layers - * Create a superframe containing the individual layers - */ -vpx_codec_err_t vpx_svc_encode(SvcContext *svc_ctx, - vpx_codec_ctx_t *codec_ctx, - struct vpx_image *rawimg, - vpx_codec_pts_t pts, - int64_t duration, int deadline) { - vpx_codec_err_t res; - vpx_codec_iter_t iter; - const vpx_codec_cx_pkt_t *cx_pkt; - SvcInternal_t *const si = get_svc_internal(svc_ctx); - if (svc_ctx == NULL || codec_ctx == NULL || si == NULL) { - return VPX_CODEC_INVALID_PARAM; - } - - svc_log_reset(svc_ctx); - - res = vpx_codec_encode(codec_ctx, rawimg, pts, (uint32_t)duration, 0, - deadline); - if (res != VPX_CODEC_OK) { - return res; - } - // save compressed data - iter = NULL; - while ((cx_pkt = vpx_codec_get_cx_data(codec_ctx, &iter))) { - switch (cx_pkt->kind) { -#if VPX_ENCODER_ABI_VERSION > (5 + VPX_CODEC_ABI_VERSION) -#if CONFIG_SPATIAL_SVC - case VPX_CODEC_SPATIAL_SVC_LAYER_PSNR: { - int i; - for (i = 0; i < svc_ctx->spatial_layers; ++i) { - int j; - svc_log(svc_ctx, SVC_LOG_DEBUG, - "SVC frame: %d, layer: %d, PSNR(Total/Y/U/V): " - "%2.3f %2.3f %2.3f %2.3f \n", - si->psnr_pkt_received, i, - cx_pkt->data.layer_psnr[i].psnr[0], - cx_pkt->data.layer_psnr[i].psnr[1], - cx_pkt->data.layer_psnr[i].psnr[2], - cx_pkt->data.layer_psnr[i].psnr[3]); - svc_log(svc_ctx, SVC_LOG_DEBUG, - "SVC frame: %d, layer: %d, SSE(Total/Y/U/V): " - "%2.3f %2.3f %2.3f %2.3f \n", - si->psnr_pkt_received, i, - cx_pkt->data.layer_psnr[i].sse[0], - cx_pkt->data.layer_psnr[i].sse[1], - cx_pkt->data.layer_psnr[i].sse[2], - cx_pkt->data.layer_psnr[i].sse[3]); - - for (j = 0; j < COMPONENTS; ++j) { - si->psnr_sum[i][j] += - cx_pkt->data.layer_psnr[i].psnr[j]; - si->sse_sum[i][j] += cx_pkt->data.layer_psnr[i].sse[j]; - } - } - ++si->psnr_pkt_received; - break; - } - case VPX_CODEC_SPATIAL_SVC_LAYER_SIZES: { - int i; - for (i = 0; i < svc_ctx->spatial_layers; ++i) - si->bytes_sum[i] += cx_pkt->data.layer_sizes[i]; - break; - } -#endif -#endif - case VPX_CODEC_PSNR_PKT: - { -#if VPX_ENCODER_ABI_VERSION > (5 + VPX_CODEC_ABI_VERSION) - int j; - svc_log(svc_ctx, SVC_LOG_DEBUG, - "frame: %d, layer: %d, PSNR(Total/Y/U/V): " - "%2.3f %2.3f %2.3f %2.3f \n", - si->psnr_pkt_received, 0, - cx_pkt->data.layer_psnr[0].psnr[0], - cx_pkt->data.layer_psnr[0].psnr[1], - cx_pkt->data.layer_psnr[0].psnr[2], - cx_pkt->data.layer_psnr[0].psnr[3]); - for (j = 0; j < COMPONENTS; ++j) { - si->psnr_sum[0][j] += - cx_pkt->data.layer_psnr[0].psnr[j]; - si->sse_sum[0][j] += cx_pkt->data.layer_psnr[0].sse[j]; - } -#endif - } - ++si->psnr_pkt_received; - break; - default: { - break; - } - } - } - - return VPX_CODEC_OK; -} - -const char *vpx_svc_get_message(const SvcContext *svc_ctx) { - const SvcInternal_t *const si = get_const_svc_internal(svc_ctx); - if (svc_ctx == NULL || si == NULL) return NULL; - return si->message_buffer; -} - -static double calc_psnr(double d) { - if (d == 0) return 100; - return -10.0 * log(d) / log(10.0); -} - -// dump accumulated statistics and reset accumulated values -const char *vpx_svc_dump_statistics(SvcContext *svc_ctx) { - int number_of_frames; - int i, j; - uint32_t bytes_total = 0; - double scale[COMPONENTS]; - double psnr[COMPONENTS]; - double mse[COMPONENTS]; - double y_scale; - - SvcInternal_t *const si = get_svc_internal(svc_ctx); - if (svc_ctx == NULL || si == NULL) return NULL; - - svc_log_reset(svc_ctx); - - number_of_frames = si->psnr_pkt_received; - if (number_of_frames <= 0) return vpx_svc_get_message(svc_ctx); - - svc_log(svc_ctx, SVC_LOG_INFO, "\n"); - for (i = 0; i < svc_ctx->spatial_layers; ++i) { - - svc_log(svc_ctx, SVC_LOG_INFO, - "Layer %d Average PSNR=[%2.3f, %2.3f, %2.3f, %2.3f], Bytes=[%u]\n", - i, (double)si->psnr_sum[i][0] / number_of_frames, - (double)si->psnr_sum[i][1] / number_of_frames, - (double)si->psnr_sum[i][2] / number_of_frames, - (double)si->psnr_sum[i][3] / number_of_frames, si->bytes_sum[i]); - // the following psnr calculation is deduced from ffmpeg.c#print_report - y_scale = si->width * si->height * 255.0 * 255.0 * number_of_frames; - scale[1] = y_scale; - scale[2] = scale[3] = y_scale / 4; // U or V - scale[0] = y_scale * 1.5; // total - - for (j = 0; j < COMPONENTS; j++) { - psnr[j] = calc_psnr(si->sse_sum[i][j] / scale[j]); - mse[j] = si->sse_sum[i][j] * 255.0 * 255.0 / scale[j]; - } - svc_log(svc_ctx, SVC_LOG_INFO, - "Layer %d Overall PSNR=[%2.3f, %2.3f, %2.3f, %2.3f]\n", i, psnr[0], - psnr[1], psnr[2], psnr[3]); - svc_log(svc_ctx, SVC_LOG_INFO, - "Layer %d Overall MSE=[%2.3f, %2.3f, %2.3f, %2.3f]\n", i, mse[0], - mse[1], mse[2], mse[3]); - - bytes_total += si->bytes_sum[i]; - // Clear sums for next time. - si->bytes_sum[i] = 0; - for (j = 0; j < COMPONENTS; ++j) { - si->psnr_sum[i][j] = 0; - si->sse_sum[i][j] = 0; - } - } - - // only display statistics once - si->psnr_pkt_received = 0; - - svc_log(svc_ctx, SVC_LOG_INFO, "Total Bytes=[%u]\n", bytes_total); - return vpx_svc_get_message(svc_ctx); -} - -void vpx_svc_release(SvcContext *svc_ctx) { - SvcInternal_t *si; - if (svc_ctx == NULL) return; - // do not use get_svc_internal as it will unnecessarily allocate an - // SvcInternal_t if it was not already allocated - si = (SvcInternal_t *)svc_ctx->internal; - if (si != NULL) { - free(si); - svc_ctx->internal = NULL; - } -} - diff --git a/vpx/svc_context.h b/vpx/svc_context.h deleted file mode 100644 index 5bc25189b..000000000 --- a/vpx/svc_context.h +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (c) 2013 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. - */ - -/** - * SvcContext - input parameters and state to encode a multi-layered - * spatial SVC frame - */ - -#ifndef VPX_SVC_CONTEXT_H_ -#define VPX_SVC_CONTEXT_H_ - -#include "./vp8cx.h" -#include "./vpx_encoder.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef enum SVC_LOG_LEVEL { - SVC_LOG_ERROR, - SVC_LOG_INFO, - SVC_LOG_DEBUG -} SVC_LOG_LEVEL; - -typedef struct { - // public interface to svc_command options - int spatial_layers; // number of spatial layers - int temporal_layers; // number of temporal layers - int temporal_layering_mode; - SVC_LOG_LEVEL log_level; // amount of information to display - int log_print; // when set, printf log messages instead of returning the - // message with svc_get_message - int output_rc_stat; // for outputting rc stats - int speed; // speed setting for codec - int threads; - int aqmode; // turns on aq-mode=3 (cyclic_refresh): 0=off, 1=on. - // private storage for vpx_svc_encode - void *internal; -} SvcContext; - -#define OPTION_BUFFER_SIZE 1024 -#define COMPONENTS 4 // psnr & sse statistics maintained for total, y, u, v - -typedef struct SvcInternal { - char options[OPTION_BUFFER_SIZE]; // set by vpx_svc_set_options - - // values extracted from option, quantizers - vpx_svc_extra_cfg_t svc_params; - int enable_auto_alt_ref[VPX_SS_MAX_LAYERS]; - int bitrates[VPX_SS_MAX_LAYERS]; - - // accumulated statistics - double psnr_sum[VPX_SS_MAX_LAYERS][COMPONENTS]; // total/Y/U/V - uint64_t sse_sum[VPX_SS_MAX_LAYERS][COMPONENTS]; - uint32_t bytes_sum[VPX_SS_MAX_LAYERS]; - - // codec encoding values - int width; // width of highest layer - int height; // height of highest layer - int kf_dist; // distance between keyframes - - // state variables - int psnr_pkt_received; - int layer; - int use_multiple_frame_contexts; - - char message_buffer[2048]; - vpx_codec_ctx_t *codec_ctx; -} SvcInternal_t; - -/** - * Set SVC options - * options are supplied as a single string separated by spaces - * Format: encoding-mode= - * layers= - * scaling-factors=/,/,... - * quantizers=,,... - */ -vpx_codec_err_t vpx_svc_set_options(SvcContext *svc_ctx, const char *options); - -/** - * initialize SVC encoding - */ -vpx_codec_err_t vpx_svc_init(SvcContext *svc_ctx, - vpx_codec_ctx_t *codec_ctx, - vpx_codec_iface_t *iface, - vpx_codec_enc_cfg_t *cfg); -/** - * encode a frame of video with multiple layers - */ -vpx_codec_err_t vpx_svc_encode(SvcContext *svc_ctx, - vpx_codec_ctx_t *codec_ctx, - struct vpx_image *rawimg, - vpx_codec_pts_t pts, - int64_t duration, int deadline); - -/** - * finished with svc encoding, release allocated resources - */ -void vpx_svc_release(SvcContext *svc_ctx); - -/** - * dump accumulated statistics and reset accumulated values - */ -const char *vpx_svc_dump_statistics(SvcContext *svc_ctx); - -/** - * get status message from previous encode - */ -const char *vpx_svc_get_message(const SvcContext *svc_ctx); - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // VPX_SVC_CONTEXT_H_ diff --git a/vpx/vp8cx.h b/vpx/vp8cx.h index 8e9b7b7f1..954ad3295 100644 --- a/vpx/vp8cx.h +++ b/vpx/vp8cx.h @@ -301,17 +301,6 @@ enum vp8e_enc_control_id { */ VP9E_SET_GF_CBR_BOOST_PCT, - /*!\brief Codec control function to set the temporal layer id. - * - * For temporal scalability: this control allows the application to set the - * layer id for each frame to be encoded. Note that this control must be set - * for every frame prior to encoding. The usage of this control function - * supersedes the internal temporal pattern counter, which is now deprecated. - * - * Supported in codecs: VP8 - */ - VP8E_SET_TEMPORAL_LAYER_ID, - /*!\brief Codec control function to set encoder screen content mode. * * 0: off, 1: On, 2: On with more aggressive rate control. @@ -428,32 +417,6 @@ enum vp8e_enc_control_id { */ VP9E_SET_NOISE_SENSITIVITY, - /*!\brief Codec control function to turn on/off SVC in encoder. - * \note Return value is VPX_CODEC_INVALID_PARAM if the encoder does not - * support SVC in its current encoding mode - * 0: off, 1: on - * - * Supported in codecs: VP9 - */ - VP9E_SET_SVC, - - /*!\brief Codec control function to set parameters for SVC. - * \note Parameters contain min_q, max_q, scaling factor for each of the - * SVC layers. - * - * Supported in codecs: VP9 - */ - VP9E_SET_SVC_PARAMETERS, - - /*!\brief Codec control function to set svc layer for spatial and temporal. - * \note Valid ranges: 0..#vpx_codec_enc_cfg::ss_number_layers for spatial - * layer and 0..#vpx_codec_enc_cfg::ts_number_layers for - * temporal layer. - * - * Supported in codecs: VP9 - */ - VP9E_SET_SVC_LAYER_ID, - /*!\brief Codec control function to set content type. * \note Valid parameter range: * VPX_CONTENT_DEFAULT = Regular video content (Default) @@ -463,22 +426,6 @@ enum vp8e_enc_control_id { */ VP9E_SET_TUNE_CONTENT, - /*!\brief Codec control function to get svc layer ID. - * \note The layer ID returned is for the data packet from the registered - * callback function. - * - * Supported in codecs: VP9 - */ - VP9E_GET_SVC_LAYER_ID, - - /*!\brief Codec control function to register callback to get per layer packet. - * \note Parameter for this control function is a structure with a callback - * function and a pointer to private data used by the callback. - * - * Supported in codecs: VP9 - */ - VP9E_REGISTER_CX_CALLBACK, - /*!\brief Codec control function to set color space info. * \note Valid ranges: 0..7, default is "UNKNOWN". * 0 = UNKNOWN, @@ -494,17 +441,6 @@ enum vp8e_enc_control_id { */ VP9E_SET_COLOR_SPACE, - /*!\brief Codec control function to set temporal layering mode. - * \note Valid ranges: 0..3, default is "0" (VP9E_TEMPORAL_LAYERING_MODE_NOLAYERING). - * 0 = VP9E_TEMPORAL_LAYERING_MODE_NOLAYERING - * 1 = VP9E_TEMPORAL_LAYERING_MODE_BYPASS - * 2 = VP9E_TEMPORAL_LAYERING_MODE_0101 - * 3 = VP9E_TEMPORAL_LAYERING_MODE_0212 - * - * Supported in codecs: VP9 - */ - VP9E_SET_TEMPORAL_LAYERING_MODE, - /*!\brief Codec control function to set minimum interval between GF/ARF frames * * By default the value is set as 4. @@ -536,14 +472,6 @@ enum vp8e_enc_control_id { */ VP9E_SET_COLOR_RANGE, - /*!\brief Codec control function to set the frame flags and buffer indices - * for spatial layers. The frame flags and buffer indices are set using the - * struct #vpx_svc_ref_frame_config defined below. - * - * Supported in codecs: VP9 - */ - VP9E_SET_SVC_REF_FRAME_CONFIG, - /*!\brief Codec control function to set intended rendering image size. * * By default, this is identical to the image size in pixels. @@ -588,33 +516,6 @@ typedef enum vpx_scaling_mode_1d { VP8E_ONETWO = 3 } VPX_SCALING_MODE; -/*!\brief Temporal layering mode enum for VP9 SVC. - * - * This set of macros define the different temporal layering modes. - * Supported codecs: VP9 (in SVC mode) - * - */ -typedef enum vp9e_temporal_layering_mode { - /*!\brief No temporal layering. - * Used when only spatial layering is used. - */ - VP9E_TEMPORAL_LAYERING_MODE_NOLAYERING = 0, - - /*!\brief Bypass mode. - * Used when application needs to control temporal layering. - * This will only work when the number of spatial layers equals 1. - */ - VP9E_TEMPORAL_LAYERING_MODE_BYPASS = 1, - - /*!\brief 0-1-0-1... temporal layering scheme with two temporal layers. - */ - VP9E_TEMPORAL_LAYERING_MODE_0101 = 2, - - /*!\brief 0-2-1-2... temporal layering scheme with three temporal layers. - */ - VP9E_TEMPORAL_LAYERING_MODE_0212 = 3 -} VP9E_TEMPORAL_LAYERING_MODE; - /*!\brief vpx region of interest map * * These defines the data structures for the region of interest map @@ -689,33 +590,6 @@ typedef enum { VPX_TUNE_SSIM } vpx_tune_metric; -/*!\brief vp9 svc layer parameters - * - * This defines the spatial and temporal layer id numbers for svc encoding. - * This is used with the #VP9E_SET_SVC_LAYER_ID control to set the spatial and - * temporal layer id for the current frame. - * - */ -typedef struct vpx_svc_layer_id { - int spatial_layer_id; /**< Spatial layer id number. */ - int temporal_layer_id; /**< Temporal layer id number. */ -} vpx_svc_layer_id_t; - -/*!\brief vp9 svc frame flag parameters. - * - * This defines the frame flags and buffer indices for each spatial layer for - * svc encoding. - * This is used with the #VP9E_SET_SVC_REF_FRAME_CONFIG control to set frame - * flags and buffer indices for each spatial layer for the current (super)frame. - * - */ -typedef struct vpx_svc_ref_frame_config { - int frame_flags[VPX_TS_MAX_LAYERS]; /**< Frame flags. */ - int lst_fb_idx[VPX_TS_MAX_LAYERS]; /**< Last buffer index. */ - int gld_fb_idx[VPX_TS_MAX_LAYERS]; /**< Golden buffer index. */ - int alt_fb_idx[VPX_TS_MAX_LAYERS]; /**< Altref buffer index. */ -} vpx_svc_ref_frame_config_t; - /*!\cond */ /*!\brief VP8 encoder control function parameter type * @@ -728,8 +602,6 @@ VPX_CTRL_USE_TYPE_DEPRECATED(VP8E_USE_REFERENCE, int) #define VPX_CTRL_VP8E_USE_REFERENCE VPX_CTRL_USE_TYPE(VP8E_SET_FRAME_FLAGS, int) #define VPX_CTRL_VP8E_SET_FRAME_FLAGS -VPX_CTRL_USE_TYPE(VP8E_SET_TEMPORAL_LAYER_ID, int) -#define VPX_CTRL_VP8E_SET_TEMPORAL_LAYER_ID VPX_CTRL_USE_TYPE(VP8E_SET_ROI_MAP, vpx_roi_map_t *) #define VPX_CTRL_VP8E_SET_ROI_MAP VPX_CTRL_USE_TYPE(VP8E_SET_ACTIVEMAP, vpx_active_map_t *) @@ -737,15 +609,6 @@ VPX_CTRL_USE_TYPE(VP8E_SET_ACTIVEMAP, vpx_active_map_t *) VPX_CTRL_USE_TYPE(VP8E_SET_SCALEMODE, vpx_scaling_mode_t *) #define VPX_CTRL_VP8E_SET_SCALEMODE -VPX_CTRL_USE_TYPE(VP9E_SET_SVC, int) -#define VPX_CTRL_VP9E_SET_SVC -VPX_CTRL_USE_TYPE(VP9E_SET_SVC_PARAMETERS, void *) -#define VPX_CTRL_VP9E_SET_SVC_PARAMETERS -VPX_CTRL_USE_TYPE(VP9E_REGISTER_CX_CALLBACK, void *) -#define VPX_CTRL_VP9E_REGISTER_CX_CALLBACK -VPX_CTRL_USE_TYPE(VP9E_SET_SVC_LAYER_ID, vpx_svc_layer_id_t *) -#define VPX_CTRL_VP9E_SET_SVC_LAYER_ID - VPX_CTRL_USE_TYPE(VP8E_SET_CPUUSED, int) #define VPX_CTRL_VP8E_SET_CPUUSED VPX_CTRL_USE_TYPE(VP8E_SET_ENABLEAUTOALTREF, unsigned int) @@ -785,8 +648,6 @@ VPX_CTRL_USE_TYPE(VP8E_GET_LAST_QUANTIZER, int *) #define VPX_CTRL_VP8E_GET_LAST_QUANTIZER VPX_CTRL_USE_TYPE(VP8E_GET_LAST_QUANTIZER_64, int *) #define VPX_CTRL_VP8E_GET_LAST_QUANTIZER_64 -VPX_CTRL_USE_TYPE(VP9E_GET_SVC_LAYER_ID, vpx_svc_layer_id_t *) -#define VPX_CTRL_VP9E_GET_SVC_LAYER_ID VPX_CTRL_USE_TYPE(VP8E_SET_MAX_INTRA_BITRATE_PCT, unsigned int) #define VPX_CTRL_VP8E_SET_MAX_INTRA_BITRATE_PCT @@ -832,9 +693,6 @@ VPX_CTRL_USE_TYPE(VP9E_GET_ACTIVEMAP, vpx_active_map_t *) VPX_CTRL_USE_TYPE(VP9E_SET_COLOR_RANGE, int) #define VPX_CTRL_VP9E_SET_COLOR_RANGE -VPX_CTRL_USE_TYPE(VP9E_SET_SVC_REF_FRAME_CONFIG, vpx_svc_ref_frame_config_t *) -#define VPX_CTRL_VP9E_SET_SVC_REF_FRAME_CONFIG - /*!\brief * * TODO(rbultje) : add support of the control in ffmpeg diff --git a/vpx/vpx_encoder.h b/vpx/vpx_encoder.h index 955e87351..9a0f48ef8 100644 --- a/vpx/vpx_encoder.h +++ b/vpx/vpx_encoder.h @@ -31,29 +31,6 @@ extern "C" { #include "./vpx_codec.h" - /*! Temporal Scalability: Maximum length of the sequence defining frame - * layer membership - */ -#define VPX_TS_MAX_PERIODICITY 16 - - /*! Temporal Scalability: Maximum number of coding layers */ -#define VPX_TS_MAX_LAYERS 5 - - /*!\deprecated Use #VPX_TS_MAX_PERIODICITY instead. */ -#define MAX_PERIODICITY VPX_TS_MAX_PERIODICITY - -/*! Temporal+Spatial Scalability: Maximum number of coding layers */ -#define VPX_MAX_LAYERS 12 // 3 temporal + 4 spatial layers are allowed. - -/*!\deprecated Use #VPX_MAX_LAYERS instead. */ -#define MAX_LAYERS VPX_MAX_LAYERS // 3 temporal + 4 spatial layers allowed. - -/*! Spatial Scalability: Maximum number of coding layers */ -#define VPX_SS_MAX_LAYERS 5 - -/*! Spatial Scalability: Default number of coding layers */ -#define VPX_SS_DEFAULT_LAYERS 1 - /*!\brief Current ABI version number * * \internal @@ -164,12 +141,6 @@ extern "C" { VPX_CODEC_STATS_PKT, /**< Two-pass statistics for this frame */ VPX_CODEC_FPMB_STATS_PKT, /**< first pass mb statistics for this frame */ VPX_CODEC_PSNR_PKT, /**< PSNR statistics for this frame */ - // Spatial SVC is still experimental and may be removed before the next ABI - // bump. -#if VPX_ENCODER_ABI_VERSION > (5 + VPX_CODEC_ABI_VERSION) - VPX_CODEC_SPATIAL_SVC_LAYER_SIZES, /**< Sizes for each layer in this frame*/ - VPX_CODEC_SPATIAL_SVC_LAYER_PSNR, /**< PSNR for each layer in this frame*/ -#endif VPX_CODEC_CUSTOM_PKT = 256 /**< Algorithm extensions */ }; @@ -206,12 +177,6 @@ extern "C" { double psnr[4]; /**< PSNR, total/y/u/v */ } psnr; /**< data for PSNR packet */ vpx_fixed_buf_t raw; /**< data for arbitrary packets */ - // Spatial SVC is still experimental and may be removed before the next - // ABI bump. -#if VPX_ENCODER_ABI_VERSION > (5 + VPX_CODEC_ABI_VERSION) - size_t layer_sizes[VPX_SS_MAX_LAYERS]; - struct vpx_psnr_pkt layer_psnr[VPX_SS_MAX_LAYERS]; -#endif /* This packet size is fixed to allow codecs to extend this * interface without having to manage storage for raw packets, @@ -222,23 +187,6 @@ extern "C" { } data; /**< packet data */ } vpx_codec_cx_pkt_t; /**< alias for struct vpx_codec_cx_pkt */ - - /*!\brief Encoder return output buffer callback - * - * This callback function, when registered, returns with packets when each - * spatial layer is encoded. - */ - // putting the definitions here for now. (agrange: find if there - // is a better place for this) - typedef void (* vpx_codec_enc_output_cx_pkt_cb_fn_t)(vpx_codec_cx_pkt_t *pkt, - void *user_data); - - /*!\brief Callback function pointer / user data pair storage */ - typedef struct vpx_codec_enc_output_cx_cb_pair { - vpx_codec_enc_output_cx_pkt_cb_fn_t output_cx_pkt; /**< Callback function */ - void *user_priv; /**< Pointer to private data */ - } vpx_codec_priv_output_cx_pkt_cb_pair_t; - /*!\brief Rational Number * * This structure holds a fractional value. @@ -670,100 +618,8 @@ extern "C" { * equal to kf_max_dist for a fixed interval. */ unsigned int kf_max_dist; - - /* - * Spatial scalability settings (ss) - */ - - /*!\brief Number of spatial coding layers. - * - * This value specifies the number of spatial coding layers to be used. - */ - unsigned int ss_number_layers; - - /*!\brief Enable auto alt reference flags for each spatial layer. - * - * These values specify if auto alt reference frame is enabled for each - * spatial layer. - */ - int ss_enable_auto_alt_ref[VPX_SS_MAX_LAYERS]; - - /*!\brief Target bitrate for each spatial layer. - * - * These values specify the target coding bitrate to be used for each - * spatial layer. - */ - unsigned int ss_target_bitrate[VPX_SS_MAX_LAYERS]; - - /*!\brief Number of temporal coding layers. - * - * This value specifies the number of temporal layers to be used. - */ - unsigned int ts_number_layers; - - /*!\brief Target bitrate for each temporal layer. - * - * These values specify the target coding bitrate to be used for each - * temporal layer. - */ - unsigned int ts_target_bitrate[VPX_TS_MAX_LAYERS]; - - /*!\brief Frame rate decimation factor for each temporal layer. - * - * These values specify the frame rate decimation factors to apply - * to each temporal layer. - */ - unsigned int ts_rate_decimator[VPX_TS_MAX_LAYERS]; - - /*!\brief Length of the sequence defining frame temporal layer membership. - * - * This value specifies the length of the sequence that defines the - * membership of frames to temporal layers. For example, if the - * ts_periodicity = 8, then the frames are assigned to coding layers with a - * repeated sequence of length 8. - */ - unsigned int ts_periodicity; - - /*!\brief Template defining the membership of frames to temporal layers. - * - * This array defines the membership of frames to temporal coding layers. - * For a 2-layer encoding that assigns even numbered frames to one temporal - * layer (0) and odd numbered frames to a second temporal layer (1) with - * ts_periodicity=8, then ts_layer_id = (0,1,0,1,0,1,0,1). - */ - unsigned int ts_layer_id[VPX_TS_MAX_PERIODICITY]; - - /*!\brief Target bitrate for each spatial/temporal layer. - * - * These values specify the target coding bitrate to be used for each - * spatial/temporal layer. - * - */ - unsigned int layer_target_bitrate[VPX_MAX_LAYERS]; - - /*!\brief Temporal layering mode indicating which temporal layering scheme to use. - * - * The value (refer to VP9E_TEMPORAL_LAYERING_MODE) specifies the - * temporal layering mode to use. - * - */ - int temporal_layering_mode; } vpx_codec_enc_cfg_t; /**< alias for struct vpx_codec_enc_cfg */ - /*!\brief vp9 svc extra configure parameters - * - * This defines max/min quantizers and scale factors for each layer - * - */ - typedef struct vpx_svc_parameters { - int max_quantizers[VPX_MAX_LAYERS]; /**< Max Q for each layer */ - int min_quantizers[VPX_MAX_LAYERS]; /**< Min Q for each layer */ - int scaling_factor_num[VPX_MAX_LAYERS]; /**< Scaling factor-numerator */ - int scaling_factor_den[VPX_MAX_LAYERS]; /**< Scaling factor-denominator */ - int temporal_layering_mode; /**< Temporal layering mode */ - } vpx_svc_extra_cfg_t; - - /*!\brief Initialize an encoder instance * * Initializes a encoder context using the given interface. Applications