mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-28 03:00:35 +00:00
b3d94bd0e4
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
1050 lines
32 KiB
C
1050 lines
32 KiB
C
/* GStreamer unit test for gstprofile
|
|
*
|
|
* Copyright (C) <2009> Edward Hervey <edward.hervey@collabora.co.uk>
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Library General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Library General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Library General Public
|
|
* License along with this library; if not, write to the
|
|
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
|
* Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include <gst/pbutils/encoding-profile.h>
|
|
#include <gst/check/gstcheck.h>
|
|
|
|
/* Helper functions to create profiles */
|
|
|
|
static GstEncodingProfile *
|
|
create_ogg_vorbis_profile (guint presence, gchar * preset)
|
|
{
|
|
GstEncodingContainerProfile *cprof;
|
|
GstCaps *ogg, *vorbis;
|
|
|
|
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");
|
|
fail_unless (gst_encoding_container_profile_add_profile (cprof,
|
|
(GstEncodingProfile *) gst_encoding_audio_profile_new (vorbis, preset,
|
|
NULL, presence)));
|
|
gst_caps_unref (vorbis);
|
|
|
|
return (GstEncodingProfile *) cprof;
|
|
}
|
|
|
|
static GstEncodingProfile *
|
|
create_ogg_theora_vorbis_profile (guint theorapresence, guint vorbispresence)
|
|
{
|
|
GstEncodingContainerProfile *prof;
|
|
GstCaps *ogg, *vorbis, *theora;
|
|
|
|
ogg = gst_caps_new_empty_simple ("application/ogg");
|
|
prof =
|
|
gst_encoding_container_profile_new ((gchar *) "myprofile", NULL, ogg,
|
|
NULL);
|
|
gst_caps_unref (ogg);
|
|
|
|
vorbis = gst_caps_new_empty_simple ("audio/x-vorbis");
|
|
fail_unless (gst_encoding_container_profile_add_profile (prof,
|
|
(GstEncodingProfile *) gst_encoding_audio_profile_new (vorbis, NULL,
|
|
NULL, vorbispresence)));
|
|
gst_caps_unref (vorbis);
|
|
|
|
theora = gst_caps_new_empty_simple ("video/x-theora");
|
|
fail_unless (gst_encoding_container_profile_add_profile (prof,
|
|
(GstEncodingProfile *) gst_encoding_video_profile_new (theora, NULL,
|
|
NULL, theorapresence)));
|
|
gst_caps_unref (theora);
|
|
|
|
return (GstEncodingProfile *) prof;
|
|
}
|
|
|
|
static GstEncodingProfile *
|
|
create_vorbis_only_profile (void)
|
|
{
|
|
GstEncodingProfile *prof;
|
|
GstCaps *vorbis;
|
|
|
|
vorbis = gst_caps_new_empty_simple ("audio/x-vorbis");
|
|
prof =
|
|
(GstEncodingProfile *) gst_encoding_audio_profile_new (vorbis, NULL, NULL,
|
|
0);
|
|
gst_caps_unref (vorbis);
|
|
|
|
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;
|
|
GstEncodingProfile *prof, *prof2;
|
|
GstCaps *ogg;
|
|
GstPad *srcpad;
|
|
GstPad *target;
|
|
|
|
/* Create an encodebin and check that it correctly changes states
|
|
* according to whether a profile is set or not */
|
|
|
|
ebin = gst_element_factory_make ("encodebin", NULL);
|
|
|
|
/* Check if the source pad was properly created */
|
|
srcpad = gst_element_get_static_pad (ebin, "src");
|
|
fail_unless (srcpad != NULL);
|
|
|
|
/* At this point, the ghostpad has *NO* target */
|
|
target = gst_ghost_pad_get_target (GST_GHOST_PAD (srcpad));
|
|
fail_unless (target == NULL);
|
|
gst_object_unref (srcpad);
|
|
|
|
/* No profile,
|
|
* switching to READY should succeed,
|
|
* but switching to PAUSED should fail
|
|
*/
|
|
fail_unless_equals_int (gst_element_set_state (ebin, GST_STATE_READY),
|
|
GST_STATE_CHANGE_SUCCESS);
|
|
fail_unless_equals_int (gst_element_set_state (ebin, GST_STATE_PAUSED),
|
|
GST_STATE_CHANGE_FAILURE);
|
|
|
|
/* Set a profile on encodebin... */
|
|
ogg = gst_caps_new_empty_simple ("application/ogg");
|
|
prof = (GstEncodingProfile *) gst_encoding_container_profile_new ((gchar *)
|
|
"myprofile", NULL, ogg, NULL);
|
|
gst_caps_unref (ogg);
|
|
|
|
g_object_set (ebin, "profile", prof, NULL);
|
|
|
|
/* ... and check the profile has been properly set */
|
|
g_object_get (ebin, "profile", &prof2, NULL);
|
|
|
|
fail_unless (gst_encoding_profile_is_equal (prof, prof2));
|
|
|
|
gst_encoding_profile_unref (prof);
|
|
gst_encoding_profile_unref (prof2);
|
|
|
|
/* Make sure we can go to PAUSED */
|
|
fail_unless_equals_int (gst_element_set_state (ebin, GST_STATE_PAUSED),
|
|
GST_STATE_CHANGE_SUCCESS);
|
|
|
|
/* At this point, the source pad *HAS* a target */
|
|
srcpad = gst_element_get_static_pad (ebin, "src");
|
|
fail_unless (srcpad != NULL);
|
|
target = gst_ghost_pad_get_target (GST_GHOST_PAD (srcpad));
|
|
fail_unless (target != NULL);
|
|
gst_object_unref (target);
|
|
gst_object_unref (srcpad);
|
|
|
|
|
|
/* 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;
|
|
|
|
GST_START_TEST (test_encodebin_sink_pads_static)
|
|
{
|
|
GstElement *ebin;
|
|
GstEncodingProfile *prof;
|
|
GstPad *srcpad, *sinkpad;
|
|
|
|
/* Create an encodebin and check that it properly creates the sink pads
|
|
* for a single-stream profile with fixed presence */
|
|
|
|
ebin = gst_element_factory_make ("encodebin", NULL);
|
|
|
|
/* streamprofile that has a forced presence of 1 */
|
|
prof = create_ogg_vorbis_profile (1, NULL);
|
|
|
|
g_object_set (ebin, "profile", prof, NULL);
|
|
|
|
gst_encoding_profile_unref (prof);
|
|
|
|
fail_unless_equals_int (gst_element_set_state (ebin, GST_STATE_PAUSED),
|
|
GST_STATE_CHANGE_SUCCESS);
|
|
|
|
/* Check if the source pad was properly created */
|
|
srcpad = gst_element_get_static_pad (ebin, "src");
|
|
fail_unless (srcpad != NULL);
|
|
gst_object_unref (srcpad);
|
|
|
|
/* 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 */
|
|
fail_unless_equals_int (gst_element_set_state (ebin, GST_STATE_NULL),
|
|
GST_STATE_CHANGE_SUCCESS);
|
|
|
|
gst_object_unref (ebin);
|
|
};
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (test_encodebin_preset)
|
|
{
|
|
GstElement *ebin;
|
|
guint64 max_delay = 0;
|
|
GstPreset *oggmuxpreset;
|
|
GstEncodingProfile *prof;
|
|
|
|
/* Create an encodebin with a bogus preset and check it fails switching states */
|
|
|
|
ebin = gst_element_factory_make ("encodebin", NULL);
|
|
oggmuxpreset = GST_PRESET (gst_element_factory_make ("oggmux", NULL));
|
|
|
|
/* streamprofile that has a forced presence of 1 */
|
|
prof = create_ogg_vorbis_profile (1, NULL);
|
|
/* We also set the name as the load_preset call will reset the element name to
|
|
* what is described in the preset... which might not be very smart tbh */
|
|
g_object_set (oggmuxpreset, "max-delay", (guint64) 12, "name",
|
|
"testingoggmux", NULL);
|
|
|
|
/* Give a name someone should never use outside of that test */
|
|
gst_preset_save_preset (oggmuxpreset, "test_encodebin_preset");
|
|
|
|
gst_encoding_profile_set_preset (prof, "test_encodebin_preset");
|
|
gst_encoding_profile_set_preset_name (prof, "oggmux");
|
|
|
|
g_object_set (ebin, "profile", prof, NULL);
|
|
|
|
gst_encoding_profile_unref (prof);
|
|
|
|
/* It will go to READY... */
|
|
fail_unless_equals_int (gst_element_set_state (ebin, GST_STATE_READY),
|
|
GST_STATE_CHANGE_SUCCESS);
|
|
/* ... and to PAUSED */
|
|
fail_unless (gst_element_set_state (ebin, GST_STATE_PAUSED) !=
|
|
GST_STATE_CHANGE_FAILURE);
|
|
|
|
gst_child_proxy_get (GST_CHILD_PROXY (ebin), "testingoggmux::max-delay",
|
|
&max_delay, NULL);
|
|
fail_unless_equals_uint64 (max_delay, 12);
|
|
|
|
gst_element_set_state (ebin, GST_STATE_NULL);
|
|
gst_preset_delete_preset (oggmuxpreset, "test_encodebin_preset");
|
|
|
|
gst_object_unref (ebin);
|
|
};
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (test_encodebin_sink_pads_nopreset_static)
|
|
{
|
|
GstElement *ebin;
|
|
GstEncodingProfile *prof;
|
|
|
|
/* Create an encodebin with a bogus preset and check it fails switching states */
|
|
|
|
ebin = gst_element_factory_make ("encodebin", NULL);
|
|
|
|
/* streamprofile that has a forced presence of 1 */
|
|
prof = create_ogg_vorbis_profile (1, (gchar *) "nowaythispresetexists");
|
|
|
|
g_object_set (ebin, "profile", prof, NULL);
|
|
|
|
gst_encoding_profile_unref (prof);
|
|
|
|
/* It will go to READY... */
|
|
fail_unless_equals_int (gst_element_set_state (ebin, GST_STATE_READY),
|
|
GST_STATE_CHANGE_SUCCESS);
|
|
/* ... but to not PAUSED */
|
|
fail_unless_equals_int (gst_element_set_state (ebin, GST_STATE_PAUSED),
|
|
GST_STATE_CHANGE_FAILURE);
|
|
|
|
gst_element_set_state (ebin, GST_STATE_NULL);
|
|
|
|
gst_object_unref (ebin);
|
|
};
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (test_encodebin_sink_pads_dynamic)
|
|
{
|
|
GstElement *ebin;
|
|
GstEncodingProfile *prof;
|
|
GstPad *srcpad, *sinkpad;
|
|
GstCaps *sinkcaps;
|
|
|
|
/* Create an encodebin and check that it properly creates the sink pads
|
|
* for a single-stream profile with a unfixed presence */
|
|
|
|
ebin = gst_element_factory_make ("encodebin", NULL);
|
|
|
|
/* streamprofile that has non-forced presence */
|
|
prof = create_ogg_vorbis_profile (0, NULL);
|
|
|
|
g_object_set (ebin, "profile", prof, NULL);
|
|
|
|
gst_encoding_profile_unref (prof);
|
|
|
|
/* Check if the source pad was properly created */
|
|
srcpad = gst_element_get_static_pad (ebin, "src");
|
|
fail_unless (srcpad != NULL);
|
|
gst_object_unref (srcpad);
|
|
|
|
/* 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;
|
|
|
|
/* Check again with the 'request-pad' signal */
|
|
sinkcaps = gst_caps_new_empty_simple ("audio/x-raw");
|
|
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;
|
|
|
|
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;
|
|
|
|
GST_START_TEST (test_encodebin_sink_pads_multiple_static)
|
|
{
|
|
GstElement *ebin;
|
|
GstEncodingProfile *prof;
|
|
GstPad *srcpad, *sinkpadvorbis, *sinkpadtheora;
|
|
|
|
/* Create an encodebin and check that it properly creates the sink pads */
|
|
|
|
ebin = gst_element_factory_make ("encodebin", NULL);
|
|
|
|
/* First try is with a streamprofile that has a forced presence of 1 */
|
|
prof = create_ogg_theora_vorbis_profile (1, 1);
|
|
|
|
g_object_set (ebin, "profile", prof, NULL);
|
|
|
|
gst_encoding_profile_unref (prof);
|
|
|
|
fail_unless_equals_int (gst_element_set_state (ebin, GST_STATE_PAUSED),
|
|
GST_STATE_CHANGE_SUCCESS);
|
|
|
|
/* Check if the source pad was properly created */
|
|
srcpad = gst_element_get_static_pad (ebin, "src");
|
|
fail_unless (srcpad != NULL);
|
|
gst_object_unref (srcpad);
|
|
|
|
/* 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 */
|
|
fail_unless_equals_int (gst_element_set_state (ebin, GST_STATE_NULL),
|
|
GST_STATE_CHANGE_SUCCESS);
|
|
|
|
gst_object_unref (ebin);
|
|
};
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (test_encodebin_sink_pads_multiple_dynamic)
|
|
{
|
|
GstElement *ebin;
|
|
GstEncodingProfile *prof;
|
|
GstPad *srcpad, *sinkpadvorbis, *sinkpadtheora;
|
|
|
|
/* Create an encodebin and check that it properly creates the sink pads
|
|
* for a multiple-stream with unfixed presence */
|
|
|
|
ebin = gst_element_factory_make ("encodebin", NULL);
|
|
|
|
/* multi-stream profile that has non-forced presence */
|
|
prof = create_ogg_theora_vorbis_profile (0, 0);
|
|
|
|
g_object_set (ebin, "profile", prof, NULL);
|
|
|
|
gst_encoding_profile_unref (prof);
|
|
|
|
/* Check if the source pad was properly created */
|
|
srcpad = gst_element_get_static_pad (ebin, "src");
|
|
fail_unless (srcpad != NULL);
|
|
gst_object_unref (srcpad);
|
|
|
|
/* 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),
|
|
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_element_release_request_pad (GST_ELEMENT (ebin), sinkpadvorbis);
|
|
gst_object_unref (sinkpadvorbis);
|
|
gst_element_release_request_pad (GST_ELEMENT (ebin), sinkpadtheora);
|
|
gst_object_unref (sinkpadtheora);
|
|
|
|
gst_object_unref (ebin);
|
|
};
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (test_encodebin_sink_pads_dynamic_encoder)
|
|
{
|
|
GstElement *ebin;
|
|
GstEncodingProfile *prof;
|
|
GstPad *srcpad, *sinkpad = NULL;
|
|
GstCaps *vorbiscaps;
|
|
|
|
/* Create an encodebin and check that it properly creates the sink pads
|
|
* for a single-stream profile with a unfixed presence */
|
|
|
|
ebin = gst_element_factory_make ("encodebin", NULL);
|
|
|
|
/* streamprofile that has non-forced presence */
|
|
prof = create_ogg_vorbis_profile (0, NULL);
|
|
|
|
g_object_set (ebin, "profile", prof, NULL);
|
|
|
|
gst_encoding_profile_unref (prof);
|
|
|
|
/* Check if the source pad was properly created */
|
|
srcpad = gst_element_get_static_pad (ebin, "src");
|
|
fail_unless (srcpad != NULL);
|
|
gst_object_unref (srcpad);
|
|
|
|
/* Check if the audio sink pad was properly created */
|
|
vorbiscaps = gst_caps_from_string ("audio/x-vorbis,channels=2,rate=44100");
|
|
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);
|
|
|
|
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;
|
|
|
|
GST_START_TEST (test_encodebin_render_audio_static)
|
|
{
|
|
GstElement *ebin, *pipeline, *audiotestsrc, *fakesink;
|
|
GstEncodingProfile *prof;
|
|
GstBus *bus;
|
|
gboolean done = FALSE;
|
|
|
|
/* Create an encodebin and render 5s of vorbis/ogg */
|
|
|
|
pipeline = gst_pipeline_new ("encodebin-pipeline");
|
|
bus = gst_pipeline_get_bus ((GstPipeline *) pipeline);
|
|
audiotestsrc = gst_element_factory_make ("audiotestsrc", NULL);
|
|
g_object_set (audiotestsrc, "num-buffers", 10, NULL);
|
|
fakesink = gst_element_factory_make ("fakesink", NULL);
|
|
|
|
ebin = gst_element_factory_make ("encodebin", NULL);
|
|
|
|
prof = create_ogg_vorbis_profile (1, NULL);
|
|
g_object_set (ebin, "profile", prof, NULL);
|
|
gst_encoding_profile_unref (prof);
|
|
|
|
gst_bin_add_many ((GstBin *) pipeline, audiotestsrc, ebin, fakesink, NULL);
|
|
|
|
fail_unless (gst_element_link_many (audiotestsrc, ebin, fakesink, NULL));
|
|
|
|
fail_unless_equals_int (gst_element_set_state (pipeline, GST_STATE_PLAYING),
|
|
GST_STATE_CHANGE_ASYNC);
|
|
|
|
while (!done) {
|
|
GstMessage *msg;
|
|
|
|
/* poll the bus until we get EOS without any errors */
|
|
msg = gst_bus_timed_pop (bus, GST_SECOND / 10);
|
|
if (msg) {
|
|
switch (GST_MESSAGE_TYPE (msg)) {
|
|
case GST_MESSAGE_ERROR:
|
|
fail ("GST_MESSAGE_ERROR");
|
|
break;
|
|
case GST_MESSAGE_EOS:
|
|
done = TRUE;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
gst_message_unref (msg);
|
|
}
|
|
}
|
|
|
|
/* Set back to NULL */
|
|
fail_unless_equals_int (gst_element_set_state (pipeline, GST_STATE_NULL),
|
|
GST_STATE_CHANGE_SUCCESS);
|
|
|
|
gst_object_unref (bus);
|
|
|
|
gst_object_unref (pipeline);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (test_encodebin_render_audio_only_static)
|
|
{
|
|
GstElement *ebin, *pipeline, *audiotestsrc, *fakesink;
|
|
GstEncodingProfile *prof;
|
|
GstBus *bus;
|
|
gboolean done = FALSE;
|
|
GstPad *sinkpad;
|
|
GstCaps *sinkcaps;
|
|
|
|
/* Create an encodebin and render 5s of vorbis only */
|
|
pipeline = gst_pipeline_new ("encodebin-pipeline");
|
|
bus = gst_pipeline_get_bus ((GstPipeline *) pipeline);
|
|
audiotestsrc = gst_element_factory_make ("audiotestsrc", NULL);
|
|
g_object_set (audiotestsrc, "num-buffers", 10, NULL);
|
|
fakesink = gst_element_factory_make ("fakesink", NULL);
|
|
|
|
ebin = gst_element_factory_make ("encodebin", NULL);
|
|
|
|
prof = create_vorbis_only_profile ();
|
|
g_object_set (ebin, "profile", prof, NULL);
|
|
gst_encoding_profile_unref (prof);
|
|
|
|
gst_bin_add_many (GST_BIN (pipeline), audiotestsrc, ebin, fakesink, NULL);
|
|
|
|
GST_DEBUG ("linking encodebin");
|
|
fail_unless (gst_element_link_many (audiotestsrc, ebin, fakesink, NULL));
|
|
|
|
/* Requesting a new pad should fail */
|
|
ASSERT_CRITICAL (gst_element_get_request_pad (ebin, "audio_0"));
|
|
|
|
sinkcaps = gst_caps_new_empty_simple ("audio/x-raw");
|
|
g_signal_emit_by_name (ebin, "request-pad", sinkcaps, &sinkpad);
|
|
gst_caps_unref (sinkcaps);
|
|
fail_if (sinkpad != NULL);
|
|
|
|
fail_unless_equals_int (gst_element_set_state (pipeline, GST_STATE_PLAYING),
|
|
GST_STATE_CHANGE_ASYNC);
|
|
|
|
while (!done) {
|
|
GstMessage *msg;
|
|
|
|
/* poll the bus until we get EOS without any errors */
|
|
msg = gst_bus_timed_pop (bus, GST_SECOND / 10);
|
|
if (msg) {
|
|
switch (GST_MESSAGE_TYPE (msg)) {
|
|
case GST_MESSAGE_ERROR:
|
|
fail ("GST_MESSAGE_ERROR");
|
|
break;
|
|
case GST_MESSAGE_EOS:
|
|
done = TRUE;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
gst_message_unref (msg);
|
|
}
|
|
}
|
|
|
|
/* Set back to NULL */
|
|
fail_unless_equals_int (gst_element_set_state (pipeline, GST_STATE_NULL),
|
|
GST_STATE_CHANGE_SUCCESS);
|
|
|
|
gst_object_unref (bus);
|
|
|
|
gst_object_unref (pipeline);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (test_encodebin_render_audio_dynamic)
|
|
{
|
|
GstElement *ebin, *pipeline, *audiotestsrc, *fakesink;
|
|
GstEncodingProfile *prof;
|
|
GstBus *bus;
|
|
GstPad *sinkpad, *srcpad;
|
|
gboolean done = FALSE;
|
|
|
|
/* Create an encodebin and render 5s of vorbis/ogg */
|
|
|
|
pipeline = gst_pipeline_new ("encodebin-pipeline");
|
|
bus = gst_pipeline_get_bus ((GstPipeline *) pipeline);
|
|
audiotestsrc = gst_element_factory_make ("audiotestsrc", NULL);
|
|
g_object_set (audiotestsrc, "num-buffers", 10, NULL);
|
|
fakesink = gst_element_factory_make ("fakesink", NULL);
|
|
|
|
ebin = gst_element_factory_make ("encodebin", NULL);
|
|
|
|
prof = create_ogg_vorbis_profile (0, NULL);
|
|
g_object_set (ebin, "profile", prof, NULL);
|
|
gst_encoding_profile_unref (prof);
|
|
|
|
gst_bin_add_many ((GstBin *) pipeline, audiotestsrc, ebin, fakesink, NULL);
|
|
|
|
srcpad = gst_element_get_static_pad (audiotestsrc, "src");
|
|
fail_unless (srcpad != NULL);
|
|
|
|
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);
|
|
|
|
gst_object_unref (srcpad);
|
|
|
|
fail_unless (gst_element_link (ebin, fakesink));
|
|
|
|
fail_unless_equals_int (gst_element_set_state (pipeline, GST_STATE_PLAYING),
|
|
GST_STATE_CHANGE_ASYNC);
|
|
|
|
while (!done) {
|
|
GstMessage *msg;
|
|
|
|
/* poll the bus until we get EOS without any errors */
|
|
msg = gst_bus_timed_pop (bus, GST_SECOND / 10);
|
|
if (msg) {
|
|
switch (GST_MESSAGE_TYPE (msg)) {
|
|
case GST_MESSAGE_ERROR:
|
|
fail ("GST_MESSAGE_ERROR");
|
|
break;
|
|
case GST_MESSAGE_EOS:
|
|
done = TRUE;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
gst_message_unref (msg);
|
|
}
|
|
}
|
|
|
|
/* Set back to NULL */
|
|
fail_unless_equals_int (gst_element_set_state (pipeline, GST_STATE_NULL),
|
|
GST_STATE_CHANGE_SUCCESS);
|
|
|
|
gst_element_release_request_pad (GST_ELEMENT (ebin), sinkpad);
|
|
gst_object_unref (sinkpad);
|
|
|
|
gst_object_unref (bus);
|
|
|
|
gst_object_unref (pipeline);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (test_encodebin_render_audio_video_static)
|
|
{
|
|
GstElement *ebin, *pipeline, *audiotestsrc, *videotestsrc, *fakesink;
|
|
GstEncodingProfile *prof;
|
|
GstBus *bus;
|
|
gboolean done = FALSE;
|
|
|
|
/* Create an encodebin and render 5s of vorbis/ogg */
|
|
|
|
pipeline = gst_pipeline_new ("encodebin-pipeline");
|
|
bus = gst_pipeline_get_bus ((GstPipeline *) pipeline);
|
|
audiotestsrc = gst_element_factory_make ("audiotestsrc", NULL);
|
|
g_object_set (audiotestsrc, "num-buffers", 10, NULL);
|
|
videotestsrc = gst_element_factory_make ("videotestsrc", NULL);
|
|
g_object_set (videotestsrc, "num-buffers", 5, NULL);
|
|
fakesink = gst_element_factory_make ("fakesink", NULL);
|
|
|
|
ebin = gst_element_factory_make ("encodebin", NULL);
|
|
|
|
prof = create_ogg_theora_vorbis_profile (1, 1);
|
|
g_object_set (ebin, "profile", prof, NULL);
|
|
gst_encoding_profile_unref (prof);
|
|
|
|
gst_bin_add_many ((GstBin *) pipeline, audiotestsrc, videotestsrc, ebin,
|
|
fakesink, NULL);
|
|
|
|
fail_unless (gst_element_link (videotestsrc, ebin));
|
|
fail_unless (gst_element_link_many (audiotestsrc, ebin, fakesink, NULL));
|
|
|
|
fail_unless_equals_int (gst_element_set_state (pipeline, GST_STATE_PLAYING),
|
|
GST_STATE_CHANGE_ASYNC);
|
|
|
|
while (!done) {
|
|
GstMessage *msg;
|
|
|
|
/* poll the bus until we get EOS without any errors */
|
|
msg = gst_bus_timed_pop (bus, GST_SECOND / 10);
|
|
if (msg) {
|
|
switch (GST_MESSAGE_TYPE (msg)) {
|
|
case GST_MESSAGE_ERROR:
|
|
fail ("GST_MESSAGE_ERROR");
|
|
break;
|
|
case GST_MESSAGE_EOS:
|
|
done = TRUE;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
gst_message_unref (msg);
|
|
}
|
|
}
|
|
|
|
/* Set back to NULL */
|
|
fail_unless_equals_int (gst_element_set_state (pipeline, GST_STATE_NULL),
|
|
GST_STATE_CHANGE_SUCCESS);
|
|
|
|
gst_object_unref (bus);
|
|
|
|
gst_object_unref (pipeline);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (test_encodebin_render_audio_video_dynamic)
|
|
{
|
|
GstElement *ebin, *pipeline, *audiotestsrc, *videotestsrc, *fakesink;
|
|
GstEncodingProfile *prof;
|
|
GstBus *bus;
|
|
gboolean done = FALSE;
|
|
GstPad *sinkpad1, *sinkpad2, *srcpad;
|
|
|
|
/* Create an encodebin and render 5s of vorbis/ogg */
|
|
|
|
pipeline = gst_pipeline_new ("encodebin-pipeline");
|
|
bus = gst_pipeline_get_bus ((GstPipeline *) pipeline);
|
|
audiotestsrc = gst_element_factory_make ("audiotestsrc", NULL);
|
|
g_object_set (audiotestsrc, "num-buffers", 10, NULL);
|
|
videotestsrc = gst_element_factory_make ("videotestsrc", NULL);
|
|
g_object_set (videotestsrc, "num-buffers", 5, NULL);
|
|
fakesink = gst_element_factory_make ("fakesink", NULL);
|
|
|
|
ebin = gst_element_factory_make ("encodebin", NULL);
|
|
|
|
prof = create_ogg_theora_vorbis_profile (0, 0);
|
|
g_object_set (ebin, "profile", prof, NULL);
|
|
gst_encoding_profile_unref (prof);
|
|
|
|
gst_bin_add_many ((GstBin *) pipeline, audiotestsrc, videotestsrc, ebin,
|
|
fakesink, NULL);
|
|
|
|
fail_unless (gst_element_link (ebin, fakesink));
|
|
|
|
srcpad = gst_element_get_static_pad (audiotestsrc, "src");
|
|
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);
|
|
|
|
fail_unless_equals_int (gst_element_set_state (pipeline, GST_STATE_PLAYING),
|
|
GST_STATE_CHANGE_ASYNC);
|
|
|
|
while (!done) {
|
|
GstMessage *msg;
|
|
|
|
/* poll the bus until we get EOS without any errors */
|
|
msg = gst_bus_timed_pop (bus, GST_SECOND / 10);
|
|
if (msg) {
|
|
switch (GST_MESSAGE_TYPE (msg)) {
|
|
case GST_MESSAGE_ERROR:
|
|
fail ("GST_MESSAGE_ERROR");
|
|
break;
|
|
case GST_MESSAGE_EOS:
|
|
done = TRUE;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
gst_message_unref (msg);
|
|
}
|
|
}
|
|
|
|
/* Set back to NULL */
|
|
fail_unless_equals_int (gst_element_set_state (pipeline, GST_STATE_NULL),
|
|
GST_STATE_CHANGE_SUCCESS);
|
|
|
|
gst_element_release_request_pad (GST_ELEMENT (ebin), sinkpad1);
|
|
gst_object_unref (sinkpad1);
|
|
gst_element_release_request_pad (GST_ELEMENT (ebin), sinkpad2);
|
|
gst_object_unref (sinkpad2);
|
|
|
|
gst_object_unref (bus);
|
|
|
|
gst_object_unref (pipeline);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (test_encodebin_impossible_element_combination)
|
|
{
|
|
GstElement *ebin;
|
|
GstEncodingProfile *prof;
|
|
GstCaps *ogg, *x264;
|
|
|
|
ebin = gst_element_factory_make ("x264enc", NULL);
|
|
if (ebin == NULL) {
|
|
GST_DEBUG ("No available h264 encoder, skipping test");
|
|
return;
|
|
}
|
|
gst_object_unref (ebin);
|
|
|
|
/* Make sure that impossible combinations of encoders and muxer
|
|
* properly fail. In this case we try putting h264 in ogg.
|
|
*
|
|
* To properly test we abort early, we use a presence of zero for the
|
|
* h264 stream profile. */
|
|
|
|
ebin = gst_element_factory_make ("encodebin", NULL);
|
|
|
|
ogg = gst_caps_new_empty_simple ("application/ogg");
|
|
prof = (GstEncodingProfile *) gst_encoding_container_profile_new ((gchar *)
|
|
"myprofile", NULL, ogg, NULL);
|
|
gst_caps_unref (ogg);
|
|
|
|
x264 = gst_caps_new_empty_simple ("video/x-h264");
|
|
fail_unless (gst_encoding_container_profile_add_profile
|
|
(GST_ENCODING_CONTAINER_PROFILE (prof),
|
|
(GstEncodingProfile *) gst_encoding_video_profile_new (x264, NULL,
|
|
NULL, 0)));
|
|
gst_caps_unref (x264);
|
|
|
|
g_object_set (ebin, "profile", prof, NULL);
|
|
gst_encoding_profile_unref (prof);
|
|
|
|
/* It will go to READY... */
|
|
fail_unless_equals_int (gst_element_set_state (ebin, GST_STATE_READY),
|
|
GST_STATE_CHANGE_SUCCESS);
|
|
/* ... but to not PAUSED */
|
|
fail_unless_equals_int (gst_element_set_state (ebin, GST_STATE_PAUSED),
|
|
GST_STATE_CHANGE_FAILURE);
|
|
|
|
gst_element_set_state (ebin, GST_STATE_NULL);
|
|
|
|
gst_object_unref (ebin);
|
|
};
|
|
|
|
GST_END_TEST;
|
|
|
|
static void
|
|
_test_encodebin_reuse (GstEncodingProfile * prof1, GstEncodingProfile * prof2)
|
|
{
|
|
GstElement *ebin;
|
|
|
|
ebin = gst_element_factory_make ("encodebin", NULL);
|
|
|
|
/* Set a profile on encodebin... */
|
|
if (prof1)
|
|
g_object_set (ebin, "profile", prof1, NULL);
|
|
|
|
/* Make sure we can go to PAUSED */
|
|
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);
|
|
|
|
if (prof2)
|
|
g_object_set (ebin, "profile", prof2, NULL);
|
|
|
|
/* Make sure we can go to PLAYING */
|
|
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_START_TEST (test_encodebin_reuse)
|
|
{
|
|
GstEncodingProfile *prof1;
|
|
GstEncodingProfile *prof2;
|
|
GstEncodingProfile *prof3;
|
|
GstCaps *caps;
|
|
|
|
caps = gst_caps_new_empty_simple ("application/ogg");
|
|
prof1 = (GstEncodingProfile *) gst_encoding_container_profile_new ((gchar *)
|
|
"myprofile", NULL, caps, NULL);
|
|
gst_caps_unref (caps);
|
|
|
|
prof2 = create_ogg_theora_vorbis_profile (1, 1);
|
|
prof3 = create_vorbis_only_profile ();
|
|
|
|
_test_encodebin_reuse (prof1, NULL);
|
|
_test_encodebin_reuse (prof1, prof1);
|
|
|
|
_test_encodebin_reuse (prof1, prof2);
|
|
|
|
_test_encodebin_reuse (prof2, prof3);
|
|
|
|
gst_encoding_profile_unref (prof1);
|
|
gst_encoding_profile_unref (prof2);
|
|
gst_encoding_profile_unref (prof3);
|
|
};
|
|
|
|
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)
|
|
{
|
|
Suite *s = suite_create ("encodebin element");
|
|
TCase *tc_chain = tcase_create ("general");
|
|
|
|
suite_add_tcase (s, tc_chain);
|
|
tcase_add_test (tc_chain, test_encodebin_states);
|
|
tcase_add_test (tc_chain, test_encodebin_sink_pads_static);
|
|
tcase_add_test (tc_chain, test_encodebin_sink_pads_nopreset_static);
|
|
tcase_add_test (tc_chain, test_encodebin_preset);
|
|
tcase_add_test (tc_chain, test_encodebin_sink_pads_dynamic);
|
|
tcase_add_test (tc_chain, test_encodebin_sink_pads_multiple_static);
|
|
tcase_add_test (tc_chain, test_encodebin_sink_pads_multiple_dynamic);
|
|
tcase_add_test (tc_chain, test_encodebin_sink_pads_dynamic_encoder);
|
|
tcase_add_test (tc_chain, test_encodebin_render_audio_static);
|
|
tcase_add_test (tc_chain, test_encodebin_render_audio_only_static);
|
|
tcase_add_test (tc_chain, test_encodebin_render_audio_dynamic);
|
|
tcase_add_test (tc_chain, test_encodebin_render_audio_video_static);
|
|
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;
|
|
}
|
|
|
|
GST_CHECK_MAIN (encodebin);
|