mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-30 05:31:15 +00:00
f3c126d07c
When doing a segment seek, the base offset in the new segment would be increased by segment.position which is basically the timestamp of the last packet. This does not include the duration of the last packet though, so might be slightly shorter than the actual duration of the clip or the requested segment. Increase the base offset by the segment duration instead when accumulating segments, which is more correct as it doesn't cut off the last frame and makes the effective loop segment duration consistent with the actual duration returned from a duration query. In case a segment stop was specified it's also possible that some data was sent beyond the stop that's necessary for decoding so the base offset increment should be based on that then and not on the timestamp of the last buffer pushed out. Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4604>
503 lines
18 KiB
C
503 lines
18 KiB
C
/* GStreamer unit test for matroskademux
|
|
* Copyright (C) 2015, 2023 Tim-Philipp Müller <tim@centricular.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., 51 Franklin St, Fifth Floor,
|
|
* Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#include <gst/check/gstcheck.h>
|
|
#include <gst/check/gstharness.h>
|
|
|
|
const gchar mkv_sub_base64[] =
|
|
"GkXfowEAAAAAAAAUQoKJbWF0cm9za2EAQoeBAkKFgQIYU4BnAQAAAAAAAg0RTZt0AQAAAAAAAIxN"
|
|
"uwEAAAAAAAASU6uEFUmpZlOsiAAAAAAAAACYTbsBAAAAAAAAElOrhBZUrmtTrIgAAAAAAAABEuya"
|
|
"AQAAAAAAABJTq4QQQ6dwU6yI///////////smgEAAAAAAAASU6uEHFO7a1OsiP//////////TbsB"
|
|
"AAAAAAAAElOrhBJUw2dTrIgAAAAAAAAB9xVJqWYBAAAAAAAAbnOkkDylQZJlrLziQo8+gsrZVtUq"
|
|
"17GDD0JARImIQNGUAAAAAABNgJ9HU3RyZWFtZXIgcGx1Z2luIHZlcnNpb24gMS40LjUAV0GZR1N0"
|
|
"cmVhbWVyIE1hdHJvc2thIG11eGVyAERhiAZfU0rcEwgAFlSuawEAAAAAAAA0rgEAAAAAAAAr14EB"
|
|
"g4ERc8WIoWF8pYlELidTbolTdWJ0aXRsZQCGjFNfVEVYVC9VVEY4AB9DtnUBAAAAAAAAmeeCA+ig"
|
|
"AQAAAAAAAA2bggfQoYeBAAAAZm9voAEAAAAAAAAUm4IH0KGOgQu4ADxpPmJhcjwvaT6gAQAAAAAA"
|
|
"AA2bggfQoYeBF3AAYmF6oAEAAAAAAAAOm4IH0KGIgScQAGbDtgCgAQAAAAAAABWbggfQoY+BMsgA"
|
|
"PGk+YmFyPC9pPgCgAQAAAAAAAA6bggfQoYiBPoAAYuR6ABJUw2cBAAAAAAAACnNzAQAAAAAAAAA=";
|
|
|
|
const gchar mkv_toc_base64[] =
|
|
"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";
|
|
|
|
static void
|
|
pad_added_cb (GstElement * matroskademux, GstPad * pad, gpointer user_data)
|
|
{
|
|
GstHarness *h = user_data;
|
|
|
|
GST_LOG_OBJECT (pad, "got new source pad");
|
|
gst_harness_add_element_src_pad (h, pad);
|
|
}
|
|
|
|
static void
|
|
pull_and_check_buffer (GstHarness * h, GstClockTime pts, GstClockTime duration,
|
|
const gchar * output)
|
|
{
|
|
GstMapInfo map;
|
|
GstBuffer *buf;
|
|
|
|
/* wait for buffer */
|
|
buf = gst_harness_pull (h);
|
|
|
|
/* Make sure there's no 0-terminator in there */
|
|
fail_unless (gst_buffer_map (buf, &map, GST_MAP_READ));
|
|
GST_MEMDUMP ("subtitle buffer", map.data, map.size);
|
|
fail_unless (map.size > 0);
|
|
fail_unless (map.data[map.size - 1] != '\0');
|
|
if (output != NULL && memcmp (map.data, output, map.size) != 0) {
|
|
g_printerr ("Got:\n");
|
|
gst_util_dump_mem (map.data, map.size);;
|
|
g_printerr ("Wanted:\n");
|
|
gst_util_dump_mem ((guint8 *) output, strlen (output));
|
|
g_error ("Did not get output expected.");
|
|
}
|
|
|
|
gst_buffer_unmap (buf, &map);
|
|
|
|
fail_unless_equals_int64 (pts, GST_BUFFER_PTS (buf));
|
|
fail_unless_equals_int64 (duration, GST_BUFFER_DURATION (buf));
|
|
|
|
gst_buffer_unref (buf);
|
|
}
|
|
|
|
GST_START_TEST (test_sub_terminator)
|
|
{
|
|
GstHarness *h;
|
|
GstBuffer *buf;
|
|
guchar *mkv_data;
|
|
gsize mkv_size;
|
|
|
|
h = gst_harness_new_with_padnames ("matroskademux", "sink", NULL);
|
|
|
|
g_signal_connect (h->element, "pad-added", G_CALLBACK (pad_added_cb), h);
|
|
|
|
mkv_data = g_base64_decode (mkv_sub_base64, &mkv_size);
|
|
fail_unless (mkv_data != NULL);
|
|
|
|
gst_harness_set_src_caps_str (h, "video/x-matroska");
|
|
|
|
buf = gst_buffer_new_wrapped (mkv_data, mkv_size);
|
|
GST_BUFFER_OFFSET (buf) = 0;
|
|
|
|
fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (h, buf));
|
|
gst_harness_push_event (h, gst_event_new_eos ());
|
|
|
|
pull_and_check_buffer (h, 1 * GST_SECOND, 2 * GST_SECOND, "foo");
|
|
pull_and_check_buffer (h, 4 * GST_SECOND, 2 * GST_SECOND, "<i>bar</i>");
|
|
pull_and_check_buffer (h, 7 * GST_SECOND, 2 * GST_SECOND, "baz");
|
|
pull_and_check_buffer (h, 11 * GST_SECOND, 2 * GST_SECOND, "f\303\266");
|
|
pull_and_check_buffer (h, 14 * GST_SECOND, 2 * GST_SECOND, "<i>bar</i>");
|
|
/* The input is invalid UTF-8 here, what happens might depend on locale */
|
|
pull_and_check_buffer (h, 17 * GST_SECOND, 2 * GST_SECOND, NULL);
|
|
|
|
fail_unless (gst_harness_try_pull (h) == NULL);
|
|
|
|
gst_harness_teardown (h);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
/* Recursively compare 2 toc entries */
|
|
static void
|
|
check_toc_entries (const GstTocEntry * original, const GstTocEntry * other)
|
|
{
|
|
gint64 start, stop, other_start, other_stop;
|
|
GstTocEntryType original_type, other_type;
|
|
const gchar *original_string_uid = NULL, *other_string_uid = NULL;
|
|
GstTagList *original_tags, *other_tags;
|
|
GList *cur, *other_cur;
|
|
|
|
original_type = gst_toc_entry_get_entry_type (original);
|
|
other_type = gst_toc_entry_get_entry_type (other);
|
|
fail_unless (original_type == other_type);
|
|
|
|
if (original_type != GST_TOC_ENTRY_TYPE_EDITION) {
|
|
original_string_uid = gst_toc_entry_get_uid (original);
|
|
other_string_uid = gst_toc_entry_get_uid (other);
|
|
fail_unless (g_strcmp0 (original_string_uid, other_string_uid) == 0);
|
|
}
|
|
|
|
if (original_type != GST_TOC_ENTRY_TYPE_EDITION) {
|
|
gst_toc_entry_get_start_stop_times (original, &start, &stop);
|
|
gst_toc_entry_get_start_stop_times (other, &other_start, &other_stop);
|
|
|
|
fail_unless (start == other_start && stop == other_stop);
|
|
}
|
|
|
|
/* tags */
|
|
original_tags = gst_toc_entry_get_tags (original);
|
|
other_tags = gst_toc_entry_get_tags (other);
|
|
fail_unless (gst_tag_list_is_equal (original_tags, other_tags));
|
|
|
|
other_cur = gst_toc_entry_get_sub_entries (other);
|
|
for (cur = gst_toc_entry_get_sub_entries (original); cur != NULL;
|
|
cur = cur->next) {
|
|
fail_unless (other_cur != NULL);
|
|
|
|
check_toc_entries (cur->data, other_cur->data);
|
|
|
|
other_cur = other_cur->next;
|
|
}
|
|
}
|
|
|
|
/* Create a new chapter */
|
|
static GstTocEntry *
|
|
new_chapter (const guint chapter_nb, const gint64 start, const gint64 stop)
|
|
{
|
|
GstTocEntry *toc_entry, *toc_sub_entry;
|
|
GstTagList *tags;
|
|
gchar title[32];
|
|
gchar artist[32];
|
|
gchar str_uid[32];
|
|
|
|
g_snprintf (str_uid, sizeof (str_uid), "uid.%d", chapter_nb);
|
|
toc_entry = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_CHAPTER, str_uid);
|
|
gst_toc_entry_set_start_stop_times (toc_entry, start, stop);
|
|
|
|
g_snprintf (title, sizeof (title), "chap.%d", chapter_nb);
|
|
g_snprintf (artist, sizeof (artist), "art.%d", chapter_nb);
|
|
tags = gst_tag_list_new (GST_TAG_TITLE, title, GST_TAG_ARTIST, artist, NULL);
|
|
gst_toc_entry_set_tags (toc_entry, tags);
|
|
|
|
g_snprintf (str_uid, sizeof (str_uid), "uid.%d.1", chapter_nb);
|
|
toc_sub_entry = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_CHAPTER, str_uid);
|
|
gst_toc_entry_set_start_stop_times (toc_sub_entry, start, (start + stop) / 2);
|
|
|
|
g_snprintf (title, sizeof (title), "nested.%d.1", chapter_nb);
|
|
g_snprintf (artist, sizeof (artist), "art.%d.1", chapter_nb);
|
|
tags = gst_tag_list_new (GST_TAG_TITLE, title, GST_TAG_ARTIST, artist, NULL);
|
|
gst_toc_entry_set_tags (toc_sub_entry, tags);
|
|
|
|
gst_toc_entry_append_sub_entry (toc_entry, toc_sub_entry);
|
|
|
|
g_snprintf (str_uid, sizeof (str_uid), "uid.%d.2", chapter_nb);
|
|
toc_sub_entry = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_CHAPTER, str_uid);
|
|
gst_toc_entry_set_start_stop_times (toc_sub_entry, (start + stop) / 2, stop);
|
|
|
|
g_snprintf (title, sizeof (title), "nested/%d.2", chapter_nb);
|
|
g_snprintf (artist, sizeof (artist), "art.%d.2", chapter_nb);
|
|
tags = gst_tag_list_new (GST_TAG_TITLE, title, GST_TAG_ARTIST, artist, NULL);
|
|
gst_toc_entry_set_tags (toc_sub_entry, tags);
|
|
|
|
gst_toc_entry_append_sub_entry (toc_entry, toc_sub_entry);
|
|
|
|
return toc_entry;
|
|
}
|
|
|
|
/* Create a reference toc which matches what is expected in mkv_toc_base64 */
|
|
static GstToc *
|
|
new_reference_toc (void)
|
|
{
|
|
GstToc *ref_toc;
|
|
GstTocEntry *toc_edition_entry, *toc_entry;
|
|
GstTagList *tags;
|
|
|
|
ref_toc = gst_toc_new (GST_TOC_SCOPE_GLOBAL);
|
|
|
|
toc_edition_entry = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_EDITION, "00");
|
|
tags = gst_tag_list_new (GST_TAG_COMMENT, "Ed", NULL);
|
|
gst_toc_entry_set_tags (toc_edition_entry, tags);
|
|
|
|
toc_entry = new_chapter (1, 0 * GST_MSECOND, 2 * GST_MSECOND);
|
|
gst_toc_entry_append_sub_entry (toc_edition_entry, toc_entry);
|
|
|
|
toc_entry = new_chapter (2, 2 * GST_MSECOND, 4 * GST_MSECOND);
|
|
gst_toc_entry_append_sub_entry (toc_edition_entry, toc_entry);
|
|
|
|
gst_toc_append_entry (ref_toc, toc_edition_entry);
|
|
|
|
return ref_toc;
|
|
}
|
|
|
|
GST_START_TEST (test_toc_demux)
|
|
{
|
|
GstHarness *h;
|
|
GstBuffer *buf;
|
|
guchar *mkv_data;
|
|
gsize mkv_size;
|
|
GstEvent *event;
|
|
gboolean update;
|
|
GstToc *ref_toc, *demuxed_toc = NULL;
|
|
GList *ref_cur, *demuxed_cur;
|
|
|
|
h = gst_harness_new_with_padnames ("matroskademux", "sink", NULL);
|
|
|
|
g_signal_connect (h->element, "pad-added", G_CALLBACK (pad_added_cb), h);
|
|
|
|
mkv_data = g_base64_decode (mkv_toc_base64, &mkv_size);
|
|
fail_unless (mkv_data != NULL);
|
|
|
|
gst_harness_set_src_caps_str (h, "audio/x-matroska");
|
|
|
|
buf = gst_buffer_new_wrapped (mkv_data, mkv_size);
|
|
GST_BUFFER_OFFSET (buf) = 0;
|
|
|
|
fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (h, buf));
|
|
gst_harness_push_event (h, gst_event_new_eos ());
|
|
|
|
event = gst_harness_try_pull_event (h);
|
|
fail_unless (event != NULL);
|
|
|
|
while (event != NULL) {
|
|
if (event->type == GST_EVENT_TOC) {
|
|
gst_event_parse_toc (event, &demuxed_toc, &update);
|
|
gst_event_unref (event);
|
|
break;
|
|
}
|
|
gst_event_unref (event);
|
|
event = gst_harness_try_pull_event (h);
|
|
}
|
|
|
|
fail_unless (demuxed_toc != NULL);
|
|
ref_toc = new_reference_toc ();
|
|
|
|
demuxed_cur = gst_toc_get_entries (demuxed_toc);
|
|
for (ref_cur = gst_toc_get_entries (ref_toc); ref_cur != NULL;
|
|
ref_cur = ref_cur->next) {
|
|
fail_unless (demuxed_cur != NULL);
|
|
|
|
check_toc_entries (ref_cur->data, demuxed_cur->data);
|
|
demuxed_cur = demuxed_cur->next;
|
|
}
|
|
|
|
gst_toc_unref (ref_toc);
|
|
gst_toc_unref (demuxed_toc);
|
|
|
|
gst_harness_teardown (h);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
static void
|
|
demux_pad_added_cb (GstElement * demux, GstPad * new_pad, gpointer user_data)
|
|
{
|
|
GstElement *sink = GST_ELEMENT (user_data);
|
|
|
|
fail_unless (gst_element_link (demux, sink));
|
|
}
|
|
|
|
static const gint64 PINKNOISE_MKV_DURATION = 116099773;
|
|
|
|
static void
|
|
run_segment_looping_test (gint64 start, gint64 stop, gdouble rate)
|
|
{
|
|
GstStateChangeReturn state_ret;
|
|
GstMessage *msg;
|
|
GstElement *src, *sink, *demux, *pipeline;
|
|
gboolean seek_ret;
|
|
GstBus *bus;
|
|
gchar *path;
|
|
|
|
g_assert (start >= 0);
|
|
g_assert (stop >= -1);
|
|
g_assert (rate > 0.0);
|
|
|
|
// only handle a rate for the middle segment case for now
|
|
g_assert (rate == 1.0 || stop != -1);
|
|
|
|
pipeline = gst_pipeline_new ("pipeline");
|
|
fail_unless (pipeline != NULL, "Failed to create pipeline!");
|
|
|
|
bus = gst_element_get_bus (pipeline);
|
|
|
|
src = gst_element_factory_make ("filesrc", "filesrc");
|
|
fail_unless (src != NULL, "Failed to create 'filesrc' element!");
|
|
|
|
demux = gst_element_factory_make ("matroskademux", "demux");
|
|
fail_unless (demux != NULL, "Failed to create matroskademux element");
|
|
|
|
sink = gst_element_factory_make ("fakesink", "fakesink");
|
|
fail_unless (sink != NULL, "Failed to create 'fakesink' element!");
|
|
|
|
gst_bin_add_many (GST_BIN (pipeline), src, demux, sink, NULL);
|
|
|
|
fail_unless (gst_element_link (src, demux));
|
|
|
|
g_signal_connect (demux, "pad-added", G_CALLBACK (demux_pad_added_cb), sink);
|
|
|
|
path = g_build_filename (GST_TEST_FILES_PATH, "pinknoise-vorbis.mkv", NULL);
|
|
GST_LOG ("reading file '%s'", path);
|
|
g_object_set (src, "location", path, NULL);
|
|
|
|
state_ret = gst_element_set_state (pipeline, GST_STATE_PAUSED);
|
|
fail_unless (state_ret != GST_STATE_CHANGE_FAILURE);
|
|
|
|
if (state_ret == GST_STATE_CHANGE_ASYNC) {
|
|
GST_LOG ("waiting for pipeline to reach PAUSED state");
|
|
state_ret = gst_element_get_state (pipeline, NULL, NULL, -1);
|
|
fail_unless_equals_int (state_ret, GST_STATE_CHANGE_SUCCESS);
|
|
}
|
|
|
|
GST_LOG ("PAUSED, let's play a little..");
|
|
state_ret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
|
fail_unless (state_ret != GST_STATE_CHANGE_FAILURE);
|
|
|
|
GST_LOG ("Send FLUSHING seek with SEGMENT flag set.. "
|
|
"(start=%" G_GINT64_FORMAT ", stop=%" G_GINT64_FORMAT ")", start, stop);
|
|
|
|
if (stop == -1) {
|
|
seek_ret = gst_element_seek_simple (pipeline, GST_FORMAT_TIME,
|
|
GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SEGMENT, start);
|
|
} else {
|
|
seek_ret = gst_element_seek (pipeline, rate, GST_FORMAT_TIME,
|
|
GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SEGMENT,
|
|
GST_SEEK_TYPE_SET, start, GST_SEEK_TYPE_SET, stop);
|
|
}
|
|
fail_unless (seek_ret == TRUE);
|
|
|
|
GST_LOG ("Waiting for pipeline to preroll again after flushing seek..");
|
|
state_ret = gst_element_get_state (pipeline, NULL, NULL, -1);
|
|
fail_unless_equals_int (state_ret, GST_STATE_CHANGE_SUCCESS);
|
|
|
|
{
|
|
GstFormat fmt = GST_FORMAT_UNDEFINED;
|
|
gint64 segment_end = 0;
|
|
|
|
GST_LOG ("Waiting for SEGMENT_DONE message..");
|
|
msg = gst_bus_timed_pop_filtered (bus, -1, GST_MESSAGE_SEGMENT_DONE);
|
|
fail_unless (msg != NULL);
|
|
|
|
gst_message_parse_segment_done (msg, &fmt, &segment_end);
|
|
fail_unless_equals_int (fmt, GST_FORMAT_TIME);
|
|
if (stop == -1) {
|
|
fail_unless_equals_int64 (segment_end, PINKNOISE_MKV_DURATION);
|
|
} else {
|
|
fail_unless_equals_int64 (segment_end, stop);
|
|
}
|
|
gst_clear_message (&msg);
|
|
}
|
|
|
|
GST_LOG ("Send non-FLUSHING seek to start new segment loop.. "
|
|
"(start=%" G_GINT64_FORMAT ", stop=%" G_GINT64_FORMAT ")", start, stop);
|
|
|
|
/* No segment flag this time, so will be expecting an EOS at the end */
|
|
if (stop == -1) {
|
|
seek_ret = gst_element_seek_simple (pipeline, GST_FORMAT_TIME, 0, start);
|
|
} else {
|
|
seek_ret = gst_element_seek (pipeline, rate, GST_FORMAT_TIME, 0,
|
|
GST_SEEK_TYPE_SET, start, GST_SEEK_TYPE_SET, stop);
|
|
}
|
|
fail_unless (seek_ret == TRUE);
|
|
|
|
GST_LOG ("Waiting for EOS message..");
|
|
msg = gst_bus_timed_pop_filtered (bus, -1, GST_MESSAGE_EOS);
|
|
fail_unless (msg != NULL);
|
|
gst_clear_message (&msg);
|
|
|
|
{
|
|
GstPad *pad = gst_element_get_static_pad (sink, "sink");
|
|
GstEvent *ev = gst_pad_get_sticky_event (pad, GST_EVENT_SEGMENT, 0);
|
|
const GstSegment *segment = NULL;
|
|
|
|
gst_event_parse_segment (ev, &segment);
|
|
|
|
GST_INFO ("segment %" GST_SEGMENT_FORMAT, segment);
|
|
|
|
fail_unless_equals_int64 (segment->start, start);
|
|
if (stop == -1) {
|
|
fail_unless_equals_int64 (segment->stop, PINKNOISE_MKV_DURATION);
|
|
fail_unless_equals_int64 (segment->duration, PINKNOISE_MKV_DURATION);
|
|
fail_unless_equals_int64 (segment->base, PINKNOISE_MKV_DURATION);
|
|
} else {
|
|
fail_unless_equals_int64 (segment->stop, stop);
|
|
fail_unless_equals_int64 (segment->duration, PINKNOISE_MKV_DURATION);
|
|
fail_unless_equals_int64 (segment->base, (stop - start) / rate);
|
|
}
|
|
|
|
gst_clear_event (&ev);
|
|
gst_clear_object (&pad);
|
|
}
|
|
|
|
fail_unless_equals_int (gst_element_set_state (pipeline, GST_STATE_NULL),
|
|
GST_STATE_CHANGE_SUCCESS);
|
|
gst_object_unref (pipeline);
|
|
gst_clear_object (&bus);
|
|
|
|
g_free (path);
|
|
}
|
|
|
|
/* Make sure segment seeks behave as expected, and the segment base offset
|
|
* is increased correctly by the clip duration rather than the last timestamp
|
|
* position. */
|
|
GST_START_TEST (test_segment_looping)
|
|
{
|
|
run_segment_looping_test (0, -1, 1.0);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
/* If we do a segment seek on a middle segment of the clip, we expect the
|
|
* base offset of the next segment to be the duration of our selected segment,
|
|
* not the duration of the entire clip, since we only played that much then. */
|
|
GST_START_TEST (test_segment_looping_middle_segment)
|
|
{
|
|
run_segment_looping_test (50 * GST_MSECOND, 100 * GST_MSECOND, 1.0);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
/* For positive non-1.0 rates the base offset of the next segment should be
|
|
* scaled accordingly, since it's in running time not stream time. */
|
|
GST_START_TEST (test_segment_looping_middle_segment_with_rate)
|
|
{
|
|
run_segment_looping_test (50 * GST_MSECOND, 100 * GST_MSECOND, 2.0);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
static Suite *
|
|
matroskademux_suite (void)
|
|
{
|
|
Suite *s = suite_create ("matroskademux");
|
|
TCase *tc_chain = tcase_create ("general");
|
|
|
|
suite_add_tcase (s, tc_chain);
|
|
tcase_add_test (tc_chain, test_sub_terminator);
|
|
tcase_add_test (tc_chain, test_toc_demux);
|
|
tcase_add_test (tc_chain, test_segment_looping);
|
|
tcase_add_test (tc_chain, test_segment_looping_middle_segment);
|
|
tcase_add_test (tc_chain, test_segment_looping_middle_segment_with_rate);
|
|
|
|
return s;
|
|
}
|
|
|
|
GST_CHECK_MAIN (matroskademux);
|