diff --git a/ChangeLog b/ChangeLog index dfcb5dde79..c6411aa796 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,62 @@ +2005-08-20 Thomas Vander Stichele + + * check/Makefile.am: + add ext dir for plugins + add vorbisdec test conditionally + * check/elements/volume.c: (setup_volume), (cleanup_volume), + (GST_START_TEST), (volume_suite): + add a test with wrong caps + * check/elements/vorbisdec.c: (chain_func), (setup_vorbisdec), + (cleanup_vorbisdec), (GST_START_TEST), (vorbisdec_suite), (main): + add a vorbisdec test + * ext/ogg/gstoggdemux.c: (gst_ogg_chain_new_stream), + (gst_ogg_demux_chain), (gst_ogg_demux_loop): + clean up debug output + * ext/vorbis/vorbisdec.c: (vorbis_dec_chain): + yay, fix a segfault/security issue in vorbisdec + gst-launch fakesrc ! vorbisdec wasn't happy + * ext/vorbis/vorbisenc.c: (vorbisenc_get_type), + (gst_vorbisenc_class_init), (gst_vorbisenc_sink_setcaps), + (gst_vorbisenc_convert_src), (gst_vorbisenc_convert_sink), + (gst_vorbisenc_src_query), (gst_vorbisenc_sink_query), + (gst_vorbisenc_init), (gst_vorbisenc_metadata_set1), + (gst_vorbisenc_set_metadata), (get_constraints_string), + (update_start_message), (gst_vorbisenc_setup), + (gst_vorbisenc_buffer_from_packet), (gst_vorbisenc_push_buffer), + (gst_vorbisenc_push_packet), (gst_vorbisenc_sink_event), + (gst_vorbisenc_chain), (gst_vorbisenc_get_property), + (gst_vorbisenc_set_property), (gst_vorbisenc_change_state): + * ext/vorbis/vorbisenc.h: + march in line + * gst/ffmpegcolorspace/gstffmpegcolorspace.c: + (gst_ffmpegcsp_transform): + have the kow come home + * gst/tcp/gstmultifdsink.c: (gst_multifdsink_class_init): + debug my func ptr + * gst/volume/gstvolume.c: (volume_set_caps): + add a debug + +2005-08-20 Thomas Vander Stichele + + * Makefile.am: + * check/.cvsignore: + * check/Makefile.am: + * check/elements/.cvsignore: + * check/elements/volume.c: (chain_func), (event_func), + (setup_volume), (cleanup_volume), (GST_START_TEST), (volume_suite), + (main): + * configure.ac: + add unit test structure for gst-plugins-base + add a test for volume + * gst/volume/gstvolume.c: (gst_volume_list_tracks), + (gst_volume_set_volume), (gst_volume_get_volume), + (gst_volume_set_mute), (gst_volume_class_init), (gst_volume_init), + (volume_funcfind), (volume_process_float), (volume_process_int16), + (volume_set_caps), (volume_transform), (volume_update_mute), + (volume_update_volume), (volume_set_property), + (volume_get_property): + document a little; use basetransform vmethod _set_caps + 2005-08-19 Andy Wingo * ext/alsa/gstalsamixertrack.h: diff --git a/check/Makefile.am b/check/Makefile.am index 52c17ba3cc..dc37610613 100644 --- a/check/Makefile.am +++ b/check/Makefile.am @@ -13,13 +13,21 @@ clean-local: clean-local-check $(CHECK_REGISTRY): $(TESTS_ENVIRONMENT) \ GST_PLUGIN_PATH_ONLY=yes \ - GST_PLUGIN_PATH=$(top_builddir)/gst \ + GST_PLUGIN_PATH=$(top_builddir)/gst:$(top_builddir)/ext \ $(GST_TOOLS_DIR)/gst-register-@GST_MAJORMINOR@ TESTS = $(GST_TOOLS_DIR)/gst-register-@GST_MAJORMINOR@ \ $(check_PROGRAMS) -check_PROGRAMS = elements/volume +if USE_VORBIS +check_vorbis = elements/vorbisdec +else +check_vorbis = +endif + +check_PROGRAMS = \ + elements/volume \ + $(check_vorbis) AM_CFLAGS = $(GST_OBJ_CFLAGS) $(GST_CHECK_CFLAGS) LDADD = $(GST_OBJ_LIBS) $(GST_CHECK_LIBS) diff --git a/check/elements/.gitignore b/check/elements/.gitignore index b638b06eb0..5993deb662 100644 --- a/check/elements/.gitignore +++ b/check/elements/.gitignore @@ -1,2 +1,3 @@ .dirstamp volume +vorbisdec diff --git a/check/elements/volume.c b/check/elements/volume.c index b2fcc2dac8..e28216f085 100644 --- a/check/elements/volume.c +++ b/check/elements/volume.c @@ -51,6 +51,16 @@ GstPad *mysrcpad, *mysinkpad; "depth = (int) 16, " \ "signed = (bool) TRUE" +#define VOLUME_WRONG_CAPS_STRING \ + "audio/x-raw-int, " \ + "channels = (int) 1, " \ + "rate = (int) 44100, " \ + "endianness = (int) BYTE_ORDER, " \ + "width = (int) 16, " \ + "depth = (int) 16, " \ + "signed = (bool) FALSE" + + static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, @@ -71,23 +81,6 @@ chain_func (GstPad * pad, GstBuffer * buffer) return GST_FLOW_OK; } -gboolean -event_func (GstPad * pad, GstEvent * event) -{ - if (GST_EVENT_TYPE (event) == GST_EVENT_EOS) { - /* we take the lock here because it's good practice to so, even though - * no buffers will be pushed anymore anyway */ - GST_STREAM_LOCK (pad); - have_eos = TRUE; - GST_STREAM_UNLOCK (pad); - gst_event_unref (event); - return TRUE; - } - - gst_event_unref (event); - return FALSE; -} - GstElement * setup_volume () { @@ -125,7 +118,6 @@ setup_volume () fail_if (srcpad == NULL, "Could not get source pad from volume"); gst_pad_set_caps (mysinkpad, NULL); gst_pad_set_chain_function (mysinkpad, chain_func); - gst_pad_set_event_function (mysinkpad, event_func); fail_unless (gst_pad_link (srcpad, mysinkpad) == GST_PAD_LINK_OK, "Could not link volume source and mysink pads"); @@ -194,7 +186,7 @@ GST_START_TEST (test_unity) ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); /* pushing gives away my reference ... */ - gst_pad_push (mysrcpad, inbuffer); + fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK); /* ... but it ends up being collected on the global buffer list */ ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); fail_unless (g_list_length (buffers) == 1); @@ -232,7 +224,7 @@ GST_START_TEST (test_half) */ /* pushing gives away my reference ... */ - gst_pad_push (mysrcpad, inbuffer); + fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK); /* ... but it ends up being modified inplace and * collected on the global buffer list */ ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); @@ -271,7 +263,7 @@ GST_START_TEST (test_double) */ /* pushing gives away my reference ... */ - gst_pad_push (mysrcpad, inbuffer); + fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK); /* ... but it ends up being modified inplace and * collected on the global buffer list */ ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); @@ -286,6 +278,50 @@ GST_START_TEST (test_double) GST_END_TEST; +GST_START_TEST (test_wrong_caps) +{ + GstElement *volume; + GstBuffer *inbuffer, *outbuffer; + gint16 in[2] = { 16384, -256 }; + GstBus *bus; + GstMessage *message; + + volume = setup_volume (); + bus = gst_bus_new (); + + fail_unless (gst_element_set_state (volume, + GST_STATE_PLAYING) == GST_STATE_SUCCESS, "could not set to playing"); + + inbuffer = gst_buffer_new_and_alloc (4); + memcpy (GST_BUFFER_DATA (inbuffer), in, 4); + gst_buffer_set_caps (inbuffer, + gst_caps_from_string (VOLUME_WRONG_CAPS_STRING)); + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + gst_buffer_ref (inbuffer); + + /* set a bus here so we avoid getting state change messages */ + gst_element_set_bus (volume, bus); + + /* pushing gives an error because it can't negotiate with wrong caps */ + fail_unless_equals_int (gst_pad_push (mysrcpad, inbuffer), + GST_FLOW_NOT_NEGOTIATED); + /* ... and the buffer would have been lost if we didn't ref it ourselves */ + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + gst_buffer_unref (inbuffer); + fail_unless_equals_int (g_list_length (buffers), 0); + + /* volume_set_caps should not have been called since basetransform caught + * the negotiation problem */ + fail_if ((message = gst_bus_pop (bus)) != NULL); + + /* cleanup */ + gst_element_set_bus (volume, NULL); + gst_object_unref (GST_OBJECT (bus)); + cleanup_volume (volume); +} + +GST_END_TEST; + Suite * volume_suite (void) @@ -297,6 +333,7 @@ volume_suite (void) tcase_add_test (tc_chain, test_unity); tcase_add_test (tc_chain, test_half); tcase_add_test (tc_chain, test_double); + tcase_add_test (tc_chain, test_wrong_caps); return s; } diff --git a/check/elements/vorbisdec.c b/check/elements/vorbisdec.c new file mode 100644 index 0000000000..c8b9aaf15b --- /dev/null +++ b/check/elements/vorbisdec.c @@ -0,0 +1,251 @@ +/* GStreamer + * + * unit test for vorbisdec + * + * Copyright (C) <2005> Thomas Vander Stichele + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include + +GList *buffers = NULL; + +/* For ease of programming we use globals to keep refs for our floating + * src and sink pads we create; otherwise we always have to do get_pad, + * get_peer, and then remove references in every test function */ +GstPad *mysrcpad, *mysinkpad; + +/* a valid first header packet */ +guchar identification_header[30] = { + 1, /* packet_type */ + 'v', 'o', 'r', 'b', 'i', 's', + 0, 0, 0, 0, /* vorbis_version */ + 2, /* audio_channels */ + 0x44, 0xac, 0, 0, /* sample_rate */ + 0xff, 0xff, 0xff, 0xff, /* bitrate_maximum */ + 0x00, 0xee, 0x02, 0x00, /* bitrate_nominal */ + 0xff, 0xff, 0xff, 0xff, /* bitrate_minimum */ + 0xb8, /* blocksize_0, blocksize_1 */ + 0x01, /* framing_flag */ +}; + +static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS_ANY); +static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS_ANY); + +GstFlowReturn +chain_func (GstPad * pad, GstBuffer * buffer) +{ + GST_DEBUG ("chain_func: received buffer %p", buffer); + buffers = g_list_append (buffers, buffer); + + return GST_FLOW_OK; +} + +GstElement * +setup_vorbisdec () +{ + GstElement *vorbisdec; + GstPad *srcpad, *sinkpad; + + GST_DEBUG ("setup_vorbisdec"); + + vorbisdec = gst_element_factory_make ("vorbisdec", "vorbisdec"); + fail_if (vorbisdec == NULL, "Could not create a vorbisdec"); + + /* sending pad */ + mysrcpad = + gst_pad_new_from_template (gst_static_pad_template_get (&srctemplate), + "src"); + fail_if (mysrcpad == NULL, "Could not create a mysrcpad"); + ASSERT_OBJECT_REFCOUNT (mysrcpad, "mysrcpad", 1); + + sinkpad = gst_element_get_pad (vorbisdec, "sink"); + fail_if (sinkpad == NULL, "Could not get source pad from vorbisdec"); + ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 2); + gst_pad_set_caps (mysrcpad, NULL); + fail_unless (gst_pad_link (mysrcpad, sinkpad) == GST_PAD_LINK_OK, + "Could not link source and vorbisdec sink pads"); + gst_object_unref (sinkpad); /* because we got it higher up */ + ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 1); + + /* receiving pad */ + mysinkpad = + gst_pad_new_from_template (gst_static_pad_template_get (&sinktemplate), + "sink"); + fail_if (mysinkpad == NULL, "Could not create a mysinkpad"); + + srcpad = gst_element_get_pad (vorbisdec, "src"); + fail_if (srcpad == NULL, "Could not get source pad from vorbisdec"); + gst_pad_set_caps (mysinkpad, NULL); + gst_pad_set_chain_function (mysinkpad, chain_func); + + fail_unless (gst_pad_link (srcpad, mysinkpad) == GST_PAD_LINK_OK, + "Could not link vorbisdec source and mysink pads"); + gst_object_unref (srcpad); /* because we got it higher up */ + ASSERT_OBJECT_REFCOUNT (srcpad, "srcpad", 1); + + return vorbisdec; +} + +void +cleanup_vorbisdec (GstElement * vorbisdec) +{ + GstPad *srcpad, *sinkpad; + + GST_DEBUG ("cleanup_vorbisdec"); + + fail_unless (gst_element_set_state (vorbisdec, GST_STATE_NULL) == + GST_STATE_SUCCESS, "could not set to null"); + ASSERT_OBJECT_REFCOUNT (vorbisdec, "vorbisdec", 1); + + /* clean up floating src pad */ + sinkpad = gst_element_get_pad (vorbisdec, "sink"); + ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 2); + + gst_pad_unlink (mysrcpad, sinkpad); + + /* pad refs held by both creator and this function (through _get) */ + ASSERT_OBJECT_REFCOUNT (mysrcpad, "srcpad", 1); + gst_object_unref (mysrcpad); + mysrcpad = NULL; + + ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 2); + gst_object_unref (sinkpad); + /* one more ref is held by vorbisdec itself */ + + /* clean up floating sink pad */ + srcpad = gst_element_get_pad (vorbisdec, "src"); + gst_pad_unlink (srcpad, mysinkpad); + + /* pad refs held by both creator and this function (through _get) */ + ASSERT_OBJECT_REFCOUNT (srcpad, "srcpad", 2); + gst_object_unref (srcpad); + /* one more ref is held by vorbisdec itself */ + + ASSERT_OBJECT_REFCOUNT (mysinkpad, "mysinkpad", 1); + gst_object_unref (mysinkpad); + mysinkpad = NULL; + + ASSERT_OBJECT_REFCOUNT (vorbisdec, "vorbisdec", 1); + gst_object_unref (vorbisdec); +} + +GST_START_TEST (test_empty_identification_header) +{ + GstElement *vorbisdec; + GstBuffer *inbuffer, *outbuffer; + GstBus *bus; + GstMessage *message; + GError *error; + gchar *debug; + + vorbisdec = setup_vorbisdec (); + bus = gst_bus_new (); + + fail_unless (gst_element_set_state (vorbisdec, + GST_STATE_PLAYING) == GST_STATE_SUCCESS, "could not set to playing"); + + inbuffer = gst_buffer_new_and_alloc (0); + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + + /* set a bus here so we avoid getting state change messages */ + gst_element_set_bus (vorbisdec, bus); + + fail_unless_equals_int (gst_pad_push (mysrcpad, inbuffer), GST_FLOW_ERROR); + /* ... but it ends up being collected on the global buffer list */ + fail_unless_equals_int (g_list_length (buffers), 0); + + fail_if ((message = gst_bus_pop (bus)) == NULL); + fail_unless_message_error (message, STREAM, DECODE); + gst_message_unref (message); + gst_element_set_bus (vorbisdec, NULL); + + /* cleanup */ + gst_object_unref (GST_OBJECT (bus)); + cleanup_vorbisdec (vorbisdec); +} + +GST_END_TEST; + + +GST_START_TEST (test_unity) +{ + GstElement *vorbisdec; + GstBuffer *inbuffer, *outbuffer; + gint16 in[2] = { 16384, -256 }; + + vorbisdec = setup_vorbisdec (); + fail_unless (gst_element_set_state (vorbisdec, + GST_STATE_PLAYING) == GST_STATE_SUCCESS, "could not set to playing"); + + inbuffer = gst_buffer_new_and_alloc (30); + memcpy (GST_BUFFER_DATA (inbuffer), identification_header, 30); + //FIXME: add a test for wrong channels, like so: + //GST_BUFFER_DATA (inbuffer)[12] = 7; + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + gst_buffer_ref (inbuffer); + + /* pushing gives away my reference ... */ + fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK); + /* ... and nothing ends up on the global buffer list */ + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + gst_buffer_unref (inbuffer); + fail_unless (g_list_length (buffers) == 0); + + /* cleanup */ + cleanup_vorbisdec (vorbisdec); +} + +GST_END_TEST; + +Suite * +vorbisdec_suite (void) +{ + Suite *s = suite_create ("vorbisdec"); + TCase *tc_chain = tcase_create ("general"); + + suite_add_tcase (s, tc_chain); + tcase_add_test (tc_chain, test_unity); + tcase_add_test (tc_chain, test_empty_identification_header); + + return s; +} + +int +main (int argc, char **argv) +{ + int nf; + + Suite *s = vorbisdec_suite (); + SRunner *sr = srunner_create (s); + + gst_check_init (&argc, &argv); + + srunner_run_all (sr, CK_NORMAL); + nf = srunner_ntests_failed (sr); + srunner_free (sr); + + return nf; +} diff --git a/ext/ogg/gstoggdemux.c b/ext/ogg/gstoggdemux.c index d026bfb0f3..a96bae3807 100644 --- a/ext/ogg/gstoggdemux.c +++ b/ext/ogg/gstoggdemux.c @@ -929,11 +929,12 @@ gst_ogg_chain_new_stream (GstOggChain * chain, glong serialno) } gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_SERIAL, serialno, NULL); + /* FIXME: either have it or remove it */ //gst_element_found_tags (GST_ELEMENT (ogg), list); gst_tag_list_free (list); - GST_LOG ("created new ogg src %p for stream with serial %08lx", ret, - serialno); + GST_DEBUG_OBJECT (chain->ogg, + "created new ogg src %p for stream with serial %08lx", ret, serialno); g_array_append_val (chain->streams, ret); @@ -2101,16 +2102,14 @@ gst_ogg_demux_chain (GstPad * pad, GstBuffer * buffer) unknown_chain: { GST_ELEMENT_ERROR (ogg, STREAM, DECODE, - ("unknown ogg chain for serial %08x detected", serialno), - ("unknown ogg chain for serial %08x detected", serialno)); + (NULL), ("unknown ogg chain for serial %08x detected", serialno)); gst_ogg_demux_send_event (ogg, gst_event_new_eos ()); return GST_FLOW_ERROR; } unknown_pad: { GST_ELEMENT_ERROR (ogg, STREAM, DECODE, - ("unknown ogg pad for serial %08d detected", serialno), - ("unknown ogg pad for serial %08d detected", serialno)); + (NULL), ("unknown ogg pad for serial %08d detected", serialno)); gst_ogg_demux_send_event (ogg, gst_event_new_eos ()); return GST_FLOW_ERROR; } @@ -2203,8 +2202,7 @@ gst_ogg_demux_loop (GstOggPad * pad) /* ERRORS */ chain_read_failed: { - GST_ELEMENT_ERROR (ogg, STREAM, DEMUX, - ("could not read chains"), ("could not read chains")); + GST_ELEMENT_ERROR (ogg, STREAM, DEMUX, (NULL), ("could not read chains")); ret = GST_FLOW_ERROR; goto pause; } @@ -2215,8 +2213,7 @@ pause: if (GST_FLOW_IS_FATAL (ret)) { gst_ogg_demux_send_event (ogg, gst_event_new_eos ()); GST_ELEMENT_ERROR (ogg, STREAM, STOPPED, - ("stream stopped, reason %d", ret), - ("stream stopped, reason %d", ret)); + (NULL), ("stream stopped, reason %d", ret)); } return; } diff --git a/ext/vorbis/vorbisdec.c b/ext/vorbis/vorbisdec.c index 15d7b782c9..9426454438 100644 --- a/ext/vorbis/vorbisdec.c +++ b/ext/vorbis/vorbisdec.c @@ -753,18 +753,24 @@ vorbis_dec_chain (GstPad * pad, GstBuffer * buffer) vd = GST_VORBIS_DEC (GST_PAD_PARENT (pad)); + if (GST_BUFFER_SIZE (buffer) == 0) { + gst_buffer_unref (buffer); + GST_ELEMENT_ERROR (vd, STREAM, DECODE, (NULL), ("Empty buffer received")); + return GST_FLOW_ERROR; + } /* make ogg_packet out of the buffer */ packet.packet = GST_BUFFER_DATA (buffer); packet.bytes = GST_BUFFER_SIZE (buffer); packet.granulepos = GST_BUFFER_OFFSET_END (buffer); packet.packetno = vd->packetno++; - /* + /* * FIXME. Is there anyway to know that this is the last packet and * set e_o_s?? */ packet.e_o_s = 0; - GST_DEBUG ("vorbis granule: %" G_GUINT64_FORMAT, packet.granulepos); + GST_DEBUG_OBJECT (vd, "vorbis granule: %" G_GUINT64_FORMAT, + packet.granulepos); /* switch depending on packet type */ if (packet.packet[0] & 1) { @@ -777,7 +783,8 @@ vorbis_dec_chain (GstPad * pad, GstBuffer * buffer) result = vorbis_handle_data_packet (vd, &packet); } - GST_DEBUG ("offset end: %" G_GUINT64_FORMAT, GST_BUFFER_OFFSET_END (buffer)); + GST_DEBUG_OBJECT (vd, "offset end: %" G_GUINT64_FORMAT, + GST_BUFFER_OFFSET_END (buffer)); done: gst_buffer_unref (buffer); diff --git a/ext/vorbis/vorbisenc.c b/ext/vorbis/vorbisenc.c index 76b5ab4b88..a50316d158 100644 --- a/ext/vorbis/vorbisenc.c +++ b/ext/vorbis/vorbisenc.c @@ -17,6 +17,13 @@ * Boston, MA 02111-1307, USA. */ +/** + * SECTION:vorbisenc + * @short_description: an encoder that encodes to Ogg/Vorbis + * @see_also: oggdemux + * + */ + #ifdef HAVE_CONFIG_H #include "config.h" @@ -43,7 +50,7 @@ GstElementDetails vorbisenc_details = { "Monty , " "Wim Taymans ", }; -/* VorbisEnc signals and args */ +/* GstVorbisEnc signals and args */ enum { /* FILL ME */ @@ -102,12 +109,12 @@ gst_vorbisenc_get_formats (GstPad * pad) #define HIGHEST_BITRATE 250001 /* highest allowed for a 44 kHz stream */ static void gst_vorbisenc_base_init (gpointer g_class); -static void gst_vorbisenc_class_init (VorbisEncClass * klass); -static void gst_vorbisenc_init (VorbisEnc * vorbisenc); +static void gst_vorbisenc_class_init (GstVorbisEncClass * klass); +static void gst_vorbisenc_init (GstVorbisEnc * vorbisenc); static gboolean gst_vorbisenc_sink_event (GstPad * pad, GstEvent * event); static GstFlowReturn gst_vorbisenc_chain (GstPad * pad, GstBuffer * buffer); -static gboolean gst_vorbisenc_setup (VorbisEnc * vorbisenc); +static gboolean gst_vorbisenc_setup (GstVorbisEnc * vorbisenc); static void gst_vorbisenc_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); @@ -126,13 +133,13 @@ vorbisenc_get_type (void) if (!vorbisenc_type) { static const GTypeInfo vorbisenc_info = { - sizeof (VorbisEncClass), + sizeof (GstVorbisEncClass), gst_vorbisenc_base_init, NULL, (GClassInitFunc) gst_vorbisenc_class_init, NULL, NULL, - sizeof (VorbisEnc), + sizeof (GstVorbisEnc), 0, (GInstanceInitFunc) gst_vorbisenc_init, }; @@ -143,8 +150,8 @@ vorbisenc_get_type (void) }; vorbisenc_type = - g_type_register_static (GST_TYPE_ELEMENT, "VorbisEnc", &vorbisenc_info, - 0); + g_type_register_static (GST_TYPE_ELEMENT, "GstVorbisEnc", + &vorbisenc_info, 0); g_type_add_interface_static (vorbisenc_type, GST_TYPE_TAG_SETTER, &tag_setter_info); @@ -192,7 +199,7 @@ gst_vorbisenc_base_init (gpointer g_class) } static void -gst_vorbisenc_class_init (VorbisEncClass * klass) +gst_vorbisenc_class_init (GstVorbisEncClass * klass) { GObjectClass *gobject_class; GstElementClass *gstelement_class; @@ -238,7 +245,7 @@ gst_vorbisenc_class_init (VorbisEncClass * klass) static gboolean gst_vorbisenc_sink_setcaps (GstPad * pad, GstCaps * caps) { - VorbisEnc *vorbisenc; + GstVorbisEnc *vorbisenc; GstStructure *structure; vorbisenc = GST_VORBISENC (GST_PAD_PARENT (pad)); @@ -261,7 +268,7 @@ gst_vorbisenc_convert_src (GstPad * pad, GstFormat src_format, gint64 src_value, GstFormat * dest_format, gint64 * dest_value) { gboolean res = TRUE; - VorbisEnc *vorbisenc; + GstVorbisEnc *vorbisenc; gint64 avg; vorbisenc = GST_VORBISENC (gst_pad_get_parent (pad)); @@ -304,7 +311,7 @@ gst_vorbisenc_convert_sink (GstPad * pad, GstFormat src_format, gboolean res = TRUE; guint scale = 1; gint bytes_per_sample; - VorbisEnc *vorbisenc; + GstVorbisEnc *vorbisenc; vorbisenc = GST_VORBISENC (gst_pad_get_parent (pad)); @@ -378,7 +385,7 @@ static gboolean gst_vorbisenc_src_query (GstPad * pad, GstQuery * query) { gboolean res = TRUE; - VorbisEnc *vorbisenc; + GstVorbisEnc *vorbisenc; vorbisenc = GST_VORBISENC (GST_PAD_PARENT (pad)); @@ -453,7 +460,7 @@ static gboolean gst_vorbisenc_sink_query (GstPad * pad, GstQuery * query) { gboolean res = TRUE; - VorbisEnc *vorbisenc; + GstVorbisEnc *vorbisenc; vorbisenc = GST_VORBISENC (GST_PAD_PARENT (pad)); @@ -481,7 +488,7 @@ error: } static void -gst_vorbisenc_init (VorbisEnc * vorbisenc) +gst_vorbisenc_init (GstVorbisEnc * vorbisenc) { vorbisenc->sinkpad = gst_pad_new_from_template (gst_vorbisenc_sink_template, "sink"); @@ -566,7 +573,7 @@ gst_vorbisenc_metadata_set1 (const GstTagList * list, const gchar * tag, const gchar *vorbistag = NULL; gchar *vorbisvalue = NULL; guint i, count; - VorbisEnc *enc = GST_VORBISENC (vorbisenc); + GstVorbisEnc *enc = GST_VORBISENC (vorbisenc); vorbistag = gst_tag_to_vorbis_tag (tag); if (vorbistag == NULL) { @@ -584,7 +591,7 @@ gst_vorbisenc_metadata_set1 (const GstTagList * list, const gchar * tag, } static void -gst_vorbisenc_set_metadata (VorbisEnc * vorbisenc) +gst_vorbisenc_set_metadata (GstVorbisEnc * vorbisenc) { GstTagList *copy; const GstTagList *user_tags; @@ -602,7 +609,7 @@ gst_vorbisenc_set_metadata (VorbisEnc * vorbisenc) } static gchar * -get_constraints_string (VorbisEnc * vorbisenc) +get_constraints_string (GstVorbisEnc * vorbisenc) { gint min = vorbisenc->min_bitrate; gint max = vorbisenc->max_bitrate; @@ -621,7 +628,7 @@ get_constraints_string (VorbisEnc * vorbisenc) } static void -update_start_message (VorbisEnc * vorbisenc) +update_start_message (GstVorbisEnc * vorbisenc) { gchar *constraints; @@ -666,7 +673,7 @@ update_start_message (VorbisEnc * vorbisenc) } static gboolean -gst_vorbisenc_setup (VorbisEnc * vorbisenc) +gst_vorbisenc_setup (GstVorbisEnc * vorbisenc) { vorbisenc->setup = FALSE; @@ -744,7 +751,7 @@ gst_vorbisenc_setup (VorbisEnc * vorbisenc) /* prepare a buffer for transmission by passing data through libvorbis */ static GstBuffer * -gst_vorbisenc_buffer_from_packet (VorbisEnc * vorbisenc, ogg_packet * packet) +gst_vorbisenc_buffer_from_packet (GstVorbisEnc * vorbisenc, ogg_packet * packet) { GstBuffer *outbuf; @@ -762,7 +769,7 @@ gst_vorbisenc_buffer_from_packet (VorbisEnc * vorbisenc, ogg_packet * packet) /* push out the buffer and do internal bookkeeping */ static void -gst_vorbisenc_push_buffer (VorbisEnc * vorbisenc, GstBuffer * buffer) +gst_vorbisenc_push_buffer (GstVorbisEnc * vorbisenc, GstBuffer * buffer) { vorbisenc->bytes_out += GST_BUFFER_SIZE (buffer); @@ -774,7 +781,7 @@ gst_vorbisenc_push_buffer (VorbisEnc * vorbisenc, GstBuffer * buffer) } static void -gst_vorbisenc_push_packet (VorbisEnc * vorbisenc, ogg_packet * packet) +gst_vorbisenc_push_packet (GstVorbisEnc * vorbisenc, ogg_packet * packet) { GstBuffer *outbuf; @@ -822,7 +829,7 @@ static gboolean gst_vorbisenc_sink_event (GstPad * pad, GstEvent * event) { gboolean res = TRUE; - VorbisEnc *vorbisenc; + GstVorbisEnc *vorbisenc; vorbisenc = GST_VORBISENC (GST_PAD_PARENT (pad)); @@ -832,6 +839,7 @@ gst_vorbisenc_sink_event (GstPad * pad, GstEvent * event) but it's easier to see here in non-clever fashion. Tell the library we're at end of stream so that it can handle the last frame and mark end of stream in the output properly */ + GST_DEBUG_OBJECT (vorbisenc, "received EOS, will process later"); vorbis_analysis_wrote (&vorbisenc->vd, 0); vorbisenc->eos = TRUE; gst_event_unref (event); @@ -859,7 +867,7 @@ static GstFlowReturn gst_vorbisenc_chain (GstPad * pad, GstBuffer * buffer) { GstBuffer *buf = GST_BUFFER (buffer); - VorbisEnc *vorbisenc; + GstVorbisEnc *vorbisenc; vorbisenc = GST_VORBISENC (GST_PAD_PARENT (pad)); @@ -877,6 +885,7 @@ gst_vorbisenc_chain (GstPad * pad, GstBuffer * buffer) } if (!vorbisenc->header_sent) { + GST_DEBUG_OBJECT (vorbisenc, "creating and sending header packets"); //gint result; /* Vorbis streams begin with three headers; the initial header (with @@ -948,16 +957,20 @@ gst_vorbisenc_chain (GstPad * pad, GstBuffer * buffer) while (vorbis_analysis_blockout (&vorbisenc->vd, &vorbisenc->vb) == 1) { ogg_packet op; + GST_LOG_OBJECT (vorbisenc, "analysed to a block"); + /* analysis */ vorbis_analysis (&vorbisenc->vb, NULL); vorbis_bitrate_addblock (&vorbisenc->vb); while (vorbis_bitrate_flushpacket (&vorbisenc->vd, &op)) { + GST_LOG_OBJECT (vorbisenc, "pushing out a data packet"); gst_vorbisenc_push_packet (vorbisenc, &op); } } if (vorbisenc->eos) { + GST_DEBUG_OBJECT (vorbisenc, "EOS, clearing state and sending event on"); /* clean up and exit. vorbis_info_clear() must be called last */ vorbis_block_clear (&vorbisenc->vb); vorbis_dsp_clear (&vorbisenc->vd); @@ -972,7 +985,7 @@ static void gst_vorbisenc_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { - VorbisEnc *vorbisenc; + GstVorbisEnc *vorbisenc; g_return_if_fail (GST_IS_VORBISENC (object)); @@ -1007,7 +1020,7 @@ static void gst_vorbisenc_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { - VorbisEnc *vorbisenc; + GstVorbisEnc *vorbisenc; g_return_if_fail (GST_IS_VORBISENC (object)); @@ -1078,7 +1091,7 @@ gst_vorbisenc_set_property (GObject * object, guint prop_id, static GstElementStateReturn gst_vorbisenc_change_state (GstElement * element) { - VorbisEnc *vorbisenc = GST_VORBISENC (element); + GstVorbisEnc *vorbisenc = GST_VORBISENC (element); GstElementState transition; GstElementStateReturn res; diff --git a/ext/vorbis/vorbisenc.h b/ext/vorbis/vorbisenc.h index c81b14261a..94c151d811 100644 --- a/ext/vorbis/vorbisenc.h +++ b/ext/vorbis/vorbisenc.h @@ -33,22 +33,22 @@ extern "C" { #define GST_TYPE_VORBISENC \ (vorbisenc_get_type()) #define GST_VORBISENC(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VORBISENC,VorbisEnc)) + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VORBISENC,GstVorbisEnc)) #define GST_VORBISENC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_VORBISENC,VorbisEncClass)) + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_VORBISENC,GstVorbisEncClass)) #define GST_IS_VORBISENC(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VORBISENC)) #define GST_IS_VORBISENC_CLASS(obj) \ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_VORBISENC)) -typedef struct _VorbisEnc VorbisEnc; -typedef struct _VorbisEncClass VorbisEncClass; +typedef struct _GstVorbisEnc GstVorbisEnc; +typedef struct _GstVorbisEncClass GstVorbisEncClass; -struct _VorbisEnc { - GstElement element; +struct _GstVorbisEnc { + GstElement element; - GstPad *sinkpad, - *srcpad; + GstPad *sinkpad; + GstPad *srcpad; vorbis_info vi; /* struct that stores all the static vorbis bitstream settings */ @@ -79,7 +79,7 @@ struct _VorbisEnc { gchar *last_message; }; -struct _VorbisEncClass { +struct _GstVorbisEncClass { GstElementClass parent_class; }; diff --git a/gst/ffmpegcolorspace/gstffmpegcolorspace.c b/gst/ffmpegcolorspace/gstffmpegcolorspace.c index 266b8d16b6..792b20ff33 100644 --- a/gst/ffmpegcolorspace/gstffmpegcolorspace.c +++ b/gst/ffmpegcolorspace/gstffmpegcolorspace.c @@ -343,7 +343,7 @@ gst_ffmpegcsp_transform (GstBaseTransform * btrans, GstBuffer * inbuf, GST_DEBUG ("from %d -> to %d", space->from_pixfmt, space->to_pixfmt); if (space->from_pixfmt == PIX_FMT_NB || space->to_pixfmt == PIX_FMT_NB) - goto unkown_format; + goto unknown_format; /* fill from with source data */ gst_ffmpegcsp_avpicture_fill (&space->from_frame, @@ -368,7 +368,7 @@ gst_ffmpegcsp_transform (GstBaseTransform * btrans, GstBuffer * inbuf, return GST_FLOW_OK; /* ERRORS */ -unkown_format: +unknown_format: { GST_ELEMENT_ERROR (space, CORE, NOT_IMPLEMENTED, (NULL), ("attempting to convert colorspaces between unknown formats")); diff --git a/gst/tcp/gstmultifdsink.c b/gst/tcp/gstmultifdsink.c index c55ed26354..00003de2ee 100644 --- a/gst/tcp/gstmultifdsink.c +++ b/gst/tcp/gstmultifdsink.c @@ -431,7 +431,8 @@ gst_multifdsink_class_init (GstMultiFdSinkClass * klass) client_removed), NULL, NULL, gst_tcp_marshal_VOID__INT_BOXED, G_TYPE_NONE, 2, G_TYPE_INT, GST_TYPE_CLIENT_STATUS); - gstelement_class->change_state = gst_multifdsink_change_state; + gstelement_class->change_state = + GST_DEBUG_FUNCPTR (gst_multifdsink_change_state); gstbasesink_class->render = gst_multifdsink_render; diff --git a/gst/volume/gstvolume.c b/gst/volume/gstvolume.c index e41fe563f1..75b5833686 100644 --- a/gst/volume/gstvolume.c +++ b/gst/volume/gstvolume.c @@ -368,6 +368,8 @@ volume_set_caps (GstBaseTransform * base, GstCaps * incaps, GstCaps * outcaps) { GstVolume *this = GST_VOLUME (base); + GST_DEBUG_OBJECT (this, + "set_caps: in %" GST_PTR_FORMAT " out %" GST_PTR_FORMAT, incaps, outcaps); volume_funcfind (this, gst_caps_get_structure (incaps, 0)); if (!this->process) { diff --git a/tests/check/Makefile.am b/tests/check/Makefile.am index 52c17ba3cc..dc37610613 100644 --- a/tests/check/Makefile.am +++ b/tests/check/Makefile.am @@ -13,13 +13,21 @@ clean-local: clean-local-check $(CHECK_REGISTRY): $(TESTS_ENVIRONMENT) \ GST_PLUGIN_PATH_ONLY=yes \ - GST_PLUGIN_PATH=$(top_builddir)/gst \ + GST_PLUGIN_PATH=$(top_builddir)/gst:$(top_builddir)/ext \ $(GST_TOOLS_DIR)/gst-register-@GST_MAJORMINOR@ TESTS = $(GST_TOOLS_DIR)/gst-register-@GST_MAJORMINOR@ \ $(check_PROGRAMS) -check_PROGRAMS = elements/volume +if USE_VORBIS +check_vorbis = elements/vorbisdec +else +check_vorbis = +endif + +check_PROGRAMS = \ + elements/volume \ + $(check_vorbis) AM_CFLAGS = $(GST_OBJ_CFLAGS) $(GST_CHECK_CFLAGS) LDADD = $(GST_OBJ_LIBS) $(GST_CHECK_LIBS) diff --git a/tests/check/elements/.gitignore b/tests/check/elements/.gitignore index b638b06eb0..5993deb662 100644 --- a/tests/check/elements/.gitignore +++ b/tests/check/elements/.gitignore @@ -1,2 +1,3 @@ .dirstamp volume +vorbisdec diff --git a/tests/check/elements/volume.c b/tests/check/elements/volume.c index b2fcc2dac8..e28216f085 100644 --- a/tests/check/elements/volume.c +++ b/tests/check/elements/volume.c @@ -51,6 +51,16 @@ GstPad *mysrcpad, *mysinkpad; "depth = (int) 16, " \ "signed = (bool) TRUE" +#define VOLUME_WRONG_CAPS_STRING \ + "audio/x-raw-int, " \ + "channels = (int) 1, " \ + "rate = (int) 44100, " \ + "endianness = (int) BYTE_ORDER, " \ + "width = (int) 16, " \ + "depth = (int) 16, " \ + "signed = (bool) FALSE" + + static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, @@ -71,23 +81,6 @@ chain_func (GstPad * pad, GstBuffer * buffer) return GST_FLOW_OK; } -gboolean -event_func (GstPad * pad, GstEvent * event) -{ - if (GST_EVENT_TYPE (event) == GST_EVENT_EOS) { - /* we take the lock here because it's good practice to so, even though - * no buffers will be pushed anymore anyway */ - GST_STREAM_LOCK (pad); - have_eos = TRUE; - GST_STREAM_UNLOCK (pad); - gst_event_unref (event); - return TRUE; - } - - gst_event_unref (event); - return FALSE; -} - GstElement * setup_volume () { @@ -125,7 +118,6 @@ setup_volume () fail_if (srcpad == NULL, "Could not get source pad from volume"); gst_pad_set_caps (mysinkpad, NULL); gst_pad_set_chain_function (mysinkpad, chain_func); - gst_pad_set_event_function (mysinkpad, event_func); fail_unless (gst_pad_link (srcpad, mysinkpad) == GST_PAD_LINK_OK, "Could not link volume source and mysink pads"); @@ -194,7 +186,7 @@ GST_START_TEST (test_unity) ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); /* pushing gives away my reference ... */ - gst_pad_push (mysrcpad, inbuffer); + fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK); /* ... but it ends up being collected on the global buffer list */ ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); fail_unless (g_list_length (buffers) == 1); @@ -232,7 +224,7 @@ GST_START_TEST (test_half) */ /* pushing gives away my reference ... */ - gst_pad_push (mysrcpad, inbuffer); + fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK); /* ... but it ends up being modified inplace and * collected on the global buffer list */ ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); @@ -271,7 +263,7 @@ GST_START_TEST (test_double) */ /* pushing gives away my reference ... */ - gst_pad_push (mysrcpad, inbuffer); + fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK); /* ... but it ends up being modified inplace and * collected on the global buffer list */ ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); @@ -286,6 +278,50 @@ GST_START_TEST (test_double) GST_END_TEST; +GST_START_TEST (test_wrong_caps) +{ + GstElement *volume; + GstBuffer *inbuffer, *outbuffer; + gint16 in[2] = { 16384, -256 }; + GstBus *bus; + GstMessage *message; + + volume = setup_volume (); + bus = gst_bus_new (); + + fail_unless (gst_element_set_state (volume, + GST_STATE_PLAYING) == GST_STATE_SUCCESS, "could not set to playing"); + + inbuffer = gst_buffer_new_and_alloc (4); + memcpy (GST_BUFFER_DATA (inbuffer), in, 4); + gst_buffer_set_caps (inbuffer, + gst_caps_from_string (VOLUME_WRONG_CAPS_STRING)); + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + gst_buffer_ref (inbuffer); + + /* set a bus here so we avoid getting state change messages */ + gst_element_set_bus (volume, bus); + + /* pushing gives an error because it can't negotiate with wrong caps */ + fail_unless_equals_int (gst_pad_push (mysrcpad, inbuffer), + GST_FLOW_NOT_NEGOTIATED); + /* ... and the buffer would have been lost if we didn't ref it ourselves */ + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + gst_buffer_unref (inbuffer); + fail_unless_equals_int (g_list_length (buffers), 0); + + /* volume_set_caps should not have been called since basetransform caught + * the negotiation problem */ + fail_if ((message = gst_bus_pop (bus)) != NULL); + + /* cleanup */ + gst_element_set_bus (volume, NULL); + gst_object_unref (GST_OBJECT (bus)); + cleanup_volume (volume); +} + +GST_END_TEST; + Suite * volume_suite (void) @@ -297,6 +333,7 @@ volume_suite (void) tcase_add_test (tc_chain, test_unity); tcase_add_test (tc_chain, test_half); tcase_add_test (tc_chain, test_double); + tcase_add_test (tc_chain, test_wrong_caps); return s; } diff --git a/tests/check/elements/vorbisdec.c b/tests/check/elements/vorbisdec.c new file mode 100644 index 0000000000..c8b9aaf15b --- /dev/null +++ b/tests/check/elements/vorbisdec.c @@ -0,0 +1,251 @@ +/* GStreamer + * + * unit test for vorbisdec + * + * Copyright (C) <2005> Thomas Vander Stichele + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include + +GList *buffers = NULL; + +/* For ease of programming we use globals to keep refs for our floating + * src and sink pads we create; otherwise we always have to do get_pad, + * get_peer, and then remove references in every test function */ +GstPad *mysrcpad, *mysinkpad; + +/* a valid first header packet */ +guchar identification_header[30] = { + 1, /* packet_type */ + 'v', 'o', 'r', 'b', 'i', 's', + 0, 0, 0, 0, /* vorbis_version */ + 2, /* audio_channels */ + 0x44, 0xac, 0, 0, /* sample_rate */ + 0xff, 0xff, 0xff, 0xff, /* bitrate_maximum */ + 0x00, 0xee, 0x02, 0x00, /* bitrate_nominal */ + 0xff, 0xff, 0xff, 0xff, /* bitrate_minimum */ + 0xb8, /* blocksize_0, blocksize_1 */ + 0x01, /* framing_flag */ +}; + +static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS_ANY); +static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS_ANY); + +GstFlowReturn +chain_func (GstPad * pad, GstBuffer * buffer) +{ + GST_DEBUG ("chain_func: received buffer %p", buffer); + buffers = g_list_append (buffers, buffer); + + return GST_FLOW_OK; +} + +GstElement * +setup_vorbisdec () +{ + GstElement *vorbisdec; + GstPad *srcpad, *sinkpad; + + GST_DEBUG ("setup_vorbisdec"); + + vorbisdec = gst_element_factory_make ("vorbisdec", "vorbisdec"); + fail_if (vorbisdec == NULL, "Could not create a vorbisdec"); + + /* sending pad */ + mysrcpad = + gst_pad_new_from_template (gst_static_pad_template_get (&srctemplate), + "src"); + fail_if (mysrcpad == NULL, "Could not create a mysrcpad"); + ASSERT_OBJECT_REFCOUNT (mysrcpad, "mysrcpad", 1); + + sinkpad = gst_element_get_pad (vorbisdec, "sink"); + fail_if (sinkpad == NULL, "Could not get source pad from vorbisdec"); + ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 2); + gst_pad_set_caps (mysrcpad, NULL); + fail_unless (gst_pad_link (mysrcpad, sinkpad) == GST_PAD_LINK_OK, + "Could not link source and vorbisdec sink pads"); + gst_object_unref (sinkpad); /* because we got it higher up */ + ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 1); + + /* receiving pad */ + mysinkpad = + gst_pad_new_from_template (gst_static_pad_template_get (&sinktemplate), + "sink"); + fail_if (mysinkpad == NULL, "Could not create a mysinkpad"); + + srcpad = gst_element_get_pad (vorbisdec, "src"); + fail_if (srcpad == NULL, "Could not get source pad from vorbisdec"); + gst_pad_set_caps (mysinkpad, NULL); + gst_pad_set_chain_function (mysinkpad, chain_func); + + fail_unless (gst_pad_link (srcpad, mysinkpad) == GST_PAD_LINK_OK, + "Could not link vorbisdec source and mysink pads"); + gst_object_unref (srcpad); /* because we got it higher up */ + ASSERT_OBJECT_REFCOUNT (srcpad, "srcpad", 1); + + return vorbisdec; +} + +void +cleanup_vorbisdec (GstElement * vorbisdec) +{ + GstPad *srcpad, *sinkpad; + + GST_DEBUG ("cleanup_vorbisdec"); + + fail_unless (gst_element_set_state (vorbisdec, GST_STATE_NULL) == + GST_STATE_SUCCESS, "could not set to null"); + ASSERT_OBJECT_REFCOUNT (vorbisdec, "vorbisdec", 1); + + /* clean up floating src pad */ + sinkpad = gst_element_get_pad (vorbisdec, "sink"); + ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 2); + + gst_pad_unlink (mysrcpad, sinkpad); + + /* pad refs held by both creator and this function (through _get) */ + ASSERT_OBJECT_REFCOUNT (mysrcpad, "srcpad", 1); + gst_object_unref (mysrcpad); + mysrcpad = NULL; + + ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 2); + gst_object_unref (sinkpad); + /* one more ref is held by vorbisdec itself */ + + /* clean up floating sink pad */ + srcpad = gst_element_get_pad (vorbisdec, "src"); + gst_pad_unlink (srcpad, mysinkpad); + + /* pad refs held by both creator and this function (through _get) */ + ASSERT_OBJECT_REFCOUNT (srcpad, "srcpad", 2); + gst_object_unref (srcpad); + /* one more ref is held by vorbisdec itself */ + + ASSERT_OBJECT_REFCOUNT (mysinkpad, "mysinkpad", 1); + gst_object_unref (mysinkpad); + mysinkpad = NULL; + + ASSERT_OBJECT_REFCOUNT (vorbisdec, "vorbisdec", 1); + gst_object_unref (vorbisdec); +} + +GST_START_TEST (test_empty_identification_header) +{ + GstElement *vorbisdec; + GstBuffer *inbuffer, *outbuffer; + GstBus *bus; + GstMessage *message; + GError *error; + gchar *debug; + + vorbisdec = setup_vorbisdec (); + bus = gst_bus_new (); + + fail_unless (gst_element_set_state (vorbisdec, + GST_STATE_PLAYING) == GST_STATE_SUCCESS, "could not set to playing"); + + inbuffer = gst_buffer_new_and_alloc (0); + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + + /* set a bus here so we avoid getting state change messages */ + gst_element_set_bus (vorbisdec, bus); + + fail_unless_equals_int (gst_pad_push (mysrcpad, inbuffer), GST_FLOW_ERROR); + /* ... but it ends up being collected on the global buffer list */ + fail_unless_equals_int (g_list_length (buffers), 0); + + fail_if ((message = gst_bus_pop (bus)) == NULL); + fail_unless_message_error (message, STREAM, DECODE); + gst_message_unref (message); + gst_element_set_bus (vorbisdec, NULL); + + /* cleanup */ + gst_object_unref (GST_OBJECT (bus)); + cleanup_vorbisdec (vorbisdec); +} + +GST_END_TEST; + + +GST_START_TEST (test_unity) +{ + GstElement *vorbisdec; + GstBuffer *inbuffer, *outbuffer; + gint16 in[2] = { 16384, -256 }; + + vorbisdec = setup_vorbisdec (); + fail_unless (gst_element_set_state (vorbisdec, + GST_STATE_PLAYING) == GST_STATE_SUCCESS, "could not set to playing"); + + inbuffer = gst_buffer_new_and_alloc (30); + memcpy (GST_BUFFER_DATA (inbuffer), identification_header, 30); + //FIXME: add a test for wrong channels, like so: + //GST_BUFFER_DATA (inbuffer)[12] = 7; + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + gst_buffer_ref (inbuffer); + + /* pushing gives away my reference ... */ + fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK); + /* ... and nothing ends up on the global buffer list */ + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + gst_buffer_unref (inbuffer); + fail_unless (g_list_length (buffers) == 0); + + /* cleanup */ + cleanup_vorbisdec (vorbisdec); +} + +GST_END_TEST; + +Suite * +vorbisdec_suite (void) +{ + Suite *s = suite_create ("vorbisdec"); + TCase *tc_chain = tcase_create ("general"); + + suite_add_tcase (s, tc_chain); + tcase_add_test (tc_chain, test_unity); + tcase_add_test (tc_chain, test_empty_identification_header); + + return s; +} + +int +main (int argc, char **argv) +{ + int nf; + + Suite *s = vorbisdec_suite (); + SRunner *sr = srunner_create (s); + + gst_check_init (&argc, &argv); + + srunner_run_all (sr, CK_NORMAL); + nf = srunner_ntests_failed (sr); + srunner_free (sr); + + return nf; +}