gstreamer/tests/check/elements/encodebin.c
Thiago Santos c9904fb639 encodebin: delay missing encoder error as passthrough is still possible
Set up a fakesink with a pad probe to replace the missing encoder to detect
if encoding was really required and only error out in this case. Otherwise
just let passthrough branch work.

This delays the error posting from the set_state function to when buffers
are really flowing. Unit test updated accordingly

https://bugzilla.gnome.org/show_bug.cgi?id=650652
2014-08-11 10:30:58 -03:00

1114 lines
33 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/pbutils/missing-plugins.h>
#include <gst/check/gstcheck.h>
/* Helper functions to create profiles */
static GstEncodingProfile *
create_ogg_profile ()
{
GstEncodingContainerProfile *prof;
GstCaps *ogg;
ogg = gst_caps_new_empty_simple ("application/ogg");
prof = gst_encoding_container_profile_new ((gchar *) "myprofile", NULL, ogg,
NULL);
gst_caps_unref (ogg);
return (GstEncodingProfile *) prof;
}
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 GstCaps *
create_unsupported_caps (void)
{
return gst_caps_new_empty_simple ("audio/x-bogus");
}
static GstEncodingProfile *
create_unsupported_profile (void)
{
GstEncodingProfile *prof;
GstCaps *caps;
caps = create_unsupported_caps ();
prof =
(GstEncodingProfile *) gst_encoding_audio_profile_new (caps, NULL, NULL,
0);
gst_caps_unref (caps);
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);
}
static void
set_profile (GstElement * ebin, GstEncodingProfile * prof)
{
g_object_set (ebin, "profile", prof, NULL);
gst_encoding_profile_unref (prof);
}
/* Tests */
GST_START_TEST (test_encodebin_set_profile)
{
GstElement *ebin;
GstEncodingProfile *prof, *prof2;
/* 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);
/* Set a profile on encodebin... */
prof = create_ogg_profile ();
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);
gst_object_unref (ebin);
};
GST_END_TEST;
GST_START_TEST (test_encodebin_can_go_to_ready_without_profile)
{
GstElement *ebin;
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 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_can_go_to_paused_with_profile)
{
GstElement *ebin;
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);
/* Set a profile on encodebin... */
set_profile (ebin, create_ogg_profile ());
/* 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;
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 */
set_profile (ebin, create_ogg_vorbis_profile (1, NULL));
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;
GstEncodingProfile *prof;
guint64 max_delay = 0;
GstPreset *oggmuxpreset;
/* 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));
/* 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");
/* streamprofile that has a forced presence of 1 */
prof = create_ogg_vorbis_profile (1, NULL);
gst_encoding_profile_set_preset (prof, "test_encodebin_preset");
gst_encoding_profile_set_preset_name (prof, "oggmux");
set_profile (ebin, 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 (oggmuxpreset);
gst_object_unref (ebin);
};
GST_END_TEST;
GST_START_TEST (test_encodebin_sink_pads_nopreset_static)
{
GstElement *ebin;
/* 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 */
set_profile (ebin,
create_ogg_vorbis_profile (1, (gchar *) "nowaythispresetexists"));
/* 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;
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 */
set_profile (ebin, create_ogg_vorbis_profile (0, NULL));
/* 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;
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 */
set_profile (ebin, create_ogg_theora_vorbis_profile (1, 1));
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;
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 */
set_profile (ebin, create_ogg_theora_vorbis_profile (0, 0));
/* 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;
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 */
set_profile (ebin, create_ogg_vorbis_profile (0, NULL));
/* 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;
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);
set_profile (ebin, create_ogg_vorbis_profile (1, NULL));
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;
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);
set_profile (ebin, create_vorbis_only_profile ());
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;
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);
set_profile (ebin, create_ogg_vorbis_profile (0, NULL));
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;
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);
set_profile (ebin, create_ogg_theora_vorbis_profile (1, 1));
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;
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);
set_profile (ebin, create_ogg_theora_vorbis_profile (0, 0));
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;
prof1 = create_ogg_profile ();
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;
GST_START_TEST (test_encodebin_missing_plugin_messages)
{
GstElement *pipeline = gst_pipeline_new ("test");
GstBus *bus = gst_pipeline_get_bus ((GstPipeline *) pipeline);
GstElement *ebin = gst_element_factory_make ("encodebin", NULL);
GstMessage *message;
GstElement *audiotestsrc;
GstPad *sinkpad, *srcpad;
audiotestsrc = gst_element_factory_make ("audiotestsrc", NULL);
g_object_set (audiotestsrc, "num-buffers", 1, NULL);
gst_bin_add ((GstBin *) pipeline, audiotestsrc);
/* first add to bin, then set profile */
gst_bin_add ((GstBin *) pipeline, ebin);
set_profile (ebin, create_unsupported_profile ());
srcpad = gst_element_get_static_pad (audiotestsrc, "src");
sinkpad = gst_element_get_static_pad (ebin, "audio_0");
fail_unless (gst_pad_link (srcpad, sinkpad) == GST_PAD_LINK_OK);
gst_object_unref (srcpad);
gst_object_unref (sinkpad);
gst_element_set_state (pipeline, GST_STATE_PLAYING);
message =
gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE,
GST_MESSAGE_ELEMENT);
fail_if (message == NULL);
fail_if (!gst_is_missing_plugin_message (message));
gst_message_unref (message);
gst_element_set_state (pipeline, GST_STATE_NULL);
gst_object_unref (bus);
gst_object_unref (pipeline);
}
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_set_profile);
tcase_add_test (tc_chain, test_encodebin_can_go_to_ready_without_profile);
tcase_add_test (tc_chain, test_encodebin_can_go_to_paused_with_profile);
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);
tcase_add_test (tc_chain, test_encodebin_missing_plugin_messages);
return s;
}
GST_CHECK_MAIN (encodebin);