yay, fix a segfault/security issue in vorbisdec gst-launch fakesrc ! vorbisdec wasn't happy add a test for vorbisdec

Original commit message from CVS:
yay, fix a segfault/security issue in vorbisdec
gst-launch fakesrc ! vorbisdec wasn't happy
add a test for vorbisdec
This commit is contained in:
Thomas Vander Stichele 2005-08-20 20:40:25 +00:00
parent 7da31ee8b4
commit 585493a9dd
16 changed files with 772 additions and 99 deletions

View file

@ -1,3 +1,62 @@
2005-08-20 Thomas Vander Stichele <thomas at apestaart dot org>
* 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 <thomas at apestaart dot org>
* 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 <wingo@pobox.com> 2005-08-19 Andy Wingo <wingo@pobox.com>
* ext/alsa/gstalsamixertrack.h: * ext/alsa/gstalsamixertrack.h:

View file

@ -13,13 +13,21 @@ clean-local: clean-local-check
$(CHECK_REGISTRY): $(CHECK_REGISTRY):
$(TESTS_ENVIRONMENT) \ $(TESTS_ENVIRONMENT) \
GST_PLUGIN_PATH_ONLY=yes \ 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@ $(GST_TOOLS_DIR)/gst-register-@GST_MAJORMINOR@
TESTS = $(GST_TOOLS_DIR)/gst-register-@GST_MAJORMINOR@ \ TESTS = $(GST_TOOLS_DIR)/gst-register-@GST_MAJORMINOR@ \
$(check_PROGRAMS) $(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) AM_CFLAGS = $(GST_OBJ_CFLAGS) $(GST_CHECK_CFLAGS)
LDADD = $(GST_OBJ_LIBS) $(GST_CHECK_LIBS) LDADD = $(GST_OBJ_LIBS) $(GST_CHECK_LIBS)

View file

@ -1,2 +1,3 @@
.dirstamp .dirstamp
volume volume
vorbisdec

View file

@ -51,6 +51,16 @@ GstPad *mysrcpad, *mysinkpad;
"depth = (int) 16, " \ "depth = (int) 16, " \
"signed = (bool) TRUE" "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", static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK, GST_PAD_SINK,
GST_PAD_ALWAYS, GST_PAD_ALWAYS,
@ -71,23 +81,6 @@ chain_func (GstPad * pad, GstBuffer * buffer)
return GST_FLOW_OK; 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 * GstElement *
setup_volume () setup_volume ()
{ {
@ -125,7 +118,6 @@ setup_volume ()
fail_if (srcpad == NULL, "Could not get source pad from volume"); fail_if (srcpad == NULL, "Could not get source pad from volume");
gst_pad_set_caps (mysinkpad, NULL); gst_pad_set_caps (mysinkpad, NULL);
gst_pad_set_chain_function (mysinkpad, chain_func); 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, fail_unless (gst_pad_link (srcpad, mysinkpad) == GST_PAD_LINK_OK,
"Could not link volume source and mysink pads"); "Could not link volume source and mysink pads");
@ -194,7 +186,7 @@ GST_START_TEST (test_unity)
ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
/* pushing gives away my reference ... */ /* 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 */ /* ... but it ends up being collected on the global buffer list */
ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
fail_unless (g_list_length (buffers) == 1); fail_unless (g_list_length (buffers) == 1);
@ -232,7 +224,7 @@ GST_START_TEST (test_half)
*/ */
/* pushing gives away my reference ... */ /* 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 /* ... but it ends up being modified inplace and
* collected on the global buffer list */ * collected on the global buffer list */
ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
@ -271,7 +263,7 @@ GST_START_TEST (test_double)
*/ */
/* pushing gives away my reference ... */ /* 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 /* ... but it ends up being modified inplace and
* collected on the global buffer list */ * collected on the global buffer list */
ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
@ -286,6 +278,50 @@ GST_START_TEST (test_double)
GST_END_TEST; 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 * Suite *
volume_suite (void) volume_suite (void)
@ -297,6 +333,7 @@ volume_suite (void)
tcase_add_test (tc_chain, test_unity); tcase_add_test (tc_chain, test_unity);
tcase_add_test (tc_chain, test_half); tcase_add_test (tc_chain, test_half);
tcase_add_test (tc_chain, test_double); tcase_add_test (tc_chain, test_double);
tcase_add_test (tc_chain, test_wrong_caps);
return s; return s;
} }

251
check/elements/vorbisdec.c Normal file
View file

@ -0,0 +1,251 @@
/* GStreamer
*
* unit test for vorbisdec
*
* Copyright (C) <2005> Thomas Vander Stichele <thomas at apestaart dot org>
*
* 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 <unistd.h>
#include <gst/check/gstcheck.h>
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;
}

View file

@ -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, gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_SERIAL, serialno,
NULL); NULL);
/* FIXME: either have it or remove it */
//gst_element_found_tags (GST_ELEMENT (ogg), list); //gst_element_found_tags (GST_ELEMENT (ogg), list);
gst_tag_list_free (list); gst_tag_list_free (list);
GST_LOG ("created new ogg src %p for stream with serial %08lx", ret, GST_DEBUG_OBJECT (chain->ogg,
serialno); "created new ogg src %p for stream with serial %08lx", ret, serialno);
g_array_append_val (chain->streams, ret); g_array_append_val (chain->streams, ret);
@ -2101,16 +2102,14 @@ gst_ogg_demux_chain (GstPad * pad, GstBuffer * buffer)
unknown_chain: unknown_chain:
{ {
GST_ELEMENT_ERROR (ogg, STREAM, DECODE, GST_ELEMENT_ERROR (ogg, STREAM, DECODE,
("unknown ogg chain for serial %08x detected", serialno), (NULL), ("unknown ogg chain for serial %08x detected", serialno));
("unknown ogg chain for serial %08x detected", serialno));
gst_ogg_demux_send_event (ogg, gst_event_new_eos ()); gst_ogg_demux_send_event (ogg, gst_event_new_eos ());
return GST_FLOW_ERROR; return GST_FLOW_ERROR;
} }
unknown_pad: unknown_pad:
{ {
GST_ELEMENT_ERROR (ogg, STREAM, DECODE, GST_ELEMENT_ERROR (ogg, STREAM, DECODE,
("unknown ogg pad for serial %08d detected", serialno), (NULL), ("unknown ogg pad for serial %08d detected", serialno));
("unknown ogg pad for serial %08d detected", serialno));
gst_ogg_demux_send_event (ogg, gst_event_new_eos ()); gst_ogg_demux_send_event (ogg, gst_event_new_eos ());
return GST_FLOW_ERROR; return GST_FLOW_ERROR;
} }
@ -2203,8 +2202,7 @@ gst_ogg_demux_loop (GstOggPad * pad)
/* ERRORS */ /* ERRORS */
chain_read_failed: chain_read_failed:
{ {
GST_ELEMENT_ERROR (ogg, STREAM, DEMUX, GST_ELEMENT_ERROR (ogg, STREAM, DEMUX, (NULL), ("could not read chains"));
("could not read chains"), ("could not read chains"));
ret = GST_FLOW_ERROR; ret = GST_FLOW_ERROR;
goto pause; goto pause;
} }
@ -2215,8 +2213,7 @@ pause:
if (GST_FLOW_IS_FATAL (ret)) { if (GST_FLOW_IS_FATAL (ret)) {
gst_ogg_demux_send_event (ogg, gst_event_new_eos ()); gst_ogg_demux_send_event (ogg, gst_event_new_eos ());
GST_ELEMENT_ERROR (ogg, STREAM, STOPPED, GST_ELEMENT_ERROR (ogg, STREAM, STOPPED,
("stream stopped, reason %d", ret), (NULL), ("stream stopped, reason %d", ret));
("stream stopped, reason %d", ret));
} }
return; return;
} }

View file

@ -753,6 +753,11 @@ vorbis_dec_chain (GstPad * pad, GstBuffer * buffer)
vd = GST_VORBIS_DEC (GST_PAD_PARENT (pad)); 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 */ /* make ogg_packet out of the buffer */
packet.packet = GST_BUFFER_DATA (buffer); packet.packet = GST_BUFFER_DATA (buffer);
packet.bytes = GST_BUFFER_SIZE (buffer); packet.bytes = GST_BUFFER_SIZE (buffer);
@ -764,7 +769,8 @@ vorbis_dec_chain (GstPad * pad, GstBuffer * buffer)
*/ */
packet.e_o_s = 0; 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 */ /* switch depending on packet type */
if (packet.packet[0] & 1) { if (packet.packet[0] & 1) {
@ -777,7 +783,8 @@ vorbis_dec_chain (GstPad * pad, GstBuffer * buffer)
result = vorbis_handle_data_packet (vd, &packet); 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: done:
gst_buffer_unref (buffer); gst_buffer_unref (buffer);

View file

@ -17,6 +17,13 @@
* Boston, MA 02111-1307, USA. * Boston, MA 02111-1307, USA.
*/ */
/**
* SECTION:vorbisenc
* @short_description: an encoder that encodes to Ogg/Vorbis
* @see_also: oggdemux
*
*/
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
@ -43,7 +50,7 @@ GstElementDetails vorbisenc_details = {
"Monty <monty@xiph.org>, " "Wim Taymans <wim@fluendo.com>", "Monty <monty@xiph.org>, " "Wim Taymans <wim@fluendo.com>",
}; };
/* VorbisEnc signals and args */ /* GstVorbisEnc signals and args */
enum enum
{ {
/* FILL ME */ /* FILL ME */
@ -102,12 +109,12 @@ gst_vorbisenc_get_formats (GstPad * pad)
#define HIGHEST_BITRATE 250001 /* highest allowed for a 44 kHz stream */ #define HIGHEST_BITRATE 250001 /* highest allowed for a 44 kHz stream */
static void gst_vorbisenc_base_init (gpointer g_class); static void gst_vorbisenc_base_init (gpointer g_class);
static void gst_vorbisenc_class_init (VorbisEncClass * klass); static void gst_vorbisenc_class_init (GstVorbisEncClass * klass);
static void gst_vorbisenc_init (VorbisEnc * vorbisenc); static void gst_vorbisenc_init (GstVorbisEnc * vorbisenc);
static gboolean gst_vorbisenc_sink_event (GstPad * pad, GstEvent * event); static gboolean gst_vorbisenc_sink_event (GstPad * pad, GstEvent * event);
static GstFlowReturn gst_vorbisenc_chain (GstPad * pad, GstBuffer * buffer); 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, static void gst_vorbisenc_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec); GValue * value, GParamSpec * pspec);
@ -126,13 +133,13 @@ vorbisenc_get_type (void)
if (!vorbisenc_type) { if (!vorbisenc_type) {
static const GTypeInfo vorbisenc_info = { static const GTypeInfo vorbisenc_info = {
sizeof (VorbisEncClass), sizeof (GstVorbisEncClass),
gst_vorbisenc_base_init, gst_vorbisenc_base_init,
NULL, NULL,
(GClassInitFunc) gst_vorbisenc_class_init, (GClassInitFunc) gst_vorbisenc_class_init,
NULL, NULL,
NULL, NULL,
sizeof (VorbisEnc), sizeof (GstVorbisEnc),
0, 0,
(GInstanceInitFunc) gst_vorbisenc_init, (GInstanceInitFunc) gst_vorbisenc_init,
}; };
@ -143,8 +150,8 @@ vorbisenc_get_type (void)
}; };
vorbisenc_type = vorbisenc_type =
g_type_register_static (GST_TYPE_ELEMENT, "VorbisEnc", &vorbisenc_info, g_type_register_static (GST_TYPE_ELEMENT, "GstVorbisEnc",
0); &vorbisenc_info, 0);
g_type_add_interface_static (vorbisenc_type, GST_TYPE_TAG_SETTER, g_type_add_interface_static (vorbisenc_type, GST_TYPE_TAG_SETTER,
&tag_setter_info); &tag_setter_info);
@ -192,7 +199,7 @@ gst_vorbisenc_base_init (gpointer g_class)
} }
static void static void
gst_vorbisenc_class_init (VorbisEncClass * klass) gst_vorbisenc_class_init (GstVorbisEncClass * klass)
{ {
GObjectClass *gobject_class; GObjectClass *gobject_class;
GstElementClass *gstelement_class; GstElementClass *gstelement_class;
@ -238,7 +245,7 @@ gst_vorbisenc_class_init (VorbisEncClass * klass)
static gboolean static gboolean
gst_vorbisenc_sink_setcaps (GstPad * pad, GstCaps * caps) gst_vorbisenc_sink_setcaps (GstPad * pad, GstCaps * caps)
{ {
VorbisEnc *vorbisenc; GstVorbisEnc *vorbisenc;
GstStructure *structure; GstStructure *structure;
vorbisenc = GST_VORBISENC (GST_PAD_PARENT (pad)); 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) GstFormat * dest_format, gint64 * dest_value)
{ {
gboolean res = TRUE; gboolean res = TRUE;
VorbisEnc *vorbisenc; GstVorbisEnc *vorbisenc;
gint64 avg; gint64 avg;
vorbisenc = GST_VORBISENC (gst_pad_get_parent (pad)); vorbisenc = GST_VORBISENC (gst_pad_get_parent (pad));
@ -304,7 +311,7 @@ gst_vorbisenc_convert_sink (GstPad * pad, GstFormat src_format,
gboolean res = TRUE; gboolean res = TRUE;
guint scale = 1; guint scale = 1;
gint bytes_per_sample; gint bytes_per_sample;
VorbisEnc *vorbisenc; GstVorbisEnc *vorbisenc;
vorbisenc = GST_VORBISENC (gst_pad_get_parent (pad)); vorbisenc = GST_VORBISENC (gst_pad_get_parent (pad));
@ -378,7 +385,7 @@ static gboolean
gst_vorbisenc_src_query (GstPad * pad, GstQuery * query) gst_vorbisenc_src_query (GstPad * pad, GstQuery * query)
{ {
gboolean res = TRUE; gboolean res = TRUE;
VorbisEnc *vorbisenc; GstVorbisEnc *vorbisenc;
vorbisenc = GST_VORBISENC (GST_PAD_PARENT (pad)); vorbisenc = GST_VORBISENC (GST_PAD_PARENT (pad));
@ -453,7 +460,7 @@ static gboolean
gst_vorbisenc_sink_query (GstPad * pad, GstQuery * query) gst_vorbisenc_sink_query (GstPad * pad, GstQuery * query)
{ {
gboolean res = TRUE; gboolean res = TRUE;
VorbisEnc *vorbisenc; GstVorbisEnc *vorbisenc;
vorbisenc = GST_VORBISENC (GST_PAD_PARENT (pad)); vorbisenc = GST_VORBISENC (GST_PAD_PARENT (pad));
@ -481,7 +488,7 @@ error:
} }
static void static void
gst_vorbisenc_init (VorbisEnc * vorbisenc) gst_vorbisenc_init (GstVorbisEnc * vorbisenc)
{ {
vorbisenc->sinkpad = vorbisenc->sinkpad =
gst_pad_new_from_template (gst_vorbisenc_sink_template, "sink"); 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; const gchar *vorbistag = NULL;
gchar *vorbisvalue = NULL; gchar *vorbisvalue = NULL;
guint i, count; guint i, count;
VorbisEnc *enc = GST_VORBISENC (vorbisenc); GstVorbisEnc *enc = GST_VORBISENC (vorbisenc);
vorbistag = gst_tag_to_vorbis_tag (tag); vorbistag = gst_tag_to_vorbis_tag (tag);
if (vorbistag == NULL) { if (vorbistag == NULL) {
@ -584,7 +591,7 @@ gst_vorbisenc_metadata_set1 (const GstTagList * list, const gchar * tag,
} }
static void static void
gst_vorbisenc_set_metadata (VorbisEnc * vorbisenc) gst_vorbisenc_set_metadata (GstVorbisEnc * vorbisenc)
{ {
GstTagList *copy; GstTagList *copy;
const GstTagList *user_tags; const GstTagList *user_tags;
@ -602,7 +609,7 @@ gst_vorbisenc_set_metadata (VorbisEnc * vorbisenc)
} }
static gchar * static gchar *
get_constraints_string (VorbisEnc * vorbisenc) get_constraints_string (GstVorbisEnc * vorbisenc)
{ {
gint min = vorbisenc->min_bitrate; gint min = vorbisenc->min_bitrate;
gint max = vorbisenc->max_bitrate; gint max = vorbisenc->max_bitrate;
@ -621,7 +628,7 @@ get_constraints_string (VorbisEnc * vorbisenc)
} }
static void static void
update_start_message (VorbisEnc * vorbisenc) update_start_message (GstVorbisEnc * vorbisenc)
{ {
gchar *constraints; gchar *constraints;
@ -666,7 +673,7 @@ update_start_message (VorbisEnc * vorbisenc)
} }
static gboolean static gboolean
gst_vorbisenc_setup (VorbisEnc * vorbisenc) gst_vorbisenc_setup (GstVorbisEnc * vorbisenc)
{ {
vorbisenc->setup = FALSE; vorbisenc->setup = FALSE;
@ -744,7 +751,7 @@ gst_vorbisenc_setup (VorbisEnc * vorbisenc)
/* prepare a buffer for transmission by passing data through libvorbis */ /* prepare a buffer for transmission by passing data through libvorbis */
static GstBuffer * static GstBuffer *
gst_vorbisenc_buffer_from_packet (VorbisEnc * vorbisenc, ogg_packet * packet) gst_vorbisenc_buffer_from_packet (GstVorbisEnc * vorbisenc, ogg_packet * packet)
{ {
GstBuffer *outbuf; GstBuffer *outbuf;
@ -762,7 +769,7 @@ gst_vorbisenc_buffer_from_packet (VorbisEnc * vorbisenc, ogg_packet * packet)
/* push out the buffer and do internal bookkeeping */ /* push out the buffer and do internal bookkeeping */
static void 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); vorbisenc->bytes_out += GST_BUFFER_SIZE (buffer);
@ -774,7 +781,7 @@ gst_vorbisenc_push_buffer (VorbisEnc * vorbisenc, GstBuffer * buffer)
} }
static void static void
gst_vorbisenc_push_packet (VorbisEnc * vorbisenc, ogg_packet * packet) gst_vorbisenc_push_packet (GstVorbisEnc * vorbisenc, ogg_packet * packet)
{ {
GstBuffer *outbuf; GstBuffer *outbuf;
@ -822,7 +829,7 @@ static gboolean
gst_vorbisenc_sink_event (GstPad * pad, GstEvent * event) gst_vorbisenc_sink_event (GstPad * pad, GstEvent * event)
{ {
gboolean res = TRUE; gboolean res = TRUE;
VorbisEnc *vorbisenc; GstVorbisEnc *vorbisenc;
vorbisenc = GST_VORBISENC (GST_PAD_PARENT (pad)); 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. 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 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 */ 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); vorbis_analysis_wrote (&vorbisenc->vd, 0);
vorbisenc->eos = TRUE; vorbisenc->eos = TRUE;
gst_event_unref (event); gst_event_unref (event);
@ -859,7 +867,7 @@ static GstFlowReturn
gst_vorbisenc_chain (GstPad * pad, GstBuffer * buffer) gst_vorbisenc_chain (GstPad * pad, GstBuffer * buffer)
{ {
GstBuffer *buf = GST_BUFFER (buffer); GstBuffer *buf = GST_BUFFER (buffer);
VorbisEnc *vorbisenc; GstVorbisEnc *vorbisenc;
vorbisenc = GST_VORBISENC (GST_PAD_PARENT (pad)); vorbisenc = GST_VORBISENC (GST_PAD_PARENT (pad));
@ -877,6 +885,7 @@ gst_vorbisenc_chain (GstPad * pad, GstBuffer * buffer)
} }
if (!vorbisenc->header_sent) { if (!vorbisenc->header_sent) {
GST_DEBUG_OBJECT (vorbisenc, "creating and sending header packets");
//gint result; //gint result;
/* Vorbis streams begin with three headers; the initial header (with /* 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) { while (vorbis_analysis_blockout (&vorbisenc->vd, &vorbisenc->vb) == 1) {
ogg_packet op; ogg_packet op;
GST_LOG_OBJECT (vorbisenc, "analysed to a block");
/* analysis */ /* analysis */
vorbis_analysis (&vorbisenc->vb, NULL); vorbis_analysis (&vorbisenc->vb, NULL);
vorbis_bitrate_addblock (&vorbisenc->vb); vorbis_bitrate_addblock (&vorbisenc->vb);
while (vorbis_bitrate_flushpacket (&vorbisenc->vd, &op)) { while (vorbis_bitrate_flushpacket (&vorbisenc->vd, &op)) {
GST_LOG_OBJECT (vorbisenc, "pushing out a data packet");
gst_vorbisenc_push_packet (vorbisenc, &op); gst_vorbisenc_push_packet (vorbisenc, &op);
} }
} }
if (vorbisenc->eos) { 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 */ /* clean up and exit. vorbis_info_clear() must be called last */
vorbis_block_clear (&vorbisenc->vb); vorbis_block_clear (&vorbisenc->vb);
vorbis_dsp_clear (&vorbisenc->vd); vorbis_dsp_clear (&vorbisenc->vd);
@ -972,7 +985,7 @@ static void
gst_vorbisenc_get_property (GObject * object, guint prop_id, GValue * value, gst_vorbisenc_get_property (GObject * object, guint prop_id, GValue * value,
GParamSpec * pspec) GParamSpec * pspec)
{ {
VorbisEnc *vorbisenc; GstVorbisEnc *vorbisenc;
g_return_if_fail (GST_IS_VORBISENC (object)); g_return_if_fail (GST_IS_VORBISENC (object));
@ -1007,7 +1020,7 @@ static void
gst_vorbisenc_set_property (GObject * object, guint prop_id, gst_vorbisenc_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec) const GValue * value, GParamSpec * pspec)
{ {
VorbisEnc *vorbisenc; GstVorbisEnc *vorbisenc;
g_return_if_fail (GST_IS_VORBISENC (object)); g_return_if_fail (GST_IS_VORBISENC (object));
@ -1078,7 +1091,7 @@ gst_vorbisenc_set_property (GObject * object, guint prop_id,
static GstElementStateReturn static GstElementStateReturn
gst_vorbisenc_change_state (GstElement * element) gst_vorbisenc_change_state (GstElement * element)
{ {
VorbisEnc *vorbisenc = GST_VORBISENC (element); GstVorbisEnc *vorbisenc = GST_VORBISENC (element);
GstElementState transition; GstElementState transition;
GstElementStateReturn res; GstElementStateReturn res;

View file

@ -33,22 +33,22 @@ extern "C" {
#define GST_TYPE_VORBISENC \ #define GST_TYPE_VORBISENC \
(vorbisenc_get_type()) (vorbisenc_get_type())
#define GST_VORBISENC(obj) \ #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) \ #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) \ #define GST_IS_VORBISENC(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VORBISENC)) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VORBISENC))
#define GST_IS_VORBISENC_CLASS(obj) \ #define GST_IS_VORBISENC_CLASS(obj) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_VORBISENC)) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_VORBISENC))
typedef struct _VorbisEnc VorbisEnc; typedef struct _GstVorbisEnc GstVorbisEnc;
typedef struct _VorbisEncClass VorbisEncClass; typedef struct _GstVorbisEncClass GstVorbisEncClass;
struct _VorbisEnc { struct _GstVorbisEnc {
GstElement element; GstElement element;
GstPad *sinkpad, GstPad *sinkpad;
*srcpad; GstPad *srcpad;
vorbis_info vi; /* struct that stores all the static vorbis bitstream vorbis_info vi; /* struct that stores all the static vorbis bitstream
settings */ settings */
@ -79,7 +79,7 @@ struct _VorbisEnc {
gchar *last_message; gchar *last_message;
}; };
struct _VorbisEncClass { struct _GstVorbisEncClass {
GstElementClass parent_class; GstElementClass parent_class;
}; };

View file

@ -343,7 +343,7 @@ gst_ffmpegcsp_transform (GstBaseTransform * btrans, GstBuffer * inbuf,
GST_DEBUG ("from %d -> to %d", space->from_pixfmt, space->to_pixfmt); 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) if (space->from_pixfmt == PIX_FMT_NB || space->to_pixfmt == PIX_FMT_NB)
goto unkown_format; goto unknown_format;
/* fill from with source data */ /* fill from with source data */
gst_ffmpegcsp_avpicture_fill (&space->from_frame, gst_ffmpegcsp_avpicture_fill (&space->from_frame,
@ -368,7 +368,7 @@ gst_ffmpegcsp_transform (GstBaseTransform * btrans, GstBuffer * inbuf,
return GST_FLOW_OK; return GST_FLOW_OK;
/* ERRORS */ /* ERRORS */
unkown_format: unknown_format:
{ {
GST_ELEMENT_ERROR (space, CORE, NOT_IMPLEMENTED, (NULL), GST_ELEMENT_ERROR (space, CORE, NOT_IMPLEMENTED, (NULL),
("attempting to convert colorspaces between unknown formats")); ("attempting to convert colorspaces between unknown formats"));

View file

@ -431,7 +431,8 @@ gst_multifdsink_class_init (GstMultiFdSinkClass * klass)
client_removed), NULL, NULL, gst_tcp_marshal_VOID__INT_BOXED, client_removed), NULL, NULL, gst_tcp_marshal_VOID__INT_BOXED,
G_TYPE_NONE, 2, G_TYPE_INT, GST_TYPE_CLIENT_STATUS); 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; gstbasesink_class->render = gst_multifdsink_render;

View file

@ -368,6 +368,8 @@ volume_set_caps (GstBaseTransform * base, GstCaps * incaps, GstCaps * outcaps)
{ {
GstVolume *this = GST_VOLUME (base); 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)); volume_funcfind (this, gst_caps_get_structure (incaps, 0));
if (!this->process) { if (!this->process) {

View file

@ -13,13 +13,21 @@ clean-local: clean-local-check
$(CHECK_REGISTRY): $(CHECK_REGISTRY):
$(TESTS_ENVIRONMENT) \ $(TESTS_ENVIRONMENT) \
GST_PLUGIN_PATH_ONLY=yes \ 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@ $(GST_TOOLS_DIR)/gst-register-@GST_MAJORMINOR@
TESTS = $(GST_TOOLS_DIR)/gst-register-@GST_MAJORMINOR@ \ TESTS = $(GST_TOOLS_DIR)/gst-register-@GST_MAJORMINOR@ \
$(check_PROGRAMS) $(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) AM_CFLAGS = $(GST_OBJ_CFLAGS) $(GST_CHECK_CFLAGS)
LDADD = $(GST_OBJ_LIBS) $(GST_CHECK_LIBS) LDADD = $(GST_OBJ_LIBS) $(GST_CHECK_LIBS)

View file

@ -1,2 +1,3 @@
.dirstamp .dirstamp
volume volume
vorbisdec

View file

@ -51,6 +51,16 @@ GstPad *mysrcpad, *mysinkpad;
"depth = (int) 16, " \ "depth = (int) 16, " \
"signed = (bool) TRUE" "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", static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK, GST_PAD_SINK,
GST_PAD_ALWAYS, GST_PAD_ALWAYS,
@ -71,23 +81,6 @@ chain_func (GstPad * pad, GstBuffer * buffer)
return GST_FLOW_OK; 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 * GstElement *
setup_volume () setup_volume ()
{ {
@ -125,7 +118,6 @@ setup_volume ()
fail_if (srcpad == NULL, "Could not get source pad from volume"); fail_if (srcpad == NULL, "Could not get source pad from volume");
gst_pad_set_caps (mysinkpad, NULL); gst_pad_set_caps (mysinkpad, NULL);
gst_pad_set_chain_function (mysinkpad, chain_func); 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, fail_unless (gst_pad_link (srcpad, mysinkpad) == GST_PAD_LINK_OK,
"Could not link volume source and mysink pads"); "Could not link volume source and mysink pads");
@ -194,7 +186,7 @@ GST_START_TEST (test_unity)
ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
/* pushing gives away my reference ... */ /* 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 */ /* ... but it ends up being collected on the global buffer list */
ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
fail_unless (g_list_length (buffers) == 1); fail_unless (g_list_length (buffers) == 1);
@ -232,7 +224,7 @@ GST_START_TEST (test_half)
*/ */
/* pushing gives away my reference ... */ /* 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 /* ... but it ends up being modified inplace and
* collected on the global buffer list */ * collected on the global buffer list */
ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
@ -271,7 +263,7 @@ GST_START_TEST (test_double)
*/ */
/* pushing gives away my reference ... */ /* 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 /* ... but it ends up being modified inplace and
* collected on the global buffer list */ * collected on the global buffer list */
ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
@ -286,6 +278,50 @@ GST_START_TEST (test_double)
GST_END_TEST; 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 * Suite *
volume_suite (void) volume_suite (void)
@ -297,6 +333,7 @@ volume_suite (void)
tcase_add_test (tc_chain, test_unity); tcase_add_test (tc_chain, test_unity);
tcase_add_test (tc_chain, test_half); tcase_add_test (tc_chain, test_half);
tcase_add_test (tc_chain, test_double); tcase_add_test (tc_chain, test_double);
tcase_add_test (tc_chain, test_wrong_caps);
return s; return s;
} }

View file

@ -0,0 +1,251 @@
/* GStreamer
*
* unit test for vorbisdec
*
* Copyright (C) <2005> Thomas Vander Stichele <thomas at apestaart dot org>
*
* 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 <unistd.h>
#include <gst/check/gstcheck.h>
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;
}