diff options
author | Alex Ashley <bugzilla@ashley-family.net> | 2015-11-10 16:41:02 +0000 |
---|---|---|
committer | Thiago Santos <thiagoss@osg.samsung.com> | 2015-12-22 11:15:32 -0300 |
commit | eafdf5673a38537fc41cfdc08c29321810387a39 (patch) | |
tree | bbe0c0cc9bef1bcda2527da991478cbc23ab0117 /tests | |
parent | ae3ed25025e34ea9b09df59d22d7ebd7294560bc (diff) | |
download | gstreamer-plugins-bad-eafdf5673a38537fc41cfdc08c29321810387a39.tar.gz |
hlsdemux: tests: add unit tests for hlsdemux
Using the new GstAdaptiveDemux test framework, add tests that
exercise hlsdemux. The following tests are added:
simpleTest
A simple playlist that contains some media URLs
testMediaPlaylist
A master playlist with a variant playlist that contains media URLs
testMediaPlaylistNotFound
A master playlist that points to a missing variant playlist
testFragmentNotFound
A master playlist with a variant playlist that contains media URLs
There is a missing media file referenced from the variant playlist.
testFragmentDownloadError
A master playlist with a variant playlist that contains media URLs
During the download of one media file, the test simulates the network
connection being dropped.
testSeek
A simple test of trying to perform a seek on an HLS stream.
Diffstat (limited to 'tests')
-rw-r--r-- | tests/check/Makefile.am | 14 | ||||
-rw-r--r-- | tests/check/elements/.gitignore | 1 | ||||
-rw-r--r-- | tests/check/elements/hls_demux.c | 594 |
3 files changed, 607 insertions, 2 deletions
diff --git a/tests/check/Makefile.am b/tests/check/Makefile.am index e558782d9..17ed637f3 100644 --- a/tests/check/Makefile.am +++ b/tests/check/Makefile.am @@ -169,8 +169,10 @@ check_curl_sftp = endif if USE_HLS -check_hlsdemux = elements/hlsdemux_m3u8 +check_hlsdemux_m3u8 = elements/hlsdemux_m3u8 +check_hls_demux = elements/hls_demux else +check_hlsdemux_m3u8 = check_hlsdemux = endif @@ -288,7 +290,8 @@ check_PROGRAMS = \ $(check_orc) \ libs/insertbin \ $(check_gl) \ - $(check_hlsdemux) \ + $(check_hlsdemux_m3u8) \ + $(check_hls_demux) \ $(EXPERIMENTAL_CHECKS) noinst_HEADERS = elements/mxfdemux.h @@ -570,6 +573,13 @@ elements_hlsdemux_m3u8_CFLAGS = $(GST_BASE_CFLAGS) $(AM_CFLAGS) -I$(top_srcdir)/ elements_hlsdemux_m3u8_LDADD = $(GST_BASE_LIBS) $(LDADD) elements_hlsdemux_m3u8_SOURCES = elements/hlsdemux_m3u8.c +elements_hls_demux_CFLAGS = $(GST_BASE_CFLAGS) $(AM_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) $(GST_PLUGINS_BAD_CFLAGS) +elements_hls_demux_LDADD = $(GST_BASE_LIBS) $(LDADD) \ + -lgsttag-$(GST_API_VERSION) \ + -lgstapp-$(GST_API_VERSION) \ + $(top_builddir)/gst-libs/gst/adaptivedemux/libgstadaptivedemux-@GST_API_VERSION@.la +elements_hls_demux_SOURCES = elements/test_http_src.c elements/test_http_src.h elements/adaptive_demux_engine.c elements/adaptive_demux_engine.h elements/adaptive_demux_common.c elements/adaptive_demux_common.h elements/hls_demux.c + orc_compositor_CFLAGS = $(ORC_CFLAGS) orc_compositor_LDADD = $(ORC_LIBS) -lorc-test-0.4 nodist_orc_compositor_SOURCES = orc/compositor.c diff --git a/tests/check/elements/.gitignore b/tests/check/elements/.gitignore index 1a52a03e4..241c44180 100644 --- a/tests/check/elements/.gitignore +++ b/tests/check/elements/.gitignore @@ -26,6 +26,7 @@ glimagesink h263parse h264parse hlsdemux_m3u8 +hls_demux id3mux imagecapturebin jifmux diff --git a/tests/check/elements/hls_demux.c b/tests/check/elements/hls_demux.c new file mode 100644 index 000000000..0918766ad --- /dev/null +++ b/tests/check/elements/hls_demux.c @@ -0,0 +1,594 @@ +/* GStreamer unit test for HLS demux + * + * 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_common.h" + +#define DEMUX_ELEMENT_NAME "hlsdemux" + +#define TS_PACKET_LEN 188 + +typedef struct _GstHlsDemuxTestInputData +{ + const gchar *uri; + const guint8 *payload; + guint64 size; +} GstHlsDemuxTestInputData; + +typedef struct _GstHlsDemuxTestCase +{ + const GstHlsDemuxTestInputData *input; + GstStructure *state; +} GstHlsDemuxTestCase; + +typedef struct _GstHlsDemuxTestAppendUriContext +{ + GQuark field_id; + const gchar *uri; +} GstHlsDemuxTestAppendUriContext; + +typedef struct _GstHlsDemuxTestSelectBitrateContext +{ + GstAdaptiveDemuxTestEngine *engine; + GstAdaptiveDemuxTestCase *testData; + guint select_count; + gulong signal_handle; +} GstHlsDemuxTestSelectBitrateContext; + +static GByteArray * +generate_transport_stream (guint length) +{ + guint pos; + guint cc = 0; + GByteArray *mpeg_ts; + + fail_unless ((length % TS_PACKET_LEN) == 0); + mpeg_ts = g_byte_array_sized_new (length); + if (!mpeg_ts) { + return NULL; + } + memset (mpeg_ts->data, 0xFF, length); + for (pos = 0; pos < length; pos += TS_PACKET_LEN) { + mpeg_ts->data[pos] = 0x47; + mpeg_ts->data[pos + 1] = 0x1F; + mpeg_ts->data[pos + 2] = 0xFF; + mpeg_ts->data[pos + 3] = cc; + cc = (cc + 1) & 0x0F; + } + return mpeg_ts; +} + +static GByteArray * +setup_test_variables (GstHlsDemuxTestInputData * inputTestData, + GstAdaptiveDemuxTestExpectedOutput * outputTestData, + GstHlsDemuxTestCase * hlsTestCase, + GstAdaptiveDemuxTestCase * engineTestData, guint segment_size) +{ + GByteArray *mpeg_ts = NULL; + + if (segment_size) { + mpeg_ts = generate_transport_stream ((segment_size)); + fail_unless (mpeg_ts != NULL); + for (guint itd = 0; inputTestData[itd].uri; ++itd) { + if (g_str_has_suffix (inputTestData[itd].uri, ".ts")) { + inputTestData[itd].payload = mpeg_ts->data; + } + } + for (guint otd = 0; outputTestData[otd].name; ++otd) { + outputTestData[otd].expected_data = mpeg_ts->data; + engineTestData->output_streams = + g_list_append (engineTestData->output_streams, &outputTestData[otd]); + } + } + hlsTestCase->input = inputTestData; + hlsTestCase->state = gst_structure_new_empty (__FUNCTION__); + return mpeg_ts; +} + +#define TESTCASE_INIT_BOILERPLATE(segment_size) \ + GstTestHTTPSrcCallbacks http_src_callbacks = { 0 }; \ + GstAdaptiveDemuxTestCallbacks engine_callbacks = { 0 }; \ + GstAdaptiveDemuxTestCase *engineTestData; \ + GstHlsDemuxTestCase hlsTestCase = { 0 }; \ + GByteArray *mpeg_ts=NULL; \ + engineTestData = gst_adaptive_demux_test_case_new(); \ + fail_unless (engineTestData!=NULL); \ + mpeg_ts = setup_test_variables(inputTestData, outputTestData, \ + &hlsTestCase, engineTestData, segment_size); \ + +#define TESTCASE_UNREF_BOILERPLATE do{ \ + if(engineTestData->signal_context){ \ + g_slice_free (GstHlsDemuxTestSelectBitrateContext, engineTestData->signal_context); \ + } \ + if(mpeg_ts) { g_byte_array_free (mpeg_ts, TRUE); } \ + gst_structure_free (hlsTestCase.state); \ + g_object_unref (engineTestData); \ +} while(0) + +static gboolean +append_request_uri (GQuark field_id, GValue * value, gpointer user_data) +{ + GstHlsDemuxTestAppendUriContext *context = + (GstHlsDemuxTestAppendUriContext *) user_data; + GValue uri_val = G_VALUE_INIT; + + if (context->field_id == field_id) { + g_value_init (&uri_val, G_TYPE_STRING); + g_value_set_string (&uri_val, context->uri); + gst_value_array_append_value (value, &uri_val); + g_value_unset (&uri_val); + } + return TRUE; +} + +static void +gst_hlsdemux_test_set_input_data (const GstHlsDemuxTestCase * test_case, + const GstHlsDemuxTestInputData * input, GstTestHTTPSrcInput * output) +{ + output->size = input->size; + output->context = (gpointer) input; + if (output->size == 0) { + output->size = strlen ((gchar *) input->payload); + } + fail_unless (input->uri != NULL); + if (g_str_has_suffix (input->uri, ".m3u8")) { + output->response_headers = gst_structure_new ("response-headers", + "Content-Type", G_TYPE_STRING, "application/vnd.apple.mpegurl", NULL); + } else if (g_str_has_suffix (input->uri, ".ts")) { + output->response_headers = gst_structure_new ("response-headers", + "Content-Type", G_TYPE_STRING, "video/mp2t", NULL); + } + if (gst_structure_has_field (test_case->state, "requests")) { + GstHlsDemuxTestAppendUriContext context = + { g_quark_from_string ("requests"), input->uri }; + gst_structure_map_in_place (test_case->state, append_request_uri, &context); + } else { + GValue requests = G_VALUE_INIT; + GValue uri_val = G_VALUE_INIT; + + g_value_init (&requests, GST_TYPE_ARRAY); + g_value_init (&uri_val, G_TYPE_STRING); + g_value_set_string (&uri_val, input->uri); + gst_value_array_append_value (&requests, &uri_val); + gst_structure_set_value (test_case->state, "requests", &requests); + g_value_unset (&uri_val); + g_value_unset (&requests); + } +} + +static gboolean +gst_hlsdemux_test_src_start (GstTestHTTPSrc * src, + const gchar * uri, GstTestHTTPSrcInput * input_data, gpointer user_data) +{ + const GstHlsDemuxTestCase *test_case = + (const GstHlsDemuxTestCase *) user_data; + guint fail_count = 0; + + GST_DEBUG ("src_start %s", uri); + for (guint i = 0; test_case->input[i].uri; ++i) { + if (strcmp (test_case->input[i].uri, uri) == 0) { + gst_hlsdemux_test_set_input_data (test_case, &test_case->input[i], + input_data); + GST_DEBUG ("open URI %s", uri); + return TRUE; + } + } + gst_structure_get_uint (test_case->state, "failure-count", &fail_count); + fail_count++; + gst_structure_set (test_case->state, "failure-count", G_TYPE_UINT, + fail_count, NULL); + return FALSE; +} + +static GstFlowReturn +gst_hlsdemux_test_src_create (GstTestHTTPSrc * src, + guint64 offset, + guint length, GstBuffer ** retbuf, gpointer context, gpointer user_data) +{ + GstBuffer *buf; + /* const GstHlsDemuxTestCase *test_case = (const GstHlsDemuxTestCase *) user_data; */ + GstHlsDemuxTestInputData *input = (GstHlsDemuxTestInputData *) context; + + buf = gst_buffer_new_allocate (NULL, length, NULL); + fail_if (buf == NULL, "Not enough memory to allocate buffer"); + fail_if (input->payload == NULL); + gst_buffer_fill (buf, 0, input->payload + offset, length); + *retbuf = buf; + return GST_FLOW_OK; +} + +static GstFlowReturn +gst_hlsdemux_test_network_error_src_create (GstTestHTTPSrc * src, + guint64 offset, + guint length, GstBuffer ** retbuf, gpointer context, gpointer user_data) +{ + const GstHlsDemuxTestCase *test_case = + (const GstHlsDemuxTestCase *) user_data; + GstHlsDemuxTestInputData *input = (GstHlsDemuxTestInputData *) context; + const gchar *failure_suffix; + guint64 failure_position = 0; + + fail_unless (test_case != NULL); + fail_unless (input != NULL); + fail_unless (input->uri != NULL); + failure_suffix = + gst_structure_get_string (test_case->state, "failure-suffix"); + if (!failure_suffix) { + failure_suffix = ".ts"; + } + if (!gst_structure_get_uint64 (test_case->state, "failure-position", + &failure_position)) { + failure_position = 10 * TS_PACKET_LEN; + } + GST_DEBUG ("network_error %s %s %" G_GUINT64_FORMAT " @ %" G_GUINT64_FORMAT, + input->uri, failure_suffix, offset, failure_position); + if (g_str_has_suffix (input->uri, failure_suffix) + && offset >= failure_position) { + GST_DEBUG ("return error"); + GST_ELEMENT_ERROR (src, RESOURCE, READ, + (("A network error occurred, or the server closed the connection unexpectedly.")), ("A network error occurred, or the server closed the connection unexpectedly.")); + *retbuf = NULL; + return GST_FLOW_ERROR; + } + return gst_hlsdemux_test_src_create (src, offset, length, retbuf, context, + user_data); +} + +/******************** Test specific code starts here **************************/ + +/* + * Test a media manifest with a single segment + * + */ +GST_START_TEST (simpleTest) +{ + /* segment_size needs to larger than 2K, otherwise gsthlsdemux will + not perform a typefind on the buffer */ + const guint segment_size = 30 * TS_PACKET_LEN; + const gchar *manifest = + "#EXTM3U \n" + "#EXT-X-TARGETDURATION:1\n" + "#EXTINF:1,Test\n" "001.ts\n" "#EXT-X-ENDLIST\n"; + GstHlsDemuxTestInputData inputTestData[] = { + {"http://unit.test/media.m3u8", (guint8 *) manifest, 0}, + {"http://unit.test/001.ts", NULL, segment_size}, + {NULL, NULL, 0}, + }; + GstAdaptiveDemuxTestExpectedOutput outputTestData[] = { + {"src_0", segment_size, NULL}, + {NULL, 0, NULL} + }; + TESTCASE_INIT_BOILERPLATE (segment_size); + + http_src_callbacks.src_start = gst_hlsdemux_test_src_start; + http_src_callbacks.src_create = gst_hlsdemux_test_src_create; + engine_callbacks.appsink_received_data = + gst_adaptive_demux_test_check_received_data; + engine_callbacks.appsink_eos = + gst_adaptive_demux_test_check_size_of_received_data; + + gst_test_http_src_install_callbacks (&http_src_callbacks, &hlsTestCase); + gst_adaptive_demux_test_run (DEMUX_ELEMENT_NAME, + inputTestData[0].uri, &engine_callbacks, engineTestData); + TESTCASE_UNREF_BOILERPLATE; +} + +GST_END_TEST; + +GST_START_TEST (testMasterPlaylist) +{ + const guint segment_size = 30 * TS_PACKET_LEN; + const gchar *master_playlist = + "#EXTM3U\n" + "#EXT-X-VERSION:4\n" + "#EXT-X-STREAM-INF:PROGRAM-ID=1, BANDWIDTH=1251135, CODECS=\"avc1.42001f mp4a.40.2\", RESOLUTION=640x352\n" + "1200.m3u8\n"; + const gchar *media_playlist = + "#EXTM3U \n" + "#EXT-X-TARGETDURATION:1\n" + "#EXTINF:1,Test\n" "001.ts\n" "#EXT-X-ENDLIST\n"; + GstHlsDemuxTestInputData inputTestData[] = { + {"http://unit.test/master.m3u8", (guint8 *) master_playlist, 0}, + {"http://unit.test/1200.m3u8", (guint8 *) media_playlist, 0}, + {"http://unit.test/001.ts", NULL, segment_size}, + {NULL, NULL, 0} + }; + GstAdaptiveDemuxTestExpectedOutput outputTestData[] = { + {"src_0", segment_size, NULL}, + {NULL, 0, NULL} + }; + const GValue *requests; + TESTCASE_INIT_BOILERPLATE (segment_size); + + http_src_callbacks.src_start = gst_hlsdemux_test_src_start; + http_src_callbacks.src_create = gst_hlsdemux_test_src_create; + engine_callbacks.appsink_received_data = + gst_adaptive_demux_test_check_received_data; + engine_callbacks.appsink_eos = + gst_adaptive_demux_test_check_size_of_received_data; + + gst_test_http_src_install_callbacks (&http_src_callbacks, &hlsTestCase); + gst_adaptive_demux_test_run (DEMUX_ELEMENT_NAME, + "http://unit.test/master.m3u8", &engine_callbacks, engineTestData); + + requests = gst_structure_get_value (hlsTestCase.state, "requests"); + fail_unless (requests != NULL); + assert_equals_uint64 (gst_value_array_get_size (requests), + sizeof (inputTestData) / sizeof (inputTestData[0]) - 1); + for (guint i = 0; inputTestData[i].uri; ++i) { + const GValue *uri; + uri = gst_value_array_get_value (requests, i); + fail_unless (uri != NULL); + assert_equals_string (inputTestData[i].uri, g_value_get_string (uri)); + } + TESTCASE_UNREF_BOILERPLATE; +} + +GST_END_TEST; + +/* + * Test seeking + * + */ +GST_START_TEST (testSeek) +{ + const guint segment_size = 60 * TS_PACKET_LEN; + const gchar *manifest = + "#EXTM3U \n" + "#EXT-X-TARGETDURATION:1\n" + "#EXTINF:1,Test\n" "001.ts\n" "#EXT-X-ENDLIST\n"; + GstHlsDemuxTestInputData inputTestData[] = { + {"http://unit.test/media.m3u8", (guint8 *) manifest, 0}, + {"http://unit.test/001.ts", NULL, segment_size}, + {NULL, NULL, 0}, + }; + GstAdaptiveDemuxTestExpectedOutput outputTestData[] = { + {"src_0", segment_size, NULL}, + {NULL, 0, NULL} + }; + GstTestHTTPSrcCallbacks http_src_callbacks = { 0 }; + GstAdaptiveDemuxTestCase *engineTestData; + GstHlsDemuxTestCase hlsTestCase = { 0 }; + GByteArray *mpeg_ts = NULL; + + engineTestData = gst_adaptive_demux_test_case_new (); + mpeg_ts = setup_test_variables (inputTestData, outputTestData, + &hlsTestCase, engineTestData, segment_size); + + http_src_callbacks.src_start = gst_hlsdemux_test_src_start; + http_src_callbacks.src_create = gst_hlsdemux_test_src_create; + engineTestData->threshold_for_seek = 20 * TS_PACKET_LEN; + + gst_test_http_src_install_callbacks (&http_src_callbacks, &hlsTestCase); + gst_adaptive_demux_test_seek (DEMUX_ELEMENT_NAME, + inputTestData[0].uri, engineTestData); + + TESTCASE_UNREF_BOILERPLATE; +} + +GST_END_TEST; + +static void +testDownloadErrorMessageCallback (GstAdaptiveDemuxTestEngine * engine, + GstMessage * msg, gpointer user_data) +{ + GError *err = NULL; + gchar *dbg_info = NULL; + + fail_unless (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR); + gst_message_parse_error (msg, &err, &dbg_info); + GST_DEBUG ("Error from element %s : %s\n", + GST_OBJECT_NAME (msg->src), err->message); + fail_unless_equals_string (GST_OBJECT_NAME (msg->src), DEMUX_ELEMENT_NAME); + g_error_free (err); + g_free (dbg_info); + g_main_loop_quit (engine->loop); +} + +/* test failing to download the media playlist */ +GST_START_TEST (testMediaPlaylistNotFound) +{ + const gchar *master_playlist = + "#EXTM3U\n" + "#EXT-X-VERSION:4\n" + "#EXT-X-STREAM-INF:PROGRAM-ID=1, BANDWIDTH=1251135, CODECS=\"avc1.42001f mp4a.40.2\", RESOLUTION=640x352\n" + "1200.m3u8\n"; + GstHlsDemuxTestInputData inputTestData[] = { + {"http://unit.test/master.m3u8", (guint8 *) master_playlist, 0}, + {NULL, NULL, 0} + }; + GstAdaptiveDemuxTestExpectedOutput outputTestData[] = { + {"src_0", 0, NULL}, + {NULL, 0, NULL} + }; + TESTCASE_INIT_BOILERPLATE (0); + + gst_structure_set (hlsTestCase.state, + "failure-count", G_TYPE_UINT, 0, + "failure-suffix", G_TYPE_STRING, "1200.m3u8", NULL); + http_src_callbacks.src_start = gst_hlsdemux_test_src_start; + http_src_callbacks.src_create = gst_hlsdemux_test_src_create; + engine_callbacks.appsink_received_data = + gst_adaptive_demux_test_check_received_data; + engine_callbacks.bus_error_message = testDownloadErrorMessageCallback; + + gst_test_http_src_install_callbacks (&http_src_callbacks, &hlsTestCase); + gst_adaptive_demux_test_run (DEMUX_ELEMENT_NAME, + "http://unit.test/master.m3u8", &engine_callbacks, engineTestData); + + TESTCASE_UNREF_BOILERPLATE; +} + +GST_END_TEST; + +static void +hlsdemux_test_check_no_data_received (GstAdaptiveDemuxTestEngine + * engine, GstAdaptiveDemuxTestOutputStream * stream, gpointer user_data) +{ + assert_equals_uint64 (stream->total_received_size, 0); + g_main_loop_quit (engine->loop); +} + +/* test failing to download a media segment (a 404 error) */ +GST_START_TEST (testFragmentNotFound) +{ + const gchar *master_playlist = + "#EXTM3U\n" + "#EXT-X-VERSION:4\n" + "#EXT-X-STREAM-INF:PROGRAM-ID=1, BANDWIDTH=1251135, CODECS=\"avc1.42001f mp4a.40.2\", RESOLUTION=640x352\n" + "1200.m3u8\n"; + const gchar *media_playlist = + "#EXTM3U \n" + "#EXT-X-TARGETDURATION:1\n" + "#EXTINF:1,Test\n" "001.ts\n" "#EXT-X-ENDLIST\n"; + GstHlsDemuxTestInputData inputTestData[] = { + {"http://unit.test/master.m3u8", (guint8 *) master_playlist, 0}, + {"http://unit.test/1200.m3u8", (guint8 *) media_playlist, 0}, + {NULL, NULL, 0} + }; + GstAdaptiveDemuxTestExpectedOutput outputTestData[] = { + {"src_0", 0, NULL}, + {NULL, 0, NULL} + }; + TESTCASE_INIT_BOILERPLATE (0); + + gst_structure_set (hlsTestCase.state, + "failure-count", G_TYPE_UINT, 0, + "failure-suffix", G_TYPE_STRING, "001.ts", NULL); + http_src_callbacks.src_start = gst_hlsdemux_test_src_start; + http_src_callbacks.src_create = gst_hlsdemux_test_src_create; + engine_callbacks.appsink_received_data = + gst_adaptive_demux_test_check_received_data; + engine_callbacks.appsink_eos = hlsdemux_test_check_no_data_received; + engine_callbacks.bus_error_message = testDownloadErrorMessageCallback; + + gst_test_http_src_install_callbacks (&http_src_callbacks, &hlsTestCase); + gst_adaptive_demux_test_run (DEMUX_ELEMENT_NAME, + "http://unit.test/master.m3u8", &engine_callbacks, engineTestData); + + TESTCASE_UNREF_BOILERPLATE; +} + +GST_END_TEST; + +/* work-around that adaptivedemux is not posting an error message + about failure to download a fragment */ +static void +missing_message_eos_callback (GstAdaptiveDemuxTestEngine * engine, + GstAdaptiveDemuxTestOutputStream * stream, gpointer user_data) +{ + GstAdaptiveDemuxTestCase *testData = GST_ADAPTIVE_DEMUX_TEST_CASE (user_data); + GstAdaptiveDemuxTestExpectedOutput *testOutputStreamData; + + fail_unless (stream != NULL); + testOutputStreamData = + gst_adaptive_demux_test_find_test_data_by_stream (testData, stream, NULL); + fail_unless (testOutputStreamData != NULL); + /* 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); + testData->count_of_finished_streams++; + GST_DEBUG ("EOS callback %d %d", + testData->count_of_finished_streams, + g_list_length (testData->output_streams)); + if (testData->count_of_finished_streams == + g_list_length (testData->output_streams)) { + g_main_loop_quit (engine->loop); + } +} + + +/* + * Test fragment download error + * Let the adaptive demux download a few bytes, then instruct the + * test soup http src element to generate an error. + */ +GST_START_TEST (testFragmentDownloadError) +{ + const guint segment_size = 30 * TS_PACKET_LEN; + const gchar *master_playlist = + "#EXTM3U\n" + "#EXT-X-VERSION:4\n" + "#EXT-X-STREAM-INF:PROGRAM-ID=1, BANDWIDTH=1251135, CODECS=\"avc1.42001f mp4a.40.2\", RESOLUTION=640x352\n" + "1200.m3u8\n"; + const gchar *media_playlist = + "#EXTM3U \n" + "#EXT-X-VERSION:4\n" + "#EXT-X-TARGETDURATION:1\n" + "#EXTINF:1,Test\n" "001.ts\n" + "#EXTINF:1,Test\n" "002.ts\n" "#EXT-X-ENDLIST\n"; + GstHlsDemuxTestInputData inputTestData[] = { + {"http://unit.test/master.m3u8", (guint8 *) master_playlist, 0}, + {"http://unit.test/1200.m3u8", (guint8 *) media_playlist, 0}, + {"http://unit.test/001.ts", NULL, segment_size}, + {"http://unit.test/002.ts", NULL, segment_size}, + {NULL, NULL, 0} + }; + GstAdaptiveDemuxTestExpectedOutput outputTestData[] = { + {"src_0", 2 * segment_size, NULL}, + {NULL, 0, NULL} + }; + const guint64 failure_position = 2048; + TESTCASE_INIT_BOILERPLATE (segment_size); + + http_src_callbacks.src_start = gst_hlsdemux_test_src_start; + http_src_callbacks.src_create = gst_hlsdemux_test_network_error_src_create; + gst_structure_set (hlsTestCase.state, + "failure-suffix", G_TYPE_STRING, "001.ts", + "failure-position", G_TYPE_UINT64, failure_position, NULL); + engine_callbacks.appsink_received_data = + gst_adaptive_demux_test_check_received_data; + engine_callbacks.appsink_eos = missing_message_eos_callback; + engine_callbacks.bus_error_message = testDownloadErrorMessageCallback; + + gst_test_http_src_install_callbacks (&http_src_callbacks, &hlsTestCase); + gst_adaptive_demux_test_run (DEMUX_ELEMENT_NAME, + inputTestData[0].uri, &engine_callbacks, engineTestData); + + TESTCASE_UNREF_BOILERPLATE; +} + +GST_END_TEST; + +static Suite * +hls_demux_suite (void) +{ + Suite *s = suite_create ("hls_demux"); + TCase *tc_basicTest = tcase_create ("basicTest"); + + tcase_add_test (tc_basicTest, simpleTest); + tcase_add_test (tc_basicTest, testMasterPlaylist); + tcase_add_test (tc_basicTest, testMediaPlaylistNotFound); + tcase_add_test (tc_basicTest, testFragmentNotFound); + tcase_add_test (tc_basicTest, testFragmentDownloadError); + tcase_add_test (tc_basicTest, testSeek); + + tcase_add_unchecked_fixture (tc_basicTest, gst_adaptive_demux_test_setup, + gst_adaptive_demux_test_teardown); + + suite_add_tcase (s, tc_basicTest); + + return s; +} + +GST_CHECK_MAIN (hls_demux); |