diff options
Diffstat (limited to 'tests/check')
-rw-r--r-- | tests/check/Makefile.am | 30 | ||||
-rw-r--r-- | tests/check/elements/.gitignore | 6 | ||||
-rw-r--r-- | tests/check/elements/aacparse.c | 240 | ||||
-rw-r--r-- | tests/check/elements/ac3parse.c | 163 | ||||
-rw-r--r-- | tests/check/elements/amrparse.c | 327 | ||||
-rw-r--r-- | tests/check/elements/deinterlace.c | 2 | ||||
-rw-r--r-- | tests/check/elements/flacparse.c | 299 | ||||
-rw-r--r-- | tests/check/elements/mpegaudioparse.c | 172 | ||||
-rw-r--r-- | tests/check/elements/parser.c | 434 | ||||
-rw-r--r-- | tests/check/elements/parser.h | 95 | ||||
-rw-r--r-- | tests/check/elements/qtmux.c | 590 | ||||
-rw-r--r-- | tests/check/elements/rtp-payloading.c | 3 | ||||
-rw-r--r-- | tests/check/pipelines/.gitignore | 1 | ||||
-rw-r--r-- | tests/check/pipelines/flacdec.c | 6 | ||||
-rw-r--r-- | tests/check/pipelines/tagschecking.c | 350 |
15 files changed, 2710 insertions, 8 deletions
diff --git a/tests/check/Makefile.am b/tests/check/Makefile.am index 1ffb7a33f..9fe0e3524 100644 --- a/tests/check/Makefile.am +++ b/tests/check/Makefile.am @@ -100,6 +100,9 @@ endif check_PROGRAMS = \ generic/states \ + elements/aacparse \ + elements/ac3parse \ + elements/amrparse \ $(check_annodex) \ elements/alphacolor \ elements/aspectratiocrop \ @@ -120,6 +123,7 @@ check_PROGRAMS = \ elements/deinterlace \ elements/deinterleave \ elements/equalizer \ + elements/flacparse \ elements/flvdemux \ elements/flvmux \ elements/icydemux \ @@ -128,7 +132,9 @@ check_PROGRAMS = \ elements/interleave \ elements/level \ elements/matroskamux \ + elements/mpegaudioparse \ elements/multifile \ + elements/qtmux \ elements/rganalysis \ elements/rglimiter \ elements/rgvolume \ @@ -144,6 +150,7 @@ check_PROGRAMS = \ elements/y4menc \ pipelines/simple-launch-lines \ pipelines/effectv \ + pipelines/tagschecking \ pipelines/wavenc \ $(check_flac) \ $(check_gdkpixbuf) \ @@ -177,6 +184,23 @@ VALGRIND_TESTS_DISABLE = \ SUPPRESSIONS = $(top_srcdir)/common/gst.supp $(srcdir)/gst-plugins-good.supp +# parser unit test convenience lib +noinst_LTLIBRARIES = libparser.la +libparser_la_SOURCES = elements/parser.c elements/parser.h +libparser_la_CFLAGS = \ + -I$(top_srcdir)/tests/check \ + $(GST_CHECK_CFLAGS) $(GST_OPTION_CFLAGS) + +elements_aacparse_LDADD = libparser.la $(LDADD) + +elements_ac3parse_LDADD = libparser.la $(LDADD) + +elements_amrparse_LDADD = libparser.la $(LDADD) + +elements_flacparse_LDADD = libparser.la $(LDADD) + +elements_mpegaudioparse_LDADD = libparser.la $(LDADD) + elements_aspectratiocrop_LDADD = $(LDADD) elements_aspectratiocrop_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(CFLAGS) $(AM_CFLAGS) @@ -211,11 +235,15 @@ elements_level_LDADD = $(LDADD) $(LIBM) elements_matroskamux_LDADD = $(GST_BASE_LIBS) $(LDADD) $(LIBM) +elements_qtmux_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(AM_CFLAGS) +elements_qtmux_LDADD = $(GST_PLUGINS_BASE_LIBS) -lgstpbutils-@GST_MAJORMINOR@ \ + $(GST_BASE_LIBS) $(GST_LIBS) $(GST_CHECK_LIBS) + elements_rtpbin_buffer_list_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) \ $(WARNING_CFLAGS) $(ERROR_CFLAGS) $(GST_CHECK_CFLAGS) $(AM_CFLAGS) elements_rtpbin_buffer_list_LDADD = $(GST_PLUGINS_BASE_LIBS) \ -lgstnetbuffer-@GST_MAJORMINOR@ -lgstrtp-@GST_MAJORMINOR@ \ - $(GST_BASE_LIBS) $(GST_LIBS_LIBS) $(GST_CHECK_LIBS) + $(GST_BASE_LIBS) $(GST_LIBS) $(GST_CHECK_LIBS) elements_rtpbin_buffer_list_SOURCES = elements/rtpbin_buffer_list.c elements_souphttpsrc_CFLAGS = $(SOUP_CFLAGS) $(AM_CFLAGS) diff --git a/tests/check/elements/.gitignore b/tests/check/elements/.gitignore index 0d06d4576..62c482a18 100644 --- a/tests/check/elements/.gitignore +++ b/tests/check/elements/.gitignore @@ -1,5 +1,8 @@ .dirstamp +aacparse +ac3parse alphacolor +amrparse apev2mux aspectratiocrop audioamplify @@ -23,6 +26,7 @@ deinterlace deinterleave equalizer gdkpixbufsink +flacparse flvdemux flvmux icydemux @@ -33,7 +37,9 @@ interleave jpegenc level matroskamux +mpegaudioparse multifile +qtmux rganalysis rglimiter rgvolume diff --git a/tests/check/elements/aacparse.c b/tests/check/elements/aacparse.c new file mode 100644 index 000000000..af10a2779 --- /dev/null +++ b/tests/check/elements/aacparse.c @@ -0,0 +1,240 @@ +/* + * GStreamer + * + * unit test for aacparse + * + * Copyright (C) 2008 Nokia Corporation. All rights reserved. + * + * Contact: Stefan Kost <stefan.kost@nokia.com> + * + * 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 <gst/check/gstcheck.h> +#include "parser.h" + +#define SRC_CAPS_CDATA "audio/mpeg, framed=(boolean)false, codec_data=(buffer)1190" +#define SRC_CAPS_TMPL "audio/mpeg, framed=(boolean)false, mpegversion=(int){2,4}" + +#define SINK_CAPS \ + "audio/mpeg, framed=(boolean)true" +#define SINK_CAPS_MPEG2 \ + "audio/mpeg, framed=(boolean)true, mpegversion=2, rate=48000, channels=2" +#define SINK_CAPS_MPEG4 \ + "audio/mpeg, framed=(boolean)true, mpegversion=4, rate=96000, channels=2" +#define SINK_CAPS_TMPL "audio/mpeg, framed=(boolean)true, mpegversion=(int){2,4}" + +GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (SINK_CAPS_TMPL) + ); + +GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (SRC_CAPS_TMPL) + ); + +/* some data */ +static guint8 adif_header[] = { + 'A', 'D', 'I', 'F' +}; + +static guint8 adts_frame_mpeg2[] = { + 0xff, 0xf9, 0x4c, 0x80, 0x01, 0xff, 0xfc, 0x21, 0x10, 0xd3, 0x20, 0x0c, + 0x32, 0x00, 0xc7 +}; + +static guint8 adts_frame_mpeg4[] = { + 0xff, 0xf1, 0x4c, 0x80, 0x01, 0xff, 0xfc, 0x21, 0x10, 0xd3, 0x20, 0x0c, + 0x32, 0x00, 0xc7 +}; + +static guint8 garbage_frame[] = { + 0xff, 0xff, 0xff, 0xff, 0xff +}; + +/* + * Test if the parser pushes data with ADIF header properly and detects the + * stream to MPEG4 properly. + */ +GST_START_TEST (test_parse_adif_normal) +{ + GstParserTest ptest; + + /* ADIF header */ + gst_parser_test_init (&ptest, adif_header, sizeof (adif_header), 1); + /* well, no garbage, followed by random data */ + ptest.series[2].size = 100; + ptest.series[2].num = 3; + /* and we do not really expect output frames */ + ptest.framed = FALSE; + /* Check that the negotiated caps are as expected */ + /* For ADIF parser assumes that data is always version 4 */ + ptest.sink_caps = + gst_caps_from_string (SINK_CAPS_MPEG4 ", stream-format=(string)adif"); + + gst_parser_test_run (&ptest, NULL); + + gst_caps_unref (ptest.sink_caps); +} + +GST_END_TEST; + + +GST_START_TEST (test_parse_adts_normal) +{ + gst_parser_test_normal (adts_frame_mpeg4, sizeof (adts_frame_mpeg4)); +} + +GST_END_TEST; + + +GST_START_TEST (test_parse_adts_drain_single) +{ + gst_parser_test_drain_single (adts_frame_mpeg4, sizeof (adts_frame_mpeg4)); +} + +GST_END_TEST; + + +GST_START_TEST (test_parse_adts_drain_garbage) +{ + gst_parser_test_drain_garbage (adts_frame_mpeg4, sizeof (adts_frame_mpeg4), + garbage_frame, sizeof (garbage_frame)); +} + +GST_END_TEST; + + +GST_START_TEST (test_parse_adts_split) +{ + gst_parser_test_split (adts_frame_mpeg4, sizeof (adts_frame_mpeg4)); +} + +GST_END_TEST; + + +GST_START_TEST (test_parse_adts_skip_garbage) +{ + gst_parser_test_skip_garbage (adts_frame_mpeg4, sizeof (adts_frame_mpeg4), + garbage_frame, sizeof (garbage_frame)); +} + +GST_END_TEST; + + +/* + * Test if the src caps are set according to stream format (MPEG version). + */ +GST_START_TEST (test_parse_adts_detect_mpeg_version) +{ + gst_parser_test_output_caps (adts_frame_mpeg2, sizeof (adts_frame_mpeg2), + NULL, SINK_CAPS_MPEG2 ", stream-format=(string)adts"); +} + +GST_END_TEST; + +#define structure_get_int(s,f) \ + (g_value_get_int(gst_structure_get_value(s,f))) +#define fail_unless_structure_field_int_equals(s,field,num) \ + fail_unless_equals_int (structure_get_int(s,field), num) +/* + * Test if the parser handles raw stream and codec_data info properly. + */ +GST_START_TEST (test_parse_handle_codec_data) +{ + GstCaps *caps; + GstStructure *s; + const gchar *stream_format; + + /* Push random data. It should get through since the parser should be + * initialized because it got codec_data in the caps */ + caps = gst_parser_test_get_output_caps (NULL, 100, SRC_CAPS_CDATA); + fail_unless (caps != NULL); + + /* Check that the negotiated caps are as expected */ + /* When codec_data is present, parser assumes that data is version 4 */ + GST_LOG ("aac output caps: %" GST_PTR_FORMAT, caps); + s = gst_caps_get_structure (caps, 0); + fail_unless (gst_structure_has_name (s, "audio/mpeg")); + fail_unless_structure_field_int_equals (s, "mpegversion", 4); + fail_unless_structure_field_int_equals (s, "channels", 2); + fail_unless_structure_field_int_equals (s, "rate", 48000); + fail_unless (gst_structure_has_field (s, "codec_data")); + fail_unless (gst_structure_has_field (s, "stream-format")); + stream_format = gst_structure_get_string (s, "stream-format"); + fail_unless (strcmp (stream_format, "raw") == 0); + + gst_caps_unref (caps); +} + +GST_END_TEST; + + +static Suite * +aacparse_suite (void) +{ + Suite *s = suite_create ("aacparse"); + TCase *tc_chain = tcase_create ("general"); + + suite_add_tcase (s, tc_chain); + /* ADIF tests */ + tcase_add_test (tc_chain, test_parse_adif_normal); + + /* ADTS tests */ + tcase_add_test (tc_chain, test_parse_adts_normal); + tcase_add_test (tc_chain, test_parse_adts_drain_single); + tcase_add_test (tc_chain, test_parse_adts_drain_garbage); + tcase_add_test (tc_chain, test_parse_adts_split); + tcase_add_test (tc_chain, test_parse_adts_skip_garbage); + tcase_add_test (tc_chain, test_parse_adts_detect_mpeg_version); + + /* Other tests */ + tcase_add_test (tc_chain, test_parse_handle_codec_data); + + return s; +} + + +/* + * TODO: + * - Both push- and pull-modes need to be tested + * * Pull-mode & EOS + */ + +int +main (int argc, char **argv) +{ + int nf; + + Suite *s = aacparse_suite (); + SRunner *sr = srunner_create (s); + + gst_check_init (&argc, &argv); + + /* init test context */ + ctx_factory = "aacparse"; + ctx_sink_template = &sinktemplate; + ctx_src_template = &srctemplate; + + srunner_run_all (sr, CK_NORMAL); + nf = srunner_ntests_failed (sr); + srunner_free (sr); + + return nf; +} diff --git a/tests/check/elements/ac3parse.c b/tests/check/elements/ac3parse.c new file mode 100644 index 000000000..03e8e1dc8 --- /dev/null +++ b/tests/check/elements/ac3parse.c @@ -0,0 +1,163 @@ +/* + * GStreamer + * + * unit test for ac3parse + * + * Copyright (C) 2008 Nokia Corporation. All rights reserved. + * + * Contact: Stefan Kost <stefan.kost@nokia.com> + * + * 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 <gst/check/gstcheck.h> +#include "parser.h" + +#define SRC_CAPS_TMPL "audio/x-ac3, framed=(boolean)false" +#define SINK_CAPS_TMPL "audio/x-ac3, framed=(boolean)true" + +GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (SINK_CAPS_TMPL) + ); + +GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (SRC_CAPS_TMPL) + ); + +/* some data */ + +static guint8 ac3_frame[512] = { + 0x0b, 0x77, 0xb6, 0xa8, 0x10, 0x40, 0x2f, 0x84, + 0x29, 0xcb, 0xfe, 0x75, 0x7c, 0xf9, 0xf3, 0xe7, + 0xcf, 0x9f, 0x3e, 0x7c, 0xf9, 0xf3, 0xe7, 0xcf, + 0x9f, 0x3e, 0x7c, 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, + 0x3e, 0x7c, 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, 0x3e, + 0x7c, 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, 0x3e, 0x7c, + 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, 0x3e, 0x7c, 0xf9, + 0xf3, 0xe7, 0xcf, 0x9f, 0x3e, 0x7c, 0xf9, 0xf3, + 0xe7, 0xcf, 0x9f, 0x3e, 0x7c, 0xf9, 0xf3, 0xe7, + 0xcf, 0x9f, 0x3e, 0x32, 0xd3, 0xff, 0xc0, 0x06, + 0xe9, 0x40, 0x00, 0x6e, 0x94, 0x00, 0x06, 0xe9, + 0x40, 0x00, 0x6e, 0x94, 0x00, 0x06, 0xe9, 0x40, + 0x00, 0x6e, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +static guint8 garbage_frame[] = { + 0xff, 0xff, 0xff, 0xff, 0xff +}; + + +GST_START_TEST (test_parse_normal) +{ + gst_parser_test_normal (ac3_frame, sizeof (ac3_frame)); +} + +GST_END_TEST; + + +GST_START_TEST (test_parse_drain_single) +{ + gst_parser_test_drain_single (ac3_frame, sizeof (ac3_frame)); +} + +GST_END_TEST; + + +GST_START_TEST (test_parse_drain_garbage) +{ + gst_parser_test_drain_garbage (ac3_frame, sizeof (ac3_frame), + garbage_frame, sizeof (garbage_frame)); +} + +GST_END_TEST; + + +GST_START_TEST (test_parse_split) +{ + gst_parser_test_split (ac3_frame, sizeof (ac3_frame)); +} + +GST_END_TEST; + + +GST_START_TEST (test_parse_skip_garbage) +{ + gst_parser_test_skip_garbage (ac3_frame, sizeof (ac3_frame), + garbage_frame, sizeof (garbage_frame)); +} + +GST_END_TEST; + + +GST_START_TEST (test_parse_detect_stream) +{ + gst_parser_test_output_caps (ac3_frame, sizeof (ac3_frame), + NULL, SINK_CAPS_TMPL ",channels=1,rate=48000"); +} + +GST_END_TEST; + + +static Suite * +ac3parse_suite (void) +{ + Suite *s = suite_create ("ac3parse"); + TCase *tc_chain = tcase_create ("general"); + + suite_add_tcase (s, tc_chain); + tcase_add_test (tc_chain, test_parse_normal); + tcase_add_test (tc_chain, test_parse_drain_single); + tcase_add_test (tc_chain, test_parse_drain_garbage); + tcase_add_test (tc_chain, test_parse_split); + tcase_add_test (tc_chain, test_parse_skip_garbage); + tcase_add_test (tc_chain, test_parse_detect_stream); + + return s; +} + + +/* + * TODO: + * - Both push- and pull-modes need to be tested + * * Pull-mode & EOS + */ + +int +main (int argc, char **argv) +{ + int nf; + + Suite *s = ac3parse_suite (); + SRunner *sr = srunner_create (s); + + gst_check_init (&argc, &argv); + + /* init test context */ + ctx_factory = "ac3parse"; + ctx_sink_template = &sinktemplate; + ctx_src_template = &srctemplate; + + srunner_run_all (sr, CK_NORMAL); + nf = srunner_ntests_failed (sr); + srunner_free (sr); + + return nf; +} diff --git a/tests/check/elements/amrparse.c b/tests/check/elements/amrparse.c new file mode 100644 index 000000000..e5d64ca57 --- /dev/null +++ b/tests/check/elements/amrparse.c @@ -0,0 +1,327 @@ +/* + * GStreamer + * + * unit test for amrparse + * + * Copyright (C) 2008 Nokia Corporation. All rights reserved. + * + * Contact: Stefan Kost <stefan.kost@nokia.com> + * + * 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 <gst/check/gstcheck.h> +#include "parser.h" + +#define SRC_CAPS_NB "audio/x-amr-nb-sh" +#define SRC_CAPS_WB "audio/x-amr-wb-sh" +#define SRC_CAPS_ANY "ANY" + +#define SINK_CAPS_NB "audio/AMR, rate=8000 , channels=1" +#define SINK_CAPS_WB "audio/AMR-WB, rate=16000 , channels=1" +#define SINK_CAPS_ANY "ANY" + +#define AMR_FRAME_DURATION (GST_SECOND/50) + +static GstStaticPadTemplate sinktemplate_nb = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (SINK_CAPS_NB) + ); + +static GstStaticPadTemplate sinktemplate_wb = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (SINK_CAPS_WB) + ); + +static GstStaticPadTemplate srctemplate_nb = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (SRC_CAPS_NB) + ); + +static GstStaticPadTemplate srctemplate_wb = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (SRC_CAPS_WB) + ); + + +/* some data */ + +static guint8 frame_data_nb[] = { + 0x0c, 0x56, 0x3c, 0x52, 0xe0, 0x61, 0xbc, 0x45, + 0x0f, 0x98, 0x2e, 0x01, 0x42, 0x02 +}; + +static guint8 frame_data_wb[] = { + 0x08, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, + 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, + 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16 +}; + +static guint8 frame_hdr_nb[] = { + '#', '!', 'A', 'M', 'R', '\n' +}; + +static guint8 frame_hdr_wb[] = { + '#', '!', 'A', 'M', 'R', '-', 'W', 'B', '\n' +}; + +static guint8 garbage_frame[] = { + 0xff, 0xff, 0xff, 0xff, 0xff +}; + + +GST_START_TEST (test_parse_nb_normal) +{ + gst_parser_test_normal (frame_data_nb, sizeof (frame_data_nb)); +} + +GST_END_TEST; + + +GST_START_TEST (test_parse_nb_drain_single) +{ + gst_parser_test_drain_single (frame_data_nb, sizeof (frame_data_nb)); +} + +GST_END_TEST; + + +GST_START_TEST (test_parse_nb_drain_garbage) +{ + gst_parser_test_drain_garbage (frame_data_nb, sizeof (frame_data_nb), + garbage_frame, sizeof (garbage_frame)); +} + +GST_END_TEST; + + +GST_START_TEST (test_parse_nb_split) +{ + gst_parser_test_split (frame_data_nb, sizeof (frame_data_nb)); +} + +GST_END_TEST; + + +GST_START_TEST (test_parse_nb_skip_garbage) +{ + gst_parser_test_skip_garbage (frame_data_nb, sizeof (frame_data_nb), + garbage_frame, sizeof (garbage_frame)); +} + +GST_END_TEST; + + +GST_START_TEST (test_parse_nb_detect_stream) +{ + GstParserTest ptest; + GstCaps *old_ctx_caps; + + /* no input caps, override ctx */ + old_ctx_caps = ctx_input_caps; + ctx_input_caps = NULL; + + /* AMR-NB header */ + gst_parser_test_init (&ptest, frame_hdr_nb, sizeof (frame_hdr_nb), 1); + /* well, no garbage, followed by real data */ + ptest.series[2].data = frame_data_nb; + ptest.series[2].size = sizeof (frame_data_nb); + ptest.series[2].num = 10; + /* header gets dropped, so ... */ + /* buffer count will not match */ + ptest.framed = FALSE; + /* total size a bit less */ + ptest.dropped = sizeof (frame_hdr_nb); + + /* Check that the negotiated caps are as expected */ + ptest.sink_caps = gst_caps_from_string (SINK_CAPS_NB); + + gst_parser_test_run (&ptest, NULL); + + gst_caps_unref (ptest.sink_caps); + + ctx_input_caps = old_ctx_caps; +} + +GST_END_TEST; + + +GST_START_TEST (test_parse_wb_normal) +{ + gst_parser_test_normal (frame_data_wb, sizeof (frame_data_wb)); +} + +GST_END_TEST; + + +GST_START_TEST (test_parse_wb_drain_single) +{ + gst_parser_test_drain_single (frame_data_wb, sizeof (frame_data_wb)); +} + +GST_END_TEST; + + +GST_START_TEST (test_parse_wb_drain_garbage) +{ + gst_parser_test_drain_garbage (frame_data_wb, sizeof (frame_data_wb), + garbage_frame, sizeof (garbage_frame)); +} + +GST_END_TEST; + + +GST_START_TEST (test_parse_wb_split) +{ + gst_parser_test_split (frame_data_wb, sizeof (frame_data_wb)); +} + +GST_END_TEST; + + +GST_START_TEST (test_parse_wb_skip_garbage) +{ + gst_parser_test_skip_garbage (frame_data_wb, sizeof (frame_data_wb), + garbage_frame, sizeof (garbage_frame)); +} + +GST_END_TEST; + + +GST_START_TEST (test_parse_wb_detect_stream) +{ + GstParserTest ptest; + GstCaps *old_ctx_caps; + + /* no input caps, override ctx */ + old_ctx_caps = ctx_input_caps; + ctx_input_caps = NULL; + + /* AMR-WB header */ + gst_parser_test_init (&ptest, frame_hdr_wb, sizeof (frame_hdr_wb), 1); + /* well, no garbage, followed by real data */ + ptest.series[2].data = frame_data_wb; + ptest.series[2].size = sizeof (frame_data_wb); + ptest.series[2].num = 10; + /* header gets dropped, so ... */ + /* buffer count will not match */ + ptest.framed = FALSE; + /* total size a bit less */ + ptest.dropped = sizeof (frame_hdr_wb); + + /* Check that the negotiated caps are as expected */ + ptest.sink_caps = gst_caps_from_string (SINK_CAPS_WB); + + gst_parser_test_run (&ptest, NULL); + + gst_caps_unref (ptest.sink_caps); + + ctx_input_caps = old_ctx_caps; +} + +GST_END_TEST; + + + +/* + * Create test suite. + */ +static Suite * +amrnb_parse_suite (void) +{ + Suite *s = suite_create ("amrwb_parse"); + TCase *tc_chain = tcase_create ("general"); + + suite_add_tcase (s, tc_chain); + /* AMR-NB tests */ + tcase_add_test (tc_chain, test_parse_nb_normal); + tcase_add_test (tc_chain, test_parse_nb_drain_single); + tcase_add_test (tc_chain, test_parse_nb_drain_garbage); + tcase_add_test (tc_chain, test_parse_nb_split); + tcase_add_test (tc_chain, test_parse_nb_detect_stream); + tcase_add_test (tc_chain, test_parse_nb_skip_garbage); + + return s; +} + +static Suite * +amrwb_parse_suite (void) +{ + Suite *s = suite_create ("amrnb_parse"); + TCase *tc_chain = tcase_create ("general"); + + suite_add_tcase (s, tc_chain); + /* AMR-WB tests */ + tcase_add_test (tc_chain, test_parse_wb_normal); + tcase_add_test (tc_chain, test_parse_wb_drain_single); + tcase_add_test (tc_chain, test_parse_wb_drain_garbage); + tcase_add_test (tc_chain, test_parse_wb_split); + tcase_add_test (tc_chain, test_parse_wb_detect_stream); + tcase_add_test (tc_chain, test_parse_wb_skip_garbage); + + return s; +} + +/* + * TODO: + * - Both push- and pull-modes need to be tested + * * Pull-mode & EOS + */ + +int +main (int argc, char **argv) +{ + int nf; + GstCaps *caps; + + Suite *s = amrnb_parse_suite (); + SRunner *sr = srunner_create (s); + + gst_check_init (&argc, &argv); + + /* init test context */ + ctx_factory = "amrparse"; + ctx_sink_template = &sinktemplate_nb; + ctx_src_template = &srctemplate_nb; + caps = gst_caps_from_string (SRC_CAPS_NB); + g_assert (caps); + ctx_input_caps = caps; + + srunner_run_all (sr, CK_NORMAL); + nf = srunner_ntests_failed (sr); + srunner_free (sr); + gst_caps_unref (caps); + + s = amrwb_parse_suite (); + sr = srunner_create (s); + + ctx_sink_template = &sinktemplate_wb; + ctx_src_template = &srctemplate_wb; + caps = gst_caps_from_string (SRC_CAPS_WB); + g_assert (caps); + ctx_input_caps = caps; + + srunner_run_all (sr, CK_NORMAL); + nf += srunner_ntests_failed (sr); + srunner_free (sr); + gst_caps_unref (caps); + + return nf; +} diff --git a/tests/check/elements/deinterlace.c b/tests/check/elements/deinterlace.c index b111c86f7..6aeb3def8 100644 --- a/tests/check/elements/deinterlace.c +++ b/tests/check/elements/deinterlace.c @@ -28,7 +28,7 @@ static gboolean gst_caps_is_interlaced (GstCaps * caps) { - GstStructure *structure; + GstStructure G_GNUC_UNUSED *structure; gboolean interlaced = FALSE; fail_unless (gst_caps_is_fixed (caps)); diff --git a/tests/check/elements/flacparse.c b/tests/check/elements/flacparse.c new file mode 100644 index 000000000..0c25bc6f5 --- /dev/null +++ b/tests/check/elements/flacparse.c @@ -0,0 +1,299 @@ +/* + * GStreamer + * + * unit test for flacparse + * + * Copyright (C) 2010 Nokia Corporation. All rights reserved. + * + * Contact: Stefan Kost <stefan.kost@nokia.com> + * + * 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 <gst/check/gstcheck.h> +#include "parser.h" + +#define SRC_CAPS_TMPL "audio/x-flac, framed=(boolean)false" +#define SINK_CAPS_TMPL "audio/x-flac, framed=(boolean)true" + +GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (SINK_CAPS_TMPL) + ); + +GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (SRC_CAPS_TMPL) + ); + +/* some data */ +static guint8 streaminfo_header[] = { + 0x7f, 0x46, 0x4c, 0x41, 0x43, 0x01, 0x00, 0x00, + 0x02, 0x66, 0x4c, 0x61, 0x43, 0x00, 0x00, 0x00, + 0x22, 0x12, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0a, 0xc4, 0x40, 0xf0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00 +}; + +static guint8 comment_header[] = { + 0x84, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 +}; + +static guint8 flac_frame[] = { + 0xff, 0xf8, 0xa9, 0x08, 0x00, 0x50, 0x18, 0x06, + 0x6a, 0x0c, 0xce, 0x13, 0x24, 0x19, 0x68, 0x00, + 0x46, 0x23, 0x08, 0xca, 0xcb, 0x58, 0x9c, 0x26, + 0x92, 0x30, 0xa6, 0x29, 0x8a, 0xca, 0xd1, 0x18, + 0xae, 0x26, 0x5c, 0x90, 0x60, 0xbf, 0x11, 0xad, + 0x43, 0x02, 0x06, 0x26, 0xbd, 0x35, 0xdd, 0xa3, + 0x11, 0xa6, 0x4d, 0x18, 0x8c, 0x9a, 0xe4, 0x62, + 0xd9, 0x23, 0x11, 0x8b, 0xcb, 0x56, 0x55, 0x45, + 0xc2, 0x18, 0x56, 0xa2, 0xe2, 0xe1, 0x18, 0x99, + 0x54, 0x98, 0x46, 0x4d, 0x08, 0x70, 0x9a, 0x64, + 0xc4, 0x18, 0x4f, 0x27, 0x64, 0x31, 0x66, 0x27, + 0x79, 0x19, 0x3c, 0x8c, 0x8c, 0xa3, 0x44, 0x18, + 0x23, 0xd2, 0x6b, 0x8b, 0x64, 0x8c, 0x21, 0x84, + 0xd6, 0x23, 0x13, 0x13, 0x2d, 0x44, 0xca, 0x5a, + 0x23, 0x09, 0x93, 0x25, 0x18, 0x10, 0x61, 0x38, + 0xb4, 0x60, 0x8f, 0x2c, 0x8d, 0x26, 0xb4, 0xc9, + 0xd9, 0x19, 0x19, 0x34, 0xd7, 0x31, 0x06, 0x10, + 0xc4, 0x30, 0x83, 0x17, 0xe2, 0x0c, 0x2c, 0xc4, + 0xc8, 0xc9, 0x3c, 0x5e, 0x93, 0x11, 0x8a, 0x62, + 0x64, 0x8c, 0x26, 0x23, 0x22, 0x30, 0x9a, 0x58, + 0x86, 0x04, 0x18, 0x4c, 0xab, 0x2b, 0x26, 0x5c, + 0x46, 0x88, 0xcb, 0xb1, 0x0d, 0x26, 0xbb, 0x5e, + 0x8c, 0xa7, 0x64, 0x31, 0x3d, 0x31, 0x06, 0x26, + 0x43, 0x17, 0xa3, 0x08, 0x61, 0x06, 0x17, 0xc4, + 0x62, 0xec, 0x4d, 0x4b, 0x2e, 0x2d, 0x4a, 0x94, + 0xa4, 0xc2, 0x31, 0x4c, 0x4c, 0x20, 0xc0, 0x83, + 0x14, 0x8c, 0x27, 0x8b, 0x31, 0x23, 0x2f, 0x23, + 0x11, 0x91, 0x94, 0x65, 0x1a, 0x20, 0xc2, 0x18, + 0x86, 0x51, 0x88, 0x62, 0x7c, 0x43, 0x2e, 0xa3, + 0x04, 0x18, 0x8c, 0x20, 0xc2, 0xf5, 0xaa, 0x94, + 0xc2, 0x31, 0x32, 0xd2, 0xb2, 0xa2, 0x30, 0xba, + 0x10, 0xc2, 0xb5, 0x89, 0xa5, 0x18, 0x10, 0x62, + 0x9a, 0x10, 0x61, 0x19, 0x72, 0x71, 0x1a, 0xb9, + 0x0c, 0x23, 0x46, 0x10, 0x62, 0x78, 0x81, 0x82, + 0x3d, 0x75, 0xea, 0x6b, 0x51, 0x8b, 0x61, 0x06, + 0x08, 0x62, 0x32, 0x5e, 0x84, 0x18, 0x27, 0x25, + 0xc2, 0x6a, 0x4b, 0x51, 0x31, 0x34, 0x5e, 0x29, + 0xa1, 0x3c, 0x4d, 0x26, 0x23, 0x10, 0xc2, 0x6b, + 0xb1, 0x0d, 0x11, 0xae, 0x46, 0x88, 0x31, 0x35, + 0xb1, 0x06, 0x08, 0x79, 0x7e, 0x4f, 0x53, 0x23, + 0x29, 0xa4, 0x30, 0x20, 0x30, 0x23, 0x5a, 0xb2, + 0xc8, 0x60, 0x9c, 0x93, 0x13, 0x17, 0x92, 0x98, + 0x46, 0x13, 0x54, 0x53, 0x08, 0xcb, 0x13, 0xa1, + 0x1a, 0x89, 0xe5, 0x46, 0x08, 0x18, 0x10, 0x30, + 0x9d, 0x68, 0xc2, 0x1c, 0x46, 0x46, 0xae, 0x62, + 0x1a, 0x46, 0x4e, 0x4d, 0x34, 0x8c, 0xbd, 0x26, + 0xc0, 0x40, 0x62, 0xc9, 0xa9, 0x31, 0x74, 0xa8, + 0x99, 0x52, 0xb0, 0x8c, 0xa9, 0x29, 0x84, 0x61, + 0x19, 0x54, 0x43, 0x02, 0x06, 0x04, 0x32, 0xe5, + 0x18, 0x21, 0x91, 0x8b, 0xf2, 0xcc, 0x10, 0x30, + 0x8e, 0x23, 0xc4, 0x76, 0x43, 0x08, 0x30, 0x83, + 0x08, 0x62, 0x6c, 0x4e, 0xe2, 0x35, 0x96, 0xd0, + 0x8e, 0x89, 0x97, 0x42, 0x18, 0x91, 0x84, 0x61, + 0x3c, 0x26, 0xa5, 0x2c, 0x4e, 0x17, 0x94, 0xb8, + 0xb5, 0xa4, 0xcb, 0x88, 0xc9, 0x84, 0x18, 0xb9, + 0x84, 0x19, 0x23, 0x2d, 0xa4, 0x64, 0x62, 0x18, + 0x86, 0x53, 0x93, 0xcb, 0x30, 0x8f, 0x2f, 0x93, + 0x55, 0xc4, 0xd7, 0x08, 0x62, 0xb8, 0x46, 0x84, + 0x68, 0xa3, 0x02, 0xaf, 0x33 +}; + +static guint8 garbage_frame[] = { + 0xff, 0xff, 0xff, 0xff, 0xff +}; + + +GST_START_TEST (test_parse_flac_normal) +{ + gst_parser_test_normal (flac_frame, sizeof (flac_frame)); +} + +GST_END_TEST; + + +GST_START_TEST (test_parse_flac_drain_single) +{ + gst_parser_test_drain_single (flac_frame, sizeof (flac_frame)); +} + +GST_END_TEST; + + +GST_START_TEST (test_parse_flac_drain_garbage) +{ + /* We always output the after frame garbage too because we + * have no way of detecting it + */ +#if 0 + gst_parser_test_drain_garbage (flac_frame, sizeof (flac_frame), + garbage_frame, sizeof (garbage_frame)); +#endif + guint8 frame[sizeof (flac_frame) + sizeof (garbage_frame)]; + + memcpy (frame, flac_frame, sizeof (flac_frame)); + memcpy (frame + sizeof (flac_frame), garbage_frame, sizeof (garbage_frame)); + + gst_parser_test_drain_single (frame, sizeof (frame)); +} + +GST_END_TEST; + + +GST_START_TEST (test_parse_flac_split) +{ + gst_parser_test_split (flac_frame, sizeof (flac_frame)); +} + +GST_END_TEST; + + +GST_START_TEST (test_parse_flac_skip_garbage) +{ + /* We always include the garbage into the frame because + * we have no easy way for finding the real end of the + * frame. The decoder will later skip the garbage + */ +#if 0 + gst_parser_test_skip_garbage (flac_frame, sizeof (flac_frame), + garbage_frame, sizeof (garbage_frame)); +#endif + guint8 frame[sizeof (flac_frame) + sizeof (garbage_frame)]; + + memcpy (frame, flac_frame, sizeof (flac_frame)); + memcpy (frame + sizeof (flac_frame), garbage_frame, sizeof (garbage_frame)); + + gst_parser_test_normal (frame, sizeof (frame)); +} + +GST_END_TEST; + + +#define structure_get_int(s,f) \ + (g_value_get_int(gst_structure_get_value(s,f))) +#define fail_unless_structure_field_int_equals(s,field,num) \ + fail_unless_equals_int (structure_get_int(s,field), num) +/* + * Test if the parser handles raw stream and codec_data info properly. + */ +GST_START_TEST (test_parse_flac_detect_stream) +{ + GstCaps *caps; + GstStructure *s; + const GValue *streamheader; + GArray *bufarr; + gint i; + + /* Push random data. It should get through since the parser should be + * initialized because it got codec_data in the caps */ + caps = gst_parser_test_get_output_caps (flac_frame, sizeof (flac_frame), + SRC_CAPS_TMPL); + fail_unless (caps != NULL); + + /* Check that the negotiated caps are as expected */ + /* When codec_data is present, parser assumes that data is version 4 */ + GST_LOG ("flac output caps: %" GST_PTR_FORMAT, caps); + s = gst_caps_get_structure (caps, 0); + fail_unless (gst_structure_has_name (s, "audio/x-flac")); + fail_unless_structure_field_int_equals (s, "channels", 1); + fail_unless_structure_field_int_equals (s, "rate", 44100); + fail_unless (gst_structure_has_field (s, "streamheader")); + streamheader = gst_structure_get_value (s, "streamheader"); + fail_unless (G_VALUE_TYPE (streamheader) == GST_TYPE_ARRAY); + bufarr = g_value_peek_pointer (streamheader); + fail_unless (bufarr->len == 2); + for (i = 0; i < bufarr->len; i++) { + GstBuffer *buf; + GValue *bufval = &g_array_index (bufarr, GValue, i); + + fail_unless (G_VALUE_TYPE (bufval) == GST_TYPE_BUFFER); + buf = g_value_peek_pointer (bufval); + if (i == 0) { + fail_unless (GST_BUFFER_SIZE (buf) == sizeof (streaminfo_header)); + fail_unless (memcmp (buf, streaminfo_header, sizeof (streaminfo_header))); + } else if (i == 1) { + fail_unless (GST_BUFFER_SIZE (buf) == sizeof (comment_header)); + fail_unless (memcmp (buf, comment_header, sizeof (comment_header))); + } + } + + gst_caps_unref (caps); +} + +GST_END_TEST; + + +static Suite * +flacparse_suite (void) +{ + Suite *s = suite_create ("flacparse"); + TCase *tc_chain = tcase_create ("general"); + + suite_add_tcase (s, tc_chain); + tcase_add_test (tc_chain, test_parse_flac_normal); + tcase_add_test (tc_chain, test_parse_flac_drain_single); + tcase_add_test (tc_chain, test_parse_flac_drain_garbage); + tcase_add_test (tc_chain, test_parse_flac_split); + tcase_add_test (tc_chain, test_parse_flac_skip_garbage); + + /* Other tests */ + tcase_add_test (tc_chain, test_parse_flac_detect_stream); + + return s; +} + + +/* + * TODO: + * - Both push- and pull-modes need to be tested + * * Pull-mode & EOS + */ + +int +main (int argc, char **argv) +{ + int nf; + + Suite *s = flacparse_suite (); + SRunner *sr = srunner_create (s); + + gst_check_init (&argc, &argv); + + /* init test context */ + ctx_factory = "flacparse"; + ctx_sink_template = &sinktemplate; + ctx_src_template = &srctemplate; + ctx_discard = 3; + ctx_headers[0].data = streaminfo_header; + ctx_headers[0].size = sizeof (streaminfo_header); + ctx_headers[1].data = comment_header; + ctx_headers[1].size = sizeof (comment_header); + /* custom offsets, and ts always repeatedly 0 */ + ctx_no_metadata = TRUE; + + srunner_run_all (sr, CK_NORMAL); + nf = srunner_ntests_failed (sr); + srunner_free (sr); + + return nf; +} diff --git a/tests/check/elements/mpegaudioparse.c b/tests/check/elements/mpegaudioparse.c new file mode 100644 index 000000000..69a08640f --- /dev/null +++ b/tests/check/elements/mpegaudioparse.c @@ -0,0 +1,172 @@ +/* + * GStreamer + * + * unit test for aacparse + * + * Copyright (C) 2008 Nokia Corporation. All rights reserved. + * + * Contact: Stefan Kost <stefan.kost@nokia.com> + * + * 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 <gst/check/gstcheck.h> +#include "parser.h" + +#define SRC_CAPS_TMPL "audio/mpeg, parsed=(boolean)false, mpegversion=(int)1" +#define SINK_CAPS_TMPL "audio/mpeg, parsed=(boolean)true, mpegversion=(int)1" + +GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (SINK_CAPS_TMPL) + ); + +GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (SRC_CAPS_TMPL) + ); + +const gchar *factory = "aacparse"; + +/* some data */ +static guint8 mp3_frame[384] = { + 0xff, 0xfb, 0x94, 0xc4, 0xff, 0x83, 0xc0, 0x00, + 0x01, 0xa4, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x34, 0x80, 0x00, 0x00, 0x04, 0x00, +}; + +static guint8 garbage_frame[] = { + 0xff, 0xff, 0xff, 0xff, 0xff +}; + + +GST_START_TEST (test_parse_normal) +{ + gst_parser_test_normal (mp3_frame, sizeof (mp3_frame)); +} + +GST_END_TEST; + + +GST_START_TEST (test_parse_drain_single) +{ + gst_parser_test_drain_single (mp3_frame, sizeof (mp3_frame)); +} + +GST_END_TEST; + + +GST_START_TEST (test_parse_drain_garbage) +{ + gst_parser_test_drain_garbage (mp3_frame, sizeof (mp3_frame), + garbage_frame, sizeof (garbage_frame)); +} + +GST_END_TEST; + + +GST_START_TEST (test_parse_split) +{ + gst_parser_test_split (mp3_frame, sizeof (mp3_frame)); +} + +GST_END_TEST; + + +GST_START_TEST (test_parse_skip_garbage) +{ + gst_parser_test_skip_garbage (mp3_frame, sizeof (mp3_frame), + garbage_frame, sizeof (garbage_frame)); +} + +GST_END_TEST; + + +#define structure_get_int(s,f) \ + (g_value_get_int(gst_structure_get_value(s,f))) +#define fail_unless_structure_field_int_equals(s,field,num) \ + fail_unless_equals_int (structure_get_int(s,field), num) + +GST_START_TEST (test_parse_detect_stream) +{ + GstStructure *s; + GstCaps *caps; + + caps = gst_parser_test_get_output_caps (mp3_frame, sizeof (mp3_frame), NULL); + + fail_unless (caps != NULL); + + GST_LOG ("mpegaudio output caps: %" GST_PTR_FORMAT, caps); + s = gst_caps_get_structure (caps, 0); + fail_unless (gst_structure_has_name (s, "audio/mpeg")); + fail_unless_structure_field_int_equals (s, "mpegversion", 1); + fail_unless_structure_field_int_equals (s, "layer", 3); + fail_unless_structure_field_int_equals (s, "channels", 1); + fail_unless_structure_field_int_equals (s, "rate", 48000); + + gst_caps_unref (caps); +} + +GST_END_TEST; + + +static Suite * +mpegaudioparse_suite (void) +{ + Suite *s = suite_create ("mpegaudioparse"); + TCase *tc_chain = tcase_create ("general"); + + suite_add_tcase (s, tc_chain); + tcase_add_test (tc_chain, test_parse_normal); + tcase_add_test (tc_chain, test_parse_drain_single); + tcase_add_test (tc_chain, test_parse_drain_garbage); + tcase_add_test (tc_chain, test_parse_split); + tcase_add_test (tc_chain, test_parse_skip_garbage); + tcase_add_test (tc_chain, test_parse_detect_stream); + + return s; +} + + +/* + * TODO: + * - Both push- and pull-modes need to be tested + * * Pull-mode & EOS + */ + +int +main (int argc, char **argv) +{ + int nf; + + Suite *s = mpegaudioparse_suite (); + SRunner *sr = srunner_create (s); + + gst_check_init (&argc, &argv); + + /* init test context */ + ctx_factory = "mpegaudioparse"; + ctx_sink_template = &sinktemplate; + ctx_src_template = &srctemplate; + + srunner_run_all (sr, CK_NORMAL); + nf = srunner_ntests_failed (sr); + srunner_free (sr); + + return nf; +} diff --git a/tests/check/elements/parser.c b/tests/check/elements/parser.c new file mode 100644 index 000000000..759688991 --- /dev/null +++ b/tests/check/elements/parser.c @@ -0,0 +1,434 @@ +/* + * GStreamer + * + * unit test for (audio) parser + * + * Copyright (C) 2008 Nokia Corporation. All rights reserved. + * + * Contact: Stefan Kost <stefan.kost@nokia.com> + * + * 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 <gst/check/gstcheck.h> +#include "elements/parser.h" + + +/* context state variables */ +const gchar *ctx_factory; +GstStaticPadTemplate *ctx_sink_template; +GstStaticPadTemplate *ctx_src_template; +GstCaps *ctx_input_caps; +GstCaps *ctx_output_caps; +guint ctx_discard = 0; +datablob ctx_headers[MAX_HEADERS] = { {NULL, 0}, }; + +gboolean ctx_no_metadata = FALSE; + +/* helper variables */ +GList *current_buf = NULL; + +GstPad *srcpad, *sinkpad; +guint dataoffset = 0; +GstClockTime ts_counter = 0; +gint64 offset_counter = 0; +guint buffer_counter = 0; + +typedef struct +{ + guint discard; + guint buffers_before_offset_skip; + guint offset_skip_amount; + const guint8 *data_to_verify; + guint data_to_verify_size; + GstCaps *caps; + gboolean no_metadata; +} buffer_verify_data_s; + +/* takes a copy of the passed buffer data */ +static GstBuffer * +buffer_new (const unsigned char *buffer_data, guint size) +{ + GstBuffer *buffer; + + buffer = gst_buffer_new_and_alloc (size); + if (buffer_data) { + memcpy (GST_BUFFER_DATA (buffer), buffer_data, size); + } else { + guint i; + /* Create a recognizable pattern (loop 0x00 -> 0xff) in the data block */ + for (i = 0; i < size; i++) { + GST_BUFFER_DATA (buffer)[i] = i % 0x100; + } + } + + gst_buffer_set_caps (buffer, GST_PAD_CAPS (srcpad)); + GST_BUFFER_OFFSET (buffer) = dataoffset; + dataoffset += size; + return buffer; +} + +/* + * Adds buffer sizes together. + */ +static void +buffer_count_size (void *buffer, void *user_data) +{ + guint *sum = (guint *) user_data; + *sum += GST_BUFFER_SIZE (buffer); +} + +/* + * Verify that given buffer contains predefined ADTS frame. + */ +static void +buffer_verify_data (void *buffer, void *user_data) +{ + buffer_verify_data_s *vdata; + + if (!user_data) { + return; + } + + vdata = (buffer_verify_data_s *) user_data; + + GST_DEBUG ("discard: %d", vdata->discard); + if (vdata->discard) { + buffer_counter++; + if (buffer_counter == vdata->discard) { + buffer_counter = 0; + vdata->discard = 0; + } + return; + } + + fail_unless (GST_BUFFER_SIZE (buffer) == vdata->data_to_verify_size); + fail_unless (memcmp (GST_BUFFER_DATA (buffer), vdata->data_to_verify, + vdata->data_to_verify_size) == 0); + + if (vdata->buffers_before_offset_skip) { + /* This is for skipping the garbage in some test cases */ + if (buffer_counter == vdata->buffers_before_offset_skip) { + offset_counter += vdata->offset_skip_amount; + } + } + if (!vdata->no_metadata) { + fail_unless (GST_BUFFER_TIMESTAMP (buffer) == ts_counter); + fail_unless (GST_BUFFER_DURATION (buffer) != 0); + fail_unless (GST_BUFFER_OFFSET (buffer) == offset_counter); + } + + if (vdata->caps) { + GST_LOG ("%" GST_PTR_FORMAT " = %" GST_PTR_FORMAT " ?", + GST_BUFFER_CAPS (buffer), vdata->caps); + fail_unless (gst_caps_is_equal (GST_BUFFER_CAPS (buffer), vdata->caps)); + } + + ts_counter += GST_BUFFER_DURATION (buffer); + offset_counter += GST_BUFFER_SIZE (buffer); + buffer_counter++; +} + +static GstElement * +setup_element (const gchar * factory, GstStaticPadTemplate * sink_template, + GstCaps * sink_caps, GstStaticPadTemplate * src_template, + GstCaps * src_caps) +{ + GstElement *element; + GstBus *bus; + + element = gst_check_setup_element (factory); + srcpad = gst_check_setup_src_pad (element, src_template, src_caps); + sinkpad = gst_check_setup_sink_pad (element, sink_template, sink_caps); + gst_pad_set_active (srcpad, TRUE); + gst_pad_set_active (sinkpad, TRUE); + + bus = gst_bus_new (); + gst_element_set_bus (element, bus); + + fail_unless (gst_element_set_state (element, + GST_STATE_PLAYING) != GST_STATE_CHANGE_FAILURE, + "could not set to playing"); + + ts_counter = offset_counter = buffer_counter = 0; + buffers = NULL; + return element; +} + +static void +cleanup_element (GstElement * element) +{ + GstBus *bus; + + /* Free parsed buffers */ + gst_check_drop_buffers (); + + bus = GST_ELEMENT_BUS (element); + gst_bus_set_flushing (bus, TRUE); + gst_object_unref (bus); + + gst_pad_set_active (srcpad, FALSE); + gst_pad_set_active (sinkpad, FALSE); + gst_check_teardown_src_pad (element); + gst_check_teardown_sink_pad (element); + gst_check_teardown_element (element); +} + +/* inits a standard test */ +void +gst_parser_test_init (GstParserTest * ptest, guint8 * data, guint size, + guint num) +{ + /* need these */ + fail_unless (ctx_factory != NULL); + fail_unless (ctx_src_template != NULL); + fail_unless (ctx_sink_template != NULL); + + /* basics */ + memset (ptest, 0, sizeof (*ptest)); + ptest->factory = ctx_factory; + ptest->sink_template = ctx_sink_template; + ptest->src_template = ctx_src_template; + ptest->framed = TRUE; + /* could be NULL if not relevant/needed */ + ptest->src_caps = ctx_input_caps; + ptest->sink_caps = ctx_output_caps; + memcpy (ptest->headers, ctx_headers, sizeof (ptest->headers)); + ptest->discard = ctx_discard; + /* some data that pleases caller */ + ptest->series[0].data = data; + ptest->series[0].size = size; + ptest->series[0].num = num; + ptest->series[0].fpb = 1; + ptest->series[1].fpb = 1; + ptest->series[2].fpb = 1; + ptest->no_metadata = ctx_no_metadata; +} + +/* + * Test if the parser pushes clean data properly. + */ +void +gst_parser_test_run (GstParserTest * test, GstCaps ** out_caps) +{ + buffer_verify_data_s vdata = { 0, 0, 0, NULL, 0, NULL, FALSE }; + GstElement *element; + GstBuffer *buffer = NULL; + GstCaps *src_caps; + guint i, j, k; + guint frames = 0, size = 0; + + element = setup_element (test->factory, test->sink_template, NULL, + test->src_template, test->src_caps); + + /* push some setup headers */ + for (j = 0; j < G_N_ELEMENTS (test->headers) && test->headers[j].data; j++) { + buffer = buffer_new (test->headers[j].data, test->headers[j].size); + fail_unless_equals_int (gst_pad_push (srcpad, buffer), GST_FLOW_OK); + } + + for (j = 0; j < 3; j++) { + for (i = 0; i < test->series[j].num; i++) { + /* sanity enforcing */ + for (k = 0; k < MAX (1, test->series[j].fpb); k++) { + if (!k) + buffer = buffer_new (test->series[j].data, test->series[j].size); + else { + GstCaps *caps = gst_buffer_get_caps (buffer); + + buffer = gst_buffer_join (buffer, + buffer_new (test->series[j].data, test->series[j].size)); + if (caps) { + gst_buffer_set_caps (buffer, caps); + gst_caps_unref (caps); + } + } + } + fail_unless_equals_int (gst_pad_push (srcpad, buffer), GST_FLOW_OK); + if (j == 0) + vdata.buffers_before_offset_skip++; + else if (j == 1) + vdata.offset_skip_amount += test->series[j].size * test->series[j].fpb; + if (j != 1) { + frames += test->series[j].fpb; + size += test->series[j].size * test->series[j].fpb; + } + } + } + gst_pad_push_event (srcpad, gst_event_new_eos ()); + + if (G_LIKELY (test->framed)) + fail_unless_equals_int (g_list_length (buffers) - test->discard, frames); + + /* if all frames are identical, do extended test, + * otherwise only verify total data size */ + if (test->series[0].data && (!test->series[2].size || + (test->series[0].size == test->series[2].size && test->series[2].data + && !memcmp (test->series[0].data, test->series[2].data, + test->series[0].size)))) { + vdata.data_to_verify = test->series[0].data; + vdata.data_to_verify_size = test->series[0].size; + vdata.caps = test->sink_caps; + vdata.discard = test->discard; + vdata.no_metadata = test->no_metadata; + g_list_foreach (buffers, buffer_verify_data, &vdata); + } else { + guint datasum = 0; + + g_list_foreach (buffers, buffer_count_size, &datasum); + size -= test->dropped; + fail_unless_equals_int (datasum, size); + } + + src_caps = gst_pad_get_negotiated_caps (sinkpad); + GST_LOG ("output caps: %" GST_PTR_FORMAT, src_caps); + + if (test->sink_caps) { + GST_LOG ("%" GST_PTR_FORMAT " = %" GST_PTR_FORMAT " ?", src_caps, + test->sink_caps); + fail_unless (gst_caps_is_equal (src_caps, test->sink_caps)); + } + + if (out_caps) + *out_caps = src_caps; + else + gst_caps_unref (src_caps); + + cleanup_element (element); +} + +/* + * Test if the parser pushes clean data properly. + */ +void +gst_parser_test_normal (guint8 * data, guint size) +{ + GstParserTest ptest; + + gst_parser_test_init (&ptest, data, size, 10); + gst_parser_test_run (&ptest, NULL); +} + +/* + * Test if parser drains its buffers properly. Even one single frame + * should be drained and pushed forward when EOS occurs. This single frame + * case is special, since normally the parser needs more data to be sure + * about stream format. But it should still push the frame forward in EOS. + */ +void +gst_parser_test_drain_single (guint8 * data, guint size) +{ + GstParserTest ptest; + + gst_parser_test_init (&ptest, data, size, 1); + gst_parser_test_run (&ptest, NULL); +} + +/* + * Make sure that parser does not drain garbage when EOS occurs. + */ +void +gst_parser_test_drain_garbage (guint8 * data, guint size, guint8 * garbage, + guint gsize) +{ + GstParserTest ptest; + + gst_parser_test_init (&ptest, data, size, 1); + ptest.series[1].data = garbage; + ptest.series[1].size = gsize; + ptest.series[1].num = 1; + gst_parser_test_run (&ptest, NULL); +} + +/* + * Test if parser splits a buffer that contains two frames into two + * separate buffers properly. + */ +void +gst_parser_test_split (guint8 * data, guint size) +{ + GstParserTest ptest; + + gst_parser_test_init (&ptest, data, size, 10); + ptest.series[0].fpb = 2; + gst_parser_test_run (&ptest, NULL); +} + +/* + * Test if the parser skips garbage between frames properly. + */ +void +gst_parser_test_skip_garbage (guint8 * data, guint size, guint8 * garbage, + guint gsize) +{ + GstParserTest ptest; + + gst_parser_test_init (&ptest, data, size, 10); + ptest.series[1].data = garbage; + ptest.series[1].size = gsize; + ptest.series[1].num = 1; + ptest.series[2].data = data; + ptest.series[2].size = size; + ptest.series[2].num = 10; + gst_parser_test_run (&ptest, NULL); +} + +/* + * Test if the src caps are set according to stream format. + */ +void +gst_parser_test_output_caps (guint8 * data, guint size, + const gchar * input_caps, const gchar * output_caps) +{ + GstParserTest ptest; + + gst_parser_test_init (&ptest, data, size, 10); + if (input_caps) { + ptest.src_caps = gst_caps_from_string (input_caps); + fail_unless (ptest.src_caps != NULL); + } + if (output_caps) { + ptest.sink_caps = gst_caps_from_string (output_caps); + fail_unless (ptest.sink_caps != NULL); + } + gst_parser_test_run (&ptest, NULL); + if (ptest.sink_caps) + gst_caps_unref (ptest.sink_caps); + if (ptest.src_caps) + gst_caps_unref (ptest.src_caps); +} + +/* + * Test if the src caps are set according to stream format. + */ +GstCaps * +gst_parser_test_get_output_caps (guint8 * data, guint size, + const gchar * input_caps) +{ + GstParserTest ptest; + GstCaps *out_caps; + + gst_parser_test_init (&ptest, data, size, 10); + if (input_caps) { + ptest.src_caps = gst_caps_from_string (input_caps); + fail_unless (ptest.src_caps != NULL); + } + gst_parser_test_run (&ptest, &out_caps); + if (ptest.src_caps) + gst_caps_unref (ptest.src_caps); + + return out_caps; +} diff --git a/tests/check/elements/parser.h b/tests/check/elements/parser.h new file mode 100644 index 000000000..470f59421 --- /dev/null +++ b/tests/check/elements/parser.h @@ -0,0 +1,95 @@ +/* + * GStreamer + * + * unit test for (audio) parser + * + * Copyright (C) 2008 Nokia Corporation. All rights reserved. + * + * Contact: Stefan Kost <stefan.kost@nokia.com> + * + * 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 <gst/check/gstcheck.h> + +#define MAX_HEADERS 10 + +typedef struct { + guint8 *data; + guint size; +} datablob; + +/* context state variables; to be set by test using this helper */ +/* mandatory */ +extern const gchar *ctx_factory; +extern GstStaticPadTemplate *ctx_sink_template; +extern GstStaticPadTemplate *ctx_src_template; +/* optional */ +extern GstCaps *ctx_input_caps; +extern GstCaps *ctx_output_caps; +extern guint ctx_discard; +extern datablob ctx_headers[MAX_HEADERS]; +extern gboolean ctx_no_metadata; + +/* no refs taken/kept, all up to caller */ +typedef struct +{ + const gchar *factory; + GstStaticPadTemplate *sink_template; + GstStaticPadTemplate *src_template; + /* caps that go into element */ + GstCaps *src_caps; + /* optional: output caps to verify */ + GstCaps *sink_caps; + /* initial headers */ + datablob headers[MAX_HEADERS]; + /* initial (header) output to forego checking */ + guint discard; + /* series of buffers; middle series considered garbage */ + struct { + /* data and size */ + guint8 *data; + guint size; + /* num of frames with above data per buffer */ + guint fpb; + /* num of buffers */ + guint num; + } series[3]; + /* sigh, weird cases */ + gboolean framed; + guint dropped; + gboolean no_metadata; +} GstParserTest; + +void gst_parser_test_init (GstParserTest * ptest, guint8 * data, guint size, guint num); + +void gst_parser_test_run (GstParserTest * test, GstCaps ** out_caps); + +void gst_parser_test_normal (guint8 *data, guint size); + +void gst_parser_test_drain_single (guint8 *data, guint size); + +void gst_parser_test_drain_garbage (guint8 *data, guint size, guint8 *garbage, guint gsize); + +void gst_parser_test_split (guint8 *data, guint size); + +void gst_parser_test_skip_garbage (guint8 *data, guint size, guint8 *garbage, guint gsize); + +void gst_parser_test_output_caps (guint8 *data, guint size, const gchar * input_caps, + const gchar * output_caps); + +GstCaps *gst_parser_test_get_output_caps (guint8 *data, guint size, const gchar * input_caps); + diff --git a/tests/check/elements/qtmux.c b/tests/check/elements/qtmux.c new file mode 100644 index 000000000..a70e34564 --- /dev/null +++ b/tests/check/elements/qtmux.c @@ -0,0 +1,590 @@ +/* GStreamer + * + * unit test for qtmux + * + * Copyright (C) <2008> Mark Nauwelaerts <mnauw@users.sf.net> + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#include <gst/check/gstcheck.h> +#include <gst/pbutils/encoding-profile.h> + +/* 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 */ +static GstPad *mysrcpad, *mysinkpad; + +#define AUDIO_CAPS_STRING "audio/mpeg, " \ + "mpegversion = (int) 1, " \ + "layer = (int) 3, " \ + "channels = (int) 2, " \ + "rate = (int) 48000" +#define VIDEO_CAPS_STRING "video/mpeg, " \ + "mpegversion = (int) 4, " \ + "width = (int) 384, " \ + "height = (int) 288, " \ + "framerate = (fraction) 25/1" + +static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("video/quicktime")); +static GstStaticPadTemplate srcvideotemplate = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (VIDEO_CAPS_STRING)); + +static GstStaticPadTemplate srcaudiotemplate = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (AUDIO_CAPS_STRING)); + + +/* setup and teardown needs some special handling for muxer */ +static GstPad * +setup_src_pad (GstElement * element, + GstStaticPadTemplate * template, GstCaps * caps, const gchar * sinkname) +{ + GstPad *srcpad, *sinkpad; + + GST_DEBUG_OBJECT (element, "setting up sending pad"); + /* sending pad */ + srcpad = gst_pad_new_from_static_template (template, "src"); + fail_if (srcpad == NULL, "Could not create a srcpad"); + ASSERT_OBJECT_REFCOUNT (srcpad, "srcpad", 1); + + if (!(sinkpad = gst_element_get_static_pad (element, sinkname))) + sinkpad = gst_element_get_request_pad (element, sinkname); + fail_if (sinkpad == NULL, "Could not get sink pad from %s", + GST_ELEMENT_NAME (element)); + /* references are owned by: 1) us, 2) qtmux, 3) collect pads */ + ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 3); + if (caps) + fail_unless (gst_pad_set_caps (srcpad, caps)); + fail_unless (gst_pad_link (srcpad, sinkpad) == GST_PAD_LINK_OK, + "Could not link source and %s sink pads", GST_ELEMENT_NAME (element)); + gst_object_unref (sinkpad); /* because we got it higher up */ + + /* references are owned by: 1) qtmux, 2) collect pads */ + ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 2); + + return srcpad; +} + +static void +teardown_src_pad (GstPad * srcpad) +{ + GstPad *sinkpad; + + /* clean up floating src pad */ + sinkpad = gst_pad_get_peer (srcpad); + fail_if (sinkpad == NULL); + /* pad refs held by 1) qtmux 2) collectpads and 3) us (through _get_peer) */ + ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 3); + + gst_pad_unlink (srcpad, sinkpad); + + /* after unlinking, pad refs still held by + * 1) qtmux and 2) collectpads and 3) us (through _get_peer) */ + ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 3); + gst_object_unref (sinkpad); + /* one more ref is held by element itself */ + + /* pad refs held by creator */ + ASSERT_OBJECT_REFCOUNT (srcpad, "srcpad", 1); + gst_object_unref (srcpad); +} + +static GstElement * +setup_qtmux (GstStaticPadTemplate * srctemplate, const gchar * sinkname) +{ + GstElement *qtmux; + + GST_DEBUG ("setup_qtmux"); + qtmux = gst_check_setup_element ("qtmux"); + mysrcpad = setup_src_pad (qtmux, srctemplate, NULL, sinkname); + mysinkpad = gst_check_setup_sink_pad (qtmux, &sinktemplate, NULL); + gst_pad_set_active (mysrcpad, TRUE); + gst_pad_set_active (mysinkpad, TRUE); + + return qtmux; +} + +static void +cleanup_qtmux (GstElement * qtmux, const gchar * sinkname) +{ + GST_DEBUG ("cleanup_qtmux"); + gst_element_set_state (qtmux, GST_STATE_NULL); + + gst_pad_set_active (mysrcpad, FALSE); + gst_pad_set_active (mysinkpad, FALSE); + teardown_src_pad (mysrcpad); + gst_check_teardown_sink_pad (qtmux); + gst_check_teardown_element (qtmux); +} + +static void +check_qtmux_pad (GstStaticPadTemplate * srctemplate, const gchar * sinkname, + guint32 dts_method) +{ + GstElement *qtmux; + GstBuffer *inbuffer, *outbuffer; + GstCaps *caps; + int num_buffers; + int i; + guint8 data0[12] = "\000\000\000\024ftypqt "; + guint8 data1[8] = "\000\000\000\001mdat"; + guint8 data2[4] = "moov"; + + qtmux = setup_qtmux (srctemplate, sinkname); + g_object_set (qtmux, "dts-method", dts_method, NULL); + fail_unless (gst_element_set_state (qtmux, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + + inbuffer = gst_buffer_new_and_alloc (1); + caps = gst_caps_copy (gst_pad_get_pad_template_caps (mysrcpad)); + gst_buffer_set_caps (inbuffer, caps); + gst_caps_unref (caps); + GST_BUFFER_TIMESTAMP (inbuffer) = 0; + GST_BUFFER_DURATION (inbuffer) = 40 * GST_MSECOND; + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK); + + /* send eos to have moov written */ + fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ()) == TRUE); + + num_buffers = g_list_length (buffers); + /* at least expect ftyp, mdat header, buffer chunk and moov */ + fail_unless (num_buffers >= 4); + + for (i = 0; i < num_buffers; ++i) { + outbuffer = GST_BUFFER (buffers->data); + fail_if (outbuffer == NULL); + buffers = g_list_remove (buffers, outbuffer); + + switch (i) { + case 0: + { + /* ftyp header */ + guint8 *data = GST_BUFFER_DATA (outbuffer); + + fail_unless (GST_BUFFER_SIZE (outbuffer) >= 20); + fail_unless (memcmp (data, data0, sizeof (data0)) == 0); + fail_unless (memcmp (data + 16, data0 + 8, 4) == 0); + break; + } + case 1: /* mdat header */ + fail_unless (GST_BUFFER_SIZE (outbuffer) == 16); + fail_unless (memcmp (GST_BUFFER_DATA (outbuffer), data1, sizeof (data1)) + == 0); + break; + case 2: /* buffer we put in */ + fail_unless (GST_BUFFER_SIZE (outbuffer) == 1); + break; + case 3: /* moov */ + fail_unless (GST_BUFFER_SIZE (outbuffer) > 8); + fail_unless (memcmp (GST_BUFFER_DATA (outbuffer) + 4, data2, + sizeof (data2)) == 0); + break; + default: + break; + } + + ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1); + gst_buffer_unref (outbuffer); + outbuffer = NULL; + } + + g_list_free (buffers); + buffers = NULL; + + cleanup_qtmux (qtmux, sinkname); +} + +static void +check_qtmux_pad_fragmented (GstStaticPadTemplate * srctemplate, + const gchar * sinkname, guint32 dts_method, gboolean streamable) +{ + GstElement *qtmux; + GstBuffer *inbuffer, *outbuffer; + GstCaps *caps; + int num_buffers; + int i; + guint8 data0[12] = "\000\000\000\024ftypqt "; + guint8 data1[4] = "mdat"; + guint8 data2[4] = "moov"; + guint8 data3[4] = "moof"; + guint8 data4[4] = "mfra"; + + qtmux = setup_qtmux (srctemplate, sinkname); + g_object_set (qtmux, "dts-method", dts_method, NULL); + g_object_set (qtmux, "fragment-duration", 2000, NULL); + g_object_set (qtmux, "streamable", streamable, NULL); + fail_unless (gst_element_set_state (qtmux, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + + inbuffer = gst_buffer_new_and_alloc (1); + caps = gst_caps_copy (gst_pad_get_pad_template_caps (mysrcpad)); + gst_buffer_set_caps (inbuffer, caps); + gst_caps_unref (caps); + GST_BUFFER_TIMESTAMP (inbuffer) = 0; + GST_BUFFER_DURATION (inbuffer) = 40 * GST_MSECOND; + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK); + + /* send eos to have all written */ + fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ()) == TRUE); + + num_buffers = g_list_length (buffers); + /* at least expect ftyp, moov, moof, mdat header, buffer chunk + * and optionally mfra */ + fail_unless (num_buffers >= 5); + + for (i = 0; i < num_buffers; ++i) { + outbuffer = GST_BUFFER (buffers->data); + fail_if (outbuffer == NULL); + buffers = g_list_remove (buffers, outbuffer); + + switch (i) { + case 0: + { + /* ftyp header */ + guint8 *data = GST_BUFFER_DATA (outbuffer); + + fail_unless (GST_BUFFER_SIZE (outbuffer) >= 20); + fail_unless (memcmp (data, data0, sizeof (data0)) == 0); + fail_unless (memcmp (data + 16, data0 + 8, 4) == 0); + break; + } + case 1: /* moov */ + fail_unless (GST_BUFFER_SIZE (outbuffer) > 8); + fail_unless (memcmp (GST_BUFFER_DATA (outbuffer) + 4, data2, + sizeof (data2)) == 0); + break; + case 2: /* moof */ + fail_unless (GST_BUFFER_SIZE (outbuffer) > 8); + fail_unless (memcmp (GST_BUFFER_DATA (outbuffer) + 4, data3, + sizeof (data3)) == 0); + break; + case 3: /* mdat header */ + fail_unless (GST_BUFFER_SIZE (outbuffer) == 8); + fail_unless (memcmp (GST_BUFFER_DATA (outbuffer) + 4, data1, + sizeof (data1)) == 0); + break; + case 4: /* buffer we put in */ + fail_unless (GST_BUFFER_SIZE (outbuffer) == 1); + break; + case 5: /* mfra */ + fail_unless (GST_BUFFER_SIZE (outbuffer) > 8); + fail_unless (memcmp (GST_BUFFER_DATA (outbuffer) + 4, data4, + sizeof (data4)) == 0); + break; + default: + break; + } + + ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1); + gst_buffer_unref (outbuffer); + outbuffer = NULL; + } + + g_list_free (buffers); + buffers = NULL; + + cleanup_qtmux (qtmux, sinkname); +} + +/* dts-method dd */ + +GST_START_TEST (test_video_pad_dd) +{ + check_qtmux_pad (&srcvideotemplate, "video_%d", 0); +} + +GST_END_TEST; + +GST_START_TEST (test_audio_pad_dd) +{ + check_qtmux_pad (&srcaudiotemplate, "audio_%d", 0); +} + +GST_END_TEST; + + +GST_START_TEST (test_video_pad_frag_dd) +{ + check_qtmux_pad_fragmented (&srcvideotemplate, "video_%d", 0, FALSE); +} + +GST_END_TEST; + +GST_START_TEST (test_audio_pad_frag_dd) +{ + check_qtmux_pad_fragmented (&srcaudiotemplate, "audio_%d", 0, FALSE); +} + +GST_END_TEST; + + +GST_START_TEST (test_video_pad_frag_dd_streamable) +{ + check_qtmux_pad_fragmented (&srcvideotemplate, "video_%d", 0, TRUE); +} + +GST_END_TEST; + + +GST_START_TEST (test_audio_pad_frag_dd_streamable) +{ + check_qtmux_pad_fragmented (&srcaudiotemplate, "audio_%d", 0, TRUE); +} + +GST_END_TEST; + +/* dts-method reorder */ + +GST_START_TEST (test_video_pad_reorder) +{ + check_qtmux_pad (&srcvideotemplate, "video_%d", 1); +} + +GST_END_TEST; + +GST_START_TEST (test_audio_pad_reorder) +{ + check_qtmux_pad (&srcaudiotemplate, "audio_%d", 1); +} + +GST_END_TEST; + + +GST_START_TEST (test_video_pad_frag_reorder) +{ + check_qtmux_pad_fragmented (&srcvideotemplate, "video_%d", 1, FALSE); +} + +GST_END_TEST; + +GST_START_TEST (test_audio_pad_frag_reorder) +{ + check_qtmux_pad_fragmented (&srcaudiotemplate, "audio_%d", 1, FALSE); +} + +GST_END_TEST; + + +GST_START_TEST (test_video_pad_frag_reorder_streamable) +{ + check_qtmux_pad_fragmented (&srcvideotemplate, "video_%d", 1, TRUE); +} + +GST_END_TEST; + + +GST_START_TEST (test_audio_pad_frag_reorder_streamable) +{ + check_qtmux_pad_fragmented (&srcaudiotemplate, "audio_%d", 1, TRUE); +} + +GST_END_TEST; + +/* dts-method asc */ + +GST_START_TEST (test_video_pad_asc) +{ + check_qtmux_pad (&srcvideotemplate, "video_%d", 2); +} + +GST_END_TEST; + +GST_START_TEST (test_audio_pad_asc) +{ + check_qtmux_pad (&srcaudiotemplate, "audio_%d", 2); +} + +GST_END_TEST; + + +GST_START_TEST (test_video_pad_frag_asc) +{ + check_qtmux_pad_fragmented (&srcvideotemplate, "video_%d", 2, FALSE); +} + +GST_END_TEST; + +GST_START_TEST (test_audio_pad_frag_asc) +{ + check_qtmux_pad_fragmented (&srcaudiotemplate, "audio_%d", 2, FALSE); +} + +GST_END_TEST; + + +GST_START_TEST (test_video_pad_frag_asc_streamable) +{ + check_qtmux_pad_fragmented (&srcvideotemplate, "video_%d", 2, TRUE); +} + +GST_END_TEST; + + +GST_START_TEST (test_audio_pad_frag_asc_streamable) +{ + check_qtmux_pad_fragmented (&srcaudiotemplate, "audio_%d", 2, TRUE); +} + +GST_END_TEST; + +GST_START_TEST (test_reuse) +{ + GstElement *qtmux = setup_qtmux (&srcvideotemplate, "video_%d"); + GstBuffer *inbuffer; + GstCaps *caps; + + gst_element_set_state (qtmux, GST_STATE_PLAYING); + gst_element_set_state (qtmux, GST_STATE_NULL); + gst_element_set_state (qtmux, GST_STATE_PLAYING); + gst_pad_set_active (mysrcpad, TRUE); + gst_pad_set_active (mysinkpad, TRUE); + + inbuffer = gst_buffer_new_and_alloc (1); + fail_unless (inbuffer != NULL); + caps = gst_caps_copy (gst_pad_get_pad_template_caps (mysrcpad)); + gst_buffer_set_caps (inbuffer, caps); + gst_caps_unref (caps); + GST_BUFFER_TIMESTAMP (inbuffer) = 0; + GST_BUFFER_DURATION (inbuffer) = 40 * GST_MSECOND; + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK); + + /* send eos to have all written */ + fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ()) == TRUE); + + cleanup_qtmux (qtmux, "video_%d"); +} + +GST_END_TEST; + +static GstEncodingContainerProfile * +create_qtmux_profile (const gchar * variant) +{ + GstEncodingContainerProfile *cprof; + GstCaps *caps; + + if (variant == NULL) { + caps = gst_caps_new_simple ("video/quicktime", NULL); + } else { + caps = gst_caps_new_simple ("video/quicktime", + "variant", G_TYPE_STRING, variant, NULL); + } + + cprof = gst_encoding_container_profile_new ("Name", "blah", caps, NULL); + gst_caps_unref (caps); + + caps = gst_caps_new_simple ("audio/x-raw-int", "width", G_TYPE_INT, 16, + "depth", G_TYPE_INT, 16, "endianness", G_TYPE_INT, 4321, + "channels", G_TYPE_INT, 2, "rate", G_TYPE_INT, 44100, + "signed", G_TYPE_BOOLEAN, TRUE, NULL); + gst_encoding_container_profile_add_profile (cprof, + GST_ENCODING_PROFILE (gst_encoding_audio_profile_new (caps, NULL, NULL, + 1))); + gst_caps_unref (caps); + + return cprof; +} + +GST_START_TEST (test_encodebin) +{ + GstEncodingContainerProfile *cprof; + GstElement *enc; + GstPad *pad; + + enc = gst_element_factory_make ("encodebin", NULL); + if (enc == NULL) + return; + + /* Make sure encodebin finds a muxer for a profile with a variant field .. */ + cprof = create_qtmux_profile ("apple"); + g_object_set (enc, "profile", cprof, NULL); + gst_encoding_profile_unref (cprof); + + /* should have created a pad after setting the profile */ + pad = gst_element_get_static_pad (enc, "audio_0"); + fail_unless (pad != NULL); + gst_object_unref (pad); + gst_object_unref (enc); + + /* ... and for a profile without a variant field */ + enc = gst_element_factory_make ("encodebin", NULL); + cprof = create_qtmux_profile (NULL); + g_object_set (enc, "profile", cprof, NULL); + gst_encoding_profile_unref (cprof); + + /* should have created a pad after setting the profile */ + pad = gst_element_get_static_pad (enc, "audio_0"); + fail_unless (pad != NULL); + gst_object_unref (pad); + gst_object_unref (enc); +} + +GST_END_TEST; + +static Suite * +qtmux_suite (void) +{ + Suite *s = suite_create ("qtmux"); + TCase *tc_chain = tcase_create ("general"); + + suite_add_tcase (s, tc_chain); + tcase_add_test (tc_chain, test_video_pad_dd); + tcase_add_test (tc_chain, test_audio_pad_dd); + tcase_add_test (tc_chain, test_video_pad_frag_dd); + tcase_add_test (tc_chain, test_audio_pad_frag_dd); + tcase_add_test (tc_chain, test_video_pad_frag_dd_streamable); + tcase_add_test (tc_chain, test_audio_pad_frag_dd_streamable); + + tcase_add_test (tc_chain, test_video_pad_reorder); + tcase_add_test (tc_chain, test_audio_pad_reorder); + tcase_add_test (tc_chain, test_video_pad_frag_reorder); + tcase_add_test (tc_chain, test_audio_pad_frag_reorder); + tcase_add_test (tc_chain, test_video_pad_frag_reorder_streamable); + tcase_add_test (tc_chain, test_audio_pad_frag_reorder_streamable); + + tcase_add_test (tc_chain, test_video_pad_asc); + tcase_add_test (tc_chain, test_audio_pad_asc); + tcase_add_test (tc_chain, test_video_pad_frag_asc); + tcase_add_test (tc_chain, test_audio_pad_frag_asc); + tcase_add_test (tc_chain, test_video_pad_frag_asc_streamable); + tcase_add_test (tc_chain, test_audio_pad_frag_asc_streamable); + + tcase_add_test (tc_chain, test_reuse); + tcase_add_test (tc_chain, test_encodebin); + + return s; +} + +GST_CHECK_MAIN (qtmux) diff --git a/tests/check/elements/rtp-payloading.c b/tests/check/elements/rtp-payloading.c index 245f33219..b2160f4a5 100644 --- a/tests/check/elements/rtp-payloading.c +++ b/tests/check/elements/rtp-payloading.c @@ -291,13 +291,12 @@ rtp_pipeline_run (rtp_pipeline * p) for (i = 0; i < LOOP_COUNT; i++) { const char *frame_data_pointer = p->frame_data; int res; - int frame_count = p->frame_count; /* Write in to the pipe. */ while (frame_count > 0) { res = write (p->fd[1], frame_data_pointer, p->frame_data_size); - + fail_unless_equals_int (res, p->frame_data_size); frame_data_pointer += p->frame_data_size; frame_count--; } diff --git a/tests/check/pipelines/.gitignore b/tests/check/pipelines/.gitignore index e81a5ec56..4396b2fa1 100644 --- a/tests/check/pipelines/.gitignore +++ b/tests/check/pipelines/.gitignore @@ -2,6 +2,7 @@ effectv flacdec simple-launch-lines +tagschecking wavenc wavpack *.check.xml diff --git a/tests/check/pipelines/flacdec.c b/tests/check/pipelines/flacdec.c index abf9a058c..ce8546e99 100644 --- a/tests/check/pipelines/flacdec.c +++ b/tests/check/pipelines/flacdec.c @@ -110,7 +110,6 @@ GST_START_TEST (test_decode_seek_full) GstEvent *event; GstBuffer *buffer = NULL; guint16 first_sample = 0; - gboolean result; guint size = 0; gchar *path = g_build_filename (GST_TEST_FILES_PATH, "audiotestsrc.flac", NULL); @@ -133,7 +132,7 @@ GST_START_TEST (test_decode_seek_full) /* do a seek that should give us the complete output */ event = gst_event_new_seek (1.0, GST_FORMAT_DEFAULT, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_SET, 20480); - result = gst_element_send_event (appsink, event); + fail_unless (gst_element_send_event (appsink, event)); gst_element_set_state (pipeline, GST_STATE_PLAYING); @@ -169,7 +168,6 @@ GST_START_TEST (test_decode_seek_partial) GstElement *appsink; GstEvent *event; GstBuffer *buffer = NULL; - gboolean result; guint size = 0; guint16 first_sample = 0; gchar *path = @@ -194,7 +192,7 @@ GST_START_TEST (test_decode_seek_partial) event = gst_event_new_seek (1.0, GST_FORMAT_DEFAULT, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_SET, 1024); GST_DEBUG ("seeking"); - result = gst_element_send_event (appsink, event); + fail_unless (gst_element_send_event (appsink, event)); GST_DEBUG ("seeked"); gst_element_set_state (pipeline, GST_STATE_PLAYING); diff --git a/tests/check/pipelines/tagschecking.c b/tests/check/pipelines/tagschecking.c new file mode 100644 index 000000000..91a556c52 --- /dev/null +++ b/tests/check/pipelines/tagschecking.c @@ -0,0 +1,350 @@ +/* GStreamer + * Copyright (C) 2008 Nokia Corporation. (contact <stefan.kost@nokia.com>) + * Copyright (C) 2010 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include <gst/check/gstcheck.h> + +static GstTagList *received_tags = NULL; + +static gboolean +bus_handler (GstBus * bus, GstMessage * message, gpointer data) +{ + GMainLoop *loop = (GMainLoop *) data; + + switch (message->type) { + case GST_MESSAGE_EOS: + g_main_loop_quit (loop); + break; + case GST_MESSAGE_WARNING: + case GST_MESSAGE_ERROR:{ + GError *gerror; + + gchar *debug; + + gst_message_parse_error (message, &gerror, &debug); + gst_object_default_error (GST_MESSAGE_SRC (message), gerror, debug); + g_error_free (gerror); + g_free (debug); + g_main_loop_quit (loop); + break; + } + case GST_MESSAGE_TAG:{ + if (received_tags == NULL) { + gst_message_parse_tag (message, &received_tags); + } else { + GstTagList *tl = NULL, *ntl = NULL; + + gst_message_parse_tag (message, &tl); + if (tl) { + ntl = gst_tag_list_merge (received_tags, tl, GST_TAG_MERGE_PREPEND); + if (ntl) { + GST_LOG ("taglists merged: %" GST_PTR_FORMAT, ntl); + gst_tag_list_free (received_tags); + received_tags = ntl; + } + gst_tag_list_free (tl); + } + } + break; + } + default: + break; + } + + return TRUE; +} + +/* + * Creates a pipeline in the form: + * fakesrc num-buffers=1 ! caps ! muxer ! filesink location=file + * + * And sets the tags in tag_str into the muxer via tagsetter. + */ +static void +test_mux_tags (const gchar * tag_str, const gchar * caps, + const gchar * muxer, const gchar * file) +{ + GstElement *pipeline; + GstBus *bus; + GMainLoop *loop; + GstTagList *sent_tags; + GstElement *mux; + GstTagSetter *setter; + gchar *launch_str; + + GST_DEBUG ("testing xmp muxing on : %s", muxer); + + launch_str = g_strdup_printf ("fakesrc num-buffers=1 ! %s ! %s name=mux ! " + "filesink location=%s name=sink", caps, muxer, file); + pipeline = gst_parse_launch (launch_str, NULL); + g_free (launch_str); + fail_unless (pipeline != NULL); + + mux = gst_bin_get_by_name (GST_BIN (pipeline), "mux"); + fail_unless (mux != NULL); + + loop = g_main_loop_new (NULL, TRUE); + fail_unless (loop != NULL); + + bus = gst_element_get_bus (pipeline); + fail_unless (bus != NULL); + gst_bus_add_watch (bus, bus_handler, loop); + gst_object_unref (bus); + + gst_element_set_state (pipeline, GST_STATE_READY); + + setter = GST_TAG_SETTER (mux); + fail_unless (setter != NULL); + sent_tags = gst_structure_from_string (tag_str, NULL); + fail_unless (sent_tags != NULL); + gst_tag_setter_merge_tags (setter, sent_tags, GST_TAG_MERGE_REPLACE); + gst_tag_list_free (sent_tags); + + gst_element_set_state (pipeline, GST_STATE_PLAYING); + g_main_loop_run (loop); + + gst_element_set_state (pipeline, GST_STATE_NULL); + + g_main_loop_unref (loop); + g_object_unref (mux); + g_object_unref (pipeline); +} + +/* + * Makes a pipeline in the form: + * filesrc location=file ! demuxer ! fakesink + * + * And gets the tags that are posted on the bus to compare + * with the tags in 'tag_str' + */ +static void +test_demux_tags (const gchar * tag_str, const gchar * demuxer, + const gchar * file) +{ + GstElement *pipeline; + GstBus *bus; + GMainLoop *loop; + GstTagList *sent_tags; + gint i, j, n_recv, n_sent; + const gchar *name_sent, *name_recv; + const GValue *value_sent, *value_recv; + gboolean found; + gint comparison; + GstElement *demux; + gchar *launch_str; + + GST_DEBUG ("testing tags : %s", tag_str); + + if (received_tags) { + gst_tag_list_free (received_tags); + received_tags = NULL; + } + + launch_str = g_strdup_printf ("filesrc location=%s ! %s name=demux ! " + "fakesink", file, demuxer); + pipeline = gst_parse_launch (launch_str, NULL); + g_free (launch_str); + fail_unless (pipeline != NULL); + + demux = gst_bin_get_by_name (GST_BIN (pipeline), "demux"); + fail_unless (demux != NULL); + + loop = g_main_loop_new (NULL, TRUE); + fail_unless (loop != NULL); + + bus = gst_element_get_bus (pipeline); + fail_unless (bus != NULL); + gst_bus_add_watch (bus, bus_handler, loop); + gst_object_unref (bus); + + sent_tags = gst_structure_from_string (tag_str, NULL); + fail_unless (sent_tags != NULL); + + gst_element_set_state (pipeline, GST_STATE_PLAYING); + g_main_loop_run (loop); + + GST_DEBUG ("mainloop done : %p", received_tags); + + /* verify tags */ + fail_unless (received_tags != NULL); + n_recv = gst_structure_n_fields (received_tags); + n_sent = gst_structure_n_fields (sent_tags); + fail_unless (n_recv >= n_sent); + /* FIXME: compare taglits values */ + for (i = 0; i < n_sent; i++) { + name_sent = gst_structure_nth_field_name (sent_tags, i); + value_sent = gst_structure_get_value (sent_tags, name_sent); + found = FALSE; + for (j = 0; j < n_recv; j++) { + name_recv = gst_structure_nth_field_name (received_tags, j); + if (!strcmp (name_sent, name_recv)) { + value_recv = gst_structure_get_value (received_tags, name_recv); + comparison = gst_value_compare (value_sent, value_recv); + if (comparison != GST_VALUE_EQUAL) { + gchar *vs = g_strdup_value_contents (value_sent); + gchar *vr = g_strdup_value_contents (value_recv); + GST_DEBUG ("sent = %s:'%s', recv = %s:'%s'", + G_VALUE_TYPE_NAME (value_sent), vs, + G_VALUE_TYPE_NAME (value_recv), vr); + g_free (vs); + g_free (vr); + } + fail_unless (comparison == GST_VALUE_EQUAL, + "tag item %s has been received with different type or value", + name_sent); + found = TRUE; + break; + } + } + fail_unless (found, "tag item %s is lost", name_sent); + } + + gst_tag_list_free (received_tags); + received_tags = NULL; + gst_tag_list_free (sent_tags); + + gst_element_set_state (pipeline, GST_STATE_NULL); + + g_main_loop_unref (loop); + g_object_unref (demux); + g_object_unref (pipeline); +} + +/* + * Tests if the muxer/demuxer pair can serialize the tags in 'tag_str' + * to a file and recover them correctly. + * + * 'caps' are used to assure the muxer accepts the fake buffer fakesrc + * will send to it. + */ +static void +test_tags (const gchar * tag_str, const gchar * caps, const gchar * muxer, + const gchar * demuxer) +{ + gchar *tmpfile; + gchar *tmp; + + tmp = g_strdup_printf ("%s%d", "gst-check-xmp-test-", g_random_int ()); + tmpfile = g_build_filename (g_get_tmp_dir (), tmp, NULL); + g_free (tmp); + + GST_DEBUG ("testing tags : %s", tag_str); + test_mux_tags (tag_str, caps, muxer, tmpfile); + test_demux_tags (tag_str, demuxer, tmpfile); + g_free (tmpfile); +} + +#define H264_CAPS "video/x-h264, width=(int)320, height=(int)240," \ + " framerate=(fraction)30/1, codec_data=(buffer)" \ + "01401592ffe10017674d401592540a0fd8088000000300" \ + "8000001e478b175001000468ee3c80, stream-format=(string)avc" + +#define COMMON_TAGS \ + "taglist,title=test_title," \ + "artist=test_artist," \ + "keywords=\"key1,key2\"," \ + "description=test_desc" + +GST_START_TEST (test_common_tags) +{ + if (!gst_default_registry_check_feature_version ("qtdemux", 0, 10, 23)) { + GST_INFO ("Skipping test, qtdemux either not available or too old"); + return; + } + test_tags (COMMON_TAGS, H264_CAPS, "qtmux", "qtdemux"); + test_tags (COMMON_TAGS, H264_CAPS, "mp4mux", "qtdemux"); + test_tags (COMMON_TAGS, H264_CAPS, "gppmux", "qtdemux"); +} + +GST_END_TEST; + +#define GEO_LOCATION_TAGS \ + "taglist,geo-location-country=Brazil," \ + "geo-location-city=\"Campina Grande\"," \ + "geo-location-sublocation=Bodocongo," \ + "geo-location-latitude=-12.125," \ + "geo-location-longitude=56.75," \ + "geo-location-elevation=327.5" + +GST_START_TEST (test_geo_location_tags) +{ + if (!gst_default_registry_check_feature_version ("qtdemux", 0, 10, 23)) { + GST_INFO ("Skipping test, qtdemux either not available or too old"); + return; + } + test_tags (GEO_LOCATION_TAGS, H264_CAPS, "qtmux", "qtdemux"); + test_tags (GEO_LOCATION_TAGS, H264_CAPS, "mp4mux", "qtdemux"); + test_tags (GEO_LOCATION_TAGS, H264_CAPS, "gppmux", "qtdemux"); +} + +GST_END_TEST; + + +#define USER_TAGS \ + "taglist,user-rating=(uint)85" + +GST_START_TEST (test_user_tags) +{ + if (!gst_default_registry_check_feature_version ("qtdemux", 0, 10, 23)) { + GST_INFO ("Skipping test, qtdemux either not available or too old"); + return; + } + + test_tags (USER_TAGS, H264_CAPS, "qtmux", "qtdemux"); + test_tags (USER_TAGS, H264_CAPS, "mp4mux", "qtdemux"); + test_tags (USER_TAGS, H264_CAPS, "gppmux", "qtdemux"); +} + +GST_END_TEST; + +static Suite * +metadata_suite (void) +{ + Suite *s = suite_create ("tagschecking"); + + TCase *tc_chain = tcase_create ("general"); + + /* time out after 60s, not the default 3 */ + tcase_set_timeout (tc_chain, 60); + + suite_add_tcase (s, tc_chain); + tcase_add_test (tc_chain, test_common_tags); + tcase_add_test (tc_chain, test_geo_location_tags); + tcase_add_test (tc_chain, test_user_tags); + + return s; +} + +int +main (int argc, char **argv) +{ + int nf; + + Suite *s = metadata_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; +} |