x264enc: Add speed-preset and [psy-]tuning properties

Use of a rate control method (pass, bitrate, quantizer, etc properties), a
preset and possibly a profile and/or tuning are now the recommended way to
configure x264 through x264enc.

If a preset/tuning are specified then these will define the default values and
the property defaults will be ignored. After this the option-string property is
applied, followed by the user-set properties, fast first pass restrictions and
finally the profile restrictions.

Addresses part of bug #607798
This commit is contained in:
Robert Swain 2010-07-21 17:09:20 +02:00
parent f269e0679f
commit b27ce43ab8
2 changed files with 209 additions and 8 deletions

View file

@ -41,6 +41,11 @@
* most players and settings, but in some cases (e.g. hardware platforms)
* a more restricted profile/level may be necessary.
*
* If a preset/tuning are specified then these will define the default values and
* the property defaults will be ignored. After this the option-string property is
* applied, followed by the user-set properties, fast first pass restrictions and
* finally the profile restrictions.
*
* <refsect2>
* <title>Example pipeline</title>
* |[
@ -54,6 +59,13 @@
* matroskamux ! filesink location=videotestsrc.avi
* ]| This example pipeline will encode a test video source to H264 using fixed
* quantization, and muxes it in a Matroska container.
* |[
* gst-launch -v videotestsrc num-buffers=1000 ! x264enc pass=5 quantizer=25 speed-preset=6 profile=1 ! \
* qtmux ! filesink location=videotestsrc.mov
* ]| This example pipeline will encode a test video source to H264 using
* constant quality at around Q25 using the 'medium' speed/quality preset and
* restricting the options used so that the output is H.264 Baseline Profile
* compliant and finally multiplexing the output in Quicktime mov format.
* </refsect2>
*/
@ -128,6 +140,9 @@ enum
ARG_INTERLACED,
ARG_OPTION_STRING,
ARG_PROFILE,
ARG_SPEED_PRESET,
ARG_PSY_TUNE,
ARG_TUNE,
};
#define ARG_THREADS_DEFAULT 1
@ -167,6 +182,9 @@ enum
#define ARG_PROFILE_DEFAULT 1 /* Main profile matches current defaults */
#define ARG_OPTION_STRING_DEFAULT ""
static GString *x264enc_defaults;
#define ARG_SPEED_PRESET_DEFAULT 0 /* no preset */
#define ARG_PSY_TUNE_DEFAULT 0 /* no psy tuning */
#define ARG_TUNE_DEFAULT 0 /* no tuning */
enum
{
@ -282,6 +300,120 @@ gst_x264_enc_profile_get_type (void)
return profile_type;
}
#define GST_X264_ENC_SPEED_PRESET_TYPE (gst_x264_enc_speed_preset_get_type())
static GType
gst_x264_enc_speed_preset_get_type (void)
{
static GType speed_preset_type = 0;
static GEnumValue *speed_preset_types;
int n, i;
if (speed_preset_type != 0)
return speed_preset_type;
n = 0;
while (x264_preset_names[n] != NULL)
n++;
speed_preset_types = g_new0 (GEnumValue, n + 2);
speed_preset_types[0].value = 0;
speed_preset_types[0].value_name = "No preset";
speed_preset_types[0].value_nick = "None";
for (i = 1; i <= n; i++) {
speed_preset_types[i].value = i;
speed_preset_types[i].value_name = x264_preset_names[i - 1];
speed_preset_types[i].value_nick = x264_preset_names[i - 1];
}
speed_preset_type =
g_enum_register_static ("GstX264EncPreset", speed_preset_types);
return speed_preset_type;
}
static const GFlagsValue tune_types[] = {
{0x0, "No tuning", "none"},
{0x1, "Still image", "stillimage"},
{0x2, "Fast decode", "fastdecode"},
{0x4, "Zero latency", "zerolatency"},
{0, NULL, NULL},
};
#define GST_X264_ENC_TUNE_TYPE (gst_x264_enc_tune_get_type())
static GType
gst_x264_enc_tune_get_type (void)
{
static GType tune_type = 0;
if (!tune_type) {
tune_type = g_flags_register_static ("GstX264EncTune", tune_types);
}
return tune_type;
}
enum
{
GST_X264_ENC_TUNE_NONE,
GST_X264_ENC_TUNE_FILM,
GST_X264_ENC_TUNE_ANIMATION,
GST_X264_ENC_TUNE_GRAIN,
GST_X264_ENC_TUNE_PSNR,
GST_X264_ENC_TUNE_SSIM,
GST_X264_ENC_TUNE_LAST
};
static const GEnumValue psy_tune_types[] = {
{GST_X264_ENC_TUNE_NONE, "No tuning", "none"},
{GST_X264_ENC_TUNE_FILM, "Film", "film"},
{GST_X264_ENC_TUNE_ANIMATION, "Animation", "animation"},
{GST_X264_ENC_TUNE_GRAIN, "Grain", "grain"},
{GST_X264_ENC_TUNE_PSNR, "PSNR", "psnr"},
{GST_X264_ENC_TUNE_SSIM, "SSIM", "ssim"},
{0, NULL, NULL},
};
#define GST_X264_ENC_PSY_TUNE_TYPE (gst_x264_enc_psy_tune_get_type())
static GType
gst_x264_enc_psy_tune_get_type (void)
{
static GType psy_tune_type = 0;
if (!psy_tune_type) {
psy_tune_type =
g_enum_register_static ("GstX264EncPsyTune", psy_tune_types);
}
return psy_tune_type;
}
static void
gst_x264_enc_build_tunings_string (GstX264Enc * x264enc)
{
int i = 1;
if (x264enc->tunings && x264enc->tunings->len)
g_string_free (x264enc->tunings, TRUE);
if (x264enc->psy_tune) {
x264enc->tunings =
g_string_new (psy_tune_types[x264enc->psy_tune].value_nick);
} else {
x264enc->tunings = g_string_new (NULL);
}
while (tune_types[i].value_name) {
if (x264enc->tune & (1 << (i - 1)))
g_string_append_printf (x264enc->tunings, "%s%s",
x264enc->tunings->len ? "," : "", tune_types[i].value_nick);
i++;
}
if (x264enc->tunings->len)
GST_DEBUG_OBJECT (x264enc, "Constructed tunings string: %s",
x264enc->tunings->str);
}
#endif
@ -419,6 +551,20 @@ gst_x264_enc_class_init (GstX264EncClass * klass)
300, 10000, ARG_VBV_BUF_CAPACITY_DEFAULT, G_PARAM_READWRITE));
#ifdef X264_PRESETS
g_object_class_install_property (gobject_class, ARG_SPEED_PRESET,
g_param_spec_enum ("speed-preset", "Speed/quality preset",
"Preset name for speed/quality tradeoff options (can affect decode "
"compatibility - impose restrictions separately for your target decoder)",
GST_X264_ENC_SPEED_PRESET_TYPE, ARG_SPEED_PRESET_DEFAULT,
G_PARAM_READWRITE));
g_object_class_install_property (gobject_class, ARG_PSY_TUNE,
g_param_spec_enum ("psy-tune", "Psychovisual tuning preset",
"Preset name for psychovisual tuning options",
GST_X264_ENC_PSY_TUNE_TYPE, ARG_PSY_TUNE_DEFAULT, G_PARAM_READWRITE));
g_object_class_install_property (gobject_class, ARG_TUNE,
g_param_spec_flags ("tune", "Content tuning preset",
"Preset name for non-psychovisual tuning options",
GST_X264_ENC_TUNE_TYPE, ARG_TUNE_DEFAULT, G_PARAM_READWRITE));
g_object_class_install_property (gobject_class, ARG_PROFILE,
g_param_spec_enum ("profile", "H.264 profile",
"Apply restrictions to meet H.264 Profile constraints. This will "
@ -700,6 +846,9 @@ gst_x264_enc_init (GstX264Enc * encoder, GstX264EncClass * klass)
encoder->profile = ARG_PROFILE_DEFAULT;
encoder->option_string = g_string_new (NULL);
encoder->option_string_prop = g_string_new (ARG_OPTION_STRING_DEFAULT);
encoder->speed_preset = ARG_SPEED_PRESET_DEFAULT;
encoder->psy_tune = ARG_PSY_TUNE_DEFAULT;
encoder->tune = ARG_TUNE_DEFAULT;
/* resources */
encoder->delay = g_queue_new ();
@ -740,6 +889,7 @@ gst_x264_enc_finalize (GObject * object)
if (ptr) \
ptr = (GString *)g_string_free (ptr, TRUE);
FREE_STRING (encoder->tunings);
FREE_STRING (encoder->option_string);
FREE_STRING (encoder->option_string_prop);
@ -822,20 +972,49 @@ gst_x264_enc_init_encoder (GstX264Enc * encoder)
GST_OBJECT_LOCK (encoder);
#ifdef X264_PRESETS
gst_x264_enc_build_tunings_string (encoder);
/* set x264 parameters and use preset/tuning if present */
GST_DEBUG_OBJECT (encoder, "Applying defaults with preset %s, tunings %s",
encoder->speed_preset ? x264_preset_names[encoder->speed_preset - 1] : "",
encoder->tunings && encoder->tunings->len ? encoder->tunings->str : "");
x264_param_default_preset (&encoder->x264param,
encoder->speed_preset ? x264_preset_names[encoder->speed_preset -
1] : NULL, encoder->tunings
&& encoder->tunings->len ? encoder->tunings->str : NULL);
/* log callback setup; part of parameters
* this needs to be done again after every *param_default* () call */
encoder->x264param.pf_log = gst_x264_enc_log_callback;
encoder->x264param.p_log_private = encoder;
encoder->x264param.i_log_level = X264_LOG_DEBUG;
/* if no preset nor tuning, use property defaults */
if (!encoder->speed_preset && !encoder->tunings->len) {
#endif /* X264_PRESETS */
GST_DEBUG_OBJECT (encoder, "Applying x264enc_defaults");
if (x264enc_defaults->len
&& gst_x264_enc_parse_options (encoder,
x264enc_defaults->str) == FALSE) {
GST_DEBUG_OBJECT (encoder,
"x264enc_defaults string contains errors. This is a bug.");
goto unlock_and_return;
}
#ifdef X264_PRESETS
} else {
/* When using presets we need to respect the default output format */
encoder->x264param.b_aud = encoder->au_nalu;
encoder->x264param.b_annexb = encoder->byte_stream;
}
#endif /* X264_PRESETS */
#if X264_BUILD >= 81
/* setup appropriate timebase for gstreamer */
encoder->x264param.i_timebase_num = 1;
encoder->x264param.i_timebase_den = 1000000000;
#endif
GST_DEBUG_OBJECT (encoder, "Applying x264enc_defaults");
if (x264enc_defaults->len
&& gst_x264_enc_parse_options (encoder, x264enc_defaults->str) == FALSE) {
GST_DEBUG_OBJECT (encoder,
"x264enc_defaults string contains errors. This is a bug.");
goto unlock_and_return;
}
/* apply user set properties */
if (encoder->option_string_prop && encoder->option_string_prop->len
&& gst_x264_enc_parse_options (encoder,
@ -1508,6 +1687,15 @@ gst_x264_enc_set_property (GObject * object, guint prop_id,
case ARG_VBV_BUF_CAPACITY:
encoder->vbv_buf_capacity = g_value_get_uint (value);
break;
case ARG_SPEED_PRESET:
encoder->speed_preset = g_value_get_enum (value);
break;
case ARG_PSY_TUNE:
encoder->psy_tune = g_value_get_enum (value);
break;
case ARG_TUNE:
encoder->tune = g_value_get_flags (value);
break;
case ARG_PROFILE:
encoder->profile = g_value_get_enum (value);
break;
@ -1790,6 +1978,15 @@ gst_x264_enc_get_property (GObject * object, guint prop_id,
case ARG_INTERLACED:
g_value_set_boolean (value, encoder->interlaced);
break;
case ARG_SPEED_PRESET:
g_value_set_enum (value, encoder->speed_preset);
break;
case ARG_PSY_TUNE:
g_value_set_enum (value, encoder->psy_tune);
break;
case ARG_TUNE:
g_value_set_flags (value, encoder->tune);
break;
case ARG_PROFILE:
g_value_set_enum (value, encoder->profile);
break;

View file

@ -87,6 +87,10 @@ struct _GstX264Enc
gint rc_lookahead;
guint noise_reduction;
gboolean interlaced;
gint speed_preset;
gint psy_tune;
guint tune;
GString *tunings;
gint profile;
GString *option_string_prop; /* option-string property */
GString *option_string; /* used by set prop */