From 694c07fe63ed47138f8c1d80dadb96c63ffa7f6c Mon Sep 17 00:00:00 2001 From: fengalin Date: Thu, 14 Dec 2017 19:05:36 +0100 Subject: [PATCH] matroska-mux: migrate test to gst_harness MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ... following the guide lines from HÃ¥vard Graff (see https://gstconf.ubicast.tv/videos/moar-better-tests/). https://bugzilla.gnome.org/show_bug.cgi?id=790686 --- tests/check/elements/matroskademux.c | 2 +- tests/check/elements/matroskamux.c | 697 +++++++++++---------------- 2 files changed, 283 insertions(+), 416 deletions(-) diff --git a/tests/check/elements/matroskademux.c b/tests/check/elements/matroskademux.c index 71bc1817f0..60b4c69112 100644 --- a/tests/check/elements/matroskademux.c +++ b/tests/check/elements/matroskademux.c @@ -136,7 +136,7 @@ GST_START_TEST (test_sub_terminator) GST_END_TEST; -/* Recusively compare 2 toc entries */ +/* Recursively compare 2 toc entries */ static void check_toc_entries (const GstTocEntry * original, const GstTocEntry * other) { diff --git a/tests/check/elements/matroskamux.c b/tests/check/elements/matroskamux.c index 97a033f833..23e56d96de 100644 --- a/tests/check/elements/matroskamux.c +++ b/tests/check/elements/matroskamux.c @@ -24,239 +24,106 @@ #include #include - -/* 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; +#include #define AC3_CAPS_STRING "audio/x-ac3, " \ "channels = (int) 1, " \ "rate = (int) 8000" #define VORBIS_TMPL_CAPS_STRING "audio/x-vorbis, " \ "channels = (int) 1, " \ - "rate = (int) 8000" -/* streamheader shouldn't be in the template caps, only in the actual caps */ -#define VORBIS_CAPS_STRING VORBIS_TMPL_CAPS_STRING \ - ", streamheader=(buffer)<10, 2020, 303030>" + "rate = (int) 8000, " \ + "streamheader=(buffer)<10, 2020, 303030>" -static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("video/x-matroska; audio/x-matroska")); -static GstStaticPadTemplate srcvorbistemplate = GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS (VORBIS_TMPL_CAPS_STRING)); - -static GstStaticPadTemplate srcac3template = GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS (AC3_CAPS_STRING)); - - -static GstPad * -setup_src_pad (GstElement * element, GstStaticPadTemplate * template) +static GstHarness * +setup_matroskamux_harness (const gchar * src_pad_str) { - GstPad *srcpad, *sinkpad; + GstHarness *h; - 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); - gst_pad_set_active (srcpad, TRUE); + h = gst_harness_new_with_padnames ("matroskamux", "audio_%u", "src"); + gst_harness_set_src_caps_str (h, src_pad_str); + gst_harness_set_sink_caps_str (h, "video/x-matroska; audio/x-matroska"); - if (!(sinkpad = gst_element_get_static_pad (element, "audio_%u"))) - sinkpad = gst_element_get_request_pad (element, "audio_%u"); - fail_if (sinkpad == NULL, "Could not get sink pad from %s", - GST_ELEMENT_NAME (element)); - /* references are owned by: 1) us, 2) matroskamux, 3) collect pads */ - ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 3); - 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) matroskamux, 2) collect pads */ - ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 2); - - return srcpad; + return h; } -static void -teardown_src_pad (GstElement * element) -{ - GstPad *srcpad, *sinkpad; - - /* clean up floating src pad */ - if (!(sinkpad = gst_element_get_static_pad (element, "audio_0"))) - sinkpad = gst_element_get_request_pad (element, "audio_0"); - /* references are owned by: 1) us, 2) matroskamux, 3) collect pads */ - ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 3); - srcpad = gst_pad_get_peer (sinkpad); - - gst_pad_unlink (srcpad, sinkpad); - - /* references are owned by: 1) us, 2) matroskamux, 3) collect pads */ - ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 3); - gst_object_unref (sinkpad); - /* one more ref is held by element itself */ - - /* pad refs held by both creator and this function (through _get_peer) */ - ASSERT_OBJECT_REFCOUNT (srcpad, "srcpad", 2); - gst_object_unref (srcpad); - gst_object_unref (srcpad); -} - -static GstPad * -setup_sink_pad (GstElement * element, GstStaticPadTemplate * template) -{ - GstPad *srcpad, *sinkpad; - - GST_DEBUG_OBJECT (element, "setting up receiving pad"); - /* receiving pad */ - sinkpad = gst_pad_new_from_static_template (template, "sink"); - - fail_if (sinkpad == NULL, "Could not create a sinkpad"); - gst_pad_set_active (sinkpad, TRUE); - - srcpad = gst_element_get_static_pad (element, "src"); - fail_if (srcpad == NULL, "Could not get source pad from %s", - GST_ELEMENT_NAME (element)); - gst_pad_set_chain_function (sinkpad, gst_check_chain_func); - - fail_unless (gst_pad_link (srcpad, sinkpad) == GST_PAD_LINK_OK, - "Could not link %s source and sink pads", GST_ELEMENT_NAME (element)); - gst_object_unref (srcpad); /* because we got it higher up */ - ASSERT_OBJECT_REFCOUNT (srcpad, "srcpad", 2); - - return sinkpad; -} - -static void -teardown_sink_pad (GstElement * element) -{ - GstPad *srcpad, *sinkpad; - - /* clean up floating sink pad */ - srcpad = gst_element_get_static_pad (element, "src"); - sinkpad = gst_pad_get_peer (srcpad); - gst_pad_unlink (srcpad, sinkpad); - - /* pad refs held by both creator and this function (through _get_pad) */ - ASSERT_OBJECT_REFCOUNT (srcpad, "srcpad", 3); - gst_object_unref (srcpad); - /* one more ref is held by element itself */ - - /* pad refs held by both creator and this function (through _get_peer) */ - ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 2); - gst_object_unref (sinkpad); - gst_object_unref (sinkpad); -} - - -gboolean downstream_is_seekable; static gboolean -matroskamux_sinkpad_query (GstPad * pad, GstObject * parent, GstQuery * query) +seekable_sinkpad_query (GstPad * pad, GstObject * parent, GstQuery * query) { gboolean ret = FALSE; if (GST_QUERY_TYPE (query) == GST_QUERY_SEEKING) { - gst_query_set_seeking (query, GST_FORMAT_BYTES, downstream_is_seekable, 0, - -1); + gst_query_set_seeking (query, GST_FORMAT_BYTES, TRUE, 0, -1); ret = TRUE; } return ret; } -static GstElement * -setup_matroskamux (GstStaticPadTemplate * srctemplate) -{ - GstElement *matroskamux; - - GST_DEBUG ("setup_matroskamux"); - matroskamux = gst_check_setup_element ("matroskamux"); - g_object_set (matroskamux, "version", 1, NULL); - mysrcpad = setup_src_pad (matroskamux, srctemplate); - mysinkpad = setup_sink_pad (matroskamux, &sinktemplate); - - fail_unless (gst_element_set_state (matroskamux, - GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, - "could not set to playing"); - - return matroskamux; -} +#define compare_buffer_to_data(buffer, data, data_size) \ +G_STMT_START { \ +fail_unless_equals_int (data_size, gst_buffer_get_size (buffer)); \ +fail_unless (gst_buffer_memcmp (buffer, 0, data, data_size) == 0); \ +} G_STMT_END static void -cleanup_matroskamux (GstElement * matroskamux) +test_ebml_header_with_version (gint version, + gconstpointer data, gsize data_size) { - GST_DEBUG ("cleanup_matroskamux"); - gst_element_set_state (matroskamux, GST_STATE_NULL); - - teardown_src_pad (matroskamux); - teardown_sink_pad (matroskamux); - gst_check_teardown_element (matroskamux); -} - -static void -check_buffer_data (GstBuffer * buffer, void *data, size_t data_size) -{ - fail_unless (gst_buffer_get_size (buffer) == data_size); - fail_unless (gst_buffer_memcmp (buffer, 0, data, data_size) == 0); -} - -GST_START_TEST (test_ebml_header) -{ - GstElement *matroskamux; + GstHarness *h; GstBuffer *inbuffer, *outbuffer; - GstAdapter *adapter; - int num_buffers; - int i; - gint available; - GstCaps *caps; - guint8 data[] = - { 0x1a, 0x45, 0xdf, 0xa3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, - 0x42, 0x82, 0x89, 0x6d, 0x61, 0x74, 0x72, 0x6f, 0x73, 0x6b, 0x61, 0x00, - 0x42, 0x87, 0x81, 0x01, - 0x42, 0x85, 0x81, 0x01 - }; - matroskamux = setup_matroskamux (&srcac3template); + h = setup_matroskamux_harness (AC3_CAPS_STRING); + g_object_set (h->element, "version", version, NULL); - caps = gst_caps_from_string (srcac3template.static_caps.string); - gst_check_setup_events (mysrcpad, matroskamux, caps, GST_FORMAT_TIME); - gst_caps_unref (caps); + inbuffer = gst_harness_create_buffer (h, 1); + fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (h, inbuffer)); + fail_unless_equals_int (2, gst_harness_buffers_received (h)); - inbuffer = gst_buffer_new_allocate (NULL, 1, 0); - ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); - fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK); - num_buffers = g_list_length (buffers); - fail_unless (num_buffers >= 1, - "expected at least 5 buffers, but got only %d", num_buffers); - - adapter = gst_adapter_new (); - for (i = 0; i < num_buffers; ++i) { - outbuffer = GST_BUFFER (buffers->data); - fail_if (outbuffer == NULL); - buffers = g_list_remove (buffers, outbuffer); - - ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1); - - gst_adapter_push (adapter, outbuffer); - } - - available = gst_adapter_available (adapter); - fail_unless (available >= sizeof (data)); - outbuffer = gst_adapter_take_buffer (adapter, sizeof (data)); - g_object_unref (adapter); - - check_buffer_data (outbuffer, data, sizeof (data)); + outbuffer = gst_harness_pull (h); + compare_buffer_to_data (outbuffer, data, data_size); gst_buffer_unref (outbuffer); - cleanup_matroskamux (matroskamux); - g_list_free (buffers); - buffers = NULL; + gst_harness_teardown (h); +} + +GST_START_TEST (test_ebml_header_v1) +{ + guint8 data_v1[] = { + 0x1a, 0x45, 0xdf, 0xa3, /* master ID */ + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, + 0x42, 0x82, /* doctype */ + 0x89, /* 9 bytes */ + 0x6d, 0x61, 0x74, 0x72, 0x6f, 0x73, 0x6b, 0x61, 0x00, /* "matroska" */ + 0x42, 0x87, /* doctypeversion */ + 0x81, /* 1 byte */ + 0x01, /* 1 */ + 0x42, 0x85, /* doctypereadversion */ + 0x81, /* 1 byte */ + 0x01, /* 1 */ + }; + + test_ebml_header_with_version (1, data_v1, sizeof (data_v1)); +} + +GST_END_TEST; + +GST_START_TEST (test_ebml_header_v2) +{ + guint8 data_v2[] = { + 0x1a, 0x45, 0xdf, 0xa3, /* master ID */ + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, + 0x42, 0x82, /* doctype */ + 0x89, /* 9 bytes */ + 0x6d, 0x61, 0x74, 0x72, 0x6f, 0x73, 0x6b, 0x61, 0x00, /* "matroska" */ + 0x42, 0x87, /* doctypeversion */ + 0x81, /* 1 byte */ + 0x02, /* 2 */ + 0x42, 0x85, /* doctypereadversion */ + 0x81, /* 1 byte */ + 0x02, /* 2 */ + }; + + test_ebml_header_with_version (2, data_v2, sizeof (data_v2)); } GST_END_TEST; @@ -264,37 +131,24 @@ GST_END_TEST; GST_START_TEST (test_vorbis_header) { - GstElement *matroskamux; + GstHarness *h; GstBuffer *inbuffer, *outbuffer; - GstCaps *caps; - int num_buffers; - int i; gboolean vorbis_header_found = FALSE; - guint8 data[12] = + gint j; + gsize buffer_size; + guint8 data[] = { 0x63, 0xa2, 0x89, 0x02, 0x01, 0x02, 0x10, 0x20, 0x20, 0x30, 0x30, 0x30 }; - matroskamux = setup_matroskamux (&srcvorbistemplate); + h = setup_matroskamux_harness (VORBIS_TMPL_CAPS_STRING); - caps = gst_caps_from_string (VORBIS_CAPS_STRING); - gst_check_setup_events (mysrcpad, matroskamux, caps, GST_FORMAT_TIME); - gst_caps_unref (caps); + inbuffer = gst_harness_create_buffer (h, 1); + fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (h, inbuffer)); - inbuffer = gst_buffer_new_allocate (NULL, 1, 0); - ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); - - fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK); - num_buffers = g_list_length (buffers); - - for (i = 0; i < num_buffers; ++i) { - gint j; - gsize buffer_size; - - outbuffer = GST_BUFFER (buffers->data); - fail_if (outbuffer == NULL); + outbuffer = gst_harness_pull (h); + while (outbuffer != NULL) { buffer_size = gst_buffer_get_size (outbuffer); - buffers = g_list_remove (buffers, outbuffer); if (!vorbis_header_found && buffer_size >= sizeof (data)) { for (j = 0; j <= buffer_size - sizeof (data); j++) { @@ -307,173 +161,192 @@ GST_START_TEST (test_vorbis_header) ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1); gst_buffer_unref (outbuffer); - outbuffer = NULL; + + outbuffer = gst_harness_try_pull (h); } fail_unless (vorbis_header_found); - cleanup_matroskamux (matroskamux); - g_list_free (buffers); - buffers = NULL; + gst_harness_teardown (h); } GST_END_TEST; -GST_START_TEST (test_block_group) +static void +test_block_group_with_version (gint version, + gconstpointer data0, gsize data0_size) { - GstElement *matroskamux; + GstHarness *h; GstBuffer *inbuffer, *outbuffer; - guint8 *indata; - GstCaps *caps; - int num_buffers; - int i; - guint8 data0[] = { 0xa0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, + guint8 data1[] = { 0x42 }; + + h = setup_matroskamux_harness (AC3_CAPS_STRING); + g_object_set (h->element, "version", version, NULL); + + /* Generate the header */ + inbuffer = gst_harness_create_buffer (h, 1); + GST_BUFFER_TIMESTAMP (inbuffer) = 0; + fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (h, inbuffer)); + fail_unless_equals_int (5, gst_harness_buffers_received (h)); + + outbuffer = gst_harness_pull (h); + fail_unless (outbuffer != NULL); + while (outbuffer != NULL) { + gst_buffer_unref (outbuffer); + outbuffer = gst_harness_try_pull (h); + } + + /* Now push a buffer */ + inbuffer = gst_harness_create_buffer (h, 1); + gst_buffer_fill (inbuffer, 0, data1, sizeof (data1)); + GST_BUFFER_TIMESTAMP (inbuffer) = 1000000; + + fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (h, inbuffer)); + + outbuffer = gst_harness_pull (h); + compare_buffer_to_data (outbuffer, data0, data0_size); + gst_buffer_unref (outbuffer); + + outbuffer = gst_harness_pull (h); + compare_buffer_to_data (outbuffer, data1, sizeof (data1)); + gst_buffer_unref (outbuffer); + + gst_harness_teardown (h); +} + +GST_START_TEST (test_block_group_v1) +{ + guint8 data0_v1[] = { 0xa0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xa1, 0x85, 0x81, 0x00, 0x01, 0x00 }; - guint8 data1[] = { 0x42 }; - matroskamux = setup_matroskamux (&srcac3template); + test_block_group_with_version (1, data0_v1, sizeof (data0_v1)); +} - caps = gst_caps_from_string (AC3_CAPS_STRING); - gst_check_setup_events (mysrcpad, matroskamux, caps, GST_FORMAT_TIME); - gst_caps_unref (caps); +GST_END_TEST; - /* Generate the header */ - inbuffer = gst_buffer_new_allocate (NULL, 1, 0); - GST_BUFFER_TIMESTAMP (inbuffer) = 0; - ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); +GST_START_TEST (test_block_group_v2) +{ + guint8 data0_v2[] = { 0xa3, 0x85, 0x81, 0x00, 0x01, 0x00 }; - fail_unless_equals_int (gst_pad_push (mysrcpad, inbuffer), GST_FLOW_OK); - num_buffers = g_list_length (buffers); - - for (i = 0; i < num_buffers; ++i) { - outbuffer = GST_BUFFER (buffers->data); - fail_if (outbuffer == NULL); - buffers = g_list_remove (buffers, outbuffer); - - ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1); - gst_buffer_unref (outbuffer); - outbuffer = NULL; - } - - g_list_free (buffers); - buffers = NULL; - - /* Now push a buffer */ - indata = g_malloc (1); - inbuffer = gst_buffer_new_wrapped (indata, 1); - indata[0] = 0x42; - GST_BUFFER_TIMESTAMP (inbuffer) = 1000000; - ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); - - fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK); - num_buffers = g_list_length (buffers); - fail_unless (num_buffers >= 2); - - 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: - check_buffer_data (outbuffer, data0, sizeof (data0)); - break; - case 1: - check_buffer_data (outbuffer, data1, sizeof (data1)); - break; - default: - break; - } - - ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1); - gst_buffer_unref (outbuffer); - outbuffer = NULL; - } - - g_list_free (buffers); - buffers = NULL; - - cleanup_matroskamux (matroskamux); + test_block_group_with_version (2, data0_v2, sizeof (data0_v2)); } GST_END_TEST; GST_START_TEST (test_reset) { - GstElement *matroskamux; + GstHarness *h; GstBuffer *inbuffer; GstBuffer *outbuffer; - int num_buffers; - int i; - GstCaps *caps; - matroskamux = setup_matroskamux (&srcac3template); + h = setup_matroskamux_harness (AC3_CAPS_STRING); - caps = gst_caps_from_string (srcac3template.static_caps.string); - gst_check_setup_events (mysrcpad, matroskamux, caps, GST_FORMAT_TIME); - gst_caps_unref (caps); + inbuffer = gst_harness_create_buffer (h, 1); + GST_BUFFER_TIMESTAMP (inbuffer) = 0; + fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (h, inbuffer)); + fail_unless_equals_int (5, gst_harness_buffers_received (h)); - inbuffer = gst_buffer_new_allocate (NULL, 1, 0); - ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); - fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK); - num_buffers = g_list_length (buffers); - fail_unless (num_buffers >= 1, - "expected at least 1 buffer, but got only %d", num_buffers); - - fail_unless (gst_element_set_state (matroskamux, - GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null"); - - fail_unless (gst_element_set_state (matroskamux, - GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, - "could not set to playing"); - - inbuffer = gst_buffer_new_allocate (NULL, 1, 0); - ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); - fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK); - num_buffers = g_list_length (buffers); - fail_unless (num_buffers >= 2, - "expected at least 2 buffers, but got only %d", num_buffers); - - for (i = 0; i < num_buffers; ++i) { - outbuffer = GST_BUFFER (buffers->data); - fail_if (outbuffer == NULL); - buffers = g_list_remove (buffers, outbuffer); - - ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1); + outbuffer = gst_harness_pull (h); + fail_unless (outbuffer != NULL); + while (outbuffer != NULL) { gst_buffer_unref (outbuffer); + outbuffer = gst_harness_try_pull (h); } - cleanup_matroskamux (matroskamux); - g_list_free (buffers); - buffers = NULL; + fail_unless_equals_int (GST_STATE_CHANGE_SUCCESS, + gst_element_set_state (h->element, GST_STATE_NULL)); + + gst_harness_play (h); + + inbuffer = gst_harness_create_buffer (h, 1); + GST_BUFFER_TIMESTAMP (inbuffer) = 0; + fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (h, inbuffer)); + + outbuffer = gst_harness_pull (h); + fail_unless (outbuffer != NULL); + while (outbuffer != NULL) { + gst_buffer_unref (outbuffer); + outbuffer = gst_harness_try_pull (h); + } + + gst_harness_teardown (h); } GST_END_TEST; GST_START_TEST (test_link_webmmux_webm_sink) { - static GstStaticPadTemplate webm_sinktemplate = - GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("video/webm; audio/webm")); - GstElement *mux; + GstHarness *h; - mux = gst_check_setup_element ("webmmux"); - mysinkpad = setup_sink_pad (mux, &webm_sinktemplate); - fail_unless (mysinkpad != NULL); + h = gst_harness_new_with_padnames ("webmmux", "audio_%u", "src"); + fail_unless (h != NULL); - fail_unless (gst_element_set_state (mux, - GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, - "could not set to playing"); + gst_harness_set_sink_caps_str (h, "video/webm; audio/webm"); - gst_element_set_state (mux, GST_STATE_NULL); + gst_harness_play (h); - teardown_sink_pad (mux); - gst_check_teardown_element (mux); + fail_unless_equals_int (GST_STATE_CHANGE_SUCCESS, + gst_element_set_state (h->element, GST_STATE_NULL)); + + gst_harness_teardown (h); +} + +GST_END_TEST; + +static gint64 timecodescales[] = { + GST_USECOND, + GST_MSECOND, + GST_MSECOND * 10, + GST_MSECOND * 100, + GST_MSECOND * 400, + /* FAILS: ? GST_MSECOND * 500, a bug? */ +}; + +GST_START_TEST (test_timecodescale) +{ + GstBuffer *inbuffer, *outbuffer; + guint8 data_h0[] = { + 0xa3, 0x85, 0x81, 0x00, 0x00, 0x00, + }; + guint8 data_h1[] = { + 0xa3, 0x85, 0x81, 0x00, 0x01, 0x00, + }; + + GstHarness *h = setup_matroskamux_harness (AC3_CAPS_STRING); + gint64 timecodescale = timecodescales[__i__]; + + g_object_set (h->element, "timecodescale", timecodescale, NULL); + g_object_set (h->element, "version", 2, NULL); + + /* Buffer 0 */ + inbuffer = gst_harness_create_buffer (h, 1); + GST_BUFFER_TIMESTAMP (inbuffer) = 0; + fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (h, inbuffer)); + + /* pull out headers */ + gst_buffer_unref (gst_harness_pull (h)); + gst_buffer_unref (gst_harness_pull (h)); + gst_buffer_unref (gst_harness_pull (h)); + + /* verify header and drop the data */ + outbuffer = gst_harness_pull (h); + compare_buffer_to_data (outbuffer, data_h0, sizeof (data_h0)); + gst_buffer_unref (outbuffer); + gst_buffer_unref (gst_harness_pull (h)); + + /* Buffer 1 */ + inbuffer = gst_harness_create_buffer (h, 1); + GST_BUFFER_TIMESTAMP (inbuffer) = timecodescale; + fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (h, inbuffer)); + + /* verify header and drop the data */ + outbuffer = gst_harness_pull (h); + compare_buffer_to_data (outbuffer, data_h1, sizeof (data_h1)); + gst_buffer_unref (outbuffer); + gst_buffer_unref (gst_harness_pull (h)); } GST_END_TEST; @@ -644,21 +517,21 @@ check_chapter (GstTocEntry * toc_entry, GstTocEntry * internal_toc_entry, GstTagList *tags; gchar *title; - guint8 chapter_atom[1] = { 0xb6 }; - guint8 chapter_uid[2] = { 0x73, 0xc4 }; - guint8 chapter_str_uid[2] = { 0x56, 0x54 }; - guint8 chapter_start[1] = { 0x91 }; - guint8 chapter_end[1] = { 0x92 }; - guint8 chapter_flag_hidden[1] = { 0x98 }; - guint8 chapter_flag_enabled[2] = { 0x45, 0x98 }; - guint8 chapter_segment_uid[2] = { 0x6e, 0x67 }; - guint8 chapter_segment_edition_uid[2] = { 0x6e, 0xbc }; - guint8 chapter_physical_equiv[2] = { 0x63, 0xc3 }; - guint8 chapter_track[1] = { 0x8f }; - guint8 chapter_track_nb[1] = { 0x89 }; - guint8 chapter_display[1] = { 0x80 }; - guint8 chapter_string[1] = { 0x85 }; - guint8 chapter_language[2] = { 0x43, 0x7c }; + guint8 chapter_atom[] = { 0xb6 }; + guint8 chapter_uid[] = { 0x73, 0xc4 }; + guint8 chapter_str_uid[] = { 0x56, 0x54 }; + guint8 chapter_start[] = { 0x91 }; + guint8 chapter_end[] = { 0x92 }; + guint8 chapter_flag_hidden[] = { 0x98 }; + guint8 chapter_flag_enabled[] = { 0x45, 0x98 }; + guint8 chapter_segment_uid[] = { 0x6e, 0x67 }; + guint8 chapter_segment_edition_uid[] = { 0x6e, 0xbc }; + guint8 chapter_physical_equiv[] = { 0x63, 0xc3 }; + guint8 chapter_track[] = { 0x8f }; + guint8 chapter_track_nb[] = { 0x89 }; + guint8 chapter_display[] = { 0x80 }; + guint8 chapter_string[] = { 0x85 }; + guint8 chapter_language[] = { 0x43, 0x7c }; fail_unless (check_id (info, index, chapter_atom, sizeof (chapter_atom), &len)); @@ -677,12 +550,12 @@ check_chapter (GstTocEntry * toc_entry, GstTocEntry * internal_toc_entry, fail_unless (check_id_read_int (info, index, chapter_start, sizeof (chapter_start), &value)); - fail_unless ((gint64) value == start_ref); + fail_unless_equals_int (start_ref, value); /* optional chapter end */ if (check_id_read_int (info, index, chapter_end, sizeof (chapter_end), &value)) { - fail_unless ((gint64) value == end_ref); + fail_unless_equals_int (end_ref, value); } fail_unless (check_id_read_int (info, index, chapter_flag_hidden, @@ -755,11 +628,11 @@ check_toc (GstToc * ref_toc, GstToc * internal_toc, GList *cur_entry, *cur_chapter; GstTocEntry *internal_edition; - guint8 edition_entry[2] = { 0x45, 0xb9 }; - guint8 edition_uid[2] = { 0x45, 0xbc }; - guint8 edition_flag_hidden[2] = { 0x45, 0xbd }; - guint8 edition_flag_default[2] = { 0x45, 0xdb }; - guint8 edition_flag_ordered[2] = { 0x45, 0xdd }; + guint8 edition_entry[] = { 0x45, 0xb9 }; + guint8 edition_uid[] = { 0x45, 0xbc }; + guint8 edition_flag_hidden[] = { 0x45, 0xbd }; + guint8 edition_flag_default[] = { 0x45, 0xdb }; + guint8 edition_flag_ordered[] = { 0x45, 0xdd }; /* edition entry */ fail_unless (check_id (info, index, edition_entry, @@ -880,16 +753,16 @@ check_tags (GstToc * ref_toc, GstToc * internal_toc, guint64 len, value, uid; gsize last_offset, next_tag; gchar *tag_name_str, *tag_string_str; - guint8 tags[4] = { 0x12, 0x54, 0xc3, 0x67 }; - guint8 tag[2] = { 0x73, 0x73 }; - guint8 tag_targets[2] = { 0x63, 0xc0 }; - guint8 tag_target_type_value[2] = { 0x68, 0xca }; - guint8 tag_target_type[2] = { 0x63, 0xca }; - guint8 tag_edition_uid[2] = { 0x63, 0xc9 }; - guint8 tag_chapter_uid[2] = { 0x63, 0xc4 }; - guint8 simple_tag[2] = { 0x67, 0xc8 }; - guint8 tag_name[2] = { 0x45, 0xa3 }; - guint8 tag_string[2] = { 0x44, 0x87 }; + guint8 tags[] = { 0x12, 0x54, 0xc3, 0x67 }; + guint8 tag[] = { 0x73, 0x73 }; + guint8 tag_targets[] = { 0x63, 0xc0 }; + guint8 tag_target_type_value[] = { 0x68, 0xca }; + guint8 tag_target_type[] = { 0x63, 0xca }; + guint8 tag_edition_uid[] = { 0x63, 0xc9 }; + guint8 tag_chapter_uid[] = { 0x63, 0xc4 }; + guint8 simple_tag[] = { 0x67, 0xc8 }; + guint8 tag_name[] = { 0x45, 0xa3 }; + guint8 tag_string[] = { 0x44, 0x87 }; if (info->size > *index + sizeof (tags)) { for (; *index < info->size - sizeof (tags); ++(*index)) { @@ -958,15 +831,15 @@ static void check_segment (GstToc * ref_toc, GstToc * internal_toc, GstMapInfo * info, gsize * index) { - guint8 matroska_segment[4] = { 0x18, 0x53, 0x80, 0x67 }; - guint8 matroska_seek_id_chapters[7] = { 0x53, 0xab, 0x84, + guint8 matroska_segment[] = { 0x18, 0x53, 0x80, 0x67 }; + guint8 matroska_seek_id_chapters[] = { 0x53, 0xab, 0x84, 0x10, 0x43, 0xA7, 0x70 }; - guint8 matroska_seek_id_tags[7] = { 0x53, 0xab, 0x84, + guint8 matroska_seek_id_tags[] = { 0x53, 0xab, 0x84, 0x12, 0x54, 0xc3, 0x67 }; - guint8 matroska_seek_pos[2] = { 0x53, 0xac }; - guint8 matroska_chapters[4] = { 0x10, 0x43, 0xA7, 0x70 }; + guint8 matroska_seek_pos[] = { 0x53, 0xac }; + guint8 matroska_chapters[] = { 0x10, 0x43, 0xA7, 0x70 }; guint64 len, value, segment_offset, chapters_offset, tags_offset; gboolean found_chapters_declaration = FALSE, found_tags_declaration = FALSE; @@ -1028,23 +901,22 @@ check_segment (GstToc * ref_toc, GstToc * internal_toc, static void test_toc (gboolean with_edition) { - GstElement *matroskamux; + GstHarness *h; GstBuffer *inbuffer, *outbuffer, *merged_buffer; GstMapInfo info; - GstCaps *caps; - int num_buffers, i; guint64 len; gsize index; GstTocSetter *toc_setter; GstToc *test_toc, *ref_toc, *internal_toc; - guint8 ebml_header[4] = { 0x1a, 0x45, 0xdf, 0xa3 }; + guint8 ebml_header[] = { 0x1a, 0x45, 0xdf, 0xa3 }; - matroskamux = setup_matroskamux (&srcac3template); - downstream_is_seekable = TRUE; - gst_pad_set_query_function (mysinkpad, matroskamux_sinkpad_query); + h = setup_matroskamux_harness (AC3_CAPS_STRING); - toc_setter = GST_TOC_SETTER (matroskamux); + /* Make element seekable */ + gst_pad_set_query_function (h->sinkpad, seekable_sinkpad_query); + + toc_setter = GST_TOC_SETTER (h->element); fail_unless (toc_setter != NULL); if (with_edition) { @@ -1055,28 +927,21 @@ test_toc (gboolean with_edition) gst_toc_setter_set_toc (toc_setter, test_toc); gst_toc_unref (test_toc); - caps = gst_caps_from_string (srcac3template.static_caps.string); - gst_check_setup_events (mysrcpad, matroskamux, caps, GST_FORMAT_TIME); - gst_caps_unref (caps); - - inbuffer = gst_buffer_new_and_alloc (1); + inbuffer = gst_harness_create_buffer (h, 1); gst_buffer_memset (inbuffer, 0, 0, 1); GST_BUFFER_TIMESTAMP (inbuffer) = 0; GST_BUFFER_DURATION (inbuffer) = 1 * GST_MSECOND; - ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); - fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK); + fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (h, inbuffer)); /* send eos to ensure everything is written */ - fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ())); + fail_unless (gst_harness_push_event (h, gst_event_new_eos ())); + + outbuffer = gst_harness_pull (h); + fail_unless (outbuffer != NULL); /* Merge buffers */ - num_buffers = g_list_length (buffers); merged_buffer = gst_buffer_new (); - for (i = 0; i < num_buffers; ++i) { - outbuffer = GST_BUFFER (buffers->data); - fail_if (outbuffer == NULL); - buffers = g_list_remove (buffers, outbuffer); - + while (outbuffer != NULL) { if (outbuffer->offset == gst_buffer_get_size (merged_buffer)) { gst_buffer_append_memory (merged_buffer, gst_buffer_get_all_memory (outbuffer)); @@ -1086,9 +951,8 @@ test_toc (gboolean with_edition) gst_buffer_unmap (outbuffer, &info); } - ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1); gst_buffer_unref (outbuffer); - outbuffer = NULL; + outbuffer = gst_harness_try_pull (h); } fail_unless (gst_buffer_map (merged_buffer, &info, GST_MAP_READ)); @@ -1106,10 +970,7 @@ test_toc (gboolean with_edition) gst_toc_unref (ref_toc); gst_buffer_unmap (merged_buffer, &info); - - cleanup_matroskamux (matroskamux); - g_list_free (buffers); - buffers = NULL; + gst_harness_teardown (h); } GST_START_TEST (test_toc_with_edition) @@ -1133,11 +994,17 @@ matroskamux_suite (void) TCase *tc_chain = tcase_create ("general"); suite_add_tcase (s, tc_chain); - tcase_add_test (tc_chain, test_ebml_header); + tcase_add_test (tc_chain, test_ebml_header_v1); + tcase_add_test (tc_chain, test_ebml_header_v2); tcase_add_test (tc_chain, test_vorbis_header); - tcase_add_test (tc_chain, test_block_group); + tcase_add_test (tc_chain, test_block_group_v1); + tcase_add_test (tc_chain, test_block_group_v2); + tcase_add_test (tc_chain, test_reset); tcase_add_test (tc_chain, test_link_webmmux_webm_sink); + tcase_add_loop_test (tc_chain, test_timecodescale, + 0, G_N_ELEMENTS (timecodescales)); + tcase_add_test (tc_chain, test_toc_with_edition); tcase_add_test (tc_chain, test_toc_without_edition); return s;