/* Action Signals */
GstPad *(*request_pad) (GstEncodeBin * encodebin, GstCaps * caps);
+ GstPad *(*request_profile_pad) (GstEncodeBin * encodebin,
+ const gchar * profilename);
};
typedef struct _StreamGroup StreamGroup;
enum
{
SIGNAL_REQUEST_PAD,
+ SIGNAL_REQUEST_PROFILE_PAD,
LAST_SIGNAL
};
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);
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));
}
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);
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;
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;
/* 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;
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);
}
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)
{
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;
/* 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 */
/* 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;
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;
/* 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 */
/* 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),
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);
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);
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);
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)
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;
}