diff --git a/ext/x264/gstx264enc.c b/ext/x264/gstx264enc.c index 655d5de74e..1fd33472c6 100644 --- a/ext/x264/gstx264enc.c +++ b/ext/x264/gstx264enc.c @@ -121,7 +121,8 @@ enum ARG_RC_MB_TREE, ARG_RC_LOOKAHEAD, ARG_NR, - ARG_INTERLACED + ARG_INTERLACED, + ARG_OPTION_STRING }; #define ARG_THREADS_DEFAULT 1 @@ -159,6 +160,8 @@ enum #define ARG_RC_LOOKAHEAD_DEFAULT 40 #define ARG_INTRA_REFRESH_DEFAULT FALSE +#define ARG_OPTION_STRING_DEFAULT "" + enum { GST_X264_ENC_PASS_CBR = 0, @@ -318,6 +321,11 @@ gst_x264_enc_class_init (GstX264EncClass * klass) gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_x264_enc_change_state); + g_object_class_install_property (gobject_class, ARG_OPTION_STRING, + g_param_spec_string ("option-string", "Option string", + "String of x264 options (overridden by element properties)", + ARG_OPTION_STRING_DEFAULT, G_PARAM_READWRITE)); + g_object_class_install_property (gobject_class, ARG_THREADS, g_param_spec_uint ("threads", "Threads", "Number of threads used by the codec (0 for automatic)", @@ -546,6 +554,7 @@ gst_x264_enc_init (GstX264Enc * encoder, GstX264EncClass * klass) encoder->rc_lookahead = ARG_RC_LOOKAHEAD_DEFAULT; encoder->noise_reduction = ARG_NR_DEFAULT; encoder->interlaced = ARG_INTERLACED_DEFAULT; + encoder->option_string_prop = g_string_new (ARG_OPTION_STRING_DEFAULT); /* resources */ encoder->delay = g_queue_new (); @@ -588,6 +597,14 @@ gst_x264_enc_finalize (GObject * object) { GstX264Enc *encoder = GST_X264_ENC (object); +#define FREE_STRING(ptr) \ + if (ptr) \ + ptr = (GString *)g_string_free (ptr, TRUE); + + FREE_STRING (encoder->option_string_prop); + +#undef FREE_STRING + g_free (encoder->mp_cache_file); encoder->mp_cache_file = NULL; g_free (encoder->buffer); @@ -600,6 +617,54 @@ gst_x264_enc_finalize (GObject * object) G_OBJECT_CLASS (parent_class)->finalize (object); } +/* + * gst_x264_enc_parse_options + * @encoder: Encoder to which options are assigned + * @str: Option string + * + * Parse option string and assign to x264 parameters + * + */ +static gboolean +gst_x264_enc_parse_options (GstX264Enc * encoder, const gchar * str) +{ + GStrv kvpairs; + guint npairs, i; + gint parse_result = 0, ret = 0; + gchar *options = (gchar *) str; + + while (*options == ':') + options++; + + kvpairs = g_strsplit (options, ":", 0); + npairs = g_strv_length (kvpairs); + + for (i = 0; i < npairs; i++) { + GStrv key_val = g_strsplit (kvpairs[i], "=", 2); + + parse_result = + x264_param_parse (&encoder->x264param, key_val[0], key_val[1]); + + if (parse_result == X264_PARAM_BAD_NAME) { + GST_ERROR_OBJECT (encoder, "Bad name for option %s=%s", + key_val[0] ? key_val[0] : "", key_val[1] ? key_val[1] : ""); + } + if (parse_result == X264_PARAM_BAD_VALUE) { + GST_ERROR_OBJECT (encoder, + "Bad value for option %s=%s (Note: a NULL value for a non-boolean triggers this)", + key_val[0] ? key_val[0] : "", key_val[1] ? key_val[1] : ""); + } + + g_strfreev (key_val); + + if (parse_result) + ret++; + } + + g_strfreev (kvpairs); + return !ret; +} + /* * gst_x264_enc_init_encoder * @encoder: Encoder which should be initialized. @@ -623,6 +688,16 @@ gst_x264_enc_init_encoder (GstX264Enc * encoder) encoder->x264param.b_sliced_threads = encoder->sliced_threads; encoder->x264param.i_sync_lookahead = encoder->sync_lookahead; #endif + + /* apply user set properties */ + if (encoder->option_string_prop && encoder->option_string_prop->len + && gst_x264_enc_parse_options (encoder, + encoder->option_string_prop->str) == FALSE) { + GST_DEBUG_OBJECT (encoder, "Your option-string contains errors."); + goto unlock_and_return; + } + + /* set up encoder parameters */ encoder->x264param.i_fps_num = encoder->fps_num; encoder->x264param.i_fps_den = encoder->fps_den; encoder->x264param.i_width = encoder->width; @@ -760,6 +835,10 @@ gst_x264_enc_init_encoder (GstX264Enc * encoder) } return TRUE; + +unlock_and_return: + GST_OBJECT_UNLOCK (encoder); + return FALSE; } /* gst_x264_enc_close_encoder @@ -1291,6 +1370,9 @@ gst_x264_enc_set_property (GObject * object, guint prop_id, goto wrong_state; switch (prop_id) { + case ARG_OPTION_STRING: + g_string_assign (encoder->option_string_prop, g_value_get_string (value)); + break; case ARG_THREADS: encoder->threads = g_value_get_uint (value); break; @@ -1518,6 +1600,9 @@ gst_x264_enc_get_property (GObject * object, guint prop_id, case ARG_INTERLACED: g_value_set_boolean (value, encoder->interlaced); break; + case ARG_OPTION_STRING: + g_value_set_string (value, encoder->option_string_prop->str); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; diff --git a/ext/x264/gstx264enc.h b/ext/x264/gstx264enc.h index bbb792b59d..32017d0da8 100644 --- a/ext/x264/gstx264enc.h +++ b/ext/x264/gstx264enc.h @@ -87,6 +87,7 @@ struct _GstX264Enc gint rc_lookahead; guint noise_reduction; gboolean interlaced; + GString *option_string_prop; /* option-string property */ /* input description */ GstVideoFormat format;