mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-30 05:31:15 +00:00
1119 lines
34 KiB
C
1119 lines
34 KiB
C
/* GStreamer
|
|
*
|
|
* SPDX-License-Identifier: LGPL-2.1
|
|
*
|
|
* Copyright (C) 2022, 2023 Collabora Ltd.
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#ifdef HAVE_VALGRIND
|
|
# include <valgrind/valgrind.h>
|
|
#endif
|
|
|
|
#include <gst/check/gstcheck.h>
|
|
|
|
#include <gst/mse/mse.h>
|
|
#include <gst/mse/gstappendpipeline-private.h>
|
|
#include <gst/mse/gstmediasource-private.h>
|
|
#include <gst/mse/gstmediasourcetrack-private.h>
|
|
#include <gst/mse/gstmediasourcetrackbuffer-private.h>
|
|
#include <gst/mse/gstmediasourcesamplemap-private.h>
|
|
|
|
static GstCheckLogFilter *
|
|
add_log_filter (GLogLevelFlags level, const gchar * regex)
|
|
{
|
|
GRegex *gregex = g_regex_new (regex, 0, 0, NULL);
|
|
return gst_check_add_log_filter ("GStreamer-MSE", level, gregex, NULL, NULL,
|
|
NULL);
|
|
}
|
|
|
|
static gchar *
|
|
test_mp4_path (void)
|
|
{
|
|
return g_build_filename (GST_TEST_FILES_PATH, "mse.mp4", NULL);
|
|
}
|
|
|
|
static gchar *
|
|
test_webm_path (void)
|
|
{
|
|
return g_build_filename (GST_TEST_FILES_PATH, "mse.webm", NULL);
|
|
}
|
|
|
|
static GstMediaSource *
|
|
opened_media_source (void)
|
|
{
|
|
GstMediaSource *media_source = gst_media_source_new ();
|
|
media_source->ready_state = GST_MEDIA_SOURCE_READY_STATE_OPEN;
|
|
return media_source;
|
|
}
|
|
|
|
static GstSample *
|
|
new_empty_sample_full (GstClockTime dts, GstClockTime pts,
|
|
GstClockTime duration, GstBufferFlags flags, GstCaps * caps,
|
|
GstSegment * segment, GstStructure * info)
|
|
{
|
|
GstBuffer *buffer = gst_buffer_new ();
|
|
GST_BUFFER_DTS (buffer) = dts;
|
|
GST_BUFFER_PTS (buffer) = pts;
|
|
GST_BUFFER_DURATION (buffer) = duration;
|
|
GST_BUFFER_FLAGS (buffer) = flags;
|
|
GstSample *sample = gst_sample_new (buffer, caps, segment, info);
|
|
gst_buffer_unref (buffer);
|
|
return sample;
|
|
}
|
|
|
|
static GstSample *
|
|
new_empty_sample_with_timing (GstClockTime dts, GstClockTime pts,
|
|
GstClockTime duration)
|
|
{
|
|
return new_empty_sample_full (dts, pts, duration, 0, NULL, NULL, NULL);
|
|
}
|
|
|
|
static GstSample *
|
|
new_sample_with_bytes_and_timing (GBytes * bytes, GstClockTime dts,
|
|
GstClockTime pts, GstClockTime duration)
|
|
{
|
|
GstBuffer *buffer = gst_buffer_new_wrapped_bytes (bytes);
|
|
GST_BUFFER_DTS (buffer) = dts;
|
|
GST_BUFFER_PTS (buffer) = pts;
|
|
GST_BUFFER_DURATION (buffer) = duration;
|
|
GstSample *sample = gst_sample_new (buffer, NULL, NULL, NULL);
|
|
gst_buffer_unref (buffer);
|
|
g_bytes_unref (bytes);
|
|
return sample;
|
|
}
|
|
|
|
GST_START_TEST (test_create_and_free)
|
|
{
|
|
GstMediaSource *media_source = gst_media_source_new ();
|
|
fail_unless (GST_IS_MEDIA_SOURCE (media_source));
|
|
gst_check_object_destroyed_on_unref (media_source);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (test_create_initial_state)
|
|
{
|
|
GstMediaSource *media_source = gst_media_source_new ();
|
|
|
|
GstSourceBufferList *buffers =
|
|
gst_media_source_get_source_buffers (media_source);
|
|
GstSourceBufferList *active_buffers =
|
|
gst_media_source_get_active_source_buffers (media_source);
|
|
|
|
fail_unless (gst_media_source_get_ready_state (media_source) ==
|
|
GST_MEDIA_SOURCE_READY_STATE_CLOSED);
|
|
fail_unless (gst_source_buffer_list_get_length (buffers) == 0);
|
|
fail_unless (gst_source_buffer_list_get_length (active_buffers) == 0);
|
|
fail_unless (gst_media_source_get_position (media_source) ==
|
|
GST_CLOCK_TIME_NONE);
|
|
|
|
gst_object_unref (media_source);
|
|
gst_object_unref (buffers);
|
|
gst_object_unref (active_buffers);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (test_add_source_buffer_with_content_type_null)
|
|
{
|
|
add_log_filter (G_LOG_LEVEL_CRITICAL,
|
|
"^.*_add_source_buffer: assertion 'type != NULL' failed");
|
|
|
|
GstMediaSource *media_source = gst_media_source_new ();
|
|
|
|
g_assert_null (gst_media_source_add_source_buffer (media_source, NULL, NULL));
|
|
|
|
gst_object_unref (media_source);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (test_add_source_buffer_with_content_type_empty)
|
|
{
|
|
GError *error = NULL;
|
|
GstMediaSource *media_source = gst_media_source_new ();
|
|
GstSourceBuffer *source_buffer =
|
|
gst_media_source_add_source_buffer (media_source, "", &error);
|
|
|
|
g_assert_null (source_buffer);
|
|
g_assert_error (error, GST_MEDIA_SOURCE_ERROR, GST_MEDIA_SOURCE_ERROR_TYPE);
|
|
|
|
gst_object_unref (media_source);
|
|
g_clear_error (&error);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (test_add_source_buffer_with_content_type_fake)
|
|
{
|
|
GError *error = NULL;
|
|
GstMediaSource *media_source = gst_media_source_new ();
|
|
GstSourceBuffer *source_buffer =
|
|
gst_media_source_add_source_buffer (media_source, "fake/type", &error);
|
|
|
|
g_assert_null (source_buffer);
|
|
g_assert_error (error, GST_MEDIA_SOURCE_ERROR,
|
|
GST_MEDIA_SOURCE_ERROR_NOT_SUPPORTED);
|
|
|
|
gst_object_unref (media_source);
|
|
g_clear_error (&error);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (test_add_source_buffer_to_unopened_media_source)
|
|
{
|
|
GError *error = NULL;
|
|
GstMediaSource *media_source = gst_media_source_new ();
|
|
GstSourceBuffer *source_buffer =
|
|
gst_media_source_add_source_buffer (media_source, "video/webm", &error);
|
|
|
|
g_assert_null (source_buffer);
|
|
g_assert_error (error, GST_MEDIA_SOURCE_ERROR,
|
|
GST_MEDIA_SOURCE_ERROR_INVALID_STATE);
|
|
|
|
gst_object_unref (media_source);
|
|
g_clear_error (&error);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (test_add_source_buffer_to_opened_media_source)
|
|
{
|
|
GError *error = NULL;
|
|
GstMediaSource *media_source = opened_media_source ();
|
|
GstSourceBufferList *buffers =
|
|
gst_media_source_get_source_buffers (media_source);
|
|
guint n_buffers_before = gst_source_buffer_list_get_length (buffers);
|
|
GstSourceBuffer *source_buffer =
|
|
gst_media_source_add_source_buffer (media_source, "video/webm", &error);
|
|
guint n_buffers_after = gst_source_buffer_list_get_length (buffers);
|
|
|
|
fail_unless (GST_IS_SOURCE_BUFFER (source_buffer));
|
|
g_assert_no_error (error);
|
|
fail_unless (n_buffers_before < n_buffers_after);
|
|
|
|
g_object_unref (media_source);
|
|
g_object_unref (buffers);
|
|
g_object_unref (source_buffer);
|
|
g_clear_error (&error);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (test_remove_source_buffer_from_unrelated_media_source)
|
|
{
|
|
GError *error = NULL;
|
|
GstMediaSource *a = opened_media_source ();
|
|
GstMediaSource *b = opened_media_source ();
|
|
GstSourceBuffer *buffer_in_b =
|
|
gst_media_source_add_source_buffer (b, "video/webm", &error);
|
|
|
|
gst_media_source_remove_source_buffer (a, buffer_in_b, &error);
|
|
g_assert_error (error, GST_MEDIA_SOURCE_ERROR,
|
|
GST_MEDIA_SOURCE_ERROR_NOT_FOUND);
|
|
|
|
gst_object_unref (a);
|
|
gst_object_unref (b);
|
|
gst_object_unref (buffer_in_b);
|
|
g_clear_error (&error);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (test_remove_source_buffer_from_parent_media_source)
|
|
{
|
|
GError *error = NULL;
|
|
GstMediaSource *media_source = opened_media_source ();
|
|
GstSourceBufferList *buffers =
|
|
gst_media_source_get_source_buffers (media_source);
|
|
GstSourceBuffer *buffer =
|
|
gst_media_source_add_source_buffer (media_source, "video/webm", &error);
|
|
|
|
guint n_buffers_before = gst_source_buffer_list_get_length (buffers);
|
|
gst_media_source_remove_source_buffer (media_source, buffer, &error);
|
|
guint n_buffers_after = gst_source_buffer_list_get_length (buffers);
|
|
|
|
g_assert_no_error (error);
|
|
fail_unless (n_buffers_before > n_buffers_after);
|
|
|
|
gst_object_unref (media_source);
|
|
gst_object_unref (buffers);
|
|
gst_object_unref (buffer);
|
|
g_clear_error (&error);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (test_set_live_seekable_range_on_unopened_media_source)
|
|
{
|
|
GError *error = NULL;
|
|
GstMediaSource *media_source = gst_media_source_new ();
|
|
|
|
gst_media_source_set_live_seekable_range (media_source, 0, 1, &error);
|
|
|
|
g_assert_error (error, GST_MEDIA_SOURCE_ERROR,
|
|
GST_MEDIA_SOURCE_ERROR_INVALID_STATE);
|
|
|
|
gst_object_unref (media_source);
|
|
g_clear_error (&error);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (test_set_backwards_live_seekable_range_on_opened_media_source)
|
|
{
|
|
GError *error = NULL;
|
|
GstMediaSource *media_source = opened_media_source ();
|
|
|
|
gst_media_source_set_live_seekable_range (media_source, 2, 1, &error);
|
|
|
|
GstMediaSourceRange range = {
|
|
.start = GST_CLOCK_TIME_NONE,
|
|
.end = GST_CLOCK_TIME_NONE,
|
|
};
|
|
gst_media_source_get_live_seekable_range (media_source, &range);
|
|
|
|
g_assert_error (error, GST_MEDIA_SOURCE_ERROR, GST_MEDIA_SOURCE_ERROR_TYPE);
|
|
fail_unless (range.start == 0);
|
|
fail_unless (range.end == 0);
|
|
|
|
gst_object_unref (media_source);
|
|
g_clear_error (&error);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (test_set_live_seekable_range_on_opened_media_source)
|
|
{
|
|
GError *error = NULL;
|
|
GstClockTime start = 1, end = 2;
|
|
GstMediaSource *media_source = opened_media_source ();
|
|
|
|
gst_media_source_set_live_seekable_range (media_source, start, end, &error);
|
|
|
|
GstMediaSourceRange range = {
|
|
.start = GST_CLOCK_TIME_NONE,
|
|
.end = GST_CLOCK_TIME_NONE,
|
|
};
|
|
gst_media_source_get_live_seekable_range (media_source, &range);
|
|
|
|
g_assert_no_error (error);
|
|
fail_unless (range.start == start);
|
|
fail_unless (range.end == end);
|
|
|
|
gst_object_unref (media_source);
|
|
g_clear_error (&error);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (test_clear_live_seekable_range_on_unopened_media_source)
|
|
{
|
|
GError *error = NULL;
|
|
GstMediaSource *media_source = gst_media_source_new ();
|
|
|
|
gst_media_source_clear_live_seekable_range (media_source, &error);
|
|
|
|
g_assert_error (error, GST_MEDIA_SOURCE_ERROR,
|
|
GST_MEDIA_SOURCE_ERROR_INVALID_STATE);
|
|
|
|
gst_object_unref (media_source);
|
|
g_clear_error (&error);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (test_clear_live_seekable_range_on_opened_media_source)
|
|
{
|
|
GError *error = NULL;
|
|
GstMediaSource *media_source = opened_media_source ();
|
|
gst_media_source_set_live_seekable_range (media_source, 1, 2, NULL);
|
|
|
|
gst_media_source_clear_live_seekable_range (media_source, &error);
|
|
GstMediaSourceRange range = {
|
|
.start = GST_CLOCK_TIME_NONE,
|
|
.end = GST_CLOCK_TIME_NONE,
|
|
};
|
|
gst_media_source_get_live_seekable_range (media_source, &range);
|
|
|
|
g_assert_no_error (error);
|
|
fail_unless (range.start == 0);
|
|
fail_unless (range.end == 0);
|
|
|
|
gst_object_unref (media_source);
|
|
g_clear_error (&error);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (test_append_pipeline_create_and_free)
|
|
{
|
|
GError *error = NULL;
|
|
GstAppendPipeline *pipeline = gst_append_pipeline_new (NULL, NULL, &error);
|
|
g_assert_no_error (error);
|
|
fail_unless (GST_IS_APPEND_PIPELINE (pipeline));
|
|
gst_check_object_destroyed_on_unref (pipeline);
|
|
g_clear_error (&error);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
typedef struct
|
|
{
|
|
GMutex mutex;
|
|
GCond eos_cond;
|
|
GCond error_cond;
|
|
} AppendPipelineTestContext;
|
|
|
|
static void
|
|
test_append_pipeline_eos (GstAppendPipeline * pipeline,
|
|
GstMediaSourceTrack * track, gpointer user_data)
|
|
{
|
|
AppendPipelineTestContext *context = user_data;
|
|
g_mutex_lock (&context->mutex);
|
|
g_cond_signal (&context->eos_cond);
|
|
g_mutex_unlock (&context->mutex);
|
|
GST_DEBUG_OBJECT (pipeline, "signalled eos");
|
|
}
|
|
|
|
static void
|
|
test_append_pipeline_error (GstAppendPipeline * pipeline, gpointer user_data)
|
|
{
|
|
AppendPipelineTestContext *context = user_data;
|
|
g_mutex_lock (&context->mutex);
|
|
g_cond_signal (&context->error_cond);
|
|
g_mutex_unlock (&context->mutex);
|
|
GST_DEBUG_OBJECT (pipeline, "signalled error");
|
|
}
|
|
|
|
static void
|
|
test_append_pipeline_await_eos (GstAppendPipeline * pipeline,
|
|
AppendPipelineTestContext * context)
|
|
{
|
|
GST_DEBUG_OBJECT (pipeline, "waiting for eos");
|
|
g_mutex_lock (&context->mutex);
|
|
while (!gst_append_pipeline_get_eos (pipeline)) {
|
|
g_cond_wait (&context->eos_cond, &context->mutex);
|
|
}
|
|
g_mutex_unlock (&context->mutex);
|
|
GST_DEBUG_OBJECT (pipeline, "received eos");
|
|
}
|
|
|
|
static void
|
|
test_append_pipeline_await_error (GstAppendPipeline * pipeline,
|
|
AppendPipelineTestContext * context)
|
|
{
|
|
GST_DEBUG_OBJECT (pipeline, "waiting for error");
|
|
g_mutex_lock (&context->mutex);
|
|
while (!gst_append_pipeline_get_failed (pipeline)) {
|
|
g_cond_wait (&context->error_cond, &context->mutex);
|
|
}
|
|
g_mutex_unlock (&context->mutex);
|
|
GST_DEBUG_OBJECT (pipeline, "received error");
|
|
}
|
|
|
|
static void
|
|
test_append_pipeline (const gchar * filename)
|
|
{
|
|
AppendPipelineTestContext context = { 0 };
|
|
GstAppendPipelineCallbacks callbacks = {
|
|
.eos = test_append_pipeline_eos,
|
|
};
|
|
GstAppendPipeline *pipeline =
|
|
gst_append_pipeline_new (&callbacks, &context, NULL);
|
|
GError *error = NULL;
|
|
|
|
gchar *data;
|
|
gsize length;
|
|
|
|
g_file_get_contents (filename, &data, &length, &error);
|
|
g_assert_no_error (error);
|
|
|
|
fail_unless (gst_append_pipeline_append (pipeline,
|
|
gst_buffer_new_wrapped (data, length)) == GST_FLOW_OK);
|
|
|
|
gst_append_pipeline_eos (pipeline);
|
|
|
|
test_append_pipeline_await_eos (pipeline, &context);
|
|
|
|
fail_if (gst_append_pipeline_get_failed (pipeline));
|
|
|
|
gst_object_unref (pipeline);
|
|
g_clear_error (&error);
|
|
}
|
|
|
|
GST_START_TEST (test_append_pipeline_mp4)
|
|
{
|
|
gchar *filename = test_mp4_path ();
|
|
test_append_pipeline (filename);
|
|
g_free (filename);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (test_append_pipeline_webm)
|
|
{
|
|
gchar *filename = test_webm_path ();
|
|
test_append_pipeline (filename);
|
|
g_free (filename);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
static GstAppendPipeline *
|
|
failed_append_pipeline (GstAppendPipelineCallbacks * callbacks,
|
|
AppendPipelineTestContext * context)
|
|
{
|
|
GstAppendPipeline *pipeline =
|
|
gst_append_pipeline_new (callbacks, context, NULL);
|
|
|
|
gst_append_pipeline_fail (pipeline);
|
|
|
|
return pipeline;
|
|
}
|
|
|
|
GST_START_TEST (test_append_pipeline_invalid_data_triggers_error)
|
|
{
|
|
AppendPipelineTestContext context = { 0 };
|
|
GstAppendPipelineCallbacks callbacks = {
|
|
.eos = test_append_pipeline_eos,
|
|
.error = test_append_pipeline_error,
|
|
};
|
|
GstAppendPipeline *pipeline = failed_append_pipeline (&callbacks, &context);
|
|
|
|
test_append_pipeline_await_error (pipeline, &context);
|
|
|
|
gst_object_unref (pipeline);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (test_append_pipeline_invalid_data_triggers_eos)
|
|
{
|
|
AppendPipelineTestContext context = { 0 };
|
|
GstAppendPipelineCallbacks callbacks = {
|
|
.eos = test_append_pipeline_eos,
|
|
.error = test_append_pipeline_error,
|
|
};
|
|
GstAppendPipeline *pipeline = failed_append_pipeline (&callbacks, &context);
|
|
|
|
test_append_pipeline_await_eos (pipeline, &context);
|
|
|
|
gst_object_unref (pipeline);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (test_append_pipeline_reset_recovery)
|
|
{
|
|
AppendPipelineTestContext context = { 0 };
|
|
GstAppendPipelineCallbacks callbacks = {
|
|
.eos = test_append_pipeline_eos,
|
|
.error = test_append_pipeline_error,
|
|
};
|
|
GstAppendPipeline *pipeline = failed_append_pipeline (&callbacks, &context);
|
|
|
|
test_append_pipeline_await_error (pipeline, &context);
|
|
fail_unless (gst_append_pipeline_get_failed (pipeline));
|
|
|
|
fail_unless (gst_append_pipeline_reset (pipeline));
|
|
fail_if (gst_append_pipeline_get_failed (pipeline));
|
|
|
|
gchar *data;
|
|
gsize length;
|
|
{
|
|
GError *error = NULL;
|
|
gchar *filename = test_webm_path ();
|
|
g_file_get_contents (filename, &data, &length, &error);
|
|
g_assert_no_error (error);
|
|
g_clear_error (&error);
|
|
g_free (filename);
|
|
}
|
|
|
|
fail_unless (gst_append_pipeline_append (pipeline,
|
|
gst_buffer_new_wrapped (data, length)) == GST_FLOW_OK);
|
|
|
|
gst_append_pipeline_eos (pipeline);
|
|
|
|
test_append_pipeline_await_eos (pipeline, &context);
|
|
|
|
fail_if (gst_append_pipeline_get_failed (pipeline));
|
|
|
|
gst_object_unref (pipeline);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (test_track_create_and_free)
|
|
{
|
|
GstMediaSourceTrack *track =
|
|
gst_media_source_track_new (GST_MEDIA_SOURCE_TRACK_TYPE_OTHER, "");
|
|
fail_unless (GST_IS_MEDIA_SOURCE_TRACK (track));
|
|
gst_check_object_destroyed_on_unref (track);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (test_track_create_with_invalid_type)
|
|
{
|
|
add_log_filter (G_LOG_LEVEL_CRITICAL,
|
|
"^.*track_new_full: assertion .*type .* failed");
|
|
|
|
g_assert_null (gst_media_source_track_new (-1, ""));
|
|
g_assert_null (gst_media_source_track_new (GST_MEDIA_SOURCE_TRACK_TYPE_OTHER +
|
|
1, ""));
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (test_track_push_with_adequate_space)
|
|
{
|
|
GstMediaSourceTrack *track =
|
|
gst_media_source_track_new_with_size (GST_MEDIA_SOURCE_TRACK_TYPE_OTHER,
|
|
"", 1);
|
|
GstBuffer *buffer = gst_buffer_new ();
|
|
GstSample *sample = gst_sample_new (buffer, NULL, NULL, NULL);
|
|
gboolean result = gst_media_source_track_push (track, sample);
|
|
fail_unless (result);
|
|
gst_buffer_unref (buffer);
|
|
gst_object_unref (track);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (test_track_push_with_inadequate_space)
|
|
{
|
|
GstMediaSourceTrack *track =
|
|
gst_media_source_track_new_with_size (GST_MEDIA_SOURCE_TRACK_TYPE_OTHER,
|
|
"", 0);
|
|
GstBuffer *buffer = gst_buffer_new ();
|
|
GstSample *sample = gst_sample_new (buffer, NULL, NULL, NULL);
|
|
gboolean result = gst_media_source_track_try_push (track, sample);
|
|
fail_if (result);
|
|
gst_sample_unref (sample);
|
|
gst_buffer_unref (buffer);
|
|
gst_object_unref (track);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (test_track_buffer_empty)
|
|
{
|
|
GstMediaSourceTrackBuffer *buffer = gst_media_source_track_buffer_new ();
|
|
|
|
GArray *ranges = gst_media_source_track_buffer_get_ranges (buffer);
|
|
fail_unless_equals_uint64 (ranges->len, 0);
|
|
|
|
gst_object_unref (buffer);
|
|
g_array_unref (ranges);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (test_track_buffer_single_span)
|
|
{
|
|
GstMediaSourceTrackBuffer *buffer = gst_media_source_track_buffer_new ();
|
|
|
|
GstSample *sample = new_empty_sample_with_timing (0, 0, 1);
|
|
gst_media_source_track_buffer_add (buffer, sample);
|
|
|
|
GArray *ranges = gst_media_source_track_buffer_get_ranges (buffer);
|
|
fail_unless_equals_uint64 (ranges->len, 1);
|
|
|
|
GstMediaSourceRange range = g_array_index (ranges, GstMediaSourceRange, 0);
|
|
fail_unless_equals_uint64 (range.start, 0);
|
|
fail_unless_equals_uint64 (range.end, 1);
|
|
|
|
gst_sample_unref (sample);
|
|
gst_object_unref (buffer);
|
|
g_array_unref (ranges);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (test_track_buffer_continuous_span)
|
|
{
|
|
GstMediaSourceTrackBuffer *buffer = gst_media_source_track_buffer_new ();
|
|
|
|
GstClockTime a_start = 0;
|
|
GstClockTime a_duration = GST_SECOND;
|
|
GstClockTime b_start = a_start + a_duration;
|
|
GstClockTime b_duration = a_duration;
|
|
GstSample *a = new_empty_sample_with_timing (a_start, a_start, a_duration);
|
|
GstSample *b = new_empty_sample_with_timing (b_start, b_start, b_duration);
|
|
gst_media_source_track_buffer_add (buffer, a);
|
|
gst_media_source_track_buffer_add (buffer, b);
|
|
|
|
GArray *ranges = gst_media_source_track_buffer_get_ranges (buffer);
|
|
fail_unless_equals_uint64 (ranges->len, 1);
|
|
|
|
GstMediaSourceRange range = g_array_index (ranges, GstMediaSourceRange, 0);
|
|
fail_unless_equals_uint64 (range.start, a_start);
|
|
fail_unless_equals_uint64 (range.end, a_start + a_duration + b_duration);
|
|
|
|
gst_sample_unref (a);
|
|
gst_sample_unref (b);
|
|
gst_object_unref (buffer);
|
|
g_array_unref (ranges);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (test_track_buffer_discontinuous_span)
|
|
{
|
|
GstMediaSourceTrackBuffer *buffer = gst_media_source_track_buffer_new ();
|
|
|
|
GstClockTime a_start = 0;
|
|
GstClockTime a_duration = GST_SECOND;
|
|
GstClockTime b_start = a_start + a_duration + GST_SECOND;
|
|
GstClockTime b_duration = a_duration;
|
|
GstSample *a = new_empty_sample_with_timing (a_start, a_start, a_duration);
|
|
GstSample *b = new_empty_sample_with_timing (b_start, b_start, b_duration);
|
|
gst_media_source_track_buffer_add (buffer, a);
|
|
gst_media_source_track_buffer_add (buffer, b);
|
|
|
|
GArray *ranges = gst_media_source_track_buffer_get_ranges (buffer);
|
|
fail_unless_equals_uint64 (ranges->len, 2);
|
|
|
|
GstMediaSourceRange range_a = g_array_index (ranges, GstMediaSourceRange, 0);
|
|
fail_unless_equals_uint64 (range_a.start, a_start);
|
|
fail_unless_equals_uint64 (range_a.end, a_start + a_duration);
|
|
|
|
GstMediaSourceRange range_b = g_array_index (ranges, GstMediaSourceRange, 1);
|
|
fail_unless_equals_uint64 (range_b.start, b_start);
|
|
fail_unless_equals_uint64 (range_b.end, b_start + b_duration);
|
|
|
|
gst_sample_unref (a);
|
|
gst_sample_unref (b);
|
|
gst_object_unref (buffer);
|
|
g_array_unref (ranges);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (test_source_buffer_generate_timestamps_mp4)
|
|
{
|
|
GstMediaSource *media_source = opened_media_source ();
|
|
GstSourceBuffer *source_buffer = gst_media_source_add_source_buffer
|
|
(media_source, "video/mp4", NULL);
|
|
|
|
fail_unless_equals_uint64 (gst_source_buffer_get_append_mode (source_buffer),
|
|
GST_SOURCE_BUFFER_APPEND_MODE_SEGMENTS);
|
|
|
|
gst_object_unref (source_buffer);
|
|
gst_object_unref (media_source);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (test_source_buffer_generate_timestamps_aac)
|
|
{
|
|
GstMediaSource *media_source = opened_media_source ();
|
|
GstSourceBuffer *source_buffer = gst_media_source_add_source_buffer
|
|
(media_source, "audio/aac", NULL);
|
|
|
|
fail_unless (GST_IS_SOURCE_BUFFER (source_buffer));
|
|
|
|
fail_unless_equals_uint64 (gst_source_buffer_get_append_mode (source_buffer),
|
|
GST_SOURCE_BUFFER_APPEND_MODE_SEQUENCE);
|
|
|
|
gst_object_unref (source_buffer);
|
|
gst_object_unref (media_source);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (test_source_buffer_change_content_type_null)
|
|
{
|
|
GstMediaSource *media_source = opened_media_source ();
|
|
GstSourceBuffer *source_buffer = gst_media_source_add_source_buffer
|
|
(media_source, "video/mp4", NULL);
|
|
|
|
fail_unless (GST_IS_SOURCE_BUFFER (source_buffer));
|
|
|
|
GError *error = NULL;
|
|
gst_source_buffer_change_content_type (source_buffer, NULL, &error);
|
|
g_assert_error (error, GST_MEDIA_SOURCE_ERROR, GST_MEDIA_SOURCE_ERROR_TYPE);
|
|
|
|
g_clear_error (&error);
|
|
gst_object_unref (source_buffer);
|
|
gst_object_unref (media_source);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (test_source_buffer_change_content_type_empty)
|
|
{
|
|
GstMediaSource *media_source = opened_media_source ();
|
|
GstSourceBuffer *source_buffer = gst_media_source_add_source_buffer
|
|
(media_source, "video/mp4", NULL);
|
|
|
|
fail_unless (GST_IS_SOURCE_BUFFER (source_buffer));
|
|
|
|
GError *error = NULL;
|
|
gst_source_buffer_change_content_type (source_buffer, "", &error);
|
|
g_assert_error (error, GST_MEDIA_SOURCE_ERROR, GST_MEDIA_SOURCE_ERROR_TYPE);
|
|
|
|
g_clear_error (&error);
|
|
gst_object_unref (source_buffer);
|
|
gst_object_unref (media_source);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (test_source_buffer_change_content_type)
|
|
{
|
|
GstMediaSource *media_source = opened_media_source ();
|
|
GstSourceBuffer *source_buffer = gst_media_source_add_source_buffer
|
|
(media_source, "video/mp4", NULL);
|
|
|
|
fail_unless (GST_IS_SOURCE_BUFFER (source_buffer));
|
|
|
|
GError *error = NULL;
|
|
gst_source_buffer_change_content_type (source_buffer, "video/webm", &error);
|
|
g_assert_error (error, GST_MEDIA_SOURCE_ERROR,
|
|
GST_MEDIA_SOURCE_ERROR_NOT_SUPPORTED);
|
|
|
|
gst_object_unref (source_buffer);
|
|
gst_object_unref (media_source);
|
|
g_clear_error (&error);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
static const gchar *unsupported_content_types[] = {
|
|
"xxx",
|
|
"text/html",
|
|
"image/jpeg",
|
|
};
|
|
|
|
GST_START_TEST (test_media_source_unsupported_content_type)
|
|
{
|
|
const gchar *content_type = unsupported_content_types[__i__];
|
|
ck_assert_msg (!gst_media_source_is_type_supported (content_type),
|
|
"%s should be rejected as an unsupported MIME type", content_type);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
static const gchar *valid_mp4_content_types[] = {
|
|
"video/mp4;codecs=\"avc1.4d001e\"", // H.264 Main Profile level 3.0
|
|
"video/mp4;codecs=\"avc1.42001e\"", // H.264 Baseline Profile level 3.0
|
|
"audio/mp4;codecs=\"mp4a.40.2\"", // MPEG4 AAC-LC
|
|
"audio/mp4;codecs=\"mp4a.40.5\"", // MPEG4 HE-AAC
|
|
"audio/mp4;codecs=\"mp4a.67\"", // MPEG2 AAC-LC
|
|
"video/mp4;codecs=\"mp4a.40.2\"",
|
|
"video/mp4;codecs=\"avc1.4d001e,mp4a.40.2\"",
|
|
"video/mp4;codecs=\"mp4a.40.2 , avc1.4d001e \"",
|
|
"video/mp4;codecs=\"avc1.4d001e,mp4a.40.5\"",
|
|
"audio/mp4;codecs=\"Opus\"",
|
|
"video/mp4;codecs=\"Opus\"",
|
|
"audio/mp4;codecs=\"fLaC\"",
|
|
"video/mp4;codecs=\"fLaC\"",
|
|
};
|
|
|
|
GST_START_TEST (test_media_source_supported_mp4_content_type)
|
|
{
|
|
const gchar *content_type = valid_mp4_content_types[__i__];
|
|
ck_assert_msg (gst_media_source_is_type_supported (content_type),
|
|
"%s must be a supported MP4 content type", content_type);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
static const gchar *valid_webm_content_types[] = {
|
|
"video/webm;codecs=\"vp8\"",
|
|
"video/webm;codecs=\"vorbis\"",
|
|
"video/webm;codecs=\"vp8,vorbis\"",
|
|
"video/webm;codecs=\"vorbis, vp8\"",
|
|
"audio/webm;codecs=\"vorbis\"",
|
|
"AUDIO/WEBM;CODECS=\"vorbis\"",
|
|
"audio/webm;codecs=vorbis;test=\"6\"",
|
|
"audio/webm;codecs=\"opus\"",
|
|
"video/webm;codecs=\"opus\"",
|
|
};
|
|
|
|
GST_START_TEST (test_media_source_supported_webm_content_type)
|
|
{
|
|
const gchar *content_type = valid_webm_content_types[__i__];
|
|
ck_assert_msg (gst_media_source_is_type_supported (content_type),
|
|
"%s must be a supported WebM content type", content_type);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (test_sample_map_create_and_destroy)
|
|
{
|
|
GstMediaSourceSampleMap *map = gst_media_source_sample_map_new ();
|
|
gst_check_object_destroyed_on_unref (map);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (test_sample_map_add_valid_sample)
|
|
{
|
|
GstMediaSourceSampleMap *map = gst_media_source_sample_map_new ();
|
|
|
|
GstSample *sample = new_empty_sample_with_timing (0, 0, 0);
|
|
|
|
fail_if (gst_media_source_sample_map_contains (map, sample));
|
|
|
|
gst_media_source_sample_map_add (map, sample);
|
|
|
|
fail_unless (gst_media_source_sample_map_contains (map, sample));
|
|
|
|
gst_object_unref (map);
|
|
gst_sample_unref (sample);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (test_sample_map_add_invalid_sample)
|
|
{
|
|
add_log_filter (G_LOG_LEVEL_CRITICAL,
|
|
"^.*_sample_map_add: assertion .* failed");
|
|
|
|
GstMediaSourceSampleMap *map = gst_media_source_sample_map_new ();
|
|
|
|
GstSample *sample = new_empty_sample_with_timing (GST_CLOCK_TIME_NONE,
|
|
GST_CLOCK_STIME_NONE, GST_CLOCK_TIME_NONE);
|
|
|
|
gst_media_source_sample_map_add (map, sample);
|
|
|
|
fail_if (gst_media_source_sample_map_contains (map, sample));
|
|
|
|
gst_object_unref (map);
|
|
gst_sample_unref (sample);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (test_sample_map_remove_sample)
|
|
{
|
|
GstMediaSourceSampleMap *map = gst_media_source_sample_map_new ();
|
|
|
|
GstSample *sample = new_empty_sample_with_timing (0, 0, 0);
|
|
gst_media_source_sample_map_add (map, sample);
|
|
|
|
gst_media_source_sample_map_remove (map, sample);
|
|
|
|
fail_if (gst_media_source_sample_map_contains (map, sample));
|
|
|
|
gst_object_unref (map);
|
|
gst_sample_unref (sample);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (test_sample_map_remove_range_from_start)
|
|
{
|
|
GstMediaSourceSampleMap *map = gst_media_source_sample_map_new ();
|
|
|
|
GstSample *samples_to_remove[100] = { NULL };
|
|
for (guint i = 0; i < G_N_ELEMENTS (samples_to_remove); i++) {
|
|
GstClockTime time = i;
|
|
GstSample *sample = new_empty_sample_with_timing (time, time, 1);
|
|
gst_media_source_sample_map_add (map, sample);
|
|
samples_to_remove[i] = sample;
|
|
}
|
|
GstSample *samples_to_preserve[100] = { NULL };
|
|
for (guint i = 0; i < G_N_ELEMENTS (samples_to_preserve); i++) {
|
|
GstClockTime time = i + G_N_ELEMENTS (samples_to_remove);
|
|
GstSample *sample = new_empty_sample_with_timing (time, time, 0);
|
|
gst_media_source_sample_map_add (map, sample);
|
|
samples_to_preserve[i] = sample;
|
|
}
|
|
|
|
gst_media_source_sample_map_remove_range_from_start (map, 100);
|
|
|
|
for (guint i = 0; i < G_N_ELEMENTS (samples_to_remove); i++) {
|
|
GstSample *sample = samples_to_remove[i];
|
|
fail_if (gst_media_source_sample_map_contains (map, sample));
|
|
gst_sample_unref (sample);
|
|
}
|
|
for (guint i = 0; i < G_N_ELEMENTS (samples_to_preserve); i++) {
|
|
GstSample *sample = samples_to_preserve[i];
|
|
fail_unless (gst_media_source_sample_map_contains (map, sample));
|
|
gst_sample_unref (sample);
|
|
}
|
|
|
|
gst_object_unref (map);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (test_sample_map_remove_range_from_start_byte_count)
|
|
{
|
|
GstMediaSourceSampleMap *map = gst_media_source_sample_map_new ();
|
|
|
|
GstSample *samples_to_remove[100] = { NULL };
|
|
const guint8 chunk[1000] = { 0 };
|
|
gsize total_bytes_to_remove = 0;
|
|
for (guint i = 0; i < G_N_ELEMENTS (samples_to_remove); i++) {
|
|
GstClockTime time = i;
|
|
gsize buffer_size = g_random_int_range (0, G_N_ELEMENTS (chunk));
|
|
GBytes *bytes = g_bytes_new_static (chunk, buffer_size);
|
|
total_bytes_to_remove += buffer_size;
|
|
GstSample *sample = new_sample_with_bytes_and_timing (bytes, time, time, 1);
|
|
gst_media_source_sample_map_add (map, sample);
|
|
samples_to_remove[i] = sample;
|
|
}
|
|
GstSample *samples_to_preserve[100] = { NULL };
|
|
for (guint i = 0; i < G_N_ELEMENTS (samples_to_preserve); i++) {
|
|
GstClockTime time = i + G_N_ELEMENTS (samples_to_remove);
|
|
GBytes *bytes = g_bytes_new_static (chunk, 1);
|
|
GstSample *sample = new_sample_with_bytes_and_timing (bytes, time, time, 0);
|
|
gst_media_source_sample_map_add (map, sample);
|
|
samples_to_preserve[i] = sample;
|
|
}
|
|
|
|
gsize bytes_removed =
|
|
gst_media_source_sample_map_remove_range_from_start (map,
|
|
G_N_ELEMENTS (samples_to_remove));
|
|
fail_unless_equals_uint64 (bytes_removed, total_bytes_to_remove);
|
|
|
|
for (guint i = 0; i < G_N_ELEMENTS (samples_to_remove); i++) {
|
|
gst_sample_unref (samples_to_remove[i]);
|
|
}
|
|
for (guint i = 0; i < G_N_ELEMENTS (samples_to_preserve); i++) {
|
|
gst_sample_unref (samples_to_preserve[i]);
|
|
}
|
|
|
|
gst_object_unref (map);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
#define DEFAULT_TCASE_TIMEOUT 15
|
|
|
|
#ifdef HAVE_VALGRIND
|
|
#define TCASE_TIMEOUT (RUNNING_ON_VALGRIND ? (5 * 60) : DEFAULT_TCASE_TIMEOUT)
|
|
#else
|
|
#define TCASE_TIMEOUT DEFAULT_TCASE_TIMEOUT
|
|
#endif
|
|
|
|
static inline TCase *
|
|
new_tcase (const gchar * name)
|
|
{
|
|
TCase *tcase = tcase_create (name);
|
|
tcase_set_timeout (tcase, TCASE_TIMEOUT);
|
|
return tcase;
|
|
}
|
|
|
|
static Suite *
|
|
mse_suite (void)
|
|
{
|
|
Suite *s = suite_create ("GstMse");
|
|
|
|
TCase *tc_media_source = new_tcase ("GstMediaSource");
|
|
TCase *tc_source_buffer = new_tcase ("GstSourceBuffer");
|
|
TCase *tc_source_buffer_list = new_tcase ("GstSourceBufferList");
|
|
TCase *tc_append_pipeline = new_tcase ("GstAppendPipeline");
|
|
TCase *tc_track = new_tcase ("GstMediaSourceTrack");
|
|
TCase *tc_track_buffer = new_tcase ("GstMediaSourceTrackBuffer");
|
|
TCase *tc_sample_map = new_tcase ("GstMediaSourceSampleMap");
|
|
|
|
tcase_add_test (tc_media_source, test_create_and_free);
|
|
tcase_add_test (tc_media_source, test_create_initial_state);
|
|
tcase_add_test (tc_media_source,
|
|
test_add_source_buffer_with_content_type_null);
|
|
tcase_add_test (tc_media_source,
|
|
test_add_source_buffer_with_content_type_empty);
|
|
tcase_add_test (tc_media_source,
|
|
test_add_source_buffer_with_content_type_fake);
|
|
tcase_add_test (tc_media_source,
|
|
test_add_source_buffer_to_unopened_media_source);
|
|
tcase_add_test (tc_media_source,
|
|
test_add_source_buffer_to_opened_media_source);
|
|
tcase_add_test (tc_media_source,
|
|
test_remove_source_buffer_from_unrelated_media_source);
|
|
tcase_add_test (tc_media_source,
|
|
test_remove_source_buffer_from_parent_media_source);
|
|
tcase_add_test (tc_media_source,
|
|
test_set_live_seekable_range_on_unopened_media_source);
|
|
tcase_add_test (tc_media_source,
|
|
test_set_backwards_live_seekable_range_on_opened_media_source);
|
|
tcase_add_test (tc_media_source,
|
|
test_set_live_seekable_range_on_opened_media_source);
|
|
tcase_add_test (tc_media_source,
|
|
test_clear_live_seekable_range_on_unopened_media_source);
|
|
tcase_add_test (tc_media_source,
|
|
test_clear_live_seekable_range_on_opened_media_source);
|
|
tcase_add_loop_test (tc_media_source,
|
|
test_media_source_unsupported_content_type,
|
|
0, G_N_ELEMENTS (unsupported_content_types));
|
|
tcase_add_loop_test (tc_media_source,
|
|
test_media_source_supported_mp4_content_type,
|
|
0, G_N_ELEMENTS (valid_mp4_content_types));
|
|
tcase_add_loop_test (tc_media_source,
|
|
test_media_source_supported_webm_content_type,
|
|
0, G_N_ELEMENTS (valid_webm_content_types));
|
|
|
|
tcase_add_test (tc_source_buffer, test_source_buffer_generate_timestamps_mp4);
|
|
tcase_add_test (tc_source_buffer, test_source_buffer_generate_timestamps_aac);
|
|
|
|
tcase_add_test (tc_source_buffer,
|
|
test_source_buffer_change_content_type_null);
|
|
tcase_add_test (tc_source_buffer,
|
|
test_source_buffer_change_content_type_empty);
|
|
tcase_add_test (tc_source_buffer, test_source_buffer_change_content_type);
|
|
|
|
tcase_add_test (tc_append_pipeline, test_append_pipeline_create_and_free);
|
|
tcase_add_test (tc_append_pipeline, test_append_pipeline_mp4);
|
|
tcase_add_test (tc_append_pipeline, test_append_pipeline_webm);
|
|
tcase_add_test (tc_append_pipeline,
|
|
test_append_pipeline_invalid_data_triggers_eos);
|
|
tcase_add_test (tc_append_pipeline,
|
|
test_append_pipeline_invalid_data_triggers_error);
|
|
tcase_add_test (tc_append_pipeline, test_append_pipeline_reset_recovery);
|
|
|
|
tcase_add_test (tc_track, test_track_create_and_free);
|
|
tcase_add_test (tc_track, test_track_create_with_invalid_type);
|
|
tcase_add_test (tc_track, test_track_push_with_adequate_space);
|
|
tcase_add_test (tc_track, test_track_push_with_inadequate_space);
|
|
|
|
tcase_add_test (tc_track_buffer, test_track_buffer_empty);
|
|
tcase_add_test (tc_track_buffer, test_track_buffer_single_span);
|
|
tcase_add_test (tc_track_buffer, test_track_buffer_continuous_span);
|
|
tcase_add_test (tc_track_buffer, test_track_buffer_discontinuous_span);
|
|
|
|
tcase_add_test (tc_sample_map, test_sample_map_create_and_destroy);
|
|
tcase_add_test (tc_sample_map, test_sample_map_add_valid_sample);
|
|
tcase_add_test (tc_sample_map, test_sample_map_add_invalid_sample);
|
|
tcase_add_test (tc_sample_map, test_sample_map_remove_sample);
|
|
tcase_add_test (tc_sample_map, test_sample_map_remove_range_from_start);
|
|
tcase_add_test (tc_sample_map,
|
|
test_sample_map_remove_range_from_start_byte_count);
|
|
|
|
suite_add_tcase (s, tc_media_source);
|
|
suite_add_tcase (s, tc_source_buffer);
|
|
suite_add_tcase (s, tc_source_buffer_list);
|
|
suite_add_tcase (s, tc_append_pipeline);
|
|
suite_add_tcase (s, tc_track);
|
|
suite_add_tcase (s, tc_track_buffer);
|
|
suite_add_tcase (s, tc_sample_map);
|
|
|
|
return s;
|
|
}
|
|
|
|
GST_CHECK_MAIN (mse)
|