| /* |
| * cmmldec.c - GStreamer CMML decoder test suite |
| * Copyright (C) 2005 Alessandro Decina |
| * |
| * Authors: |
| * Alessandro Decina <alessandro@nnva.org> |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Library General Public |
| * License as published by the Free Software Foundation; either |
| * version 2 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Library General Public License for more details. |
| * |
| * You should have received a copy of the GNU Library General Public |
| * License along with this library; if not, write to the |
| * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
| * Boston, MA 02111-1307, USA. |
| */ |
| |
| /* FIXME 0.11: suppress warnings for deprecated API such as GValueArray |
| * with newer GLib versions (>= 2.31.0) */ |
| #define GLIB_DISABLE_DEPRECATION_WARNINGS |
| |
| #include <gst/check/gstcheck.h> |
| #include <gst/tag/tag.h> |
| |
| #define SINK_CAPS "text/x-cmml" |
| #define SRC_CAPS "text/x-cmml, encoded=(boolean)TRUE" |
| |
| #define IDENT_HEADER \ |
| "CMML\x00\x00\x00\x00"\ |
| "\x03\x00\x00\x00"\ |
| "\xe8\x03\x00\x00\x00\x00\x00\x00"\ |
| "\x01\x00\x00\x00\x00\x00\x00\x00"\ |
| "\x20" |
| #define IDENT_HEADER_SIZE 29 |
| |
| #define PREAMBLE_NO_PI \ |
| "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n"\ |
| "<!DOCTYPE cmml SYSTEM \"cmml.dtd\">\n" |
| #define PREAMBLE PREAMBLE_NO_PI "<?cmml?>" |
| #define PREAMBLE_DECODED PREAMBLE_NO_PI "<cmml >" |
| |
| #define HEAD_TAG \ |
| "<head>"\ |
| "<title>The Research Hunter</title>"\ |
| "<meta name=\"DC.audience\" content=\"General\"/>"\ |
| "<meta name=\"DC.author\" content=\"CSIRO Publishing\"/>"\ |
| "<meta name=\"DC.format\" content=\"video\"/>"\ |
| "<meta name=\"DC.language\" content=\"English\"/>"\ |
| "<meta name=\"DC.publisher\" content=\"CSIRO Australia\"/>"\ |
| "</head>" |
| |
| #define HEAD_TAG_DECODED HEAD_TAG |
| |
| #define CLIP_TEMPLATE \ |
| "<clip id=\"%s\" track=\"%s\">"\ |
| "<a href=\"http://www.csiro.au/\">http://www.csiro.au</a>"\ |
| "<img src=\"images/index1.jpg\"/>"\ |
| "<desc>Welcome to CSIRO</desc>"\ |
| "<meta name=\"test\" content=\"test content\"/>"\ |
| "</clip>" |
| |
| #define CLIP_TEMPLATE_DECODED \ |
| "<clip id=\"%s\" track=\"%s\" start=\"%s\">"\ |
| "<a href=\"http://www.csiro.au/\">http://www.csiro.au</a>"\ |
| "<img src=\"images/index1.jpg\"/>"\ |
| "<desc>Welcome to CSIRO</desc>"\ |
| "<meta name=\"test\" content=\"test content\"/>"\ |
| "</clip>" |
| |
| #define EMPTY_CLIP_TEMPLATE \ |
| "<clip id=\"%s\" track=\"%s\" />" |
| |
| #define END_TAG \ |
| "</cmml>" |
| |
| #define fail_unless_equals_flow_return(a, b) \ |
| G_STMT_START { \ |
| gchar *a_up = g_ascii_strup (gst_flow_get_name (a), -1); \ |
| gchar *b_up = g_ascii_strup (gst_flow_get_name (b), -1); \ |
| fail_unless (a == b, \ |
| "'" #a "' (GST_FLOW_%s) is not equal to '" #b "' (GST_FLOW_%s)", \ |
| a_up, b_up); \ |
| g_free (a_up); \ |
| g_free (b_up); \ |
| } G_STMT_END; |
| |
| static GstElement *cmmldec; |
| |
| static GstBus *bus; |
| |
| static GstFlowReturn flow; |
| |
| static GList *current_buf; |
| |
| static gint64 granulerate; |
| |
| static guint8 granuleshift; |
| |
| static GstPad *srcpad, *sinkpad; |
| |
| static GList *events; |
| |
| static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", |
| GST_PAD_SINK, |
| GST_PAD_ALWAYS, |
| GST_STATIC_CAPS (SINK_CAPS) |
| ); |
| |
| static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src", |
| GST_PAD_SRC, |
| GST_PAD_ALWAYS, |
| GST_STATIC_CAPS (SRC_CAPS) |
| ); |
| |
| static GstBuffer * |
| buffer_new (const gchar * buffer_data, guint size) |
| { |
| GstBuffer *buffer; |
| guint8 *data; |
| |
| data = g_malloc (size); |
| memcpy (data, buffer_data, size); |
| |
| if (data) |
| buffer = gst_buffer_new_wrapped (data, size); |
| else |
| buffer = gst_buffer_new (); |
| |
| return buffer; |
| } |
| |
| static void |
| buffer_unref (void *buffer, void *user_data) |
| { |
| ASSERT_OBJECT_REFCOUNT (buffer, "buf", 1); |
| gst_buffer_unref (GST_BUFFER (buffer)); |
| } |
| |
| static void |
| event_unref (void *event, void *user_data) |
| { |
| ASSERT_OBJECT_REFCOUNT (event, "event", 1); |
| gst_event_unref (GST_EVENT (event)); |
| } |
| |
| static gboolean |
| cmmldec_sink_event (GstPad * pad, GstObject * parent, GstEvent * event) |
| { |
| GST_LOG ("received event %" GST_PTR_FORMAT, event); |
| |
| switch (GST_EVENT_TYPE (event)) { |
| case GST_EVENT_TAG: |
| events = g_list_append (events, event); |
| break; |
| default: |
| gst_event_unref (event); |
| break; |
| } |
| |
| return TRUE; |
| } |
| |
| static void |
| setup_cmmldec (void) |
| { |
| GST_DEBUG ("setup_cmmldec"); |
| cmmldec = gst_check_setup_element ("cmmldec"); |
| srcpad = gst_check_setup_src_pad (cmmldec, &srctemplate); |
| sinkpad = gst_check_setup_sink_pad (cmmldec, &sinktemplate); |
| gst_pad_set_event_function (sinkpad, cmmldec_sink_event); |
| gst_pad_set_active (srcpad, TRUE); |
| gst_pad_set_active (sinkpad, TRUE); |
| |
| bus = gst_bus_new (); |
| gst_element_set_bus (cmmldec, bus); |
| |
| fail_unless (gst_element_set_state (cmmldec, |
| GST_STATE_PLAYING) != GST_STATE_CHANGE_FAILURE, |
| "could not set to playing"); |
| |
| granulerate = GST_SECOND / 1000; |
| granuleshift = 32; |
| buffers = NULL; |
| } |
| |
| static void |
| teardown_cmmldec (void) |
| { |
| g_list_foreach (buffers, buffer_unref, NULL); |
| g_list_free (buffers); |
| buffers = NULL; |
| current_buf = NULL; |
| |
| gst_bus_set_flushing (bus, TRUE); |
| gst_object_unref (bus); |
| |
| GST_DEBUG ("teardown_cmmldec"); |
| gst_pad_set_active (srcpad, FALSE); |
| gst_pad_set_active (sinkpad, FALSE); |
| gst_check_teardown_src_pad (cmmldec); |
| gst_check_teardown_sink_pad (cmmldec); |
| gst_check_teardown_element (cmmldec); |
| |
| /* sticky stuff cleared above first */ |
| g_list_foreach (events, event_unref, NULL); |
| g_list_free (events); |
| events = NULL; |
| } |
| |
| static void |
| check_output_buffer_is_equal (const gchar * name, |
| const gchar * data, gint refcount) |
| { |
| GstBuffer *buffer; |
| GstMapInfo map; |
| |
| if (current_buf == NULL) |
| current_buf = buffers; |
| else |
| current_buf = g_list_next (current_buf); |
| |
| fail_unless (current_buf != NULL); |
| |
| buffer = GST_BUFFER (current_buf->data); |
| gst_buffer_map (buffer, &map, GST_MAP_READ); |
| |
| ASSERT_OBJECT_REFCOUNT (buffer, name, refcount); |
| fail_unless (memcmp (map.data, data, map.size) == 0, |
| "'%s' (%s) is not equal to (%s)", name, map.data, data); |
| |
| gst_buffer_unmap (buffer, &map); |
| } |
| |
| static GstFlowReturn |
| push_data (const gchar * name, const gchar * data, gint size, gint64 granulepos) |
| { |
| GstBuffer *buffer; |
| |
| buffer = buffer_new (data, size); |
| GST_BUFFER_OFFSET_END (buffer) = granulepos; |
| return gst_pad_push (srcpad, buffer); |
| } |
| |
| static void |
| push_caps (void) |
| { |
| GstCaps *caps; |
| |
| caps = gst_caps_from_string (SRC_CAPS); |
| fail_unless (gst_pad_set_caps (srcpad, caps)); |
| gst_caps_unref (caps); |
| } |
| |
| static GObject * |
| cmml_tag_message_pop (GstBus * bus, const gchar * tag) |
| { |
| GstTagList *taglist; |
| const GValue *value; |
| GObject *obj = NULL; |
| GstEvent *event; |
| |
| if (!events) |
| return NULL; |
| |
| event = (GstEvent *) events->data; |
| events = g_list_delete_link (events, events); |
| gst_event_parse_tag (event, &taglist); |
| |
| value = gst_tag_list_get_value_index (taglist, tag, 0); |
| if (value == NULL) |
| goto exit; |
| |
| obj = g_value_dup_object (value); |
| |
| exit: |
| gst_event_unref (event); |
| |
| return obj; |
| } |
| |
| static void |
| check_headers (void) |
| { |
| GObject *head_tag; |
| |
| gchar *title, *base; |
| |
| GValueArray *meta; |
| |
| push_caps (); |
| |
| /* push the ident header */ |
| flow = push_data ("ident-header", IDENT_HEADER, IDENT_HEADER_SIZE, 0); |
| fail_unless_equals_flow_return (flow, GST_FLOW_OK); |
| |
| /* push the cmml preamble */ |
| flow = push_data ("preamble", PREAMBLE, strlen (PREAMBLE), 0); |
| fail_unless_equals_flow_return (flow, GST_FLOW_OK); |
| |
| /* push the head tag */ |
| flow = push_data ("head", HEAD_TAG, strlen (HEAD_TAG), 0); |
| fail_unless_equals_flow_return (flow, GST_FLOW_OK); |
| |
| fail_unless_equals_int (g_list_length (buffers), 2); |
| |
| /* check the decoded preamble */ |
| check_output_buffer_is_equal ("cmml-preamble-buffer", PREAMBLE_DECODED, 1); |
| |
| /* check the decoded head tag */ |
| check_output_buffer_is_equal ("head-tag-buffer", HEAD_TAG_DECODED, 1); |
| |
| /* check the GstCmmlTagHead tag object */ |
| head_tag = cmml_tag_message_pop (bus, GST_TAG_CMML_HEAD); |
| fail_unless (head_tag != NULL); |
| g_object_get (head_tag, |
| "title", &title, "base-uri", &base, "meta", &meta, NULL); |
| fail_unless_equals_string ("The Research Hunter", title); |
| fail_unless (base == NULL); |
| fail_unless (meta != NULL); |
| fail_unless_equals_int (meta->n_values, 10); |
| |
| g_free (title); |
| g_free (base); |
| g_value_array_free (meta); |
| g_object_unref (head_tag); |
| } |
| |
| static GstFlowReturn |
| push_clip_full (const gchar * name, const gchar * track, const gchar * template, |
| GstClockTime prev, GstClockTime start) |
| { |
| gchar *clip; |
| |
| gint64 keyindex, keyoffset, granulepos; |
| |
| GstFlowReturn res; |
| |
| if (track == NULL) |
| track = "default"; |
| |
| if (prev == GST_CLOCK_TIME_NONE) |
| prev = 0; |
| |
| keyindex = prev / granulerate << granuleshift; |
| keyoffset = (start - prev) / granulerate; |
| granulepos = keyindex + keyoffset; |
| |
| clip = g_strdup_printf (template, name, track); |
| res = push_data (name, clip, strlen (clip), granulepos); |
| g_free (clip); |
| |
| return res; |
| } |
| |
| static GstFlowReturn |
| push_clip (const gchar * name, const gchar * track, |
| GstClockTime prev, GstClockTime start) |
| { |
| return push_clip_full (name, track, CLIP_TEMPLATE, prev, start); |
| } |
| |
| static GstFlowReturn |
| push_empty_clip (const gchar * name, const gchar * track, GstClockTime start) |
| { |
| return push_clip_full (name, track, |
| EMPTY_CLIP_TEMPLATE, GST_CLOCK_TIME_NONE, start); |
| } |
| |
| |
| static void |
| check_output_clip (const gchar * name, const gchar * track, |
| const gchar * start, const gchar * end) |
| { |
| gchar *decoded_clip; |
| |
| if (track == NULL) |
| track = "default"; |
| |
| decoded_clip = g_strdup_printf (CLIP_TEMPLATE_DECODED, name, track, start); |
| check_output_buffer_is_equal (name, decoded_clip, 1); |
| g_free (decoded_clip); |
| } |
| |
| GST_START_TEST (test_dec) |
| { |
| GstClockTime clip1_start = 1 * GST_SECOND + 234 * GST_MSECOND; |
| |
| GstClockTime clip2_start = clip1_start; |
| |
| GstClockTime clip3_start = |
| ((100 * 3600) + (59 * 60) + 59) * GST_SECOND + 678 * GST_MSECOND; |
| |
| check_headers (); |
| |
| flow = push_clip ("clip-1", "default", GST_CLOCK_TIME_NONE, clip1_start); |
| fail_unless_equals_flow_return (flow, GST_FLOW_OK); |
| |
| flow = push_clip ("clip-2", "othertrack", GST_CLOCK_TIME_NONE, clip2_start); |
| fail_unless_equals_flow_return (flow, GST_FLOW_OK); |
| |
| flow = push_clip ("clip-3", "default", clip1_start, clip3_start); |
| fail_unless_equals_flow_return (flow, GST_FLOW_OK); |
| |
| /* send EOS to flush clip-2 and clip-3 */ |
| gst_pad_send_event (GST_PAD_PEER (srcpad), gst_event_new_eos ()); |
| |
| check_output_clip ("clip-1", "default", "0:00:01.234", NULL); |
| check_output_clip ("clip-2", "othertrack", "0:00:01.234", NULL); |
| check_output_clip ("clip-3", "default", "100:59:59.678", NULL); |
| check_output_buffer_is_equal ("cmml-end-tag", END_TAG, 1); |
| } |
| |
| GST_END_TEST; |
| |
| GST_START_TEST (test_preamble_no_pi) |
| { |
| push_caps (); |
| |
| flow = push_data ("ident-header", IDENT_HEADER, IDENT_HEADER_SIZE, 0); |
| fail_unless_equals_flow_return (flow, GST_FLOW_OK); |
| fail_unless_equals_int (g_list_length (buffers), 0); |
| |
| flow = push_data ("preamble-no-pi", |
| PREAMBLE_NO_PI, strlen (PREAMBLE_NO_PI), 0); |
| fail_unless_equals_flow_return (flow, GST_FLOW_OK); |
| fail_unless_equals_int (g_list_length (buffers), 1); |
| |
| check_output_buffer_is_equal ("cmml-preamble-buffer", |
| PREAMBLE_NO_PI "<cmml>", 1); |
| } |
| |
| GST_END_TEST; |
| |
| GST_START_TEST (test_tags) |
| { |
| GObject *tag; |
| |
| gboolean empty; |
| |
| gchar *id, *track; |
| |
| gint64 start_time, end_time; |
| |
| gchar *anchor_href, *anchor_text; |
| |
| gchar *img_src, *img_alt; |
| |
| gchar *desc; |
| |
| GValueArray *meta; |
| |
| GstClockTime clip1_start; |
| |
| check_headers (); |
| |
| clip1_start = 1 * GST_SECOND + 234 * GST_MSECOND; |
| flow = push_clip ("clip-1", "default", 0, clip1_start); |
| fail_unless_equals_flow_return (flow, GST_FLOW_OK); |
| |
| tag = cmml_tag_message_pop (bus, GST_TAG_CMML_CLIP); |
| fail_unless (tag != NULL); |
| |
| g_object_get (tag, "id", &id, "empty", &empty, "track", &track, |
| "start-time", &start_time, "end-time", &end_time, |
| "anchor-uri", &anchor_href, "anchor-text", &anchor_text, |
| "img-uri", &img_src, "img-alt", &img_alt, |
| "description", &desc, "meta", &meta, NULL); |
| |
| fail_unless (empty == FALSE); |
| fail_unless_equals_string (id, "clip-1"); |
| fail_unless_equals_string (track, "default"); |
| fail_unless_equals_int (start_time, 1 * GST_SECOND + 234 * GST_MSECOND); |
| fail_unless_equals_uint64 (end_time, GST_CLOCK_TIME_NONE); |
| fail_unless_equals_string (anchor_href, "http://www.csiro.au/"); |
| fail_unless_equals_string (anchor_text, "http://www.csiro.au"); |
| fail_unless_equals_string (img_src, "images/index1.jpg"); |
| fail_unless (img_alt == NULL); |
| fail_unless_equals_string (desc, "Welcome to CSIRO"); |
| fail_unless (meta != NULL); |
| fail_unless_equals_int (meta->n_values, 2); |
| |
| g_free (id); |
| g_free (track); |
| g_free (anchor_href); |
| g_free (anchor_text); |
| g_free (img_src); |
| g_free (img_alt); |
| g_free (desc); |
| g_value_array_free (meta); |
| g_object_unref (tag); |
| } |
| |
| GST_END_TEST; |
| |
| GST_START_TEST (test_wait_clip_end) |
| { |
| GObject *tag; |
| |
| gchar *id; |
| |
| GstClockTime end_time = 0; |
| |
| GstClockTime clip1_start = 1 * GST_SECOND + 234 * GST_MSECOND; |
| |
| GstClockTime clip2_start = 2 * GST_SECOND + 234 * GST_MSECOND; |
| |
| GstClockTime clip3_start = 3 * GST_SECOND + 234 * GST_MSECOND; |
| |
| GstClockTime clip3_end = 4 * GST_SECOND + 234 * GST_MSECOND; |
| |
| GstClockTime clip4_start = 5 * GST_SECOND + 234 * GST_MSECOND; |
| |
| g_object_set (cmmldec, "wait-clip-end-time", TRUE, NULL); |
| |
| check_headers (); |
| |
| flow = push_clip ("clip-1", "default", 0, clip1_start); |
| fail_unless_equals_flow_return (flow, GST_FLOW_OK); |
| /* no tag has been posted yet */ |
| fail_unless (cmml_tag_message_pop (bus, GST_TAG_CMML_CLIP) == NULL); |
| |
| flow = push_clip ("clip-2", "default", clip1_start, clip2_start); |
| fail_unless_equals_flow_return (flow, GST_FLOW_OK); |
| |
| tag = cmml_tag_message_pop (bus, GST_TAG_CMML_CLIP); |
| fail_unless (tag != NULL); |
| g_object_get (tag, "id", &id, "end-time", &end_time, NULL); |
| /* clip-1 is posted when clip-2 is decoded. clip-1 ends when clip-2 starts */ |
| fail_unless_equals_string (id, "clip-1"); |
| fail_unless_equals_int (end_time, clip2_start); |
| g_free (id); |
| g_object_unref (tag); |
| |
| flow = push_clip ("clip-3", "default", clip2_start, clip3_start); |
| fail_unless_equals_flow_return (flow, GST_FLOW_OK); |
| |
| tag = cmml_tag_message_pop (bus, GST_TAG_CMML_CLIP); |
| fail_unless (tag != NULL); |
| g_object_get (tag, "id", &id, "end-time", &end_time, NULL); |
| /* clip-2 is posted when clip-3 is decoded. It ends when clip-3 starts */ |
| fail_unless_equals_string (id, "clip-2"); |
| fail_unless_equals_int (end_time, clip3_start); |
| g_free (id); |
| g_object_unref (tag); |
| |
| flow = push_empty_clip ("empty-clip", "default", clip3_end); |
| tag = cmml_tag_message_pop (bus, GST_TAG_CMML_CLIP); |
| fail_unless (tag != NULL); |
| g_object_get (tag, "id", &id, "end-time", &end_time, NULL); |
| /* clip-3 ends when empty-clip is decoded */ |
| fail_unless_equals_string (id, "clip-3"); |
| fail_unless_equals_int (end_time, clip3_end); |
| g_free (id); |
| g_object_unref (tag); |
| |
| flow = push_clip ("clip-4", "default", clip3_start, clip4_start); |
| fail_unless_equals_flow_return (flow, GST_FLOW_OK); |
| |
| /* an empty clip just marks the end of the previous one, so no tag is posted |
| * for empty-clip */ |
| fail_unless (cmml_tag_message_pop (bus, GST_TAG_CMML_CLIP) == NULL); |
| /* send EOS to flush clip-4 */ |
| gst_pad_send_event (GST_PAD_PEER (srcpad), gst_event_new_eos ()); |
| |
| tag = cmml_tag_message_pop (bus, GST_TAG_CMML_CLIP); |
| fail_unless (tag != NULL); |
| g_object_get (tag, "id", &id, NULL); |
| fail_unless_equals_string (id, "clip-4"); |
| g_free (id); |
| g_object_unref (tag); |
| } |
| |
| GST_END_TEST; |
| |
| GST_START_TEST (test_weird_input) |
| { |
| const gchar *bad_xml = "<?xml version=\"1.0\"?><a><b></a>"; |
| |
| push_caps (); |
| |
| /* malformed ident header */ |
| flow = push_data ("bad-ident-header", "CMML\0\0\0\0garbage", 15, 0); |
| fail_unless_equals_flow_return (flow, GST_FLOW_ERROR); |
| |
| /* push invalid xml */ |
| flow = push_data ("bad-xml", bad_xml, strlen (bad_xml), 0); |
| fail_unless_equals_flow_return (flow, GST_FLOW_ERROR); |
| |
| /* and now for something completely different: an empty buffer. This is valid |
| * as 'NIL' EOS pages are allowed */ |
| flow = push_data ("empty-eos", NULL, 0, 0); |
| fail_unless_equals_flow_return (flow, GST_FLOW_OK); |
| } |
| |
| GST_END_TEST; |
| |
| GST_START_TEST (test_sink_query_convert) |
| { |
| guint64 keyindex, keyoffset, granulepos; |
| |
| GstClockTime index_time, offset_time; |
| |
| GstFormat dstfmt = GST_FORMAT_TIME; |
| |
| gint64 dstval; |
| |
| /* send headers to set the granulerate */ |
| check_headers (); |
| |
| /* create a 1|1 granulepos */ |
| index_time = 1 * GST_SECOND; |
| offset_time = 1 * GST_SECOND; |
| |
| keyindex = (index_time / granulerate) << granuleshift; |
| keyoffset = offset_time / granulerate; |
| granulepos = keyindex + keyoffset; |
| |
| fail_unless (gst_pad_query_convert (GST_PAD_PEER (srcpad), |
| GST_FORMAT_DEFAULT, granulepos, dstfmt, &dstval)); |
| |
| fail_unless (dstfmt == GST_FORMAT_TIME); |
| /* fail unless dstval == index + offset */ |
| fail_unless_equals_int (2 * GST_SECOND, dstval); |
| } |
| |
| GST_END_TEST; |
| |
| static Suite * |
| cmmldec_suite (void) |
| { |
| Suite *s = suite_create ("cmmldec"); |
| |
| TCase *tc_general = tcase_create ("general"); |
| |
| suite_add_tcase (s, tc_general); |
| tcase_add_checked_fixture (tc_general, setup_cmmldec, teardown_cmmldec); |
| tcase_add_test (tc_general, test_dec); |
| tcase_add_test (tc_general, test_tags); |
| tcase_add_test (tc_general, test_preamble_no_pi); |
| tcase_add_test (tc_general, test_wait_clip_end); |
| tcase_add_test (tc_general, test_sink_query_convert); |
| tcase_add_test (tc_general, test_weird_input); |
| |
| return s; |
| } |
| |
| GST_CHECK_MAIN (cmmldec); |