summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEdward Hervey <edward@collabora.com>2013-03-28 15:20:19 +0100
committerEdward Hervey <edward@collabora.com>2013-03-31 12:02:05 +0200
commitb3d94bd0e4ce735c3529a20068689a1113a85639 (patch)
tree85b1ec89026c8ff7eb5485b43e317ed3ad31c50f
parentbc4238f95928fe770df1cfa69e6c0e5667ffa654 (diff)
encodebin: Add action signal to get pad for a given profile
This allows getting a pad for a specific encoding profile, which can be useful when there are several stream profiles of the same type. Also update the encodebin unit tests so that we check that the returned pad has the right caps. https://bugzilla.gnome.org/show_bug.cgi?id=689845
-rw-r--r--gst/encoding/gstencodebin.c75
-rw-r--r--tests/check/elements/encodebin.c99
2 files changed, 167 insertions, 7 deletions
diff --git a/gst/encoding/gstencodebin.c b/gst/encoding/gstencodebin.c
index dd49c430f..b567fc245 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 3ffa80d69..b8964623c 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;
}