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
This commit is contained in:
Edward Hervey 2013-03-28 15:20:19 +01:00
parent bc4238f959
commit b3d94bd0e4
2 changed files with 167 additions and 7 deletions

View file

@ -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)
{

View file

@ -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;
}