1 /* GStreamer unit test for MSS
2 *
3 * Copyright (C) 2016 Samsung Electronics. All rights reserved.
4 * Author: Thiago Santos <thiagoss@osg.samsung.com>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 */
21
22 #include <gst/check/gstcheck.h>
23 #include "adaptive_demux_common.h"
24
25 #define DEMUX_ELEMENT_NAME "mssdemux"
26
27 #define COPY_OUTPUT_TEST_DATA(outputTestData,testData) do { \
28 guint otdPos, otdLen = sizeof((outputTestData)) / sizeof((outputTestData)[0]); \
29 for(otdPos=0; otdPos<otdLen; ++otdPos){ \
30 (testData)->output_streams = g_list_append ((testData)->output_streams, &(outputTestData)[otdPos]); \
31 } \
32 } while(0)
33
34 typedef struct _GstMssDemuxTestInputData
35 {
36 const gchar *uri;
37 const guint8 *payload;
38 guint64 size;
39 } GstMssDemuxTestInputData;
40
41 static gboolean
gst_mssdemux_http_src_start(GstTestHTTPSrc * src,const gchar * uri,GstTestHTTPSrcInput * input_data,gpointer user_data)42 gst_mssdemux_http_src_start (GstTestHTTPSrc * src,
43 const gchar * uri, GstTestHTTPSrcInput * input_data, gpointer user_data)
44 {
45 const GstMssDemuxTestInputData *input =
46 (const GstMssDemuxTestInputData *) user_data;
47 guint i;
48
49
50 for (i = 0; input[i].uri; ++i) {
51 if (strcmp (input[i].uri, uri) == 0) {
52 input_data->context = (gpointer) & input[i];
53 input_data->size = input[i].size;
54 if (input[i].size == 0)
55 input_data->size = strlen ((gchar *) input[i].payload);
56 return TRUE;
57 }
58 }
59
60 return FALSE;
61 }
62
63 static GstFlowReturn
gst_mssdemux_http_src_create(GstTestHTTPSrc * src,guint64 offset,guint length,GstBuffer ** retbuf,gpointer context,gpointer user_data)64 gst_mssdemux_http_src_create (GstTestHTTPSrc * src,
65 guint64 offset,
66 guint length, GstBuffer ** retbuf, gpointer context, gpointer user_data)
67 {
68 /* const GstMssDemuxTestInputData *input =
69 (const GstMssDemuxTestInputData *) user_data; */
70 const GstMssDemuxTestInputData *input =
71 (const GstMssDemuxTestInputData *) context;
72 GstBuffer *buf;
73
74 buf = gst_buffer_new_allocate (NULL, length, NULL);
75 fail_if (buf == NULL, "Not enough memory to allocate buffer");
76
77 if (input->payload) {
78 gst_buffer_fill (buf, 0, input->payload + offset, length);
79 } else {
80 GstMapInfo info;
81 guint pattern;
82 guint64 i;
83
84 pattern = offset - offset % sizeof (pattern);
85
86 gst_buffer_map (buf, &info, GST_MAP_WRITE);
87 for (i = 0; i < length; ++i) {
88 gchar pattern_byte_to_write = (offset + i) % sizeof (pattern);
89 if (pattern_byte_to_write == 0) {
90 pattern = offset + i;
91 }
92 info.data[i] = (pattern >> (pattern_byte_to_write * 8)) & 0xFF;
93 }
94 gst_buffer_unmap (buf, &info);
95 }
96 *retbuf = buf;
97 return GST_FLOW_OK;
98 }
99
100 /******************** Test specific code starts here **************************/
101
102 /*
103 * Test an mpd with an audio and a video stream
104 *
105 */
GST_START_TEST(simpleTest)106 GST_START_TEST (simpleTest)
107 {
108 const gchar *mpd =
109 "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
110 "<SmoothStreamingMedia MajorVersion=\"2\" MinorVersion=\"0\" Duration=\"40000000\">"
111 "<StreamIndex Type=\"video\" QualityLevels=\"1\" Chunks=\"1\" Url=\"QualityLevels({bitrate})/Fragments(video={start time})\">"
112 "<QualityLevel Index=\"0\" Bitrate=\"480111\" FourCC=\"H264\" MaxWidth=\"1024\" MaxHeight=\"436\" CodecPrivateData=\"000\" />"
113 "<c n=\"0\" d=\"10000000\" />"
114 "<c n=\"1\" d=\"10000000\" />"
115 "<c n=\"2\" d=\"10000000\" />"
116 "<c n=\"3\" d=\"10000000\" />"
117 "</StreamIndex>"
118 "<StreamIndex Type=\"audio\" Language=\"eng\" QualityLevels=\"1\" Chunks=\"1\" Url=\"QualityLevels({bitrate})/Fragments(audio_eng={start time})\">"
119 "<QualityLevel Index=\"0\" Bitrate=\"200029\" FourCC=\"AACL\" SamplingRate=\"48000\" Channels=\"2\" BitsPerSample=\"16\" PacketSize=\"4\" AudioTag=\"255\" CodecPrivateData=\"1190\" />"
120 "<c n=\"0\" d=\"40000000\" />" "</StreamIndex>" "</SmoothStreamingMedia>";
121
122 GstMssDemuxTestInputData inputTestData[] = {
123 {"http://unit.test/Manifest", (guint8 *) mpd, 0},
124 {"http://unit.test/QualityLevels(480111)/Fragments(video=0)", NULL, 9000},
125 {"http://unit.test/QualityLevels(480111)/Fragments(video=10000000)", NULL,
126 9000},
127 {"http://unit.test/QualityLevels(480111)/Fragments(video=20000000)", NULL,
128 9000},
129 {"http://unit.test/QualityLevels(480111)/Fragments(video=30000000)", NULL,
130 9000},
131 {"http://unit.test/QualityLevels(200029)/Fragments(audio_eng=0)", NULL,
132 5000},
133 {NULL, NULL, 0},
134 };
135 GstTestHTTPSrcCallbacks http_src_callbacks = { 0 };
136 GstAdaptiveDemuxTestExpectedOutput outputTestData[] = {
137 {"audio_00", 5000, NULL},
138 {"video_00", 4 * 9000, NULL}
139 };
140 GstAdaptiveDemuxTestCallbacks test_callbacks = { 0 };
141 GstAdaptiveDemuxTestCase *testData;
142
143 testData = gst_adaptive_demux_test_case_new ();
144 http_src_callbacks.src_start = gst_mssdemux_http_src_start;
145 http_src_callbacks.src_create = gst_mssdemux_http_src_create;
146 gst_test_http_src_install_callbacks (&http_src_callbacks, inputTestData);
147
148 COPY_OUTPUT_TEST_DATA (outputTestData, testData);
149 test_callbacks.appsink_received_data =
150 gst_adaptive_demux_test_check_received_data;
151 test_callbacks.appsink_eos =
152 gst_adaptive_demux_test_check_size_of_received_data;
153
154 gst_adaptive_demux_test_run (DEMUX_ELEMENT_NAME, "http://unit.test/Manifest",
155 &test_callbacks, testData);
156 g_object_unref (testData);
157 }
158
159 GST_END_TEST;
160
161 /*
162 * Test seeking
163 *
164 */
GST_START_TEST(testSeek)165 GST_START_TEST (testSeek)
166 {
167 const gchar *mpd =
168 "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
169 "<SmoothStreamingMedia MajorVersion=\"2\" MinorVersion=\"0\" Duration=\"40000000\">"
170 "<StreamIndex Type=\"audio\" Language=\"eng\" QualityLevels=\"1\" Chunks=\"1\" Url=\"QualityLevels({bitrate})/Fragments(audio_eng={start time})\">"
171 "<QualityLevel Index=\"0\" Bitrate=\"200029\" FourCC=\"AACL\" SamplingRate=\"48000\" Channels=\"2\" BitsPerSample=\"16\" PacketSize=\"4\" AudioTag=\"255\" CodecPrivateData=\"1190\" />"
172 "<c n=\"0\" d=\"450346666\" />"
173 "</StreamIndex>" "</SmoothStreamingMedia>";
174 GstMssDemuxTestInputData inputTestData[] = {
175 {"http://unit.test/Manifest", (guint8 *) mpd, 0},
176 {"http://unit.test/QualityLevels(200029)/Fragments(audio_eng=0)", NULL,
177 10000},
178 {NULL, NULL, 0},
179 };
180 GstTestHTTPSrcCallbacks http_src_callbacks = { 0 };
181 GstAdaptiveDemuxTestExpectedOutput outputTestData[] = {
182 {"audio_00", 10000, NULL},
183 };
184 GstAdaptiveDemuxTestCase *testData;
185
186 testData = gst_adaptive_demux_test_case_new ();
187
188 http_src_callbacks.src_start = gst_mssdemux_http_src_start;
189 http_src_callbacks.src_create = gst_mssdemux_http_src_create;
190 COPY_OUTPUT_TEST_DATA (outputTestData, testData);
191
192 /* media segment starts at 4687
193 * Issue a seek request after media segment has started to be downloaded
194 * on the first pad listed in GstAdaptiveDemuxTestOutputStreamData and the
195 * first chunk of at least one byte has already arrived in AppSink
196 */
197 testData->threshold_for_seek = 4687 + 1;
198
199 /* seek to 5ms.
200 * Because there is only one fragment, we expect the whole file to be
201 * downloaded again
202 */
203 testData->seek_event =
204 gst_event_new_seek (1.0, GST_FORMAT_TIME,
205 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT, GST_SEEK_TYPE_SET,
206 5 * GST_MSECOND, GST_SEEK_TYPE_NONE, 0);
207
208 gst_test_http_src_install_callbacks (&http_src_callbacks, inputTestData);
209 gst_adaptive_demux_test_seek (DEMUX_ELEMENT_NAME,
210 "http://unit.test/Manifest", testData);
211 g_object_unref (testData);
212 }
213
214 GST_END_TEST;
215
216
217 static void
run_seek_position_test(gdouble rate,GstSeekType start_type,guint64 seek_start,GstSeekType stop_type,guint64 seek_stop,GstSeekFlags flags,guint64 segment_start,guint64 segment_stop,gint segments)218 run_seek_position_test (gdouble rate, GstSeekType start_type,
219 guint64 seek_start, GstSeekType stop_type, guint64 seek_stop,
220 GstSeekFlags flags, guint64 segment_start, guint64 segment_stop,
221 gint segments)
222 {
223 const gchar *mpd =
224 "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
225 "<SmoothStreamingMedia MajorVersion=\"2\" MinorVersion=\"0\" Duration=\"40000000\">"
226 "<StreamIndex Type=\"audio\" Language=\"eng\" QualityLevels=\"1\" Chunks=\"1\" Url=\"QualityLevels({bitrate})/Fragments(audio_eng={start time})\">"
227 "<QualityLevel Index=\"0\" Bitrate=\"200029\" FourCC=\"AACL\" SamplingRate=\"48000\" Channels=\"2\" BitsPerSample=\"16\" PacketSize=\"4\" AudioTag=\"255\" CodecPrivateData=\"1190\" />"
228 "<c n=\"0\" d=\"10000000\" />"
229 "<c n=\"1\" d=\"10000000\" />"
230 "<c n=\"2\" d=\"10000000\" />"
231 "<c n=\"3\" d=\"10000000\" />" "</StreamIndex>" "</SmoothStreamingMedia>";
232 GstMssDemuxTestInputData inputTestData[] = {
233 {"http://unit.test/Manifest", (guint8 *) mpd, 0},
234 {"http://unit.test/QualityLevels(200029)/Fragments(audio_eng=0)", NULL,
235 10000},
236 {"http://unit.test/QualityLevels(200029)/Fragments(audio_eng=10000000)",
237 NULL, 10000},
238 {"http://unit.test/QualityLevels(200029)/Fragments(audio_eng=20000000)",
239 NULL, 10000},
240 {"http://unit.test/QualityLevels(200029)/Fragments(audio_eng=30000000)",
241 NULL, 10000},
242 {NULL, NULL, 0},
243 };
244 GstTestHTTPSrcCallbacks http_src_callbacks = { 0 };
245 GstAdaptiveDemuxTestExpectedOutput outputTestData[] = {
246 /* 1 from the init segment */
247 {"audio_00", segments * 10000, NULL},
248 };
249 GstAdaptiveDemuxTestCase *testData;
250
251 testData = gst_adaptive_demux_test_case_new ();
252
253 http_src_callbacks.src_start = gst_mssdemux_http_src_start;
254 http_src_callbacks.src_create = gst_mssdemux_http_src_create;
255 COPY_OUTPUT_TEST_DATA (outputTestData, testData);
256
257 /* media segment starts at 4687
258 * Issue a seek request after media segment has started to be downloaded
259 * on the first pad listed in GstAdaptiveDemuxTestOutputStreamData and the
260 * first chunk of at least one byte has already arrived in AppSink
261 */
262 testData->threshold_for_seek = 4687 + 1;
263
264 /* FIXME hack to avoid having a 0 seqnum */
265 gst_util_seqnum_next ();
266
267 /* seek to 5ms.
268 * Because there is only one fragment, we expect the whole file to be
269 * downloaded again
270 */
271 testData->seek_event =
272 gst_event_new_seek (rate, GST_FORMAT_TIME, flags, start_type,
273 seek_start, stop_type, seek_stop);
274
275 gst_test_http_src_install_callbacks (&http_src_callbacks, inputTestData);
276 gst_adaptive_demux_test_seek (DEMUX_ELEMENT_NAME,
277 "http://unit.test/Manifest", testData);
278 g_object_unref (testData);
279 }
280
GST_START_TEST(testSeekKeyUnitPosition)281 GST_START_TEST (testSeekKeyUnitPosition)
282 {
283 /* Seek to 1.5s with key unit, it should go back to 1.0s. 3 segments will be
284 * pushed */
285 run_seek_position_test (1.0, GST_SEEK_TYPE_SET, 1500 * GST_MSECOND,
286 GST_SEEK_TYPE_NONE, 0, GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT,
287 1000 * GST_MSECOND, -1, 3);
288 }
289
290 GST_END_TEST;
291
292
GST_START_TEST(testSeekUpdateStopPosition)293 GST_START_TEST (testSeekUpdateStopPosition)
294 {
295 run_seek_position_test (1.0, GST_SEEK_TYPE_NONE, 1500 * GST_MSECOND,
296 GST_SEEK_TYPE_SET, 3000 * GST_MSECOND, 0, 0, 3000 * GST_MSECOND, 3);
297 }
298
299 GST_END_TEST;
300
GST_START_TEST(testSeekPosition)301 GST_START_TEST (testSeekPosition)
302 {
303 /* Seek to 1.5s without key unit, it should keep the 1.5s, but still push
304 * from the 1st segment, so 3 segments will be
305 * pushed */
306 run_seek_position_test (1.0, GST_SEEK_TYPE_SET, 1500 * GST_MSECOND,
307 GST_SEEK_TYPE_NONE, 0, GST_SEEK_FLAG_FLUSH, 1500 * GST_MSECOND, -1, 3);
308 }
309
310 GST_END_TEST;
311
GST_START_TEST(testSeekSnapBeforePosition)312 GST_START_TEST (testSeekSnapBeforePosition)
313 {
314 /* Seek to 1.5s, snap before, it go to 1s */
315 run_seek_position_test (1.0, GST_SEEK_TYPE_SET, 1500 * GST_MSECOND,
316 GST_SEEK_TYPE_NONE, 0,
317 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT | GST_SEEK_FLAG_SNAP_BEFORE,
318 1000 * GST_MSECOND, -1, 3);
319 }
320
321 GST_END_TEST;
322
323
GST_START_TEST(testSeekSnapAfterPosition)324 GST_START_TEST (testSeekSnapAfterPosition)
325 {
326 /* Seek to 1.5s with snap after, it should move to 2s */
327 run_seek_position_test (1.0, GST_SEEK_TYPE_SET, 1500 * GST_MSECOND,
328 GST_SEEK_TYPE_NONE, 0,
329 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT | GST_SEEK_FLAG_SNAP_AFTER,
330 2000 * GST_MSECOND, -1, 2);
331 }
332
333 GST_END_TEST;
334
335
GST_START_TEST(testReverseSeekSnapBeforePosition)336 GST_START_TEST (testReverseSeekSnapBeforePosition)
337 {
338 run_seek_position_test (-1.0, GST_SEEK_TYPE_SET, 1000 * GST_MSECOND,
339 GST_SEEK_TYPE_SET, 2500 * GST_MSECOND,
340 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT | GST_SEEK_FLAG_SNAP_BEFORE,
341 1000 * GST_MSECOND, 3000 * GST_MSECOND, 2);
342 }
343
344 GST_END_TEST;
345
346
GST_START_TEST(testReverseSeekSnapAfterPosition)347 GST_START_TEST (testReverseSeekSnapAfterPosition)
348 {
349 run_seek_position_test (-1.0, GST_SEEK_TYPE_SET, 1000 * GST_MSECOND,
350 GST_SEEK_TYPE_SET, 2500 * GST_MSECOND,
351 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT | GST_SEEK_FLAG_SNAP_AFTER,
352 1000 * GST_MSECOND, 2000 * GST_MSECOND, 1);
353 }
354
355 GST_END_TEST;
356
357 static void
testDownloadErrorMessageCallback(GstAdaptiveDemuxTestEngine * engine,GstMessage * msg,gpointer user_data)358 testDownloadErrorMessageCallback (GstAdaptiveDemuxTestEngine * engine,
359 GstMessage * msg, gpointer user_data)
360 {
361 GError *err = NULL;
362 gchar *dbg_info = NULL;
363
364 fail_unless (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR);
365 gst_message_parse_error (msg, &err, &dbg_info);
366 GST_DEBUG ("Error from element %s : %s",
367 GST_OBJECT_NAME (msg->src), err->message);
368 fail_unless_equals_string (GST_OBJECT_NAME (msg->src), DEMUX_ELEMENT_NAME);
369 /*GST_DEBUG ("dbg_info=%s", dbg_info); */
370 g_error_free (err);
371 g_free (dbg_info);
372 g_main_loop_quit (engine->loop);
373 }
374
375 /*
376 * Test error case of failing to download a segment
377 */
GST_START_TEST(testDownloadError)378 GST_START_TEST (testDownloadError)
379 {
380 const gchar *mpd =
381 "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
382 "<SmoothStreamingMedia MajorVersion=\"2\" MinorVersion=\"0\" Duration=\"40000000\">"
383 "<StreamIndex Type=\"audio\" Language=\"eng\" QualityLevels=\"1\" Chunks=\"1\" Url=\"QualityLevels({bitrate})/Fragments(audio_eng={start time})\">"
384 "<QualityLevel Index=\"0\" Bitrate=\"200029\" FourCC=\"AACL\" SamplingRate=\"48000\" Channels=\"2\" BitsPerSample=\"16\" PacketSize=\"4\" AudioTag=\"255\" CodecPrivateData=\"1190\" />"
385 "<c n=\"0\" d=\"40000000\" />" "</StreamIndex>" "</SmoothStreamingMedia>";
386
387 GstMssDemuxTestInputData inputTestData[] = {
388 {"http://unit.test/Manifest", (guint8 *) mpd, 0},
389 {NULL, NULL, 0},
390 };
391 GstTestHTTPSrcCallbacks http_src_callbacks = { 0 };
392 GstAdaptiveDemuxTestExpectedOutput outputTestData[] = {
393 {"audio_00", 0, NULL},
394 };
395 GstAdaptiveDemuxTestCallbacks test_callbacks = { 0 };
396 GstAdaptiveDemuxTestCase *testData;
397
398 testData = gst_adaptive_demux_test_case_new ();
399 http_src_callbacks.src_start = gst_mssdemux_http_src_start;
400 http_src_callbacks.src_create = gst_mssdemux_http_src_create;
401 COPY_OUTPUT_TEST_DATA (outputTestData, testData);
402 test_callbacks.appsink_received_data =
403 gst_adaptive_demux_test_check_received_data;
404 test_callbacks.bus_error_message = testDownloadErrorMessageCallback;
405 test_callbacks.appsink_eos =
406 gst_adaptive_demux_test_check_size_of_received_data;
407
408 gst_test_http_src_install_callbacks (&http_src_callbacks, inputTestData);
409 gst_adaptive_demux_test_run (DEMUX_ELEMENT_NAME, "http://unit.test/Manifest",
410 &test_callbacks, testData);
411 g_object_unref (testData);
412 }
413
414 GST_END_TEST;
415
416 /* generate queries to adaptive demux */
417 static gboolean
testQueryCheckDataReceived(GstAdaptiveDemuxTestEngine * engine,GstAdaptiveDemuxTestOutputStream * stream,GstBuffer * buffer,gpointer user_data)418 testQueryCheckDataReceived (GstAdaptiveDemuxTestEngine * engine,
419 GstAdaptiveDemuxTestOutputStream * stream,
420 GstBuffer * buffer, gpointer user_data)
421 {
422 GList *pads;
423 GstPad *pad;
424 GstQuery *query;
425 gboolean ret;
426 gint64 duration;
427 gboolean seekable;
428 gint64 segment_start;
429 gint64 segment_end;
430 gchar *uri;
431 gchar *redirect_uri;
432 gboolean redirect_permanent;
433
434 pads = GST_ELEMENT_PADS (stream->appsink);
435
436 /* AppSink should have only 1 pad */
437 fail_unless (pads != NULL);
438 fail_unless (g_list_length (pads) == 1);
439 pad = GST_PAD (pads->data);
440
441 query = gst_query_new_duration (GST_FORMAT_TIME);
442 ret = gst_pad_peer_query (pad, query);
443 fail_unless (ret == TRUE);
444 gst_query_parse_duration (query, NULL, &duration);
445 fail_unless (duration == GST_SECOND);
446 gst_query_unref (query);
447
448 query = gst_query_new_seeking (GST_FORMAT_TIME);
449 ret = gst_pad_peer_query (pad, query);
450 fail_unless (ret == TRUE);
451 gst_query_parse_seeking (query, NULL, &seekable, &segment_start,
452 &segment_end);
453 fail_unless (seekable == TRUE);
454 fail_unless (segment_start == 0);
455 fail_unless (segment_end == duration);
456 gst_query_unref (query);
457
458 query = gst_query_new_uri ();
459 ret = gst_pad_peer_query (pad, query);
460 fail_unless (ret == TRUE);
461 gst_query_parse_uri (query, &uri);
462 gst_query_parse_uri_redirection (query, &redirect_uri);
463 gst_query_parse_uri_redirection_permanent (query, &redirect_permanent);
464 fail_unless (strcmp (uri, "http://unit.test/Manifest") == 0);
465 /* adaptive demux does not reply with redirect information */
466 fail_unless (redirect_uri == NULL);
467 fail_unless (redirect_permanent == FALSE);
468 g_free (uri);
469 g_free (redirect_uri);
470 gst_query_unref (query);
471
472 return gst_adaptive_demux_test_check_received_data (engine,
473 stream, buffer, user_data);
474 }
475
476 /*
477 * Test queries
478 *
479 */
GST_START_TEST(testQuery)480 GST_START_TEST (testQuery)
481 {
482 const gchar *mpd =
483 "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
484 "<SmoothStreamingMedia MajorVersion=\"2\" MinorVersion=\"0\" Duration=\"10000000\">"
485 "<StreamIndex Type=\"audio\" Language=\"eng\" QualityLevels=\"1\" Chunks=\"1\" Url=\"QualityLevels({bitrate})/Fragments(audio_eng={start time})\">"
486 "<QualityLevel Index=\"0\" Bitrate=\"200029\" FourCC=\"AACL\" SamplingRate=\"48000\" Channels=\"2\" BitsPerSample=\"16\" PacketSize=\"4\" AudioTag=\"255\" CodecPrivateData=\"1190\" />"
487 "<c n=\"0\" d=\"10000000\" />" "</StreamIndex>" "</SmoothStreamingMedia>";
488 GstMssDemuxTestInputData inputTestData[] = {
489 {"http://unit.test/Manifest", (guint8 *) mpd, 0},
490 {"http://unit.test/QualityLevels(200029)/Fragments(audio_eng=0)", NULL,
491 5000},
492 {NULL, NULL, 0},
493 };
494 GstTestHTTPSrcCallbacks http_src_callbacks = { 0 };
495 GstAdaptiveDemuxTestExpectedOutput outputTestData[] = {
496 {"audio_00", 5000, NULL},
497 };
498 GstAdaptiveDemuxTestCallbacks test_callbacks = { 0 };
499 GstAdaptiveDemuxTestCase *testData;
500
501 testData = gst_adaptive_demux_test_case_new ();
502 http_src_callbacks.src_start = gst_mssdemux_http_src_start;
503 http_src_callbacks.src_create = gst_mssdemux_http_src_create;
504 COPY_OUTPUT_TEST_DATA (outputTestData, testData);
505 test_callbacks.appsink_received_data = testQueryCheckDataReceived;
506 test_callbacks.appsink_eos =
507 gst_adaptive_demux_test_check_size_of_received_data;
508
509 gst_test_http_src_install_callbacks (&http_src_callbacks, inputTestData);
510 gst_adaptive_demux_test_run (DEMUX_ELEMENT_NAME,
511 "http://unit.test/Manifest", &test_callbacks, testData);
512 g_object_unref (testData);
513 }
514
515 GST_END_TEST;
516
517 static GstFlowReturn
test_fragment_download_error_src_create(GstTestHTTPSrc * src,guint64 offset,guint length,GstBuffer ** retbuf,gpointer context,gpointer user_data)518 test_fragment_download_error_src_create (GstTestHTTPSrc * src,
519 guint64 offset,
520 guint length, GstBuffer ** retbuf, gpointer context, gpointer user_data)
521 {
522 const GstMssDemuxTestInputData *input =
523 (const GstMssDemuxTestInputData *) context;
524 fail_unless (input != NULL);
525 if (!g_str_has_suffix (input->uri, ".mpd") && offset > 2000) {
526 GST_DEBUG ("network_error %s %" G_GUINT64_FORMAT " @ %d",
527 input->uri, offset, 2000);
528 GST_ELEMENT_ERROR (src, RESOURCE, READ,
529 (("A network error occurred, or the server closed the connection unexpectedly.")), ("A network error occurred, or the server closed the connection unexpectedly."));
530 return GST_FLOW_ERROR;
531 }
532 return gst_mssdemux_http_src_create (src, offset, length, retbuf, context,
533 user_data);
534 }
535
536 /* function to check total size of data received by AppSink
537 * will be called when AppSink receives eos.
538 */
539 static void
testFragmentDownloadErrorCheckSizeOfDataReceived(GstAdaptiveDemuxTestEngine * engine,GstAdaptiveDemuxTestOutputStream * stream,gpointer user_data)540 testFragmentDownloadErrorCheckSizeOfDataReceived (GstAdaptiveDemuxTestEngine *
541 engine, GstAdaptiveDemuxTestOutputStream * stream, gpointer user_data)
542 {
543 GstAdaptiveDemuxTestCase *testData = GST_ADAPTIVE_DEMUX_TEST_CASE (user_data);
544 GstAdaptiveDemuxTestExpectedOutput *testOutputStreamData;
545
546 testOutputStreamData =
547 gst_adaptive_demux_test_find_test_data_by_stream (testData, stream, NULL);
548 fail_unless (testOutputStreamData != NULL);
549
550 /* expect to receive more than 0 */
551 fail_unless (stream->total_received_size > 0,
552 "size validation failed for %s, expected > 0, received %d",
553 testOutputStreamData->name, stream->total_received_size);
554
555 /* expect to receive less than file size */
556 fail_unless (stream->total_received_size <
557 testOutputStreamData->expected_size,
558 "size validation failed for %s, expected < %d received %d",
559 testOutputStreamData->name, testOutputStreamData->expected_size,
560 stream->total_received_size);
561 }
562
563 /*
564 * Test fragment download error
565 * Let the adaptive demux download a few bytes, then instruct the
566 * GstTestHTTPSrc element to generate an error.
567 */
GST_START_TEST(testFragmentDownloadError)568 GST_START_TEST (testFragmentDownloadError)
569 {
570 const gchar *mpd =
571 "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
572 "<SmoothStreamingMedia MajorVersion=\"2\" MinorVersion=\"0\" Duration=\"4000000\">"
573 "<StreamIndex Type=\"audio\" Language=\"eng\" QualityLevels=\"1\" Chunks=\"1\" Url=\"QualityLevels({bitrate})/Fragments(audio_eng={start time})\">"
574 "<QualityLevel Index=\"0\" Bitrate=\"200029\" FourCC=\"AACL\" SamplingRate=\"48000\" Channels=\"2\" BitsPerSample=\"16\" PacketSize=\"4\" AudioTag=\"255\" CodecPrivateData=\"1190\" />"
575 "<c n=\"0\" d=\"10000000\" />" "</StreamIndex>" "</SmoothStreamingMedia>";
576
577 GstMssDemuxTestInputData inputTestData[] = {
578 {"http://unit.test/Manifest", (guint8 *) mpd, 0},
579 {"http://unit.test/QualityLevels(200029)/Fragments(audio_eng=0)", NULL,
580 5000},
581 {NULL, NULL, 0},
582 };
583 GstTestHTTPSrcCallbacks http_src_callbacks = { 0 };
584 GstAdaptiveDemuxTestExpectedOutput outputTestData[] = {
585 {"audio_00", 5000, NULL},
586 };
587 GstAdaptiveDemuxTestCallbacks test_callbacks = { 0 };
588 GstAdaptiveDemuxTestCase *testData;
589
590 testData = gst_adaptive_demux_test_case_new ();
591 http_src_callbacks.src_start = gst_mssdemux_http_src_start;
592 http_src_callbacks.src_create = test_fragment_download_error_src_create;
593 COPY_OUTPUT_TEST_DATA (outputTestData, testData);
594 test_callbacks.appsink_received_data =
595 gst_adaptive_demux_test_check_received_data;
596 test_callbacks.appsink_eos = testFragmentDownloadErrorCheckSizeOfDataReceived;
597 /* test_callbacks.demux_sent_eos = gst_adaptive_demux_test_check_size_of_received_data; */
598
599 test_callbacks.bus_error_message = testDownloadErrorMessageCallback;
600
601 gst_test_http_src_install_callbacks (&http_src_callbacks, inputTestData);
602 gst_adaptive_demux_test_run (DEMUX_ELEMENT_NAME,
603 "http://unit.test/Manifest", &test_callbacks, testData);
604 g_object_unref (testData);
605 }
606
607 GST_END_TEST;
608
609 static Suite *
mss_demux_suite(void)610 mss_demux_suite (void)
611 {
612 Suite *s = suite_create ("mss_demux");
613 TCase *tc_basicTest = tcase_create ("basicTest");
614
615 tcase_add_test (tc_basicTest, simpleTest);
616 tcase_add_test (tc_basicTest, testSeek);
617 tcase_add_test (tc_basicTest, testSeekKeyUnitPosition);
618 tcase_add_test (tc_basicTest, testSeekPosition);
619 tcase_add_test (tc_basicTest, testSeekUpdateStopPosition);
620 tcase_add_test (tc_basicTest, testSeekSnapBeforePosition);
621 tcase_add_test (tc_basicTest, testSeekSnapAfterPosition);
622 tcase_add_test (tc_basicTest, testReverseSeekSnapBeforePosition);
623 tcase_add_test (tc_basicTest, testReverseSeekSnapAfterPosition);
624 tcase_add_test (tc_basicTest, testDownloadError);
625 tcase_add_test (tc_basicTest, testFragmentDownloadError);
626 tcase_add_test (tc_basicTest, testQuery);
627
628 tcase_add_unchecked_fixture (tc_basicTest, gst_adaptive_demux_test_setup,
629 gst_adaptive_demux_test_teardown);
630
631 suite_add_tcase (s, tc_basicTest);
632
633 return s;
634 }
635
636 GST_CHECK_MAIN (mss_demux);
637