From 4bf8ef724b9313529a7c4c70eb6595dfcdf5811e Mon Sep 17 00:00:00 2001 From: Sreerenj Balachandran Date: Tue, 9 Aug 2016 15:53:47 +0300 Subject: [PATCH] libs: encoder: vp9: Adds CBR and VBR Encoding support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://bugzilla.gnome.org/show_bug.cgi?id=766832 Signed-off-by: Hyunjun Ko Signed-off-by: Víctor Manuel Jáquez Leal --- gst-libs/gst/vaapi/gstvaapiencoder_vp9.c | 100 ++++++++++++++++++++++- gst-libs/gst/vaapi/gstvaapiencoder_vp9.h | 4 +- 2 files changed, 102 insertions(+), 2 deletions(-) diff --git a/gst-libs/gst/vaapi/gstvaapiencoder_vp9.c b/gst-libs/gst/vaapi/gstvaapiencoder_vp9.c index 8bb9f2307c..f4d93113bd 100644 --- a/gst-libs/gst/vaapi/gstvaapiencoder_vp9.c +++ b/gst-libs/gst/vaapi/gstvaapiencoder_vp9.c @@ -39,7 +39,9 @@ /* Supported set of VA rate controls, within this implementation */ #define SUPPORTED_RATECONTROLS \ - (GST_VAAPI_RATECONTROL_MASK (CQP)) + (GST_VAAPI_RATECONTROL_MASK (CQP) | \ + GST_VAAPI_RATECONTROL_MASK (CBR) | \ + GST_VAAPI_RATECONTROL_MASK (VBR)) /* Supported set of tuning options, within this implementation */ #define SUPPORTED_TUNE_OPTIONS \ @@ -56,6 +58,9 @@ #define MAX_FRAME_WIDTH 4096 #define MAX_FRAME_HEIGHT 4096 +/* Default CPB length (in milliseconds) */ +#define DEFAULT_CPB_LENGTH 1500 + typedef enum { GST_VAAPI_ENCODER_VP9_REF_PIC_MODE_0 = 0, @@ -101,8 +106,47 @@ struct _GstVaapiEncoderVP9 guint frame_num; GstVaapiSurfaceProxy *ref_list[GST_VP9_REF_FRAMES]; /* reference list */ guint ref_list_idx; /* next free slot in ref_list */ + + /* Bitrate contral parameters, CPB = Coded Picture Buffer */ + guint bitrate_bits; /* bitrate (bits) */ + guint cpb_length; /* length of CPB buffer (ms) */ }; +/* Estimates a good enough bitrate if none was supplied */ +static void +ensure_bitrate (GstVaapiEncoderVP9 * encoder) +{ + GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder); + guint bitrate; + + switch (GST_VAAPI_ENCODER_RATE_CONTROL (encoder)) { + case GST_VAAPI_RATECONTROL_CBR: + case GST_VAAPI_RATECONTROL_VBR: + if (!base_encoder->bitrate) { + /* FIXME: Provide better estimation */ + /* Using a 1/6 compression ratio */ + /* 12 bits per pixel fro yuv420 */ + base_encoder->bitrate = + (GST_VAAPI_ENCODER_WIDTH (encoder) * + GST_VAAPI_ENCODER_HEIGHT (encoder) * 12 / 6) * + GST_VAAPI_ENCODER_FPS_N (encoder) / + GST_VAAPI_ENCODER_FPS_D (encoder) / 1000; + GST_INFO ("target bitrate computed to %u kbps", base_encoder->bitrate); + } + + bitrate = (base_encoder->bitrate * 1000); + if (bitrate != encoder->bitrate_bits) { + GST_DEBUG ("HRD bitrate: %u bits/sec", bitrate); + encoder->bitrate_bits = bitrate; + } + + break; + default: + base_encoder->bitrate = 0; + break; + } +} + /* Derives the profile that suits best to the configuration */ static GstVaapiEncoderStatus ensure_profile (GstVaapiEncoderVP9 * encoder) @@ -110,6 +154,9 @@ ensure_profile (GstVaapiEncoderVP9 * encoder) /* Always start from "simple" profile for maximum compatibility */ encoder->profile = GST_VAAPI_PROFILE_VP9_0; + /* Ensure bitrate if not set already */ + ensure_bitrate (encoder); + return GST_VAAPI_ENCODER_STATUS_SUCCESS; } @@ -182,6 +229,7 @@ fill_sequence (GstVaapiEncoderVP9 * encoder, GstVaapiEncSequence * sequence) /* keyframe maximum interval */ seq_param->kf_max_dist = base_encoder->keyframe_period; seq_param->intra_period = base_encoder->keyframe_period; + seq_param->bits_per_second = encoder->bitrate_bits; return TRUE; } @@ -215,6 +263,36 @@ error: } } +static gboolean +ensure_control_rate_params (GstVaapiEncoderVP9 * encoder) +{ + if (GST_VAAPI_ENCODER_RATE_CONTROL (encoder) == GST_VAAPI_RATECONTROL_CQP) + return TRUE; + + /* *INDENT-OFF* */ + /* RateControl params */ + GST_VAAPI_ENCODER_VA_RATE_CONTROL (encoder) = (VAEncMiscParameterRateControl) { + .bits_per_second = encoder->bitrate_bits, + .target_percentage = 70, + .window_size = encoder->cpb_length, + }; + + /* HRD params */ + GST_VAAPI_ENCODER_VA_HRD (encoder) = (VAEncMiscParameterHRD) { + .buffer_size = encoder->bitrate_bits * 2, + .initial_buffer_fullness = encoder->bitrate_bits, + }; + + /* FrameRate params */ + GST_VAAPI_ENCODER_VA_FRAME_RATE (encoder) = (VAEncMiscParameterFrameRate) { + .framerate = (guint) GST_VAAPI_ENCODER_FPS_D (encoder) << 16 | + GST_VAAPI_ENCODER_FPS_N (encoder), + }; + /* *INDENT-ON* */ + + return TRUE; +} + static gboolean ensure_misc_params (GstVaapiEncoderVP9 * encoder, GstVaapiEncPicture * picture) { @@ -222,6 +300,8 @@ ensure_misc_params (GstVaapiEncoderVP9 * encoder, GstVaapiEncPicture * picture) if (!gst_vaapi_encoder_ensure_param_quality_level (base_encoder, picture)) return FALSE; + if (!gst_vaapi_encoder_ensure_param_control_rate (base_encoder, picture)) + return FALSE; return TRUE; } @@ -439,6 +519,7 @@ gst_vaapi_encoder_vp9_reconfigure (GstVaapiEncoder * base_encoder) if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS) return status; + ensure_control_rate_params (encoder); return set_context_info (base_encoder); } @@ -451,6 +532,7 @@ gst_vaapi_encoder_vp9_init (GstVaapiEncoder * base_encoder) encoder->loop_filter_level = DEFAULT_LOOP_FILTER_LEVEL; encoder->sharpness_level = DEFAULT_SHARPNESS_LEVEL; encoder->yac_qi = DEFAULT_YAC_QINDEX; + encoder->cpb_length = DEFAULT_CPB_LENGTH; memset (encoder->ref_list, 0, G_N_ELEMENTS (encoder->ref_list) * sizeof (encoder->ref_list[0])); @@ -483,6 +565,9 @@ gst_vaapi_encoder_vp9_set_property (GstVaapiEncoder * base_encoder, case GST_VAAPI_ENCODER_VP9_PROP_REF_PIC_MODE: encoder->ref_pic_mode = g_value_get_enum (value); break; + case GST_VAAPI_ENCODER_VP9_PROP_CPB_LENGTH: + encoder->cpb_length = g_value_get_uint (value); + break; default: return GST_VAAPI_ENCODER_STATUS_ERROR_INVALID_PARAMETER; } @@ -569,6 +654,19 @@ gst_vaapi_encoder_vp9_get_default_properties (void) GST_VAAPI_ENCODER_VP9_REF_PIC_MODE_0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** + * GstVaapiEncoderVP9:cpb-length: + * + * The size of the Coded Picture Buffer , which means + * the window size in milliseconds. + * + */ + GST_VAAPI_ENCODER_PROPERTIES_APPEND (props, + GST_VAAPI_ENCODER_VP9_PROP_CPB_LENGTH, + g_param_spec_uint ("cpb-length", + "CPB Length", "Length of the CPB_buffer/window_size in milliseconds", + 1, 10000, DEFAULT_CPB_LENGTH, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); return props; } diff --git a/gst-libs/gst/vaapi/gstvaapiencoder_vp9.h b/gst-libs/gst/vaapi/gstvaapiencoder_vp9.h index 2ddcbd40d6..7967a98002 100644 --- a/gst-libs/gst/vaapi/gstvaapiencoder_vp9.h +++ b/gst-libs/gst/vaapi/gstvaapiencoder_vp9.h @@ -38,6 +38,7 @@ typedef struct _GstVaapiEncoderVP9 GstVaapiEncoderVP9; * @GST_VAAPI_ENCODER_VP9_PROP_LOOP_SHARPNESS_LEVEL: Sharpness Level(uint). * @GST_VAAPI_ENCODER_VP9_PROP_YAC_Q_INDEX: Quantization table index for luma AC * @GST_VAAPI_ENCODER_VP9_PROP_REF_PIC_MODE: Reference picute selection modes + * @GST_VAAPI_ENCODER_VP9_PROP_CPB_LENGTH:Length of CPB buffer in milliseconds * * The set of VP9 encoder specific configurable properties. */ @@ -45,7 +46,8 @@ typedef enum { GST_VAAPI_ENCODER_VP9_PROP_LOOP_FILTER_LEVEL = -1, GST_VAAPI_ENCODER_VP9_PROP_SHARPNESS_LEVEL = -2, GST_VAAPI_ENCODER_VP9_PROP_YAC_Q_INDEX = -3, - GST_VAAPI_ENCODER_VP9_PROP_REF_PIC_MODE = -4 + GST_VAAPI_ENCODER_VP9_PROP_REF_PIC_MODE = -4, + GST_VAAPI_ENCODER_VP9_PROP_CPB_LENGTH = -5 } GstVaapiEncoderVP9Prop; GstVaapiEncoder *