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\n",
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\n", 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