1 /* GStreamer
2 *
3 * unit test for hlsdemux
4 *
5 * Copyright (C) <2012> Fluendo S.A <support@fluendo.com>
6 * Authors: Andoni Morales Alastruey <amorales@fluendo.com>
7 * Copyright (C) 2014 Sebastian Dröge <sebastian@centricular.com>
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
18 *
19 * You should have received a copy of the GNU Library General Public
20 * License along with this library; if not, write to the
21 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 * Boston, MA 02111-1307, USA.
23 */
24
25 #include <unistd.h>
26
27 #include <gst/check/gstcheck.h>
28
29 #undef GST_CAT_DEFAULT
30 #include "m3u8.h"
31 #include "m3u8.c"
32
33 GST_DEBUG_CATEGORY (hls_debug);
34
35 static const gchar *INVALID_PLAYLIST = "#EXTM3 UINVALID";
36
37 static const gchar *ON_DEMAND_PLAYLIST = "#EXTM3U \n\
38 #EXT-X-TARGETDURATION:10\n\
39 #EXTINF:10,Test\n\
40 http://media.example.com/001.ts\n\
41 #EXTINF:10,Test\n\
42 http://media.example.com/002.ts\n\
43 #EXTINF:10,Test\n\
44 http://media.example.com/003.ts\n\
45 #EXTINF:10,Test\n\
46 http://media.example.com/004.ts\n\
47 #EXT-X-ENDLIST";
48
49 static const gchar *DOUBLES_PLAYLIST = "#EXTM3U \n\
50 #EXT-X-TARGETDURATION:10\n\
51 #EXTINF:10.321,Test\n\
52 http://media.example.com/001.ts\n\
53 #EXTINF:9.6789,Test\n\
54 http://media.example.com/002.ts\n\
55 #EXTINF:10.2344,Test\n\
56 http://media.example.com/003.ts\n\
57 #EXTINF:9.92,Test\n\
58 http://media.example.com/004.ts\n\
59 #EXT-X-ENDLIST";
60
61 static const gchar *LIVE_PLAYLIST = "#EXTM3U\n\
62 #EXT-X-TARGETDURATION:8\n\
63 #EXT-X-MEDIA-SEQUENCE:2680\n\
64 \n\
65 #EXTINF:8,\n\
66 https://priv.example.com/fileSequence2680.ts\n\
67 #EXTINF:8,\n\
68 https://priv.example.com/fileSequence2681.ts\n\
69 #EXTINF:8,\n\
70 https://priv.example.com/fileSequence2682.ts\n\
71 #EXTINF:8,\n\
72 https://priv.example.com/fileSequence2683.ts";
73
74 static const gchar *LIVE_ROTATED_PLAYLIST = "#EXTM3U\n\
75 #EXT-X-TARGETDURATION:8\n\
76 #EXT-X-MEDIA-SEQUENCE:3001\n\
77 \n\
78 #EXTINF:8,\n\
79 https://priv.example.com/fileSequence3001.ts\n\
80 #EXTINF:8,\n\
81 https://priv.example.com/fileSequence3002.ts\n\
82 #EXTINF:8,\n\
83 https://priv.example.com/fileSequence3003.ts\n\
84 #EXTINF:8,\n\
85 https://priv.example.com/fileSequence3004.ts";
86
87 static const gchar *VARIANT_PLAYLIST = "#EXTM3U \n\
88 #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=128000\n\
89 http://example.com/low.m3u8\n\
90 #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=256000\n\
91 http://example.com/mid.m3u8\n\
92 #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=768000\n\
93 http://example.com/hi.m3u8\n\
94 #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=65000,CODECS=\"mp4a.40.5\"\n\
95 http://example.com/audio-only.m3u8";
96
97 static const gchar *VARIANT_PLAYLIST_WITH_URI_MISSING = "#EXTM3U \n\
98 #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=128000\n\
99 http://example.com/low.m3u8\n\
100 #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=256000\n\
101 \n\
102 #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=768000\n\
103 http://example.com/hi.m3u8\n\
104 #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=65000,CODECS=\"mp4a.40.5\"\n\
105 http://example.com/audio-only.m3u8";
106
107 static const gchar *EMPTY_LINES_VARIANT_PLAYLIST = "#EXTM3U \n\
108 #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=128000\n\n\
109 http://example.com/low.m3u8\n\n\
110 #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=256000\n\n\
111 http://example.com/mid.m3u8\n\n\
112 #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=768000\n\n\
113 http://example.com/hi.m3u8\n\n\
114 #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=65000,CODECS=\"mp4a.40.5\"\n\n\
115 http://example.com/audio-only.m3u8";
116
117 static const gchar *WINDOWS_EMPTY_LINES_VARIANT_PLAYLIST = "#EXTM3U \r\n\
118 #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=128000\r\n\r\n\
119 http://example.com/low.m3u8\r\n\r\n\
120 #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=256000\r\n\r\n\
121 http://example.com/mid.m3u8\r\n\r\n\
122 #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=768000\r\n\r\n\
123 http://example.com/hi.m3u8\r\n\r\n\
124 #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=65000,CODECS=\"mp4a.40.5\"\r\n\r\n\
125 http://example.com/audio-only.m3u8";
126
127 static const gchar *EMPTY_LINES_PLAYLIST = "#EXTM3U \n\n\
128 #EXT-X-TARGETDURATION:10\n\
129 #EXTINF:10,Testr\n\n\
130 http://media.example.com/001.ts\n\n\
131 #EXTINF:10,Test\n\n\
132 http://media.example.com/002.ts\n\n\
133 #EXTINF:10,Test\n\n\
134 http://media.example.com/003.ts\n\n\
135 #EXTINF:10,Test\n\n\
136 http://media.example.com/004.ts\n\n\
137 #EXT-X-ENDLIST";
138
139 static const gchar *WINDOWS_EMPTY_LINES_PLAYLIST = "#EXTM3U \r\n\
140 #EXT-X-TARGETDURATION:10\r\n\r\n\
141 #EXTINF:10,Test\r\n\r\n\
142 http://media.example.com/001.ts\r\n\r\n\
143 #EXTINF:10,Test\r\n\r\n\
144 http://media.example.com/002.ts\r\n\r\n\
145 #EXTINF:10,Test\r\n\r\n\
146 http://media.example.com/003.ts\r\n\r\n\
147 #EXTINF:10,Test\r\n\r\n\
148 http://media.example.com/004.ts\r\n\r\n\
149 #EXT-X-ENDLIST";
150
151 static const gchar *BYTE_RANGES_PLAYLIST = "#EXTM3U \n\
152 #EXT-X-TARGETDURATION:40\n\
153 #EXTINF:10,Test\n\
154 #EXT-X-BYTERANGE:1000@100\n\
155 http://media.example.com/all.ts\n\
156 #EXTINF:10,Test\n\
157 #EXT-X-BYTERANGE:1000@1000\n\
158 http://media.example.com/all.ts\n\
159 #EXTINF:10,Test\n\
160 #EXT-X-BYTERANGE:1000@2000\n\
161 http://media.example.com/all.ts\n\
162 #EXTINF:10,Test\n\
163 #EXT-X-BYTERANGE:1000@3000\n\
164 http://media.example.com/all.ts\n\
165 #EXT-X-ENDLIST";
166
167 static const gchar *BYTE_RANGES_ACC_OFFSET_PLAYLIST = "#EXTM3U \n\
168 #EXT-X-TARGETDURATION:40\n\
169 #EXTINF:10,Test\n\
170 #EXT-X-BYTERANGE:1000\n\
171 http://media.example.com/all.ts\n\
172 #EXTINF:10,Test\n\
173 #EXT-X-BYTERANGE:1000\n\
174 http://media.example.com/all.ts\n\
175 #EXTINF:10,Test\n\
176 #EXT-X-BYTERANGE:1000\n\
177 http://media.example.com/all.ts\n\
178 #EXTINF:10,Test\n\
179 #EXT-X-BYTERANGE:1000\n\
180 http://media.example.com/all.ts\n\
181 #EXT-X-ENDLIST";
182
183 #if 0
184 static const gchar *ALTERNATE_AUDIO_PLAYLIST = "#EXTM3U\n\
185 #EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID=\"aac\",NAME=\"English\",\
186 DEFAULT=YES,AUTOSELECT=YES,LANGUAGE=\"en\" \n\
187 #EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID=\"aac\",NAME=\"Deutsche\",\
188 DEFAULT=NO,AUTOSELECT=YES,LANGUAGE=\"de\",\
189 URI=\"http://localhost/main/german-audio.m3u8\"\n\
190 #EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID=\"aac\",NAME=\"Commentary\",\
191 DEFAULT=NO,AUTOSELECT=NO,\
192 URI=\"http://localhost/commentary/audio-only.m3u8\"\n\
193 #EXT-X-STREAM-INF:BANDWIDTH=128000,CODECS=\"avc1.42001f\",AUDIO=\"aac\"\n\
194 low/video-only.m3u8\n\
195 #EXT-X-STREAM-INF:BANDWIDTH=256000,CODECS=\"avc1.42001f\",AUDIO=\"aac\"\n\
196 mid/video-only.m3u8\n\
197 #EXT-X-STREAM-INF:BANDWIDTH=768000,CODECS=\"avc1.42001f\",AUDIO=\"aac\"\n\
198 hi/video-only.m3u8\n\
199 #EXT-X-STREAM-INF:BANDWIDTH=65000,CODECS=\"mp4a.40.5\",AUDIO=\"aac\"\n\
200 main/english-audio.m3u8";
201
202 static const gchar *ALT_AUDIO_PLAYLIST_WITH_VIDEO_AUDIO = "#EXTM3U\n\
203 #EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID=\"aac\",NAME=\"English\",\
204 DEFAULT=YES,AUTOSELECT=YES,LANGUAGE=\"en\" \n\
205 #EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID=\"aac\",NAME=\"Deutsche\",\
206 DEFAULT=NO,AUTOSELECT=YES,LANGUAGE=\"de\",\
207 URI=\"http://localhost/main/german-audio.m3u8\"\n\
208 #EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID=\"aac\",NAME=\"Commentary\",\
209 DEFAULT=NO,AUTOSELECT=NO,\
210 URI=\"http://localhost/commentary/audio-only.m3u8\"\n\
211 #EXT-X-STREAM-INF:BANDWIDTH=128000,CODECS=\"avc1.42001f, mp4a.40.5\",AUDIO=\"aac\"\n\
212 low/video-audio.m3u8\n\
213 #EXT-X-STREAM-INF:BANDWIDTH=256000,CODECS=\"avc1.42001f, mp4a.40.5\",AUDIO=\"aac\"\n\
214 mid/video-audio.m3u8\n\
215 #EXT-X-STREAM-INF:BANDWIDTH=768000,CODECS=\"avc1.42001f, mp4a.40.5\",AUDIO=\"aac\"\n\
216 hi/video-audio.m3u8\n\
217 #EXT-X-STREAM-INF:BANDWIDTH=65000,CODECS=\"mp4a.40.5\",AUDIO=\"aac\"\n\
218 main/english-audio.m3u8";
219
220 static const gchar *ON_DEMAND_LOW_VIDEO_ONLY_PLAYLIST = "#EXTM3U \n\
221 #EXT-X-TARGETDURATION:10\n\
222 #EXTINF:10,Test\n\
223 http://media.example.com/low/video-only-001.ts\n\
224 #EXTINF:10,Test\n\
225 http://media.example.com/low/video-only-002.ts\n\
226 #EXTINF:10,Test\n\
227 http://media.example.com/low/video-only-003.ts\n\
228 #EXTINF:10,Test\n\
229 http://media.example.com/low/video-only-004.ts\n\
230 #EXT-X-ENDLIST";
231
232 static const gchar *ON_DEMAND_MID_VIDEO_ONLY_PLAYLIST = "#EXTM3U \n\
233 #EXT-X-TARGETDURATION:10\n\
234 #EXTINF:10,Test\n\
235 http://media.example.com/mid/video-only-001.ts\n\
236 #EXTINF:10,Test\n\
237 http://media.example.com/mid/video-only-002.ts\n\
238 #EXTINF:10,Test\n\
239 http://media.example.com/mid/video-only-003.ts\n\
240 #EXTINF:10,Test\n\
241 http://media.example.com/mid/video-only-004.ts\n\
242 #EXT-X-ENDLIST";
243
244 static const gchar *ON_DEMAND_ENGLISH_PLAYLIST = "#EXTM3U \n\
245 #EXT-X-TARGETDURATION:10\n\
246 #EXTINF:10,Test\n\
247 http://media.example.com/audio/english-001.ts\n\
248 #EXTINF:10,Test\n\
249 http://media.example.com/audio/english-002.ts\n\
250 #EXTINF:10,Test\n\
251 http://media.example.com/audio/english-003.ts\n\
252 #EXTINF:10,Test\n\
253 http://media.example.com/audio/english-004.ts\n\
254 #EXT-X-ENDLIST";
255
256 static const gchar *ON_DEMAND_GERMAN_PLAYLIST = "#EXTM3U \n\
257 #EXT-X-TARGETDURATION:10\n\
258 #EXTINF:10,Test\n\
259 http://media.example.com/audio/german-001.ts\n\
260 #EXTINF:10,Test\n\
261 http://media.example.com/audio/german-002.ts\n\
262 #EXTINF:10,Test\n\
263 http://media.example.com/audio/german-003.ts\n\
264 #EXTINF:10,Test\n\
265 http://media.example.com/audio/german-004.ts\n\
266 #EXT-X-ENDLIST";
267
268 static const gchar *SUBTITLES_PLAYLIST = "#EXTM3U\n\
269 #EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID=\"subs\",NAME=\"English\",\
270 DEFAULT=YES,LANGUAGE=\"en\",\
271 URI=\"http://localhost/main/subs-en.m3u8\"\n\
272 #EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID=\"subs\",NAME=\"Deutsche\",\
273 DEFAULT=NO,LANGUAGE=\"de\",\
274 URI=\"http://localhost/main/subs-de.m3u8\"\n\
275 #EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID=\"subs\",NAME=\"Spanish\",\
276 DEFAULT=NO,LANGUAGE=\"es\",\
277 URI=\"http://localhost/main/subs-es.m3u8\"\n\
278 #EXT-X-STREAM-INF:BANDWIDTH=128000,CODECS=\"avc1.42001f, mp4a.40.5\",SUBTITLES=\"subs\"\n\
279 low/video-audio.m3u8\n\
280 #EXT-X-STREAM-INF:BANDWIDTH=256000,CODECS=\"avc1.42001f, mp4a.40.5\",SUBTITLES=\"subs\"\n\
281 mid/video-audio.m3u8\n\
282 #EXT-X-STREAM-INF:BANDWIDTH=768000,CODECS=\"avc1.42001f, mp4a.40.5\",SUBTITLES=\"subs\"\n\
283 hi/video-audio.m3u8";
284 #endif
285
286 static const gchar *AES_128_ENCRYPTED_PLAYLIST = "#EXTM3U \n\
287 #EXT-X-TARGETDURATION:10\n\
288 #EXTINF:10,Test\n\
289 http://media.example.com/mid/video-only-001.ts\n\
290 #EXT-X-KEY:METHOD=NONE\n\
291 #EXTINF:10,Test\n\
292 http://media.example.com/mid/video-only-002.ts\n\
293 #EXT-X-KEY:METHOD=AES-128,URI=\"https://priv.example.com/key.bin\"\n\
294 #EXTINF:10,Test\n\
295 http://media.example.com/mid/video-only-003.ts\n\
296 #EXT-X-KEY:METHOD=AES-128,URI=\"https://priv.example.com/key2.bin\",IV=0x00000000000000000000000000000001\n\
297 #EXTINF:10,Test\n\
298 http://media.example.com/mid/video-only-004.ts\n\
299 #EXTINF:10,Test\n\
300 http://media.example.com/mid/video-only-005.ts\n\
301 #EXT-X-ENDLIST";
302
303 static const gchar *WINDOWS_LINE_ENDINGS_PLAYLIST = "#EXTM3U \r\n\
304 #EXT-X-TARGETDURATION:10\r\n\
305 #EXTINF:10,Test\r\n\
306 http://media.example.com/001.ts\r\n\
307 #EXTINF:10,Test\r\n\
308 http://media.example.com/002.ts\r\n\
309 #EXTINF:10,Test\r\n\
310 http://media.example.com/003.ts\r\n\
311 #EXTINF:10,Test\r\n\
312 http://media.example.com/004.ts\r\n\
313 #EXT-X-ENDLIST";
314
315 static const gchar *WINDOWS_LINE_ENDINGS_VARIANT_PLAYLIST = "#EXTM3U \r\n\
316 #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=128000\r\n\
317 http://example.com/low.m3u8\r\n\
318 #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=256000\r\n\
319 http://example.com/mid.m3u8\r\n\
320 #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=768000\r\n\
321 http://example.com/hi.m3u8\r\n\
322 #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=65000,CODECS=\"mp4a.40.5\"\r\n\
323 http://example.com/audio-only.m3u8";
324
325 static GstHLSMasterPlaylist *
load_playlist(const gchar * data)326 load_playlist (const gchar * data)
327 {
328 GstHLSMasterPlaylist *master;
329
330 master = gst_hls_master_playlist_new_from_data (g_strdup (data),
331 "http://localhost/test.m3u8");
332 fail_unless (master != NULL);
333
334 return master;
335 }
336
GST_START_TEST(test_load_main_playlist_invalid)337 GST_START_TEST (test_load_main_playlist_invalid)
338 {
339 GstHLSMasterPlaylist *master;
340
341 master =
342 gst_hls_master_playlist_new_from_data (g_strdup (INVALID_PLAYLIST), NULL);
343 fail_unless (master == NULL);
344 }
345
346 GST_END_TEST;
347
GST_START_TEST(test_load_main_playlist_rendition)348 GST_START_TEST (test_load_main_playlist_rendition)
349 {
350 GstHLSMasterPlaylist *master;
351 GstHLSVariantStream *variant;
352
353 master = load_playlist (ON_DEMAND_PLAYLIST);
354 variant = master->default_variant;
355
356 assert_equals_int (g_list_length (variant->m3u8->files), 4);
357 assert_equals_int (master->version, 0);
358
359 gst_hls_master_playlist_unref (master);
360 }
361
362 GST_END_TEST;
363
364 static void
do_test_load_main_playlist_variant(const gchar * playlist)365 do_test_load_main_playlist_variant (const gchar * playlist)
366 {
367 GstHLSMasterPlaylist *master;
368 GstHLSVariantStream *stream;
369 GList *tmp;
370
371 master = gst_hls_master_playlist_new_from_data (g_strdup (playlist), NULL);
372 fail_unless (master != NULL);
373
374 assert_equals_int (g_list_length (master->variants), 4);
375
376 /* Audio-Only */
377 tmp = g_list_first (master->variants);
378 stream = tmp->data;
379 assert_equals_int (stream->bandwidth, 65000);
380 assert_equals_int (stream->program_id, 1);
381 assert_equals_string (stream->uri, "http://example.com/audio-only.m3u8");
382 assert_equals_string (stream->codecs, "mp4a.40.5");
383
384 /* Low */
385 tmp = g_list_next (tmp);
386 stream = tmp->data;
387 assert_equals_int (stream->bandwidth, 128000);
388 assert_equals_int (stream->program_id, 1);
389 assert_equals_string (stream->uri, "http://example.com/low.m3u8");
390
391 /* Mid */
392 tmp = g_list_next (tmp);
393 stream = tmp->data;
394 assert_equals_int (stream->bandwidth, 256000);
395 assert_equals_int (stream->program_id, 1);
396 assert_equals_string (stream->uri, "http://example.com/mid.m3u8");
397
398 /* High */
399 tmp = g_list_next (tmp);
400 stream = tmp->data;
401 assert_equals_int (stream->bandwidth, 768000);
402 assert_equals_int (stream->program_id, 1);
403 assert_equals_string (stream->uri, "http://example.com/hi.m3u8");
404
405 /* Check the first playlist is selected */
406 assert_equals_int (master->default_variant != NULL, TRUE);
407 assert_equals_int (master->default_variant->bandwidth, 128000);
408
409 gst_hls_master_playlist_unref (master);
410 }
411
GST_START_TEST(test_load_main_playlist_variant)412 GST_START_TEST (test_load_main_playlist_variant)
413 {
414 do_test_load_main_playlist_variant (VARIANT_PLAYLIST);
415 }
416
417 GST_END_TEST;
418
GST_START_TEST(test_load_main_playlist_variant_with_missing_uri)419 GST_START_TEST (test_load_main_playlist_variant_with_missing_uri)
420 {
421 GstHLSMasterPlaylist *master;
422
423 master = load_playlist (VARIANT_PLAYLIST_WITH_URI_MISSING);
424 assert_equals_int (g_list_length (master->variants), 3);
425 gst_hls_master_playlist_unref (master);
426 }
427
428 GST_END_TEST;
429
GST_START_TEST(test_load_windows_line_endings_variant_playlist)430 GST_START_TEST (test_load_windows_line_endings_variant_playlist)
431 {
432 do_test_load_main_playlist_variant (WINDOWS_LINE_ENDINGS_VARIANT_PLAYLIST);
433 }
434
435 GST_END_TEST;
436
GST_START_TEST(test_load_main_playlist_with_empty_lines)437 GST_START_TEST (test_load_main_playlist_with_empty_lines)
438 {
439 do_test_load_main_playlist_variant (EMPTY_LINES_VARIANT_PLAYLIST);
440 }
441
442 GST_END_TEST;
443
GST_START_TEST(test_load_windows_main_playlist_with_empty_lines)444 GST_START_TEST (test_load_windows_main_playlist_with_empty_lines)
445 {
446 do_test_load_main_playlist_variant (WINDOWS_EMPTY_LINES_VARIANT_PLAYLIST);
447 }
448
449 GST_END_TEST;
450
451 static void
check_on_demand_playlist(const gchar * data)452 check_on_demand_playlist (const gchar * data)
453 {
454 GstHLSMasterPlaylist *master;
455 GstM3U8 *pl;
456 GstM3U8MediaFile *file;
457
458 master = load_playlist (data);
459 pl = master->default_variant->m3u8;
460
461 /* Sequence should be 0 as it's an ondemand playlist */
462 assert_equals_int (pl->sequence, 0);
463 /* Check that we are not live */
464 assert_equals_int (gst_m3u8_is_live (pl), FALSE);
465 /* Check number of entries */
466 assert_equals_int (g_list_length (pl->files), 4);
467 /* Check first media segments */
468 file = GST_M3U8_MEDIA_FILE (g_list_first (pl->files)->data);
469 assert_equals_string (file->uri, "http://media.example.com/001.ts");
470 assert_equals_int (file->sequence, 0);
471 /* Check last media segments */
472 file = GST_M3U8_MEDIA_FILE (g_list_last (pl->files)->data);
473 assert_equals_string (file->uri, "http://media.example.com/004.ts");
474 assert_equals_int (file->sequence, 3);
475
476 gst_hls_master_playlist_unref (master);
477 }
478
GST_START_TEST(test_on_demand_playlist)479 GST_START_TEST (test_on_demand_playlist)
480 {
481 check_on_demand_playlist (ON_DEMAND_PLAYLIST);
482 }
483
484 GST_END_TEST;
485
GST_START_TEST(test_windows_line_endings_playlist)486 GST_START_TEST (test_windows_line_endings_playlist)
487 {
488 check_on_demand_playlist (WINDOWS_LINE_ENDINGS_PLAYLIST);
489 }
490
491 GST_END_TEST;
492
GST_START_TEST(test_empty_lines_playlist)493 GST_START_TEST (test_empty_lines_playlist)
494 {
495 check_on_demand_playlist (EMPTY_LINES_PLAYLIST);
496 }
497
498 GST_END_TEST;
499
GST_START_TEST(test_windows_empty_lines_playlist)500 GST_START_TEST (test_windows_empty_lines_playlist)
501 {
502 check_on_demand_playlist (WINDOWS_EMPTY_LINES_PLAYLIST);
503 }
504
505 GST_END_TEST;
506
GST_START_TEST(test_live_playlist)507 GST_START_TEST (test_live_playlist)
508 {
509 GstHLSMasterPlaylist *master;
510 GstM3U8 *pl;
511 GstM3U8MediaFile *file;
512 gint64 start = -1;
513 gint64 stop = -1;
514
515 master = load_playlist (LIVE_PLAYLIST);
516
517 pl = master->default_variant->m3u8;
518 /* Check that we are live */
519 assert_equals_int (gst_m3u8_is_live (pl), TRUE);
520 assert_equals_int (pl->sequence, 2680);
521 /* Check number of entries */
522 assert_equals_int (g_list_length (pl->files), 4);
523 /* Check first media segments */
524 file = GST_M3U8_MEDIA_FILE (g_list_first (pl->files)->data);
525 assert_equals_string (file->uri,
526 "https://priv.example.com/fileSequence2680.ts");
527 assert_equals_int (file->sequence, 2680);
528 /* Check last media segments */
529 file = GST_M3U8_MEDIA_FILE (g_list_last (pl->files)->data);
530 assert_equals_string (file->uri,
531 "https://priv.example.com/fileSequence2683.ts");
532 assert_equals_int (file->sequence, 2683);
533 fail_unless (gst_m3u8_get_seek_range (pl, &start, &stop));
534 assert_equals_int64 (start, 0);
535 assert_equals_float (stop / (double) GST_SECOND, 8.0);
536
537 gst_hls_master_playlist_unref (master);
538 }
539
540 GST_END_TEST;
541
542 /* This test is for live sreams in which we pause the stream for more than the
543 * DVR window and we resume playback. The playlist has rotated completely and
544 * there is a jump in the media sequence that must be handled correctly. */
GST_START_TEST(test_live_playlist_rotated)545 GST_START_TEST (test_live_playlist_rotated)
546 {
547 GstHLSMasterPlaylist *master;
548 GstM3U8 *pl;
549 GstM3U8MediaFile *file;
550 gboolean ret;
551
552 master = load_playlist (LIVE_PLAYLIST);
553 pl = master->default_variant->m3u8;
554
555 assert_equals_int (pl->sequence, 2680);
556 /* Check first media segments */
557 file = GST_M3U8_MEDIA_FILE (g_list_first (pl->files)->data);
558 assert_equals_int (file->sequence, 2680);
559
560 ret = gst_m3u8_update (pl, g_strdup (LIVE_ROTATED_PLAYLIST));
561 assert_equals_int (ret, TRUE);
562 file = gst_m3u8_get_next_fragment (pl, TRUE, NULL, NULL);
563 fail_unless (file != NULL);
564 gst_m3u8_media_file_unref (file);
565
566 /* FIXME: Sequence should last - 3. Should it? */
567 assert_equals_int (pl->sequence, 3001);
568 /* Check first media segments */
569 file = GST_M3U8_MEDIA_FILE (g_list_first (pl->files)->data);
570 assert_equals_int (file->sequence, 3001);
571
572 gst_hls_master_playlist_unref (master);
573 }
574
575 GST_END_TEST;
576
GST_START_TEST(test_playlist_with_doubles_duration)577 GST_START_TEST (test_playlist_with_doubles_duration)
578 {
579 GstHLSMasterPlaylist *master;
580 GstM3U8 *pl;
581 GstM3U8MediaFile *file;
582 gint64 start = -1;
583 gint64 stop = -1;
584
585 master = load_playlist (DOUBLES_PLAYLIST);
586 pl = master->default_variant->m3u8;
587
588 /* Check first media segments */
589 file = GST_M3U8_MEDIA_FILE (g_list_nth_data (pl->files, 0));
590 assert_equals_float (file->duration / (double) GST_SECOND, 10.321);
591 file = GST_M3U8_MEDIA_FILE (g_list_nth_data (pl->files, 1));
592 assert_equals_float (file->duration / (double) GST_SECOND, 9.6789);
593 file = GST_M3U8_MEDIA_FILE (g_list_nth_data (pl->files, 2));
594 assert_equals_float (file->duration / (double) GST_SECOND, 10.2344);
595 file = GST_M3U8_MEDIA_FILE (g_list_nth_data (pl->files, 3));
596 assert_equals_float (file->duration / (double) GST_SECOND, 9.92);
597 fail_unless (gst_m3u8_get_seek_range (pl, &start, &stop));
598 assert_equals_int64 (start, 0);
599 assert_equals_float (stop / (double) GST_SECOND,
600 10.321 + 9.6789 + 10.2344 + 9.92);
601
602 gst_hls_master_playlist_unref (master);
603 }
604
605 GST_END_TEST;
606
GST_START_TEST(test_playlist_with_encryption)607 GST_START_TEST (test_playlist_with_encryption)
608 {
609 GstHLSMasterPlaylist *master;
610 GstM3U8 *pl;
611 GstM3U8MediaFile *file;
612 guint8 iv1[16] = { 0, };
613 guint8 iv2[16] = { 0, };
614
615 iv1[15] = 1;
616 iv2[15] = 2;
617
618 master = load_playlist (AES_128_ENCRYPTED_PLAYLIST);
619 pl = master->default_variant->m3u8;
620
621 assert_equals_int (g_list_length (pl->files), 5);
622
623 /* Check all media segments */
624 file = GST_M3U8_MEDIA_FILE (g_list_nth_data (pl->files, 0));
625 fail_unless (file->key == NULL);
626
627 file = GST_M3U8_MEDIA_FILE (g_list_nth_data (pl->files, 1));
628 fail_unless (file->key == NULL);
629
630 file = GST_M3U8_MEDIA_FILE (g_list_nth_data (pl->files, 2));
631 fail_unless (file->key != NULL);
632 assert_equals_string (file->key, "https://priv.example.com/key.bin");
633 fail_unless (memcmp (&file->iv, iv2, 16) == 0);
634
635 file = GST_M3U8_MEDIA_FILE (g_list_nth_data (pl->files, 3));
636 fail_unless (file->key != NULL);
637 assert_equals_string (file->key, "https://priv.example.com/key2.bin");
638 fail_unless (memcmp (&file->iv, iv1, 16) == 0);
639
640 file = GST_M3U8_MEDIA_FILE (g_list_nth_data (pl->files, 4));
641 fail_unless (file->key != NULL);
642 assert_equals_string (file->key, "https://priv.example.com/key2.bin");
643 fail_unless (memcmp (&file->iv, iv1, 16) == 0);
644
645 gst_hls_master_playlist_unref (master);
646 }
647
648 GST_END_TEST;
649
650
GST_START_TEST(test_update_invalid_playlist)651 GST_START_TEST (test_update_invalid_playlist)
652 {
653 GstHLSMasterPlaylist *master;
654 GstM3U8 *pl;
655 gboolean ret;
656
657 /* Test updates in on-demand playlists */
658 master = load_playlist (ON_DEMAND_PLAYLIST);
659 pl = master->default_variant->m3u8;
660 assert_equals_int (g_list_length (pl->files), 4);
661 ret = gst_m3u8_update (pl, g_strdup ("#INVALID"));
662 assert_equals_int (ret, FALSE);
663
664 gst_hls_master_playlist_unref (master);
665 }
666
667 GST_END_TEST;
668
GST_START_TEST(test_update_playlist)669 GST_START_TEST (test_update_playlist)
670 {
671 GstHLSMasterPlaylist *master;
672 GstM3U8 *pl;
673 gchar *live_pl;
674 gboolean ret;
675
676 /* Test updates in on-demand playlists */
677 master = load_playlist (ON_DEMAND_PLAYLIST);
678 pl = master->default_variant->m3u8;
679 assert_equals_int (g_list_length (pl->files), 4);
680 ret = gst_m3u8_update (pl, g_strdup (ON_DEMAND_PLAYLIST));
681 assert_equals_int (ret, TRUE);
682 assert_equals_int (g_list_length (pl->files), 4);
683 gst_hls_master_playlist_unref (master);
684
685 /* Test updates in live playlists */
686 master = load_playlist (LIVE_PLAYLIST);
687 pl = master->default_variant->m3u8;
688 assert_equals_int (g_list_length (pl->files), 4);
689 /* Add a new entry to the playlist and check the update */
690 live_pl = g_strdup_printf ("%s\n%s\n%s", LIVE_PLAYLIST, "#EXTINF:8",
691 "https://priv.example.com/fileSequence2683.ts");
692 ret = gst_m3u8_update (pl, live_pl);
693 assert_equals_int (ret, TRUE);
694 assert_equals_int (g_list_length (pl->files), 5);
695 /* Test sliding window */
696 ret = gst_m3u8_update (pl, g_strdup (LIVE_PLAYLIST));
697 assert_equals_int (ret, TRUE);
698 assert_equals_int (g_list_length (pl->files), 4);
699 gst_hls_master_playlist_unref (master);
700 }
701
702 GST_END_TEST;
703
GST_START_TEST(test_playlist_media_files)704 GST_START_TEST (test_playlist_media_files)
705 {
706 GstHLSMasterPlaylist *master;
707 GstM3U8 *pl;
708 GstM3U8MediaFile *file;
709
710 master = load_playlist (ON_DEMAND_PLAYLIST);
711 pl = master->default_variant->m3u8;
712
713 /* Check number of entries */
714 assert_equals_int (g_list_length (pl->files), 4);
715 /* Check first media segments */
716 file = GST_M3U8_MEDIA_FILE (g_list_first (pl->files)->data);
717 assert_equals_string (file->uri, "http://media.example.com/001.ts");
718 assert_equals_int (file->sequence, 0);
719 assert_equals_float (file->duration, 10 * (double) GST_SECOND);
720 assert_equals_int (file->offset, 0);
721 assert_equals_int (file->size, -1);
722 assert_equals_string (file->title, "Test");
723
724 gst_hls_master_playlist_unref (master);
725 }
726
727 GST_END_TEST;
728
GST_START_TEST(test_playlist_byte_range_media_files)729 GST_START_TEST (test_playlist_byte_range_media_files)
730 {
731 GstHLSMasterPlaylist *master;
732 GstM3U8 *pl;
733 GstM3U8MediaFile *file;
734
735 master = load_playlist (BYTE_RANGES_PLAYLIST);
736 pl = master->default_variant->m3u8;
737
738 /* Check number of entries */
739 assert_equals_int (g_list_length (pl->files), 4);
740 /* Check first media segments */
741 file = GST_M3U8_MEDIA_FILE (g_list_first (pl->files)->data);
742 assert_equals_string (file->uri, "http://media.example.com/all.ts");
743 assert_equals_int (file->sequence, 0);
744 assert_equals_float (file->duration, 10 * (double) GST_SECOND);
745 assert_equals_int (file->offset, 100);
746 assert_equals_int (file->size, 1000);
747 /* Check last media segments */
748 file = GST_M3U8_MEDIA_FILE (g_list_last (pl->files)->data);
749 assert_equals_string (file->uri, "http://media.example.com/all.ts");
750 assert_equals_int (file->sequence, 3);
751 assert_equals_float (file->duration, 10 * (double) GST_SECOND);
752 assert_equals_int (file->offset, 3000);
753 assert_equals_int (file->size, 1000);
754
755 gst_hls_master_playlist_unref (master);
756
757
758 master = load_playlist (BYTE_RANGES_ACC_OFFSET_PLAYLIST);
759 pl = master->default_variant->m3u8;
760
761 /* Check number of entries */
762 assert_equals_int (g_list_length (pl->files), 4);
763 /* Check first media segments */
764 file = GST_M3U8_MEDIA_FILE (g_list_first (pl->files)->data);
765 assert_equals_string (file->uri, "http://media.example.com/all.ts");
766 assert_equals_int (file->sequence, 0);
767 assert_equals_float (file->duration, 10 * (double) GST_SECOND);
768 assert_equals_int (file->offset, 0);
769 assert_equals_int (file->size, 1000);
770 /* Check last media segments */
771 file = GST_M3U8_MEDIA_FILE (g_list_last (pl->files)->data);
772 assert_equals_string (file->uri, "http://media.example.com/all.ts");
773 assert_equals_int (file->sequence, 3);
774 assert_equals_float (file->duration, 10 * (double) GST_SECOND);
775 assert_equals_int (file->offset, 3000);
776 assert_equals_int (file->size, 1000);
777
778 gst_hls_master_playlist_unref (master);
779 }
780
781 GST_END_TEST;
782
GST_START_TEST(test_get_next_fragment)783 GST_START_TEST (test_get_next_fragment)
784 {
785 GstHLSMasterPlaylist *master;
786 GstM3U8 *pl;
787 GstM3U8MediaFile *mf;
788 gboolean discontinous;
789 GstClockTime timestamp;
790
791 master = load_playlist (BYTE_RANGES_PLAYLIST);
792 pl = master->default_variant->m3u8;
793
794 /* Check the next fragment */
795 mf = gst_m3u8_get_next_fragment (pl, TRUE, ×tamp, &discontinous);
796 fail_unless (mf != NULL);
797 assert_equals_int (discontinous, FALSE);
798 assert_equals_string (mf->uri, "http://media.example.com/all.ts");
799 assert_equals_uint64 (timestamp, 0);
800 assert_equals_uint64 (mf->duration, 10 * GST_SECOND);
801 assert_equals_uint64 (mf->offset, 100);
802 assert_equals_uint64 (mf->offset + mf->size, 1100);
803 gst_m3u8_media_file_unref (mf);
804
805 gst_m3u8_advance_fragment (pl, TRUE);
806
807 /* Check next media segments */
808 mf = gst_m3u8_get_next_fragment (pl, TRUE, ×tamp, &discontinous);
809 fail_unless (mf != NULL);
810 assert_equals_int (discontinous, FALSE);
811 assert_equals_string (mf->uri, "http://media.example.com/all.ts");
812 assert_equals_uint64 (timestamp, 10 * GST_SECOND);
813 assert_equals_uint64 (mf->duration, 10 * GST_SECOND);
814 assert_equals_uint64 (mf->offset, 1000);
815 assert_equals_uint64 (mf->offset + mf->size, 2000);
816 gst_m3u8_media_file_unref (mf);
817
818 gst_m3u8_advance_fragment (pl, TRUE);
819
820 /* Check next media segments */
821 mf = gst_m3u8_get_next_fragment (pl, TRUE, ×tamp, &discontinous);
822 assert_equals_int (discontinous, FALSE);
823 assert_equals_string (mf->uri, "http://media.example.com/all.ts");
824 assert_equals_uint64 (timestamp, 20 * GST_SECOND);
825 assert_equals_uint64 (mf->duration, 10 * GST_SECOND);
826 assert_equals_uint64 (mf->offset, 2000);
827 assert_equals_uint64 (mf->offset + mf->size, 3000);
828 gst_m3u8_media_file_unref (mf);
829
830 gst_hls_master_playlist_unref (master);
831 }
832
833 GST_END_TEST;
834
GST_START_TEST(test_get_duration)835 GST_START_TEST (test_get_duration)
836 {
837 GstHLSMasterPlaylist *master;
838 GstM3U8 *pl;
839
840 /* Test duration for on-demand playlists */
841 master = load_playlist (ON_DEMAND_PLAYLIST);
842 pl = master->default_variant->m3u8;
843
844 assert_equals_uint64 (gst_m3u8_get_duration (pl), 40 * GST_SECOND);
845 gst_hls_master_playlist_unref (master);
846
847 /* Test duration for live playlists */
848 master = load_playlist (LIVE_PLAYLIST);
849 pl = master->default_variant->m3u8;
850 assert_equals_uint64 (gst_m3u8_get_duration (pl), GST_CLOCK_TIME_NONE);
851
852 gst_hls_master_playlist_unref (master);
853 }
854
855 GST_END_TEST;
856
GST_START_TEST(test_get_target_duration)857 GST_START_TEST (test_get_target_duration)
858 {
859 GstHLSMasterPlaylist *master;
860 GstM3U8 *pl;
861
862 master = load_playlist (ON_DEMAND_PLAYLIST);
863 pl = master->default_variant->m3u8;
864
865 assert_equals_uint64 (gst_m3u8_get_target_duration (pl), 10 * GST_SECOND);
866
867 gst_hls_master_playlist_unref (master);
868 }
869
870 GST_END_TEST;
871
872
GST_START_TEST(test_get_stream_for_bitrate)873 GST_START_TEST (test_get_stream_for_bitrate)
874 {
875 GstHLSMasterPlaylist *master;
876 GstHLSVariantStream *stream;
877
878 master = load_playlist (VARIANT_PLAYLIST);
879 stream = gst_hls_master_playlist_get_variant_for_bitrate (master, NULL, 0);
880
881 assert_equals_int (stream->bandwidth, 65000);
882
883 stream =
884 gst_hls_master_playlist_get_variant_for_bitrate (master, NULL,
885 G_MAXINT32);
886 assert_equals_int (stream->bandwidth, 768000);
887 stream =
888 gst_hls_master_playlist_get_variant_for_bitrate (master, NULL, 300000);
889 assert_equals_int (stream->bandwidth, 256000);
890 stream =
891 gst_hls_master_playlist_get_variant_for_bitrate (master, NULL, 500000);
892 assert_equals_int (stream->bandwidth, 256000);
893 stream =
894 gst_hls_master_playlist_get_variant_for_bitrate (master, NULL, 255000);
895 assert_equals_int (stream->bandwidth, 128000);
896
897 gst_hls_master_playlist_unref (master);
898 }
899
900 GST_END_TEST;
901
902 #if 0
903 static void
904 do_test_seek (GstM3U8Client * client, guint seek_pos, gint pos)
905 {
906 GstClockTime cur_pos;
907 gboolean ret;
908
909 ret = gst_m3u8_client_seek (client, seek_pos * GST_SECOND);
910 if (pos == -1) {
911 assert_equals_int (ret, FALSE);
912 return;
913 }
914 assert_equals_int (ret, TRUE);
915 gst_m3u8_client_get_current_position (client, &cur_pos, NULL);
916 assert_equals_uint64 (cur_pos, pos * GST_SECOND);
917 }
918
919 GST_START_TEST (test_seek)
920 {
921 GstM3U8Client *client;
922
923 master = load_playlist (ON_DEMAND_PLAYLIST);
924
925 /* Test seek in the middle of a fragment */
926 do_test_seek (client, 1, 0);
927 do_test_seek (client, 11, 10);
928 do_test_seek (client, 22, 20);
929 do_test_seek (client, 39, 30);
930
931 /* Test exact seeks */
932 do_test_seek (client, 0, 0);
933 do_test_seek (client, 10, 10);
934 do_test_seek (client, 20, 20);
935 do_test_seek (client, 30, 30);
936
937 /* Test invalid seeks (end if list should be 30 + 10) */
938 do_test_seek (client, 39, 30);
939 do_test_seek (client, 40, -1);
940 gst_hls_master_playlist_unref (master);
941
942 /* Test seeks on a live playlist */
943 master = load_playlist (LIVE_PLAYLIST);
944 do_test_seek (client, 0, 0);
945
946 do_test_seek (client, 8, 8);
947 do_test_seek (client, 20, 16);
948 do_test_seek (client, 30, 24);
949
950 do_test_seek (client, 3000, -1);
951 gst_hls_master_playlist_unref (master);
952 }
953
954 GST_END_TEST;
955
956 GST_START_TEST (test_alternate_audio_playlist)
957 {
958 GstM3U8Client *client;
959 GstM3U8Media *media;
960 GList *alternates;
961
962 master = load_playlist (ALTERNATE_AUDIO_PLAYLIST);
963
964 assert_equals_int (g_list_length (client->main->streams), 4);
965 assert_equals_int (g_hash_table_size (client->main->video_rendition_groups),
966 0);
967 assert_equals_int (g_hash_table_size (client->main->audio_rendition_groups),
968 1);
969 assert_equals_int (g_hash_table_size (client->
970 selected_stream->audio_alternates), 3);
971 assert_equals_int (g_hash_table_size (client->
972 selected_stream->video_alternates), 0);
973
974 alternates =
975 g_hash_table_lookup (client->main->audio_rendition_groups, "aac");
976 assert_equals_int (alternates != NULL, TRUE);
977 media = GST_M3U8_MEDIA (g_list_nth_data (alternates, 0));
978 assert_equals_int (media->media_type, GST_M3U8_MEDIA_TYPE_AUDIO);
979 assert_equals_string (media->group_id, "aac");
980 assert_equals_string (media->name, "English");
981 assert_equals_string (media->language, "en");
982 assert_equals_string (media->uri, "http://localhost/main/english-audio.m3u8");
983 assert_equals_string (media->uri, GST_M3U8 (media->playlist)->uri);
984 assert_equals_int (media->is_default, TRUE);
985 assert_equals_int (media->autoselect, TRUE);
986
987 assert_equals_int (g_hash_table_size (client->
988 selected_stream->audio_alternates), 3);
989 /* Check the list of audio alternates */
990 alternates = gst_m3u8_client_get_alternates (client,
991 GST_M3U8_MEDIA_TYPE_AUDIO);
992 assert_equals_int (g_list_length (alternates), 3);
993 /* Default comes always first */
994 assert_equals_string (g_list_nth_data (alternates, 0), "English");
995 assert_equals_string (g_list_nth_data (alternates, 1), "Commentary");
996 assert_equals_string (g_list_nth_data (alternates, 2), "Deutsche");
997
998 gst_hls_master_playlist_unref (master);
999 }
1000
1001 GST_END_TEST;
1002
1003 GST_START_TEST (test_subtitles_playlist)
1004 {
1005 GstM3U8Client *client;
1006 GstM3U8Media *media;
1007 GList *alternates;
1008
1009 master = load_playlist (SUBTITLES_PLAYLIST);
1010
1011 assert_equals_int (g_list_length (client->main->streams), 3);
1012 assert_equals_int (g_hash_table_size (client->main->video_rendition_groups),
1013 0);
1014 assert_equals_int (g_hash_table_size (client->main->audio_rendition_groups),
1015 0);
1016 assert_equals_int (g_hash_table_size (client->main->subtt_rendition_groups),
1017 1);
1018 assert_equals_int (g_hash_table_size (client->
1019 selected_stream->audio_alternates), 0);
1020 assert_equals_int (g_hash_table_size (client->
1021 selected_stream->video_alternates), 0);
1022 assert_equals_int (g_hash_table_size (client->
1023 selected_stream->subtt_alternates), 3);
1024
1025 alternates =
1026 g_hash_table_lookup (client->main->subtt_rendition_groups, "subs");
1027 assert_equals_int (alternates != NULL, TRUE);
1028 media = GST_M3U8_MEDIA (g_list_nth_data (alternates, 0));
1029 assert_equals_int (media->media_type, GST_M3U8_MEDIA_TYPE_SUBTITLES);
1030 assert_equals_string (media->group_id, "subs");
1031 assert_equals_string (media->name, "English");
1032 assert_equals_string (media->language, "en");
1033 assert_equals_string (media->uri, "http://localhost/main/subs-en.m3u8");
1034 assert_equals_string (media->uri, GST_M3U8 (media->playlist)->uri);
1035 assert_equals_int (media->is_default, TRUE);
1036 assert_equals_int (media->autoselect, FALSE);
1037
1038 /* Check the list of subtitles */
1039 alternates = gst_m3u8_client_get_alternates (client,
1040 GST_M3U8_MEDIA_TYPE_SUBTITLES);
1041 assert_equals_int (g_list_length (alternates), 3);
1042 assert_equals_string (g_list_nth_data (alternates, 0), "Deutsche");
1043 assert_equals_string (g_list_nth_data (alternates, 1), "Spanish");
1044 assert_equals_string (g_list_nth_data (alternates, 2), "English");
1045
1046 gst_hls_master_playlist_unref (master);
1047 }
1048
1049 GST_END_TEST;
1050 GST_START_TEST (test_select_subs_alternate)
1051 {
1052 GstM3U8Client *client;
1053 const gchar *a_uri, *v_uri, *s_uri;
1054 gboolean ret;
1055
1056 /* Check with a playlist with alternative audio renditions where the video
1057 * stream is video-only and therefor we always have 2 playlists, one for
1058 * video and another one for audio */
1059 master = load_playlist (SUBTITLES_PLAYLIST);
1060 gst_m3u8_client_get_current_uri (client, &v_uri, &a_uri, &s_uri);
1061 assert_equals_int (a_uri == NULL, TRUE);
1062 assert_equals_int (s_uri != NULL, TRUE);
1063 assert_equals_string (s_uri, "http://localhost/main/subs-de.m3u8");
1064 assert_equals_int (v_uri != NULL, TRUE);
1065 assert_equals_string (v_uri, "http://localhost/low/video-audio.m3u8");
1066
1067 ret =
1068 gst_m3u8_client_set_alternate (client, GST_M3U8_MEDIA_TYPE_SUBTITLES,
1069 "English");
1070 assert_equals_int (ret, TRUE);
1071 gst_m3u8_client_get_current_uri (client, &v_uri, &a_uri, &s_uri);
1072 assert_equals_int (a_uri == NULL, TRUE);
1073 assert_equals_int (v_uri != NULL, TRUE);
1074 assert_equals_string (v_uri, "http://localhost/low/video-audio.m3u8");
1075 assert_equals_int (s_uri != NULL, TRUE);
1076 assert_equals_string (s_uri, "http://localhost/main/subs-en.m3u8");
1077
1078 ret =
1079 gst_m3u8_client_set_alternate (client, GST_M3U8_MEDIA_TYPE_SUBTITLES,
1080 "Spanish");
1081 assert_equals_int (ret, TRUE);
1082 gst_m3u8_client_get_current_uri (client, &v_uri, &a_uri, &s_uri);
1083 assert_equals_int (a_uri == NULL, TRUE);
1084 assert_equals_int (v_uri != NULL, TRUE);
1085 assert_equals_string (v_uri, "http://localhost/low/video-audio.m3u8");
1086 assert_equals_int (s_uri != NULL, TRUE);
1087 assert_equals_string (s_uri, "http://localhost/main/subs-es.m3u8");
1088
1089 ret =
1090 gst_m3u8_client_set_alternate (client, GST_M3U8_MEDIA_TYPE_SUBTITLES,
1091 NULL);
1092 assert_equals_int (ret, TRUE);
1093 gst_m3u8_client_get_current_uri (client, &v_uri, &a_uri, &s_uri);
1094 assert_equals_int (a_uri == NULL, TRUE);
1095 assert_equals_int (v_uri != NULL, TRUE);
1096 assert_equals_string (v_uri, "http://localhost/low/video-audio.m3u8");
1097 assert_equals_int (s_uri == NULL, TRUE);
1098
1099 gst_hls_master_playlist_unref (master);
1100 }
1101
1102 GST_END_TEST;
1103 GST_START_TEST (test_select_alternate)
1104 {
1105 GstM3U8Client *client;
1106 const gchar *a_uri, *v_uri, *s_uri;
1107 gboolean ret;
1108
1109 /* Check with a playlist with alternative audio renditions where the video
1110 * stream is video-only and therefor we always have 2 playlists, one for
1111 * video and another one for audio */
1112 master = load_playlist (ALTERNATE_AUDIO_PLAYLIST);
1113 gst_m3u8_client_get_current_uri (client, &v_uri, &a_uri, &s_uri);
1114 assert_equals_int (a_uri != NULL, TRUE);
1115 assert_equals_string (a_uri, "http://localhost/main/english-audio.m3u8");
1116 assert_equals_int (v_uri != NULL, TRUE);
1117 assert_equals_string (v_uri, "http://localhost/low/video-only.m3u8");
1118 assert_equals_int (s_uri == NULL, TRUE);
1119
1120 ret =
1121 gst_m3u8_client_set_alternate (client, GST_M3U8_MEDIA_TYPE_AUDIO,
1122 "Deutsche");
1123 assert_equals_int (ret, TRUE);
1124 gst_m3u8_client_get_current_uri (client, &v_uri, &a_uri, &s_uri);
1125 assert_equals_int (a_uri != NULL, TRUE);
1126 assert_equals_string (a_uri, "http://localhost/main/german-audio.m3u8");
1127 assert_equals_int (v_uri != NULL, TRUE);
1128 assert_equals_string (v_uri, "http://localhost/low/video-only.m3u8");
1129 assert_equals_int (s_uri == NULL, TRUE);
1130
1131 /* Check that selecting the audio-only fallback stream we only have the audio
1132 * uri */
1133 gst_m3u8_client_set_current (client,
1134 GST_M3U8_STREAM (client->main->streams->data));
1135 gst_m3u8_client_get_current_uri (client, &v_uri, &a_uri, &s_uri);
1136 assert_equals_int (a_uri != NULL, TRUE);
1137 assert_equals_string (a_uri, "http://localhost/main/german-audio.m3u8");
1138 assert_equals_int (v_uri == NULL, TRUE);
1139 assert_equals_int (s_uri == NULL, TRUE);
1140
1141 gst_hls_master_playlist_unref (master);
1142
1143 /* Now check with a playlist with alternative audio renditions where the
1144 * video * stream has the default audio rendition muxed and therefore we
1145 * only have 2 playlists when the audio alternative rendition is not the
1146 * default one */
1147 master = load_playlist (ALT_AUDIO_PLAYLIST_WITH_VIDEO_AUDIO);
1148 gst_m3u8_client_get_current_uri (client, &v_uri, &a_uri, &s_uri);
1149 assert_equals_int (a_uri == NULL, TRUE);
1150 assert_equals_int (v_uri != NULL, TRUE);
1151 assert_equals_string (v_uri, "http://localhost/low/video-audio.m3u8");
1152 assert_equals_int (s_uri == NULL, TRUE);
1153
1154 /* Check that selecting the audio-only fallback stream we only have the audio
1155 * uri */
1156 gst_m3u8_client_set_current (client,
1157 GST_M3U8_STREAM (client->main->streams->data));
1158 gst_m3u8_client_get_current_uri (client, &v_uri, &a_uri, &s_uri);
1159 assert_equals_int (a_uri != NULL, TRUE);
1160 assert_equals_string (a_uri, "http://localhost/main/english-audio.m3u8");
1161 assert_equals_int (v_uri == NULL, TRUE);
1162 assert_equals_int (s_uri == NULL, TRUE);
1163
1164 /* Get back to the audio-video stream */
1165 gst_m3u8_client_set_current (client,
1166 GST_M3U8_STREAM (client->main->streams->next->data));
1167 /* Now set a different audio and check that we have 2 playlists */
1168 ret =
1169 gst_m3u8_client_set_alternate (client, GST_M3U8_MEDIA_TYPE_AUDIO,
1170 "Deutsche");
1171 assert_equals_int (ret, TRUE);
1172 gst_m3u8_client_get_current_uri (client, &v_uri, &a_uri, &s_uri);
1173 assert_equals_int (a_uri != NULL, TRUE);
1174 assert_equals_string (a_uri, "http://localhost/main/german-audio.m3u8");
1175 assert_equals_int (v_uri != NULL, TRUE);
1176 assert_equals_string (v_uri, "http://localhost/low/video-audio.m3u8");
1177 assert_equals_int (s_uri == NULL, TRUE);
1178
1179 gst_hls_master_playlist_unref (master);
1180 }
1181
1182 GST_END_TEST;
1183
1184 GST_START_TEST (test_simulation)
1185 {
1186 GstM3U8Client *client;
1187 const gchar *a_uri, *v_uri, *s_uri;
1188 GstFragment *a_frag, *v_frag, *s_frag;
1189 gboolean ret;
1190
1191 master = load_playlist (ALTERNATE_AUDIO_PLAYLIST);
1192 /* The default selection should be audio-only, which only has audio and not
1193 * video */
1194 gst_m3u8_client_get_current_uri (client, &v_uri, &a_uri, &s_uri);
1195 assert_equals_int (a_uri != NULL, TRUE);
1196 assert_equals_string (a_uri, "http://localhost/main/english-audio.m3u8");
1197 assert_equals_int (v_uri != NULL, TRUE);
1198 assert_equals_string (v_uri, "http://localhost/low/video-only.m3u8");
1199 assert_equals_int (s_uri == NULL, TRUE);
1200
1201 /* Update the playlists */
1202 ret = gst_m3u8_update (client,
1203 g_strdup (ON_DEMAND_LOW_VIDEO_ONLY_PLAYLIST),
1204 g_strdup (ON_DEMAND_ENGLISH_PLAYLIST), NULL);
1205 assert_equals_int (ret, TRUE);
1206 assert_equals_int (g_list_length (client->selected_stream->selected_video->
1207 files), 4);
1208 assert_equals_int (g_list_length (client->selected_stream->selected_audio->
1209 files), 4);
1210
1211 /* Get the first fragment */
1212 gst_m3u8_client_get_next_fragment (client, &v_frag, &a_frag, &s_frag);
1213 assert_equals_int (v_frag != NULL, TRUE);
1214 assert_equals_int (a_frag != NULL, TRUE);
1215 assert_equals_string (v_frag->name,
1216 "http://media.example.com/low/video-only-001.ts");
1217 assert_equals_string (a_frag->name,
1218 "http://media.example.com/audio/english-001.ts");
1219 g_object_unref (v_frag);
1220 g_object_unref (a_frag);
1221
1222 /* Get the next fragment */
1223 gst_m3u8_client_get_next_fragment (client, &v_frag, &a_frag, &s_frag);
1224 assert_equals_int (v_frag != NULL, TRUE);
1225 assert_equals_int (a_frag != NULL, TRUE);
1226 assert_equals_string (v_frag->name,
1227 "http://media.example.com/low/video-only-002.ts");
1228 assert_equals_string (a_frag->name,
1229 "http://media.example.com/audio/english-002.ts");
1230 g_object_unref (v_frag);
1231 g_object_unref (a_frag);
1232
1233 /* Switch to German audio */
1234 ret =
1235 gst_m3u8_client_set_alternate (client, GST_M3U8_MEDIA_TYPE_AUDIO,
1236 "Deutsche");
1237 assert_equals_int (ret, TRUE);
1238 /* Get the new uri's */
1239 gst_m3u8_client_get_current_uri (client, &v_uri, &a_uri, &s_uri);
1240 assert_equals_int (a_uri != NULL, TRUE);
1241 assert_equals_string (a_uri, "http://localhost/main/german-audio.m3u8");
1242 /* On demand so the uri does not need to be downloaded again */
1243 assert_equals_int (v_uri == NULL, TRUE);
1244 assert_equals_int (s_uri == NULL, TRUE);
1245 /* Update the new uri's */
1246 ret =
1247 gst_m3u8_update (client,
1248 g_strdup (ON_DEMAND_LOW_VIDEO_ONLY_PLAYLIST),
1249 g_strdup (ON_DEMAND_GERMAN_PLAYLIST), NULL);
1250 assert_equals_int (ret, TRUE);
1251 gst_m3u8_client_get_next_fragment (client, &v_frag, &a_frag, &s_frag);
1252 assert_equals_int (s_frag == NULL, TRUE);
1253 assert_equals_int (v_frag != NULL, TRUE);
1254 assert_equals_int (a_frag != NULL, TRUE);
1255 assert_equals_string (a_frag->name,
1256 "http://media.example.com/audio/german-003.ts");
1257 assert_equals_string (v_frag->name,
1258 "http://media.example.com/low/video-only-003.ts");
1259 g_object_unref (v_frag);
1260 g_object_unref (a_frag);
1261
1262 /* Switch to a higher bitrate */
1263 gst_m3u8_client_set_current (client,
1264 gst_m3u8_client_get_stream_for_bitrate (client, 260000));
1265 gst_m3u8_client_get_current_uri (client, &v_uri, &a_uri, &s_uri);
1266 assert_equals_int (a_uri != NULL, TRUE);
1267 assert_equals_string (a_uri, "http://localhost/main/german-audio.m3u8");
1268 assert_equals_int (v_uri != NULL, TRUE);
1269 assert_equals_string (v_uri, "http://localhost/mid/video-only.m3u8");
1270 assert_equals_int (s_uri == NULL, TRUE);
1271 ret =
1272 gst_m3u8_update (client,
1273 g_strdup (ON_DEMAND_MID_VIDEO_ONLY_PLAYLIST),
1274 g_strdup (ON_DEMAND_GERMAN_PLAYLIST), NULL);
1275 assert_equals_int (ret, TRUE);
1276 gst_m3u8_client_get_next_fragment (client, &v_frag, &a_frag, &s_frag);
1277 assert_equals_int (s_frag == NULL, TRUE);
1278 assert_equals_int (a_frag != NULL, TRUE);
1279 assert_equals_int (v_frag != NULL, TRUE);
1280 assert_equals_string (a_frag->name,
1281 "http://media.example.com/audio/german-004.ts");
1282 assert_equals_string (v_frag->name,
1283 "http://media.example.com/mid/video-only-004.ts");
1284 g_object_unref (v_frag);
1285 g_object_unref (a_frag);
1286
1287 /* Seek to the beginning */
1288 gst_m3u8_client_seek (client, 0);
1289 gst_m3u8_client_get_next_fragment (client, &v_frag, &a_frag, &s_frag);
1290 assert_equals_int (s_frag == NULL, TRUE);
1291 assert_equals_int (a_frag != NULL, TRUE);
1292 assert_equals_int (v_frag != NULL, TRUE);
1293 assert_equals_string (a_frag->name,
1294 "http://media.example.com/audio/german-001.ts");
1295 assert_equals_string (v_frag->name,
1296 "http://media.example.com/mid/video-only-001.ts");
1297 g_object_unref (v_frag);
1298 g_object_unref (a_frag);
1299
1300 /* Select English audio again */
1301 ret =
1302 gst_m3u8_client_set_alternate (client, GST_M3U8_MEDIA_TYPE_AUDIO,
1303 "English");
1304 assert_equals_int (ret, TRUE);
1305 gst_m3u8_client_get_next_fragment (client, &v_frag, &a_frag, &s_frag);
1306 assert_equals_int (s_frag == NULL, TRUE);
1307 assert_equals_int (a_frag != NULL, TRUE);
1308 assert_equals_int (v_frag != NULL, TRUE);
1309 assert_equals_string (a_frag->name,
1310 "http://media.example.com/audio/english-002.ts");
1311 assert_equals_string (v_frag->name,
1312 "http://media.example.com/mid/video-only-002.ts");
1313 g_object_unref (v_frag);
1314 g_object_unref (a_frag);
1315
1316 /* Go to the audio-only fallback */
1317 gst_m3u8_client_set_current (client,
1318 gst_m3u8_client_get_stream_for_bitrate (client, 20000));
1319 gst_m3u8_client_get_next_fragment (client, &v_frag, &a_frag, &s_frag);
1320 assert_equals_int (s_frag == NULL, TRUE);
1321 assert_equals_int (a_frag != NULL, TRUE);
1322 assert_equals_int (v_frag == NULL, TRUE);
1323 assert_equals_string (a_frag->name,
1324 "http://media.example.com/audio/english-003.ts");
1325 g_object_unref (a_frag);
1326
1327 /* Go to mid again */
1328 gst_m3u8_client_set_current (client,
1329 gst_m3u8_client_get_stream_for_bitrate (client, 260000));
1330 gst_m3u8_client_get_next_fragment (client, &v_frag, &a_frag, &s_frag);
1331 assert_equals_int (s_frag == NULL, TRUE);
1332 assert_equals_int (a_frag != NULL, TRUE);
1333 assert_equals_int (v_frag != NULL, TRUE);
1334 assert_equals_string (a_frag->name,
1335 "http://media.example.com/audio/english-004.ts");
1336 assert_equals_string (v_frag->name,
1337 "http://media.example.com/mid/video-only-004.ts");
1338 g_object_unref (a_frag);
1339 g_object_unref (v_frag);
1340
1341 /* End of stream */
1342 ret = gst_m3u8_client_get_next_fragment (client, &v_frag, &a_frag, &s_frag);
1343 assert_equals_int (ret, FALSE);
1344
1345 gst_hls_master_playlist_unref (master);
1346 }
1347
1348 GST_END_TEST;
1349 #endif
1350
GST_START_TEST(test_url_with_slash_query_param)1351 GST_START_TEST (test_url_with_slash_query_param)
1352 {
1353 static const gchar *MASTER_PLAYLIST = "#EXTM3U \n"
1354 "#EXT-X-VERSION:4\n"
1355 "#EXT-X-STREAM-INF:PROGRAM-ID=1, BANDWIDTH=1251135, CODECS=\"avc1.42001f, mp4a.40.2\", RESOLUTION=640x352\n"
1356 "1251/media.m3u8?acl=/*1054559_h264_1500k.mp4\n";
1357 GstHLSMasterPlaylist *master;
1358 GstHLSVariantStream *stream;
1359 GstM3U8 *media;
1360
1361 master = load_playlist (MASTER_PLAYLIST);
1362
1363 assert_equals_int (g_list_length (master->variants), 1);
1364 stream = g_list_nth_data (master->variants, 0);
1365 media = stream->m3u8;
1366
1367 assert_equals_string (media->uri,
1368 "http://localhost/1251/media.m3u8?acl=/*1054559_h264_1500k.mp4");
1369 gst_hls_master_playlist_unref (master);
1370 }
1371
1372 GST_END_TEST;
1373
GST_START_TEST(test_stream_inf_tag)1374 GST_START_TEST (test_stream_inf_tag)
1375 {
1376 static const gchar *MASTER_PLAYLIST = "#EXTM3U \n"
1377 "#EXT-X-VERSION:4\n"
1378 "#EXT-X-STREAM-INF:PROGRAM-ID=1, BANDWIDTH=1251135, CODECS=\"avc1.42001f, mp4a.40.2\", RESOLUTION=640x352\n"
1379 "media.m3u8\n";
1380 GstHLSMasterPlaylist *master;
1381 GstHLSVariantStream *stream;
1382
1383 master = load_playlist (MASTER_PLAYLIST);
1384
1385 assert_equals_int (g_list_length (master->variants), 1);
1386 stream = g_list_nth_data (master->variants, 0);
1387
1388 assert_equals_int64 (stream->program_id, 1);
1389 assert_equals_int64 (stream->width, 640);
1390 assert_equals_int64 (stream->height, 352);
1391 assert_equals_int64 (stream->bandwidth, 1251135);
1392 assert_equals_string (stream->codecs, "avc1.42001f, mp4a.40.2");
1393 gst_hls_master_playlist_unref (master);
1394 }
1395
1396 GST_END_TEST;
1397
1398 static Suite *
hlsdemux_suite(void)1399 hlsdemux_suite (void)
1400 {
1401 Suite *s = suite_create ("hlsdemux_m3u8");
1402 TCase *tc_m3u8 = tcase_create ("m3u8client");
1403
1404 GST_DEBUG_CATEGORY_INIT (hls_debug, "hlsdemux_m3u", 0, "hlsdemux m3u test");
1405
1406 suite_add_tcase (s, tc_m3u8);
1407 tcase_add_test (tc_m3u8, test_load_main_playlist_invalid);
1408 tcase_add_test (tc_m3u8, test_load_main_playlist_rendition);
1409 tcase_add_test (tc_m3u8, test_load_main_playlist_variant);
1410 tcase_add_test (tc_m3u8, test_load_main_playlist_variant_with_missing_uri);
1411 tcase_add_test (tc_m3u8, test_load_windows_line_endings_variant_playlist);
1412 tcase_add_test (tc_m3u8, test_load_main_playlist_with_empty_lines);
1413 tcase_add_test (tc_m3u8, test_load_windows_main_playlist_with_empty_lines);
1414 tcase_add_test (tc_m3u8, test_on_demand_playlist);
1415 tcase_add_test (tc_m3u8, test_windows_line_endings_playlist);
1416 tcase_add_test (tc_m3u8, test_windows_empty_lines_playlist);
1417 tcase_add_test (tc_m3u8, test_empty_lines_playlist);
1418 tcase_add_test (tc_m3u8, test_live_playlist);
1419 tcase_add_test (tc_m3u8, test_live_playlist_rotated);
1420 tcase_add_test (tc_m3u8, test_playlist_with_doubles_duration);
1421 tcase_add_test (tc_m3u8, test_playlist_with_encryption);
1422 tcase_add_test (tc_m3u8, test_update_invalid_playlist);
1423 tcase_add_test (tc_m3u8, test_update_playlist);
1424 tcase_add_test (tc_m3u8, test_playlist_media_files);
1425 tcase_add_test (tc_m3u8, test_playlist_byte_range_media_files);
1426 tcase_add_test (tc_m3u8, test_get_next_fragment);
1427 tcase_add_test (tc_m3u8, test_get_duration);
1428 tcase_add_test (tc_m3u8, test_get_target_duration);
1429 tcase_add_test (tc_m3u8, test_get_stream_for_bitrate);
1430 #if 0
1431 tcase_add_test (tc_m3u8, test_seek);
1432 tcase_add_test (tc_m3u8, test_alternate_audio_playlist);
1433 tcase_add_test (tc_m3u8, test_subtitles_playlist);
1434 tcase_add_test (tc_m3u8, test_select_alternate);
1435 tcase_add_test (tc_m3u8, test_select_subs_alternate);
1436 tcase_add_test (tc_m3u8, test_simulation);
1437 #endif
1438 tcase_add_test (tc_m3u8, test_url_with_slash_query_param);
1439 tcase_add_test (tc_m3u8, test_stream_inf_tag);
1440 return s;
1441 }
1442
1443 GST_CHECK_MAIN (hlsdemux);
1444