diff --git a/gst/encoding/gstencodebin.c b/gst/encoding/gstencodebin.c index dd49c430f8..b567fc245e 100644 --- a/gst/encoding/gstencodebin.c +++ b/gst/encoding/gstencodebin.c @@ -199,6 +199,8 @@ struct _GstEncodeBinClass /* Action Signals */ GstPad *(*request_pad) (GstEncodeBin * encodebin, GstCaps * caps); + GstPad *(*request_profile_pad) (GstEncodeBin * encodebin, + const gchar * profilename); }; typedef struct _StreamGroup StreamGroup; @@ -254,6 +256,7 @@ enum enum { SIGNAL_REQUEST_PAD, + SIGNAL_REQUEST_PROFILE_PAD, LAST_SIGNAL }; @@ -314,6 +317,8 @@ static StreamGroup *_create_stream_group (GstEncodeBin * ebin, static void stream_group_remove (GstEncodeBin * ebin, StreamGroup * sgroup); static GstPad *gst_encode_bin_request_pad_signal (GstEncodeBin * encodebin, GstCaps * caps); +static GstPad *gst_encode_bin_request_profile_pad_signal (GstEncodeBin * + encodebin, const gchar * profilename); static inline GstElement *_get_formatter (GstEncodeBin * ebin, GstEncodingProfile * sprof); @@ -402,7 +407,26 @@ gst_encode_bin_class_init (GstEncodeBinClass * klass) request_pad), NULL, NULL, g_cclosure_marshal_generic, GST_TYPE_PAD, 1, GST_TYPE_CAPS); + /** + * GstEncodeBin::request-profile-pad + * @encodebin: a #GstEncodeBin instance + * @profilename: the name of a #GstEncodingProfile + * + * Use this method to request an unused sink request #GstPad from the profile + * @profilename. You must release the pad with + * gst_element_release_request_pad() when you are done with it. + * + * Returns: A compatible #GstPad, or %NULL if no compatible #GstPad could be + * created or is available. + */ + gst_encode_bin_signals[SIGNAL_REQUEST_PROFILE_PAD] = + g_signal_new ("request-profile-pad", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (GstEncodeBinClass, + request_profile_pad), NULL, NULL, g_cclosure_marshal_generic, + GST_TYPE_PAD, 1, G_TYPE_STRING); + klass->request_pad = gst_encode_bin_request_pad_signal; + klass->request_profile_pad = gst_encode_bin_request_profile_pad_signal; gst_element_class_add_pad_template (gstelement_klass, gst_static_pad_template_get (&muxer_src_template)); @@ -599,7 +623,8 @@ stream_profile_used_count (GstEncodeBin * ebin, GstEncodingProfile * sprof) } static inline GstEncodingProfile * -next_unused_stream_profile (GstEncodeBin * ebin, GType ptype, GstCaps * caps) +next_unused_stream_profile (GstEncodeBin * ebin, GType ptype, + const gchar * name, GstCaps * caps) { GST_DEBUG_OBJECT (ebin, "ptype:%s, caps:%" GST_PTR_FORMAT, g_type_name (ptype), caps); @@ -619,6 +644,32 @@ next_unused_stream_profile (GstEncodeBin * ebin, GType ptype, GstCaps * caps) if (GST_IS_ENCODING_CONTAINER_PROFILE (ebin->profile)) { const GList *tmp; + if (name) { + /* If we have a name, try to find a profile with the same name */ + tmp = + gst_encoding_container_profile_get_profiles + (GST_ENCODING_CONTAINER_PROFILE (ebin->profile)); + + for (; tmp; tmp = tmp->next) { + GstEncodingProfile *sprof = (GstEncodingProfile *) tmp->data; + const gchar *profilename = gst_encoding_profile_get_name (sprof); + + if (profilename && !strcmp (name, profilename)) { + guint presence = gst_encoding_profile_get_presence (sprof); + GST_DEBUG ("Found profile matching the requested name"); + + if (presence == 0 + || presence > stream_profile_used_count (ebin, sprof)) + return sprof; + + GST_WARNING ("Matching stream already used"); + return NULL; + } + } + GST_DEBUG + ("No profiles matching requested pad name, carrying on with normal stream matching"); + } + for (tmp = gst_encoding_container_profile_get_profiles (GST_ENCODING_CONTAINER_PROFILE (ebin->profile)); tmp; @@ -626,16 +677,16 @@ next_unused_stream_profile (GstEncodeBin * ebin, GType ptype, GstCaps * caps) GstEncodingProfile *sprof = (GstEncodingProfile *) tmp->data; /* Pick an available Stream profile for which: - * * either it is of the compatibly raw type, + * * either it is of the compatible raw type, * * OR we can pass it through directly without encoding */ if (G_TYPE_FROM_INSTANCE (sprof) == ptype) { guint presence = gst_encoding_profile_get_presence (sprof); GST_DEBUG ("Found a stream profile with the same type"); - if ((presence == 0) + if (presence == 0 || (presence > stream_profile_used_count (ebin, sprof))) return sprof; - } else if ((caps != NULL) && (ptype == G_TYPE_NONE)) { + } else if (caps && ptype == G_TYPE_NONE) { GstCaps *outcaps; gboolean res; @@ -665,7 +716,7 @@ request_pad_for_stream (GstEncodeBin * encodebin, GType ptype, /* Figure out if we have a unused GstEncodingProfile we can use for * these caps */ - sprof = next_unused_stream_profile (encodebin, ptype, caps); + sprof = next_unused_stream_profile (encodebin, ptype, name, caps); if (G_UNLIKELY (sprof == NULL)) goto no_stream_profile; @@ -698,8 +749,8 @@ gst_encode_bin_request_new_pad (GstElement * element, GST_DEBUG_OBJECT (element, "templ:%s, name:%s", templ->name_template, name); - /* Identify the stream group */ - if (caps != NULL) { + /* Identify the stream group (if name or caps have been provided) */ + if (caps != NULL || name != NULL) { res = request_pad_for_stream (ebin, G_TYPE_NONE, name, (GstCaps *) caps); } @@ -732,6 +783,16 @@ gst_encode_bin_request_pad_signal (GstEncodeBin * encodebin, GstCaps * caps) return pad ? GST_PAD_CAST (gst_object_ref (pad)) : NULL; } +static GstPad * +gst_encode_bin_request_profile_pad_signal (GstEncodeBin * encodebin, + const gchar * profilename) +{ + GstPad *pad = + request_pad_for_stream (encodebin, G_TYPE_NONE, profilename, NULL); + + return pad ? GST_PAD_CAST (gst_object_ref (pad)) : NULL; +} + static inline StreamGroup * find_stream_group_from_pad (GstEncodeBin * ebin, GstPad * pad) { diff --git a/tests/check/elements/encodebin.c b/tests/check/elements/encodebin.c index 3ffa80d69d..b8964623c0 100644 --- a/tests/check/elements/encodebin.c +++ b/tests/check/elements/encodebin.c @@ -90,6 +90,23 @@ create_vorbis_only_profile (void) return prof; } +static void +_caps_match (GstPad * sinkpad, const gchar * capsname) +{ + GstCaps *caps, *sinkcaps; + gchar *name; + + caps = gst_caps_from_string (capsname); + sinkcaps = gst_pad_query_caps (sinkpad, NULL); + fail_unless (sinkcaps != NULL); + name = gst_caps_to_string (sinkcaps); + fail_unless (gst_caps_is_subset (sinkcaps, caps), + "caps ('%s') are not a subset of ('%s')", name, capsname); + g_free (name); + gst_caps_unref (sinkcaps); + gst_caps_unref (caps); +} + GST_START_TEST (test_encodebin_states) { GstElement *ebin; @@ -188,6 +205,8 @@ GST_START_TEST (test_encodebin_sink_pads_static) /* Check if the audio sink pad was properly created */ sinkpad = gst_element_get_static_pad (ebin, "audio_0"); fail_unless (sinkpad != NULL); + /* Check caps match */ + _caps_match (sinkpad, "audio/x-raw;audio/x-vorbis"); gst_object_unref (sinkpad); /* Set back to NULL */ @@ -304,6 +323,7 @@ GST_START_TEST (test_encodebin_sink_pads_dynamic) /* Check if the audio sink pad can be requested */ sinkpad = gst_element_get_request_pad (ebin, "audio_0"); fail_unless (sinkpad != NULL); + _caps_match (sinkpad, "audio/x-raw;audio/x-vorbis"); gst_element_release_request_pad (ebin, sinkpad); gst_object_unref (sinkpad); sinkpad = NULL; @@ -313,6 +333,7 @@ GST_START_TEST (test_encodebin_sink_pads_dynamic) g_signal_emit_by_name (ebin, "request-pad", sinkcaps, &sinkpad); gst_caps_unref (sinkcaps); fail_unless (sinkpad != NULL); + _caps_match (sinkpad, "audio/x-raw;audio/x-vorbis"); gst_element_release_request_pad (ebin, sinkpad); gst_object_unref (sinkpad); sinkpad = NULL; @@ -357,11 +378,13 @@ GST_START_TEST (test_encodebin_sink_pads_multiple_static) /* Check if the audio sink pad was properly created */ sinkpadvorbis = gst_element_get_static_pad (ebin, "audio_0"); fail_unless (sinkpadvorbis != NULL); + _caps_match (sinkpadvorbis, "audio/x-raw;audio/x-vorbis"); gst_object_unref (sinkpadvorbis); /* Check if the video sink pad was properly created */ sinkpadtheora = gst_element_get_static_pad (ebin, "video_1"); fail_unless (sinkpadtheora != NULL); + _caps_match (sinkpadtheora, "video/x-raw;video/x-theora"); gst_object_unref (sinkpadtheora); /* Set back to NULL */ @@ -398,10 +421,12 @@ GST_START_TEST (test_encodebin_sink_pads_multiple_dynamic) /* Check if the audio sink pad was properly created */ sinkpadvorbis = gst_element_get_request_pad (ebin, "audio_0"); + _caps_match (sinkpadvorbis, "audio/x-raw;audio/x-vorbis"); fail_unless (sinkpadvorbis != NULL); /* Check if the video sink pad was properly created */ sinkpadtheora = gst_element_get_request_pad (ebin, "video_1"); + _caps_match (sinkpadtheora, "video/x-raw;video/x-theora"); fail_unless (sinkpadtheora != NULL); fail_unless_equals_int (gst_element_set_state (ebin, GST_STATE_PAUSED), @@ -450,6 +475,7 @@ GST_START_TEST (test_encodebin_sink_pads_dynamic_encoder) g_signal_emit_by_name (ebin, "request-pad", vorbiscaps, &sinkpad); gst_caps_unref (vorbiscaps); fail_unless (sinkpad != NULL); + _caps_match (sinkpad, "audio/x-raw;audio/x-vorbis"); gst_element_release_request_pad (ebin, sinkpad); gst_object_unref (sinkpad); @@ -622,6 +648,7 @@ GST_START_TEST (test_encodebin_render_audio_dynamic) sinkpad = gst_element_get_request_pad (ebin, "audio_0"); fail_unless (sinkpad != NULL); + _caps_match (sinkpad, "audio/x-raw;audio/x-vorbis"); fail_unless_equals_int (gst_pad_link (srcpad, sinkpad), GST_PAD_LINK_OK); @@ -762,11 +789,13 @@ GST_START_TEST (test_encodebin_render_audio_video_dynamic) sinkpad1 = gst_element_get_request_pad (ebin, "audio_0"); fail_unless (srcpad != NULL); fail_unless (sinkpad1 != NULL); + _caps_match (sinkpad1, "audio/x-raw;audio/x-vorbis"); fail_unless_equals_int (gst_pad_link (srcpad, sinkpad1), GST_PAD_LINK_OK); gst_object_unref (srcpad); srcpad = gst_element_get_static_pad (videotestsrc, "src"); sinkpad2 = gst_element_get_request_pad (ebin, "video_1"); + _caps_match (sinkpad2, "video/x-raw;video/x-theora"); fail_unless_equals_int (gst_pad_link (srcpad, sinkpad2), GST_PAD_LINK_OK); gst_object_unref (srcpad); @@ -921,6 +950,75 @@ GST_START_TEST (test_encodebin_reuse) GST_END_TEST; +GST_START_TEST (test_encodebin_named_requests) +{ + GstElement *ebin; + GstEncodingContainerProfile *cprof; + GstCaps *ogg, *vorbis, *theora; + GstEncodingProfile *vorbisprof, *theoraprof; + GstPad *srcpad, *sinkpadvorbis, *sinkpadtheora; + + /* Create a profile with vorbis/theora named profile */ + ogg = gst_caps_new_empty_simple ("application/ogg"); + cprof = + gst_encoding_container_profile_new ((gchar *) "myprofile", NULL, ogg, + NULL); + gst_caps_unref (ogg); + + vorbis = gst_caps_new_empty_simple ("audio/x-vorbis"); + vorbisprof = + (GstEncodingProfile *) gst_encoding_audio_profile_new (vorbis, NULL, NULL, + 0); + gst_encoding_profile_set_name (vorbisprof, "vorbisprofile"); + fail_unless (gst_encoding_container_profile_add_profile (cprof, vorbisprof)); + gst_caps_unref (vorbis); + + theora = gst_caps_new_empty_simple ("video/x-theora"); + theoraprof = + (GstEncodingProfile *) gst_encoding_video_profile_new (theora, NULL, NULL, + 0); + gst_encoding_profile_set_name (theoraprof, "theoraprofile"); + fail_unless (gst_encoding_container_profile_add_profile (cprof, theoraprof)); + gst_caps_unref (theora); + + ebin = gst_element_factory_make ("encodebin", NULL); + + /* First try is with a streamprofile that has a forced presence of 1 */ + g_object_set (ebin, "profile", cprof, NULL); + + gst_encoding_profile_unref (cprof); + + /* Check if the source pad was properly created */ + srcpad = gst_element_get_static_pad (ebin, "src"); + fail_unless (srcpad != NULL); + gst_object_unref (srcpad); + + /* Request a vorbis profile pad */ + g_signal_emit_by_name (ebin, "request-profile-pad", "vorbisprofile", + &sinkpadvorbis); + fail_unless (sinkpadvorbis != NULL); + _caps_match (sinkpadvorbis, "audio/x-raw;audio/x-vorbis"); + gst_object_unref (sinkpadvorbis); + + /* Request a theora profile pad */ + g_signal_emit_by_name (ebin, "request-profile-pad", "theoraprofile", + &sinkpadtheora); + fail_unless (sinkpadtheora != NULL); + _caps_match (sinkpadtheora, "video/x-raw;video/x-theora"); + gst_object_unref (sinkpadtheora); + + fail_unless_equals_int (gst_element_set_state (ebin, GST_STATE_PAUSED), + GST_STATE_CHANGE_SUCCESS); + + /* Set back to NULL */ + fail_unless_equals_int (gst_element_set_state (ebin, GST_STATE_NULL), + GST_STATE_CHANGE_SUCCESS); + + gst_object_unref (ebin); + +} + +GST_END_TEST; static Suite * encodebin_suite (void) @@ -944,6 +1042,7 @@ encodebin_suite (void) tcase_add_test (tc_chain, test_encodebin_render_audio_video_dynamic); tcase_add_test (tc_chain, test_encodebin_impossible_element_combination); tcase_add_test (tc_chain, test_encodebin_reuse); + tcase_add_test (tc_chain, test_encodebin_named_requests); return s; }