mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-20 23:36:38 +00:00
5c99f9cf37
This is a C99 feature.
535 lines
18 KiB
C
535 lines
18 KiB
C
/* A set of utility functions that are common between elements
|
|
* based upon GstAdaptiveDemux
|
|
*
|
|
* Copyright (c) <2015> YouView TV 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.
|
|
*/
|
|
|
|
#include <gst/check/gstcheck.h>
|
|
#include "adaptive_demux_engine.h"
|
|
#include "adaptive_demux_common.h"
|
|
|
|
#define GST_TEST_HTTP_SRC_NAME "testhttpsrc"
|
|
|
|
#define gst_adaptive_demux_test_case_parent_class parent_class
|
|
|
|
static void gst_adaptive_demux_test_case_dispose (GObject * object);
|
|
static void gst_adaptive_demux_test_case_finalize (GObject * object);
|
|
static void gst_adaptive_demux_test_case_clear (GstAdaptiveDemuxTestCase *
|
|
testData);
|
|
|
|
G_DEFINE_TYPE (GstAdaptiveDemuxTestCase, gst_adaptive_demux_test_case,
|
|
G_TYPE_OBJECT);
|
|
|
|
static void
|
|
gst_adaptive_demux_test_case_class_init (GstAdaptiveDemuxTestCaseClass * klass)
|
|
{
|
|
GObjectClass *object = G_OBJECT_CLASS (klass);
|
|
|
|
object->dispose = gst_adaptive_demux_test_case_dispose;
|
|
object->finalize = gst_adaptive_demux_test_case_finalize;
|
|
}
|
|
|
|
static void
|
|
gst_adaptive_demux_test_case_init (GstAdaptiveDemuxTestCase * testData)
|
|
{
|
|
testData->output_streams = NULL;
|
|
testData->test_task = NULL;
|
|
g_rec_mutex_init (&testData->test_task_lock);
|
|
g_mutex_init (&testData->test_task_state_lock);
|
|
g_cond_init (&testData->test_task_state_cond);
|
|
gst_adaptive_demux_test_case_clear (testData);
|
|
}
|
|
|
|
static void
|
|
gst_adaptive_demux_test_case_clear (GstAdaptiveDemuxTestCase * testData)
|
|
{
|
|
if (testData->output_streams) {
|
|
g_list_free (testData->output_streams);
|
|
testData->output_streams = NULL;
|
|
}
|
|
testData->count_of_finished_streams = 0;
|
|
if (testData->test_task) {
|
|
gst_task_stop (testData->test_task);
|
|
gst_task_join (testData->test_task);
|
|
gst_object_unref (testData->test_task);
|
|
testData->test_task = NULL;
|
|
}
|
|
testData->signal_context = NULL;
|
|
testData->test_task_state = TEST_TASK_STATE_NOT_STARTED;
|
|
testData->threshold_for_seek = 0;
|
|
gst_event_replace (&testData->seek_event, NULL);
|
|
testData->signal_context = NULL;
|
|
}
|
|
|
|
|
|
static void
|
|
gst_adaptive_demux_test_case_dispose (GObject * object)
|
|
{
|
|
GstAdaptiveDemuxTestCase *testData = GST_ADAPTIVE_DEMUX_TEST_CASE (object);
|
|
|
|
gst_adaptive_demux_test_case_clear (testData);
|
|
|
|
GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
|
|
}
|
|
|
|
static void
|
|
gst_adaptive_demux_test_case_finalize (GObject * object)
|
|
{
|
|
GstAdaptiveDemuxTestCase *testData = GST_ADAPTIVE_DEMUX_TEST_CASE (object);
|
|
|
|
g_cond_clear (&testData->test_task_state_cond);
|
|
g_mutex_clear (&testData->test_task_state_lock);
|
|
g_rec_mutex_clear (&testData->test_task_lock);
|
|
if (testData->test_task) {
|
|
gst_task_stop (testData->test_task);
|
|
gst_task_join (testData->test_task);
|
|
gst_object_unref (testData->test_task);
|
|
testData->test_task = NULL;
|
|
}
|
|
if (testData->output_streams) {
|
|
g_list_free (testData->output_streams);
|
|
testData->output_streams = NULL;
|
|
}
|
|
|
|
GST_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
|
|
}
|
|
|
|
/**
|
|
* gst_adaptive_demux_test_case_new:
|
|
*
|
|
* Creates a new #GstAdaptiveDemuxTestCase. Free with g_object_unref().
|
|
*
|
|
* Returns: (transfer full): a new #GstAdaptiveDemuxTestCase
|
|
*/
|
|
GstAdaptiveDemuxTestCase *
|
|
gst_adaptive_demux_test_case_new (void)
|
|
{
|
|
return g_object_newv (GST_TYPE_ADAPTIVE_DEMUX_TEST_CASE, 0, NULL);
|
|
}
|
|
|
|
|
|
GstAdaptiveDemuxTestExpectedOutput *
|
|
gst_adaptive_demux_test_find_test_data_by_stream (GstAdaptiveDemuxTestCase *
|
|
testData, GstAdaptiveDemuxTestOutputStream * stream, guint * index)
|
|
{
|
|
gchar *pad_name;
|
|
GstAdaptiveDemuxTestExpectedOutput *ret = NULL;
|
|
guint count = 0;
|
|
|
|
pad_name = gst_pad_get_name (stream->pad);
|
|
fail_unless (pad_name != NULL);
|
|
for (GList * walk = testData->output_streams; walk; walk = g_list_next (walk)) {
|
|
GstAdaptiveDemuxTestExpectedOutput *td = walk->data;
|
|
if (strcmp (td->name, pad_name) == 0) {
|
|
ret = td;
|
|
if (index)
|
|
*index = count;
|
|
}
|
|
++count;
|
|
}
|
|
g_free (pad_name);
|
|
return ret;
|
|
}
|
|
|
|
/* function to validate data received by AppSink */
|
|
gboolean
|
|
gst_adaptive_demux_test_check_received_data (GstAdaptiveDemuxTestEngine *
|
|
engine, GstAdaptiveDemuxTestOutputStream * stream, GstBuffer * buffer,
|
|
gpointer user_data)
|
|
{
|
|
GstMapInfo info;
|
|
guint pattern;
|
|
guint64 streamOffset;
|
|
GstAdaptiveDemuxTestCase *testData = GST_ADAPTIVE_DEMUX_TEST_CASE (user_data);
|
|
GstAdaptiveDemuxTestExpectedOutput *testOutputStreamData;
|
|
guint64 i;
|
|
|
|
fail_unless (stream != NULL);
|
|
fail_unless (engine->pipeline != NULL);
|
|
testOutputStreamData =
|
|
gst_adaptive_demux_test_find_test_data_by_stream (testData, stream, NULL);
|
|
fail_unless (testOutputStreamData != NULL);
|
|
|
|
GST_DEBUG
|
|
("total_received_size=%" G_GUINT64_FORMAT
|
|
" segment_received_size = %" G_GUINT64_FORMAT
|
|
" buffer_size=%" G_GUINT64_FORMAT
|
|
" expected_size=%" G_GUINT64_FORMAT
|
|
" segment_start = %" G_GUINT64_FORMAT,
|
|
stream->total_received_size,
|
|
stream->segment_received_size,
|
|
(guint64) gst_buffer_get_size (buffer),
|
|
testOutputStreamData->expected_size, stream->segment_start);
|
|
|
|
/* Only verify after seeking */
|
|
if (testData->seek_event && testData->seeked)
|
|
fail_unless (stream->total_received_size +
|
|
stream->segment_received_size +
|
|
gst_buffer_get_size (buffer) <= testOutputStreamData->expected_size,
|
|
"Received unexpected data, please check what segments are being downloaded");
|
|
|
|
streamOffset = stream->segment_start + stream->segment_received_size;
|
|
if (testOutputStreamData->expected_data) {
|
|
gsize size = gst_buffer_get_size (buffer);
|
|
if (gst_buffer_memcmp (buffer, 0,
|
|
&testOutputStreamData->expected_data[streamOffset], size) == 0) {
|
|
return TRUE;
|
|
}
|
|
/* If buffers do not match, fall back to a slower byte-based check
|
|
so that the test can output the position where the received data
|
|
diverges from expected_data
|
|
*/
|
|
}
|
|
|
|
gst_buffer_map (buffer, &info, GST_MAP_READ);
|
|
|
|
pattern = streamOffset - streamOffset % sizeof (pattern);
|
|
for (i = 0; i != info.size; ++i) {
|
|
guint received = info.data[i];
|
|
guint expected;
|
|
|
|
if (testOutputStreamData->expected_data) {
|
|
fail_unless (streamOffset + i < testOutputStreamData->expected_size);
|
|
expected = testOutputStreamData->expected_data[streamOffset + i];
|
|
} else {
|
|
gchar pattern_byte_to_read;
|
|
|
|
pattern_byte_to_read = (streamOffset + i) % sizeof (pattern);
|
|
if (pattern_byte_to_read == 0) {
|
|
pattern = streamOffset + i;
|
|
}
|
|
|
|
expected = (pattern >> (pattern_byte_to_read * 8)) & 0xFF;
|
|
#if 0
|
|
GST_DEBUG
|
|
("received '0x%02x' expected '0x%02x' offset %" G_GUINT64_FORMAT
|
|
" pattern=%08x byte_to_read=%d",
|
|
received, expected, i, pattern, pattern_byte_to_read);
|
|
#endif
|
|
}
|
|
|
|
fail_unless (received == expected,
|
|
"output validation failed: received '0x%02x' expected '0x%02x' byte %"
|
|
G_GUINT64_FORMAT " offset=%" G_GUINT64_FORMAT "\n", received, expected,
|
|
i, streamOffset);
|
|
}
|
|
|
|
gst_buffer_unmap (buffer, &info);
|
|
return TRUE;
|
|
}
|
|
|
|
/* AppSink EOS callback.
|
|
* To be used by tests that don't expect AppSink to receive EOS.
|
|
*/
|
|
void
|
|
gst_adaptive_demux_test_unexpected_eos (GstAdaptiveDemuxTestEngine *
|
|
engine, GstAdaptiveDemuxTestOutputStream * stream, gpointer user_data)
|
|
{
|
|
fail_if (TRUE);
|
|
}
|
|
|
|
/* AppSink EOS callback.
|
|
* To be used by tests that expect AppSink to receive EOS.
|
|
* Will check total size of data received by AppSink.
|
|
*/
|
|
void
|
|
gst_adaptive_demux_test_check_size_of_received_data (GstAdaptiveDemuxTestEngine
|
|
* engine, GstAdaptiveDemuxTestOutputStream * stream, gpointer user_data)
|
|
{
|
|
GstAdaptiveDemuxTestCase *testData = GST_ADAPTIVE_DEMUX_TEST_CASE (user_data);
|
|
GstAdaptiveDemuxTestExpectedOutput *testOutputStreamData;
|
|
|
|
testOutputStreamData =
|
|
gst_adaptive_demux_test_find_test_data_by_stream (testData, stream, NULL);
|
|
fail_unless (testOutputStreamData != NULL);
|
|
|
|
fail_unless (stream->total_received_size ==
|
|
testOutputStreamData->expected_size,
|
|
"size validation failed, expected %d received %d",
|
|
testOutputStreamData->expected_size, stream->total_received_size);
|
|
testData->count_of_finished_streams++;
|
|
if (testData->count_of_finished_streams ==
|
|
g_list_length (testData->output_streams)) {
|
|
g_main_loop_quit (engine->loop);
|
|
}
|
|
}
|
|
|
|
typedef struct _SeekTaskContext
|
|
{
|
|
GstElement *pipeline;
|
|
GstTask *task;
|
|
GstEvent *seek_event;
|
|
} SeekTaskContext;
|
|
|
|
/* function to generate a seek event. Will be run in a separate thread */
|
|
static void
|
|
testSeekTaskDoSeek (gpointer user_data)
|
|
{
|
|
SeekTaskContext *context = (SeekTaskContext *) user_data;
|
|
GstTask *task;
|
|
|
|
GST_DEBUG ("testSeekTaskDoSeek calling seek");
|
|
|
|
fail_unless (GST_IS_EVENT (context->seek_event));
|
|
fail_unless (GST_EVENT_TYPE (context->seek_event) == GST_EVENT_SEEK);
|
|
|
|
if (!gst_element_send_event (GST_ELEMENT (context->pipeline),
|
|
context->seek_event))
|
|
fail ("Seek failed!\n");
|
|
GST_DEBUG ("seek ok");
|
|
task = context->task;
|
|
g_slice_free (SeekTaskContext, context);
|
|
gst_task_stop (task);
|
|
}
|
|
|
|
/* function to be called during seek test when demux sends data to AppSink
|
|
* It monitors the data sent and after a while will generate a seek request.
|
|
*/
|
|
static gboolean
|
|
testSeekAdaptiveDemuxSendsData (GstAdaptiveDemuxTestEngine * engine,
|
|
GstAdaptiveDemuxTestOutputStream * stream,
|
|
GstBuffer * buffer, gpointer user_data)
|
|
{
|
|
GstAdaptiveDemuxTestCase *testData = GST_ADAPTIVE_DEMUX_TEST_CASE (user_data);
|
|
SeekTaskContext *seekContext;
|
|
GstAdaptiveDemuxTestExpectedOutput *testOutputStreamData;
|
|
guint index = 0;
|
|
|
|
testOutputStreamData =
|
|
gst_adaptive_demux_test_find_test_data_by_stream (testData, stream,
|
|
&index);
|
|
fail_unless (testOutputStreamData != NULL);
|
|
/* first entry in testData->output_streams is the
|
|
PAD on which to perform the seek */
|
|
if (index == 0 &&
|
|
testData->test_task == NULL &&
|
|
(stream->total_received_size + stream->segment_received_size) >=
|
|
testData->threshold_for_seek) {
|
|
GstSeekFlags seek_flags;
|
|
|
|
testData->threshold_for_seek =
|
|
stream->total_received_size + stream->segment_received_size;
|
|
|
|
gst_event_parse_seek (testData->seek_event, NULL, NULL, &seek_flags, NULL,
|
|
NULL, NULL, NULL);
|
|
if (seek_flags & GST_SEEK_FLAG_FLUSH)
|
|
testOutputStreamData->expected_size += testData->threshold_for_seek;
|
|
|
|
GST_DEBUG ("starting seek task");
|
|
|
|
g_mutex_lock (&testData->test_task_state_lock);
|
|
testData->test_task_state =
|
|
TEST_TASK_STATE_WAITING_FOR_TESTSRC_STATE_CHANGE;
|
|
g_mutex_unlock (&testData->test_task_state_lock);
|
|
|
|
seekContext = g_slice_new (SeekTaskContext);
|
|
seekContext->pipeline = engine->pipeline;
|
|
seekContext->seek_event = gst_event_ref (testData->seek_event);
|
|
testData->test_task = seekContext->task =
|
|
gst_task_new ((GstTaskFunction) testSeekTaskDoSeek, seekContext, NULL);
|
|
gst_task_set_lock (testData->test_task, &testData->test_task_lock);
|
|
gst_task_start (testData->test_task);
|
|
|
|
GST_DEBUG ("seek task started");
|
|
|
|
if (seek_flags & GST_SEEK_FLAG_FLUSH) {
|
|
g_mutex_lock (&testData->test_task_state_lock);
|
|
|
|
GST_DEBUG ("waiting for seek task to change state on testsrc");
|
|
|
|
/* wait for test_task to run, send a flush start event to AppSink
|
|
* and change the testhttpsrc element state from PLAYING to PAUSED
|
|
*/
|
|
while (testData->test_task_state ==
|
|
TEST_TASK_STATE_WAITING_FOR_TESTSRC_STATE_CHANGE) {
|
|
g_cond_wait (&testData->test_task_state_cond,
|
|
&testData->test_task_state_lock);
|
|
}
|
|
testData->seeked = TRUE;
|
|
g_mutex_unlock (&testData->test_task_state_lock);
|
|
/* we can continue now, but this buffer will be rejected by AppSink
|
|
* because it is in flushing mode
|
|
*/
|
|
GST_DEBUG ("seek task changed state on testsrc, resuming");
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
testSeekAdaptiveAppSinkEvent (GstAdaptiveDemuxTestEngine * engine,
|
|
GstAdaptiveDemuxTestOutputStream * stream,
|
|
GstEvent * event, gpointer user_data)
|
|
{
|
|
GstAdaptiveDemuxTestCase *testData = GST_ADAPTIVE_DEMUX_TEST_CASE (user_data);
|
|
GstAdaptiveDemuxTestExpectedOutput *testOutputStreamData;
|
|
guint index = 0;
|
|
|
|
testOutputStreamData =
|
|
gst_adaptive_demux_test_find_test_data_by_stream (testData, stream,
|
|
&index);
|
|
fail_unless (testOutputStreamData != NULL);
|
|
|
|
if (testData->seek_event && GST_EVENT_TYPE (event) == GST_EVENT_SEGMENT
|
|
&& testOutputStreamData->post_seek_segment.format != GST_FORMAT_UNDEFINED
|
|
&& gst_event_get_seqnum (event) ==
|
|
gst_event_get_seqnum (testData->seek_event)) {
|
|
const GstSegment *seek_segment;
|
|
|
|
|
|
gst_event_parse_segment (event, &seek_segment);
|
|
fail_unless (seek_segment->format ==
|
|
testOutputStreamData->post_seek_segment.format);
|
|
fail_unless (seek_segment->rate ==
|
|
testOutputStreamData->post_seek_segment.rate);
|
|
fail_unless (seek_segment->start ==
|
|
testOutputStreamData->post_seek_segment.start);
|
|
fail_unless (seek_segment->stop ==
|
|
testOutputStreamData->post_seek_segment.stop);
|
|
fail_unless (seek_segment->base ==
|
|
testOutputStreamData->post_seek_segment.base);
|
|
fail_unless (seek_segment->time ==
|
|
testOutputStreamData->post_seek_segment.time);
|
|
|
|
testOutputStreamData->segment_verification_needed = FALSE;
|
|
}
|
|
}
|
|
|
|
/* callback called when main_loop detects a state changed event */
|
|
static void
|
|
testSeekOnStateChanged (GstBus * bus, GstMessage * msg, gpointer user_data)
|
|
{
|
|
GstAdaptiveDemuxTestCase *testData = GST_ADAPTIVE_DEMUX_TEST_CASE (user_data);
|
|
GstState old_state, new_state;
|
|
const char *srcName = GST_OBJECT_NAME (msg->src);
|
|
|
|
gst_message_parse_state_changed (msg, &old_state, &new_state, NULL);
|
|
GST_DEBUG ("Element %s changed state from %s to %s",
|
|
GST_OBJECT_NAME (msg->src),
|
|
gst_element_state_get_name (old_state),
|
|
gst_element_state_get_name (new_state));
|
|
|
|
if (strstr (srcName, "srcbin") == srcName &&
|
|
old_state == GST_STATE_PLAYING && new_state == GST_STATE_PAUSED) {
|
|
g_mutex_lock (&testData->test_task_state_lock);
|
|
if (testData->test_task_state ==
|
|
TEST_TASK_STATE_WAITING_FOR_TESTSRC_STATE_CHANGE) {
|
|
GST_DEBUG ("changing test_task_state");
|
|
testData->test_task_state = TEST_TASK_STATE_EXITING;
|
|
gst_bus_remove_signal_watch (bus);
|
|
g_cond_signal (&testData->test_task_state_cond);
|
|
}
|
|
g_mutex_unlock (&testData->test_task_state_lock);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Issue a seek request after media segment has started to be downloaded
|
|
* on the first pad listed in GstAdaptiveDemuxTestOutputStreamData and the
|
|
* first chunk of at least one byte has already arrived in AppSink
|
|
*/
|
|
static void
|
|
testSeekPreTestCallback (GstAdaptiveDemuxTestEngine * engine,
|
|
gpointer user_data)
|
|
{
|
|
GstAdaptiveDemuxTestCase *testData = GST_ADAPTIVE_DEMUX_TEST_CASE (user_data);
|
|
GstBus *bus;
|
|
|
|
/* register a callback to listen for state change events */
|
|
bus = gst_pipeline_get_bus (GST_PIPELINE (engine->pipeline));
|
|
gst_bus_add_signal_watch (bus);
|
|
g_signal_connect (bus, "message::state-changed",
|
|
G_CALLBACK (testSeekOnStateChanged), testData);
|
|
gst_object_unref (bus);
|
|
}
|
|
|
|
static void
|
|
testSeekPostTestCallback (GstAdaptiveDemuxTestEngine * engine,
|
|
gpointer user_data)
|
|
{
|
|
GstAdaptiveDemuxTestCase *testData = GST_ADAPTIVE_DEMUX_TEST_CASE (user_data);
|
|
for (GList * walk = testData->output_streams; walk; walk = g_list_next (walk)) {
|
|
GstAdaptiveDemuxTestExpectedOutput *td = walk->data;
|
|
|
|
fail_if (td->segment_verification_needed);
|
|
}
|
|
}
|
|
|
|
/* function to check total size of data received by AppSink
|
|
* will be called when AppSink receives eos.
|
|
*/
|
|
void gst_adaptive_demux_test_download_error_size_of_received_data
|
|
(GstAdaptiveDemuxTestEngine * engine,
|
|
GstAdaptiveDemuxTestOutputStream * stream, gpointer user_data)
|
|
{
|
|
GstAdaptiveDemuxTestCase *testData = GST_ADAPTIVE_DEMUX_TEST_CASE (user_data);
|
|
GstAdaptiveDemuxTestExpectedOutput *testOutputStreamData;
|
|
|
|
testOutputStreamData =
|
|
gst_adaptive_demux_test_find_test_data_by_stream (testData, stream, NULL);
|
|
fail_unless (testOutputStreamData != NULL);
|
|
/* expect to receive more than 0 */
|
|
fail_unless (stream->total_received_size > 0,
|
|
"size validation failed for %s, expected > 0, received %d",
|
|
testOutputStreamData->name, stream->total_received_size);
|
|
|
|
/* expect to receive less than file size */
|
|
fail_unless (stream->total_received_size <
|
|
testOutputStreamData->expected_size,
|
|
"size validation failed for %s, expected < %d received %d",
|
|
testOutputStreamData->name, testOutputStreamData->expected_size,
|
|
stream->total_received_size);
|
|
if (testData->count_of_finished_streams ==
|
|
g_list_length (testData->output_streams)) {
|
|
g_main_loop_quit (engine->loop);
|
|
}
|
|
}
|
|
|
|
void
|
|
gst_adaptive_demux_test_seek (const gchar * element_name,
|
|
const gchar * manifest_uri, GstAdaptiveDemuxTestCase * testData)
|
|
{
|
|
GstAdaptiveDemuxTestCallbacks cb = { 0 };
|
|
cb.appsink_received_data = gst_adaptive_demux_test_check_received_data;
|
|
cb.appsink_eos = gst_adaptive_demux_test_check_size_of_received_data;
|
|
cb.appsink_event = testSeekAdaptiveAppSinkEvent;
|
|
cb.pre_test = testSeekPreTestCallback;
|
|
cb.post_test = testSeekPostTestCallback;
|
|
cb.demux_sent_data = testSeekAdaptiveDemuxSendsData;
|
|
gst_adaptive_demux_test_run (element_name, manifest_uri, &cb, testData);
|
|
/* the call to g_object_unref of testData will clean up the seek task */
|
|
}
|
|
|
|
void
|
|
gst_adaptive_demux_test_setup (void)
|
|
{
|
|
GstRegistry *registry;
|
|
gboolean ret;
|
|
|
|
registry = gst_registry_get ();
|
|
ret = gst_test_http_src_register_plugin (registry, GST_TEST_HTTP_SRC_NAME);
|
|
fail_unless (ret);
|
|
}
|
|
|
|
void
|
|
gst_adaptive_demux_test_teardown (void)
|
|
{
|
|
gst_test_http_src_install_callbacks (NULL, NULL);
|
|
gst_test_http_src_set_default_blocksize (0);
|
|
}
|