1 /*****************************************************************************
2 * hds.c: Http Dynamic Streaming (HDS) stream filter
3 *****************************************************************************
5 * Author: Jonathan Thambidurai <jonathan _AT_ fastly _DOT_ com>
6 * Heavily inspired by SMooth module of Frédéric Yhuel <fyhuel _AT_ viotech _DOT_ net>
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 *****************************************************************************/
27 #include <limits.h> /* INT_MAX */
29 #include <vlc_common.h>
30 #include <vlc_plugin.h>
31 #include <vlc_stream.h>
32 #include <vlc_strings.h> /* b64_decode */
34 #include <vlc_charset.h> /* FromCharset */
35 #include <vlc_es.h> /* UNKNOWN_ES */
37 typedef struct chunk_s
39 int64_t duration; /* chunk duration in afrt timescale units */
43 uint32_t frun_entry; /* Used to speed things up in vod situations */
47 uint32_t mdat_pos; /* position in the mdat */
58 typedef struct segment_run_s
60 uint32_t first_segment;
61 uint32_t fragments_per_segment;
64 typedef struct fragment_run_s
66 uint32_t fragment_number_start;
67 uint32_t fragment_duration;
68 uint64_t fragment_timestamp;
72 typedef struct hds_stream_s
74 /* linked-list of chunks */
76 chunk_t *chunks_livereadpos;
77 chunk_t *chunks_downloadpos;
79 char* quality_segment_modifier;
81 /* we can make this configurable */
82 uint64_t download_leadtime;
84 /* in timescale units */
85 uint32_t afrt_timescale;
87 /* these two values come from the abst */
89 uint64_t live_current_time;
91 /* kilobits per second */
94 vlc_mutex_t abst_lock;
99 /* can be left as null */
102 /* these come from the manifest media section */
107 /* this comes from the bootstrap info */
110 #define MAX_HDS_SERVERS 10
111 char* server_entries[MAX_HDS_SERVERS];
112 uint8_t server_entry_count;
114 #define MAX_HDS_SEGMENT_RUNS 256
115 segment_run_t segment_runs[MAX_HDS_SEGMENT_RUNS];
116 uint8_t segment_run_count;
118 #define MAX_HDS_FRAGMENT_RUNS 10000
119 fragment_run_t fragment_runs[MAX_HDS_FRAGMENT_RUNS];
120 uint32_t fragment_run_count;
123 /* this is effectively just a sanity check mechanism */
124 #define MAX_REQUEST_SIZE (50*1024*1024)
126 #define BITRATE_AS_BYTES_PER_SECOND 1024/8
130 char *base_url; /* URL common part for chunks */
131 vlc_thread_t live_thread;
132 vlc_thread_t dl_thread;
134 /* we pend on peek until some number of segments arrives; otherwise
135 * the downstream system dies in case of playback */
136 uint64_t chunk_count;
138 vlc_array_t *hds_streams; /* available streams */
140 /* Buffer that holds the very first bytes of the stream: the FLV
141 * file header and a possible metadata packet.
144 size_t flv_header_len;
145 size_t flv_header_bytes_sent;
146 uint64_t duration_seconds;
147 uint64_t playback_offset;
153 typedef struct _bootstrap_info {
161 typedef struct _media_info {
170 #define MAX_BOOTSTRAP_INFO 10
171 #define MAX_MEDIA_ELEMENTS 10
172 #define MAX_XML_DEPTH 256
174 typedef struct _manifest {
175 char* element_stack[MAX_XML_DEPTH];
176 bootstrap_info bootstraps[MAX_BOOTSTRAP_INFO];
177 media_info medias[MAX_MEDIA_ELEMENTS];
178 xml_reader_t *vlc_reader;
182 static unsigned char flv_header_bytes[] = {
187 0x5, //indicates audio and video
191 0x9, // length of header
195 0x0, // initial "trailer"
198 static unsigned char amf_object_end[] = { 0x0, 0x0, 0x9 };
200 #define FLV_FILE_HEADER_LEN sizeof(flv_header_bytes)
201 #define FLV_TAG_HEADER_LEN 15
202 #define SCRIPT_TAG 0x12
204 /*****************************************************************************
206 *****************************************************************************/
207 static int Open( vlc_object_t * );
208 static void Close( vlc_object_t * );
211 set_category( CAT_INPUT )
212 set_subcategory( SUBCAT_INPUT_STREAM_FILTER )
213 set_description( N_("HTTP Dynamic Streaming") )
214 set_shortname( "Dynamic Streaming")
215 add_shortcut( "hds" )
216 set_capability( "stream_filter", 30 )
217 set_callbacks( Open, Close )
220 static int Read( stream_t *, void *, unsigned );
221 static int Peek( stream_t *, const uint8_t **, unsigned );
222 static int Control( stream_t *, int , va_list );
224 static inline bool isFQUrl( char* url )
226 return ( NULL != vlc_strcasestr( url, "https://") ||
227 NULL != vlc_strcasestr( url, "http://" ) );
230 static bool isHDS( stream_t *s )
233 int i_size = stream_Peek( s->p_source, (const uint8_t**) &peek, 200 );
239 if( !memcmp( peek, "\xFF\xFE", 2 ) )
241 str = FromCharset( "UTF-16LE", peek, i_size );
243 else if( !memcmp( peek, "\xFE\xFF", 2 ) )
245 str = FromCharset( "UTF-16BE", peek, i_size );
248 str = strndup( peek, i_size );
253 bool ret = strstr( str, "<manifest" ) != NULL;
258 static uint64_t get_stream_size( stream_t* s )
260 stream_sys_t *p_sys = s->p_sys;
265 if ( vlc_array_count( p_sys->hds_streams ) == 0 )
268 hds_stream_t* hds_stream = p_sys->hds_streams->pp_elems[0];
270 if ( hds_stream->bitrate == 0 )
273 return p_sys->flv_header_len + p_sys->duration_seconds *
274 hds_stream->bitrate * BITRATE_AS_BYTES_PER_SECOND;
277 static uint8_t* parse_asrt( vlc_object_t* p_this,
282 uint8_t* data_p = data;
284 uint32_t asrt_len = 0;
285 asrt_len = U32_AT( data_p );
286 if( asrt_len > data_end - data ||
287 data_end - data < 14 )
289 msg_Err( p_this, "Not enough asrt data (%"PRIu32", %tu)", asrt_len,
294 data_p += sizeof(asrt_len);
296 if( 0 != memcmp( "asrt", data_p, 4 ) )
298 msg_Err( p_this, "Cant find asrt in bootstrap" );
303 /* ignore flags and versions (we don't handle multiple updates) */
306 uint8_t quality_entry_count = *data_p;
307 bool quality_found = false;
310 if( ! s->quality_segment_modifier )
312 quality_found = true;
315 while( quality_entry_count-- > 0 )
317 char* str_start = (char*) data_p;
318 data_p = memchr( data_p, '\0', data_end - data_p );
321 msg_Err( p_this, "Couldn't find quality entry string in asrt" );
326 if( ! quality_found )
328 if( ! strncmp( str_start, s->quality_segment_modifier,
329 strlen(s->quality_segment_modifier) ) )
331 quality_found = true;
335 if( data_p >= data_end )
337 msg_Err( p_this, "Premature end of asrt in quality entries" );
342 if( data_end - data_p < 4 )
344 msg_Err( p_this, "Premature end of asrt after quality entries" );
348 uint32_t segment_run_entry_count = U32_AT( data_p );
349 data_p += sizeof(segment_run_entry_count);
351 if( data_end - data_p < 8 * segment_run_entry_count )
353 msg_Err( p_this, "Not enough data in asrt for segment run entries" );
357 if( segment_run_entry_count >= MAX_HDS_SEGMENT_RUNS )
359 msg_Err( p_this, "Too many segment runs" );
363 while( segment_run_entry_count-- > 0 )
367 s->segment_runs[s->segment_run_count].first_segment = U32_AT(data_p);
373 s->segment_runs[s->segment_run_count].fragments_per_segment = U32_AT(data_p);
377 s->segment_run_count++;
383 static uint8_t* parse_afrt( vlc_object_t* p_this,
388 uint8_t* data_p = data;
390 uint32_t afrt_len = U32_AT( data_p );
391 if( afrt_len > data_end - data ||
392 data_end - data < 9 )
394 msg_Err( p_this, "Not enough afrt data %u, %td", afrt_len,
398 data_p += sizeof(afrt_len);
400 if( 0 != memcmp( data_p, "afrt", 4 ) )
402 msg_Err( p_this, "Cant find afrt in bootstrap" );
407 /* ignore flags and versions (we don't handle multiple updates) */
410 if( data_end - data_p < 9 )
412 msg_Err( p_this, "afrt is too short" );
416 s->afrt_timescale = U32_AT( data_p );
419 bool quality_found = false;
420 if( ! s->quality_segment_modifier )
422 quality_found = true;
425 uint32_t quality_entry_count = *data_p;
427 while( quality_entry_count-- > 0 )
429 char* str_start = (char*)data_p;
430 data_p = memchr( data_p, '\0', data_end - data_p );
433 msg_Err( p_this, "Couldn't find quality entry string in afrt" );
438 if( ! quality_found )
440 if( ! strncmp( str_start, s->quality_segment_modifier,
441 strlen(s->quality_segment_modifier) ) )
443 quality_found = true;
448 if( data_end - data_p < 5 )
450 msg_Err( p_this, "No more space in afrt after quality entries" );
454 uint32_t fragment_run_entry_count = U32_AT( data_p );
455 data_p += sizeof(uint32_t);
457 while(fragment_run_entry_count-- > 0)
459 if( data_end - data_p < 16 )
461 msg_Err( p_this, "Not enough data in afrt" );
465 if( s->fragment_run_count >= MAX_HDS_FRAGMENT_RUNS )
467 msg_Err( p_this, "Too many fragment runs, exiting" );
471 s->fragment_runs[s->fragment_run_count].fragment_number_start = U32_AT(data_p);
474 s->fragment_runs[s->fragment_run_count].fragment_timestamp = U64_AT( data_p );
477 s->fragment_runs[s->fragment_run_count].fragment_duration = U32_AT( data_p );
480 s->fragment_runs[s->fragment_run_count].discont = 0;
481 if( s->fragment_runs[s->fragment_run_count].fragment_duration == 0 )
483 /* discontinuity flag */
484 s->fragment_runs[s->fragment_run_count].discont = *(data_p++);
487 s->fragment_run_count++;
490 if ( s->fragment_runs[s->fragment_run_count-1].fragment_number_start == 0 &&
491 s->fragment_runs[s->fragment_run_count-1].fragment_timestamp == 0 &&
492 s->fragment_runs[s->fragment_run_count-1].fragment_duration == 0 &&
493 s->fragment_runs[s->fragment_run_count-1].discont == 0 )
495 /* ignore sentinel value */
496 s->fragment_run_count--;
502 static inline chunk_t* chunk_new()
504 chunk_t* chunk = calloc(1, sizeof(chunk_t));
508 static void chunk_free( chunk_t * chunk )
510 FREENULL( chunk->data );
514 static void parse_BootstrapData( vlc_object_t* p_this,
519 uint8_t* data_p = data;
521 uint32_t abst_len = U32_AT( data_p );
522 if( abst_len > data_end - data
523 || data_end - data < 29 /* min size of data */ )
525 msg_Warn( p_this, "Not enough bootstrap data" );
528 data_p += sizeof(abst_len);
530 if( 0 != memcmp( data_p, "abst", 4 ) )
532 msg_Warn( p_this, "Cant find abst in bootstrap" );
540 /* we ignore the version */
543 /* some flags we don't care about here because they are
549 s->timescale = U32_AT( data_p );
550 data_p += sizeof(s->timescale);
552 s->live_current_time = U64_AT( data_p );
553 data_p += sizeof(s->live_current_time);
555 /* smtpe time code offset */
558 s->movie_id = strndup( (char*)data_p, data_end - data_p );
559 data_p += ( strlen( s->movie_id ) + 1 );
561 if( data_end - data_p < 4 ) {
562 msg_Warn( p_this, "Not enough bootstrap after Movie Identifier" );
566 uint8_t server_entry_count = 0;
567 server_entry_count = (uint8_t) *data_p;
570 s->server_entry_count = 0;
571 while( server_entry_count-- > 0 )
573 if( s->server_entry_count < MAX_HDS_SERVERS )
575 s->server_entries[s->server_entry_count++] = strndup( (char*)data_p,
577 data_p += strlen( s->server_entries[s->server_entry_count-1] ) + 1;
581 msg_Warn( p_this, "Too many servers" );
582 data_p = memchr( data_p, '\0', data_end - data_p );
585 msg_Err( p_this, "Couldn't find server entry" );
591 if( data_p >= data_end )
593 msg_Warn( p_this, "Premature end of bootstrap info while reading servers" );
598 if( data_end - data_p < 3 ) {
599 msg_Warn( p_this, "Not enough bootstrap after Servers" );
603 s->quality_segment_modifier = NULL;
605 uint8_t quality_entry_count = *data_p;
608 if( quality_entry_count > 1 )
610 msg_Err( p_this, "I don't know what to do with multiple quality levels in the bootstrap - shouldn't this be handled at the manifest level?" );
614 s->quality_segment_modifier = NULL;
615 while( quality_entry_count-- > 0 )
617 if( s->quality_segment_modifier )
619 s->quality_segment_modifier = strndup( (char*)data_p, data_end - data_p );
621 data_p += strnlen( (char*)data_p, data_end - data_p ) + 1;
624 if( data_end - data_p < 2 ) {
625 msg_Warn( p_this, "Not enough bootstrap after quality entries" );
629 /* ignoring "DrmData" */
630 data_p = memchr( data_p, '\0', data_end - data_p );
633 msg_Err( p_this, "Couldn't find DRM Data" );
638 if( data_end - data_p < 2 ) {
639 msg_Warn( p_this, "Not enough bootstrap after drm data" );
643 /* ignoring "metadata" */
644 data_p = memchr( data_p, '\0', data_end - data_p );
647 msg_Err( p_this, "Couldn't find metadata");
652 if( data_end - data_p < 2 ) {
653 msg_Warn( p_this, "Not enough bootstrap after drm data" );
657 uint8_t asrt_count = *data_p;
660 s->segment_run_count = 0;
661 while( asrt_count-- > 0 &&
663 (data_p = parse_asrt( p_this, s, data_p, data_end )) );
667 msg_Warn( p_this, "Couldn't find afrt data" );
671 uint8_t afrt_count = *data_p;
674 s->fragment_run_count = 0;
675 while( afrt_count-- > 0 &&
677 (data_p = parse_afrt( p_this, s, data_p, data_end )) );
680 /* this only works with ANSI characters - this is ok
681 for the bootstrapinfo field which this function is
682 exclusively used for since it is merely a base64 encoding
684 static bool is_whitespace( char c )
694 /* see above note for is_whitespace */
695 static void whitespace_substr( char** start,
698 while( is_whitespace( **start ) && *start != *end ) {
705 while( is_whitespace(*(*end - 1) ) ) {
710 /* returns length (could be zero, indicating all of remaining data) */
711 /* ptr is to start of data, right after 'mdat' string */
712 static uint32_t find_chunk_mdat( vlc_object_t* p_this,
713 uint8_t* chunkdata, uint8_t* chunkdata_end,
716 uint8_t* boxname = NULL;
717 uint8_t* boxdata = NULL;
718 uint64_t boxsize = 0;
721 if( chunkdata_end < chunkdata ||
722 chunkdata_end - chunkdata < 8 )
724 msg_Err( p_this, "Couldn't find mdat in box 1!" );
729 boxsize = (uint64_t)U32_AT( chunkdata );
737 if( chunkdata_end - chunkdata >= 12 )
739 boxsize = U64_AT(chunkdata);
744 msg_Err( p_this, "Couldn't find mdat in box 2!");
749 chunkdata += (boxsize - 16);
754 chunkdata += (boxsize - 8);
756 } while ( 0 != memcmp( boxname, "mdat", 4 ) );
760 return chunkdata_end - ((uint8_t*)boxdata);
763 /* returns data ptr if valid (updating the chunk itself
764 tells the reader that the chunk is safe to read, which is not yet correct)*/
765 static uint8_t* download_chunk( stream_t *s,
767 hds_stream_t* stream, chunk_t* chunk )
769 const char* quality = "";
770 char* server_base = sys->base_url;
771 if( stream->server_entry_count > 0 &&
772 strlen(stream->server_entries[0]) > 0 )
774 server_base = stream->server_entries[0];
777 if( stream->quality_segment_modifier )
779 quality = stream->quality_segment_modifier;
782 const char* movie_id = "";
783 if( stream->url && strlen(stream->url) > 0 )
785 if( isFQUrl( stream->url ) )
787 server_base = stream->url;
791 movie_id = stream->url;
796 if( 0 > asprintf( &fragment_url, "%s/%s%sSeg%u-Frag%u",
801 chunk->frag_num ) ) {
802 msg_Err(s, "Failed to allocate memory for fragment url" );
806 msg_Info(s, "Downloading fragment %s", fragment_url );
808 stream_t* download_stream = stream_UrlNew( s, fragment_url );
809 if( ! download_stream )
811 msg_Err(s, "Failed to download fragment %s", fragment_url );
812 free( fragment_url );
813 chunk->failed = true;
816 free( fragment_url );
818 int64_t size = stream_Size( download_stream );
819 chunk->data_len = (uint32_t) size;
821 if( size > MAX_REQUEST_SIZE )
823 msg_Err(s, "Strangely-large chunk of %"PRIi64" Bytes", size );
827 uint8_t* data = malloc( size );
830 msg_Err(s, "Couldn't allocate chunk" );
834 int read = stream_Read( download_stream, data,
836 chunk->data_len = read;
840 msg_Err( s, "Requested %"PRIi64" bytes, "\
841 "but only got %d", size, read );
842 data = realloc( chunk->data, read );
845 chunk->failed = true;
850 chunk->failed = false;
853 stream_Delete( download_stream );
857 static void* download_thread( void* p )
859 vlc_object_t* p_this = (vlc_object_t*)p;
860 stream_t* s = (stream_t*) p_this;
861 stream_sys_t* sys = s->p_sys;
863 if ( vlc_array_count( sys->hds_streams ) == 0 )
866 // TODO: Change here for selectable stream
867 hds_stream_t* hds_stream = sys->hds_streams->pp_elems[0];
869 int canc = vlc_savecancel();
871 vlc_mutex_lock( & hds_stream->dl_lock );
873 while( ! sys->closed )
875 if( ! hds_stream->chunks_downloadpos )
877 chunk_t* chunk = hds_stream->chunks_head;
878 while(chunk && chunk->data )
883 if( chunk && ! chunk->data )
884 hds_stream->chunks_downloadpos = chunk;
887 while( hds_stream->chunks_downloadpos )
889 chunk_t *chunk = hds_stream->chunks_downloadpos;
891 uint8_t *data = download_chunk( (stream_t*)p_this,
896 if( ! chunk->failed )
899 find_chunk_mdat( p_this,
901 data + chunk->data_len,
902 & chunk->mdat_data );
903 if( chunk->mdat_len == 0 ) {
904 chunk->mdat_len = chunk->data_len - (chunk->mdat_data - data);
906 hds_stream->chunks_downloadpos = chunk->next;
913 vlc_cond_wait( & hds_stream->dl_cond,
914 & hds_stream->dl_lock );
917 vlc_mutex_unlock( & hds_stream->dl_lock );
919 vlc_restorecancel( canc );
923 static chunk_t* generate_new_chunk(
924 vlc_object_t* p_this,
926 hds_stream_t* hds_stream )
928 stream_t* s = (stream_t*) p_this;
929 stream_sys_t *sys = s->p_sys;
930 chunk_t *chunk = chunk_new();
931 unsigned int frun_entry = 0;
934 msg_Err( p_this, "Couldn't allocate new chunk!" );
940 chunk->timestamp = last_chunk->timestamp + last_chunk->duration;
941 chunk->frag_num = last_chunk->frag_num + 1;
945 frun_entry = last_chunk->frun_entry;
950 fragment_run_t* first_frun = hds_stream->fragment_runs;
953 chunk->timestamp = (hds_stream->live_current_time * ((uint64_t)hds_stream->afrt_timescale)) / ((uint64_t)hds_stream->timescale);
957 chunk->timestamp = first_frun->fragment_timestamp;
958 chunk->frag_num = first_frun->fragment_number_start;
962 for( ; frun_entry < hds_stream->fragment_run_count;
965 /* check for discontinuity first */
966 if( hds_stream->fragment_runs[frun_entry].fragment_duration == 0 )
968 if( frun_entry == hds_stream->fragment_run_count - 1 )
970 msg_Err( p_this, "Discontinuity but can't find next timestamp!");
974 chunk->frag_num = hds_stream->fragment_runs[frun_entry+1].fragment_number_start;
975 chunk->duration = hds_stream->fragment_runs[frun_entry+1].fragment_duration;
976 chunk->timestamp = hds_stream->fragment_runs[frun_entry+1].fragment_timestamp;
982 if( chunk->frag_num == 0 )
984 if( frun_entry == hds_stream->fragment_run_count - 1 ||
985 ( chunk->timestamp >= hds_stream->fragment_runs[frun_entry].fragment_timestamp &&
986 chunk->timestamp < hds_stream->fragment_runs[frun_entry+1].fragment_timestamp )
989 fragment_run_t* frun = hds_stream->fragment_runs + frun_entry;
990 chunk->frag_num = frun->fragment_number_start + ( (chunk->timestamp - frun->fragment_timestamp) /
991 frun->fragment_duration );
992 chunk->duration = frun->fragment_duration;
997 if( hds_stream->fragment_runs[frun_entry].fragment_number_start <=
999 (frun_entry == hds_stream->fragment_run_count - 1 ||
1000 hds_stream->fragment_runs[frun_entry+1].fragment_number_start > chunk->frag_num ) )
1002 chunk->duration = hds_stream->fragment_runs[frun_entry].fragment_duration;
1003 chunk->timestamp = hds_stream->fragment_runs[frun_entry].fragment_timestamp +
1004 chunk->duration * (chunk->frag_num - hds_stream->fragment_runs[frun_entry].fragment_number_start);
1009 if( frun_entry == hds_stream->fragment_run_count )
1011 msg_Err( p_this, "Couldn'd find the fragment run!" );
1012 chunk_free( chunk );
1017 unsigned int segment = 0;
1018 uint64_t fragments_accum = chunk->frag_num;
1019 for( srun_entry = 0; srun_entry < hds_stream->segment_run_count;
1022 segment = hds_stream->segment_runs[srun_entry].first_segment +
1023 (chunk->frag_num - fragments_accum ) / hds_stream->segment_runs[srun_entry].fragments_per_segment;
1025 if( srun_entry + 1 == hds_stream->segment_run_count ||
1026 hds_stream->segment_runs[srun_entry+1].first_segment > segment )
1031 fragments_accum += (
1032 (hds_stream->segment_runs[srun_entry+1].first_segment -
1033 hds_stream->segment_runs[srun_entry].first_segment) *
1034 hds_stream->segment_runs[srun_entry].fragments_per_segment );
1037 chunk->seg_num = segment;
1038 chunk->frun_entry = frun_entry;
1042 if( (chunk->timestamp + chunk->duration) / hds_stream->afrt_timescale >= sys->duration_seconds )
1051 static void maintain_live_chunks(
1052 vlc_object_t* p_this,
1053 hds_stream_t* hds_stream
1056 if( ! hds_stream->chunks_head )
1058 /* just start with the earliest in the abst
1059 * maybe it would be better to use the currentMediaTime?
1060 * but then we are right on the edge of buffering, esp for
1061 * small fragments */
1062 hds_stream->chunks_head = generate_new_chunk(
1063 p_this, 0, hds_stream );
1064 hds_stream->chunks_livereadpos = hds_stream->chunks_head;
1067 chunk_t* chunk = hds_stream->chunks_head;
1069 while( chunk && ( chunk->timestamp * ((uint64_t)hds_stream->timescale) )
1070 / ((uint64_t)hds_stream->afrt_timescale)
1071 <= hds_stream->live_current_time )
1075 chunk = chunk->next;
1079 chunk->next = generate_new_chunk( p_this, chunk, hds_stream );
1080 chunk = chunk->next;
1086 vlc_cond_signal( & hds_stream->dl_cond );
1088 chunk = hds_stream->chunks_head;
1089 while( chunk && chunk->data && chunk->mdat_pos >= chunk->mdat_len && chunk->next )
1091 chunk_t* next_chunk = chunk->next;
1092 chunk_free( chunk );
1096 if( ! hds_stream->chunks_livereadpos )
1097 hds_stream->chunks_livereadpos = hds_stream->chunks_head;
1099 hds_stream->chunks_head = chunk;
1103 static void* live_thread( void* p )
1105 vlc_object_t* p_this = (vlc_object_t*)p;
1106 stream_t* s = (stream_t*) p_this;
1107 stream_sys_t* sys = s->p_sys;
1109 if ( vlc_array_count( sys->hds_streams ) == 0 )
1112 // TODO: Change here for selectable stream
1113 hds_stream_t* hds_stream = sys->hds_streams->pp_elems[0];
1115 int canc = vlc_savecancel();
1119 if( hds_stream->abst_url &&
1120 ( isFQUrl( hds_stream->abst_url ) ) )
1122 if( !( abst_url = strdup( hds_stream->abst_url ) ) )
1127 char* server_base = sys->base_url;
1130 if( 0 > asprintf( &abst_url, "%s/%s",
1132 hds_stream->abst_url ) )
1138 mtime_t last_dl_start_time;
1140 while( ! sys->closed )
1142 last_dl_start_time = mdate();
1143 stream_t* download_stream = stream_UrlNew( p_this, abst_url );
1144 if( ! download_stream )
1146 msg_Err( p_this, "Failed to download abst %s", abst_url );
1150 int64_t size = stream_Size( download_stream );
1151 uint8_t* data = malloc( size );
1152 int read = stream_Read( download_stream, data,
1156 msg_Err( p_this, "Requested %"PRIi64" bytes, " \
1157 "but only got %d", size, read );
1162 vlc_mutex_lock( & hds_stream->abst_lock );
1163 parse_BootstrapData( p_this, hds_stream,
1164 data, data + read );
1165 vlc_mutex_unlock( & hds_stream->abst_lock );
1166 maintain_live_chunks( p_this, hds_stream );
1171 stream_Delete( download_stream );
1174 mwait( last_dl_start_time + ( ((int64_t)hds_stream->fragment_runs[hds_stream->fragment_run_count-1].fragment_duration) * 1000000LL) / ((int64_t)hds_stream->afrt_timescale) );
1181 vlc_restorecancel( canc );
1185 static int init_Manifest( stream_t *s, manifest_t *m )
1187 memset(m, 0, sizeof(*m));
1188 stream_t *st = s->p_source;
1189 m->vlc_xml = xml_Create( st );
1192 msg_Err( s, "Failed to open XML parser" );
1193 return VLC_EGENERIC;
1196 m->vlc_reader = xml_ReaderCreate( m->vlc_xml, st );
1197 if( !m->vlc_reader )
1199 msg_Err( s, "Failed to open source for parsing" );
1200 return VLC_EGENERIC;
1206 static void cleanup_Manifest( manifest_t *m )
1208 for (unsigned i = 0; i < MAX_XML_DEPTH; i++)
1209 free( m->element_stack[i] );
1211 for( unsigned i = 0; i < MAX_MEDIA_ELEMENTS; i++ )
1213 free( m->medias[i].stream_id );
1214 free( m->medias[i].media_url );
1215 free( m->medias[i].bootstrap_id );
1216 free( m->medias[i].metadata );
1219 for( unsigned i = 0; i < MAX_BOOTSTRAP_INFO; i++ )
1221 free( m->bootstraps[i].data );
1222 free( m->bootstraps[i].id );
1223 free( m->bootstraps[i].url );
1224 free( m->bootstraps[i].profile );
1228 xml_ReaderDelete( m->vlc_reader );
1230 xml_Delete( m->vlc_xml );
1233 static void cleanup_threading( hds_stream_t *stream )
1235 vlc_mutex_destroy( &stream->dl_lock );
1236 vlc_cond_destroy( &stream->dl_cond );
1237 vlc_mutex_destroy( &stream->abst_lock );
1240 static void write_int_24( uint8_t *p, uint32_t val )
1242 *p = ( val & 0xFF0000 ) >> 16;
1243 *( p + 1 ) = ( val & 0xFF00 ) >> 8;
1244 *( p + 2 ) = val & 0xFF;
1247 static void write_int_32( uint8_t *p, uint32_t val )
1249 *p = ( val & 0xFF000000 ) >> 24;
1250 *( p + 1 ) = ( val & 0xFF0000 ) >> 16;
1251 *( p + 2 ) = ( val & 0xFF00 ) >> 8;
1252 *( p + 3 ) = val & 0xFF;
1255 static size_t write_flv_header_and_metadata(
1256 uint8_t **pp_buffer,
1257 const uint8_t *p_metadata_payload,
1258 size_t metadata_payload_len )
1260 size_t metadata_packet_len;
1261 if ( metadata_payload_len > 0 && p_metadata_payload )
1262 metadata_packet_len = FLV_TAG_HEADER_LEN + metadata_payload_len;
1264 metadata_packet_len = 0;
1265 size_t data_len = FLV_FILE_HEADER_LEN + metadata_packet_len;
1267 *pp_buffer = malloc( data_len );
1274 memcpy( *pp_buffer, flv_header_bytes, FLV_FILE_HEADER_LEN );
1276 if ( metadata_packet_len > 0 )
1278 uint8_t *p = *pp_buffer + FLV_FILE_HEADER_LEN;
1285 write_int_24( p, metadata_payload_len );
1288 // timestamp and stream id
1293 memcpy( p, p_metadata_payload, metadata_payload_len );
1294 p += metadata_payload_len;
1296 // packet payload size
1297 write_int_32( p, metadata_packet_len );
1303 static void initialize_header_and_metadata( stream_sys_t* p_sys, hds_stream_t *stream )
1305 p_sys->flv_header_len =
1306 write_flv_header_and_metadata( &p_sys->flv_header, stream->metadata,
1307 stream->metadata_len );
1310 static int parse_Manifest( stream_t *s, manifest_t *m )
1312 int type = UNKNOWN_ES;
1314 msg_Dbg( s, "Manifest parsing\n" );
1318 stream_sys_t *sys = s->p_sys;
1320 sys->duration_seconds = 0;
1322 uint8_t bootstrap_idx = 0;
1323 uint8_t media_idx = 0;
1324 uint8_t current_element_idx = 0;
1325 char* current_element = NULL;
1327 const char* attr_name;
1328 const char* attr_value;
1330 char** element_stack = m->element_stack;
1331 bootstrap_info *bootstraps = m->bootstraps;
1332 media_info *medias = m->medias;
1333 xml_reader_t *vlc_reader = m->vlc_reader;
1334 char* media_id = NULL;
1336 #define TIMESCALE 10000000
1337 while( (type = xml_ReaderNextNode( vlc_reader, (const char**) &node )) > 0 )
1341 case XML_READER_STARTELEM:
1342 if( current_element_idx == 0 && element_stack[current_element_idx] == 0 ) {
1343 if( !( element_stack[current_element_idx] = strdup( node ) ) )
1346 if ( !( element_stack[++current_element_idx] = strdup( node ) ) )
1351 case XML_READER_ENDELEM:
1352 if( current_element && ! strcmp( current_element, "bootstrapInfo") ) {
1353 if( bootstrap_idx + 1 == MAX_BOOTSTRAP_INFO ) {
1354 msg_Warn( (vlc_object_t*) s, "Too many bootstraps, ignoring" );
1360 free( current_element );
1361 current_element = NULL;
1362 element_stack[current_element_idx--] = 0;
1366 if( ! element_stack[current_element_idx] ) {
1370 current_element = element_stack[current_element_idx];
1372 if( type == XML_READER_STARTELEM && ! strcmp( current_element, "media") )
1374 if( media_idx == MAX_MEDIA_ELEMENTS )
1376 msg_Err( (vlc_object_t*) s, "Too many media elements, quitting" );
1377 return VLC_EGENERIC;
1380 while( ( attr_name = xml_ReaderNextAttr( vlc_reader, &attr_value )) )
1382 if( !strcmp(attr_name, "streamId" ) )
1384 if( !( medias[media_idx].stream_id = strdup( attr_value ) ) )
1387 else if( !strcmp(attr_name, "url" ) )
1389 if( !( medias[media_idx].media_url = strdup( attr_value ) ) )
1392 else if( !strcmp(attr_name, "bootstrapInfoId" ) )
1394 if( !( medias[media_idx].bootstrap_id = strdup( attr_value ) ) )
1397 else if( !strcmp(attr_name, "bitrate" ) )
1399 medias[media_idx].bitrate = (uint32_t) atoi( attr_value );
1405 else if( type == XML_READER_STARTELEM && ! strcmp( current_element, "bootstrapInfo") )
1407 while( ( attr_name = xml_ReaderNextAttr( vlc_reader, &attr_value )) )
1409 if( !strcmp(attr_name, "url" ) )
1411 if( !( bootstraps[bootstrap_idx].url = strdup( attr_value ) ) )
1414 else if( !strcmp(attr_name, "id" ) )
1416 if( !( bootstraps[bootstrap_idx].id = strdup( attr_value ) ) )
1419 else if( !strcmp(attr_name, "profile" ) )
1421 if( !( bootstraps[bootstrap_idx].profile = strdup( attr_value ) ) )
1427 else if( type == XML_READER_TEXT )
1429 if( ! strcmp( current_element, "bootstrapInfo" ) )
1432 char* end = start + strlen(start);
1433 whitespace_substr( &start, &end );
1436 bootstraps[bootstrap_idx].data_len =
1437 vlc_b64_decode_binary( (uint8_t**)&bootstraps[bootstrap_idx].data, start );
1438 if( ! bootstraps[bootstrap_idx].data )
1440 msg_Err( (vlc_object_t*) s, "Couldn't decode bootstrap info" );
1443 else if( ! strcmp( current_element, "duration" ) )
1445 double shutup_gcc = atof( node );
1446 sys->duration_seconds = (uint64_t) shutup_gcc;
1448 else if( ! strcmp( current_element, "id" ) )
1450 if( ! strcmp( element_stack[current_element_idx-1], "manifest" ) )
1452 if( !( media_id = strdup( node ) ) )
1456 else if( ! strcmp( current_element, "metadata" ) &&
1457 ! strcmp( element_stack[current_element_idx-1], "media" ) &&
1458 ( media_idx >= 1 ) )
1460 uint8_t mi = media_idx - 1;
1461 if ( ! medias[mi].metadata )
1464 char* end = start + strlen(start);
1465 whitespace_substr( &start, &end );
1468 medias[mi].metadata_len =
1469 vlc_b64_decode_binary( (uint8_t**)&medias[mi].metadata, start );
1471 if ( ! medias[mi].metadata )
1474 uint8_t *end_marker =
1475 medias[mi].metadata + medias[mi].metadata_len - sizeof(amf_object_end);
1476 if ( ( end_marker < medias[mi].metadata ) ||
1477 memcmp(end_marker, amf_object_end, sizeof(amf_object_end)) != 0 )
1479 msg_Dbg( (vlc_object_t*)s, "Ignoring invalid metadata packet on stream %d", mi );
1480 FREENULL( medias[mi].metadata );
1481 medias[mi].metadata_len = 0;
1488 for( int i = 0; i <= media_idx; i++ )
1490 for( int j = 0; j < bootstrap_idx; j++ )
1492 if( ( ! medias[i].bootstrap_id && ! bootstraps[j].id ) ||
1493 (medias[i].bootstrap_id && bootstraps[j].id &&
1494 ! strcmp( medias[i].bootstrap_id, bootstraps[j].id ) ) )
1496 hds_stream_t* new_stream = malloc(sizeof(hds_stream_t));
1502 memset( new_stream, 0, sizeof(hds_stream_t));
1504 vlc_mutex_init( & new_stream->abst_lock );
1505 vlc_mutex_init( & new_stream->dl_lock );
1506 vlc_cond_init( & new_stream->dl_cond );
1508 if( sys->duration_seconds )
1517 if( medias[i].media_url )
1519 if( !(new_stream->url = strdup( medias[i].media_url ) ) )
1522 cleanup_threading( new_stream );
1528 if( medias[i].metadata )
1530 new_stream->metadata = malloc( medias[i].metadata_len );
1531 if ( ! new_stream->metadata )
1533 free( new_stream->url );
1535 cleanup_threading( new_stream );
1540 memcpy( new_stream->metadata, medias[i].metadata, medias[i].metadata_len );
1541 new_stream->metadata_len = medias[i].metadata_len;
1546 parse_BootstrapData( (vlc_object_t*)s,
1549 bootstraps[j].data + bootstraps[j].data_len );
1551 new_stream->download_leadtime = 15;
1553 new_stream->chunks_head = generate_new_chunk(
1554 (vlc_object_t*) s, 0, new_stream );
1555 chunk_t* chunk = new_stream->chunks_head;
1556 uint64_t total_duration = chunk->duration;
1557 while( chunk && total_duration/new_stream->afrt_timescale < new_stream->download_leadtime )
1559 chunk->next = generate_new_chunk(
1560 (vlc_object_t*) s, chunk, new_stream );
1561 chunk = chunk->next;
1563 total_duration += chunk->duration;
1568 if( !(new_stream->abst_url = strdup( bootstraps[j].url ) ) )
1570 free( new_stream->metadata );
1571 free( new_stream->url );
1573 cleanup_threading( new_stream );
1579 new_stream->bitrate = medias[i].bitrate;
1581 vlc_array_append( sys->hds_streams, new_stream );
1583 msg_Info( (vlc_object_t*)s, "New track with quality_segment(%s), bitrate(%u), timescale(%u), movie_id(%s), segment_run_count(%d), fragment_run_count(%u)",
1584 new_stream->quality_segment_modifier?new_stream->quality_segment_modifier:"", new_stream->bitrate, new_stream->timescale,
1585 new_stream->movie_id, new_stream->segment_run_count, new_stream->fragment_run_count );
1592 cleanup_Manifest( m );
1598 static void hds_free( hds_stream_t *p_stream )
1600 FREENULL( p_stream->quality_segment_modifier );
1602 FREENULL( p_stream->abst_url );
1604 cleanup_threading( p_stream );
1606 FREENULL( p_stream->metadata );
1607 FREENULL( p_stream->url );
1608 FREENULL( p_stream->movie_id );
1609 for( int i = 0; i < p_stream->server_entry_count; i++ )
1611 FREENULL( p_stream->server_entries[i] );
1614 chunk_t* chunk = p_stream->chunks_head;
1617 chunk_t* next = chunk->next;
1618 chunk_free( chunk );
1625 static void SysCleanup( stream_sys_t *p_sys )
1627 if ( p_sys->hds_streams )
1629 for ( int i=0; i< p_sys->hds_streams->i_count ; i++ )
1630 hds_free( p_sys->hds_streams->pp_elems[i] );
1631 vlc_array_destroy( p_sys->hds_streams );
1633 free( p_sys->base_url );
1636 static int Open( vlc_object_t *p_this )
1638 stream_t *s = (stream_t*)p_this;
1639 stream_sys_t *p_sys;
1642 return VLC_EGENERIC;
1644 msg_Info( p_this, "HTTP Dynamic Streaming (%s)", s->psz_path );
1646 s->p_sys = p_sys = calloc( 1, sizeof(*p_sys ) );
1647 if( unlikely( p_sys == NULL ) )
1650 char *uri_without_query = NULL;
1651 size_t pathlen = strcspn( s->psz_path, "?" );
1652 if( unlikely( ( pathlen > INT_MAX ) ||
1653 ( asprintf( &uri_without_query, "%s://%.*s", s->psz_access,
1654 (int)pathlen, s->psz_path ) < 0 ) ) )
1660 /* remove the last part of the url */
1661 char *pos = strrchr( uri_without_query, '/');
1663 p_sys->base_url = uri_without_query;
1665 p_sys->flv_header_bytes_sent = 0;
1667 p_sys->hds_streams = vlc_array_new();
1670 if( init_Manifest( s, &m ) || parse_Manifest( s, &m ) )
1672 cleanup_Manifest( &m );
1678 s->pf_control = Control;
1680 if( vlc_clone( &p_sys->dl_thread, download_thread, s, VLC_THREAD_PRIORITY_INPUT ) )
1686 msg_Info( p_this, "Live stream detected" );
1688 if( vlc_clone( &p_sys->live_thread, live_thread, s, VLC_THREAD_PRIORITY_INPUT ) )
1697 SysCleanup( p_sys );
1699 return VLC_EGENERIC;
1702 static void Close( vlc_object_t *p_this )
1704 stream_t *s = (stream_t*)p_this;
1705 stream_sys_t *p_sys = s->p_sys;
1707 // TODO: Change here for selectable stream
1708 hds_stream_t *stream = vlc_array_count(p_sys->hds_streams) ?
1709 s->p_sys->hds_streams->pp_elems[0] : NULL;
1711 p_sys->closed = true;
1713 vlc_cond_signal( & stream->dl_cond );
1715 vlc_join( p_sys->dl_thread, NULL );
1719 vlc_join( p_sys->live_thread, NULL );
1722 SysCleanup( p_sys );
1726 static int send_flv_header( hds_stream_t *stream, stream_sys_t* p_sys,
1727 void* buffer, unsigned i_read, bool peek )
1729 if ( !p_sys->flv_header )
1731 initialize_header_and_metadata( p_sys, stream );
1734 uint32_t to_be_read = i_read;
1735 uint32_t header_remaining =
1736 p_sys->flv_header_len - p_sys->flv_header_bytes_sent;
1737 if( to_be_read > header_remaining ) {
1738 to_be_read = header_remaining;
1741 memcpy( buffer, p_sys->flv_header + p_sys->flv_header_bytes_sent, to_be_read );
1745 p_sys->flv_header_bytes_sent += to_be_read;
1750 static unsigned read_chunk_data(
1751 vlc_object_t* p_this,
1752 uint8_t* buffer, unsigned read_len,
1753 hds_stream_t* stream,
1757 stream_t* s = (stream_t*) p_this;
1758 stream_sys_t* sys = s->p_sys;
1759 chunk_t* chunk = stream->chunks_head;
1760 uint8_t* buffer_start = buffer;
1763 if( chunk && chunk->eof && chunk->mdat_pos >= chunk->mdat_len ) {
1768 while( chunk && chunk->data && read_len > 0 && ! (chunk->eof && chunk->mdat_pos >= chunk->mdat_len ) )
1770 /* in the live case, it is necessary to store the next
1771 * pointer here, since as soon as we increment the mdat_pos, that
1772 * chunk may be deleted */
1773 chunk_t* next = chunk->next;
1775 if( chunk->mdat_pos < chunk->mdat_len )
1777 unsigned cp_len = chunk->mdat_len - chunk->mdat_pos;
1778 if( cp_len > read_len )
1780 memcpy( buffer, chunk->mdat_data + chunk->mdat_pos,
1785 chunk->mdat_pos += cp_len;
1788 if( ! sys->live && (chunk->mdat_pos >= chunk->mdat_len || chunk->failed) )
1795 /* make sure there is at least one chunk in the queue */
1796 if( ! chunk->next && ! chunk->eof )
1798 chunk->next = generate_new_chunk( p_this, chunk, stream );
1804 chunk_free( chunk );
1806 stream->chunks_head = chunk;
1809 else if( sys->live && (chunk->mdat_pos >= chunk->mdat_len || chunk->failed) )
1817 stream->chunks_livereadpos = chunk;
1820 /* new chunk generation is handled by a different thread in live case */
1823 chunk = stream->chunks_head;
1826 uint64_t total_duration = chunk->duration;
1827 while( chunk && total_duration/stream->afrt_timescale < stream->download_leadtime && ! chunk->eof )
1829 if( ! chunk->next && ! chunk->eof )
1831 chunk->next = generate_new_chunk( p_this, chunk, stream );
1837 chunk = chunk->next;
1840 total_duration += chunk->duration;
1847 vlc_cond_signal( & stream->dl_cond );
1850 return ( ((uint8_t*)buffer) - ((uint8_t*)buffer_start));
1853 static inline bool header_unfinished( stream_sys_t *p_sys )
1855 return p_sys->flv_header_bytes_sent < p_sys->flv_header_len;
1858 static int Read( stream_t *s, void *buffer, unsigned i_read )
1860 stream_sys_t *p_sys = s->p_sys;
1862 if ( vlc_array_count( p_sys->hds_streams ) == 0 )
1865 // TODO: change here for selectable stream
1866 hds_stream_t *stream = s->p_sys->hds_streams->pp_elems[0];
1869 uint8_t *buffer_uint8 = (uint8_t*) buffer;
1871 if ( header_unfinished( p_sys ) )
1873 unsigned hdr_bytes = send_flv_header( stream, p_sys, buffer, i_read, false );
1874 length += hdr_bytes;
1875 i_read -= hdr_bytes;
1876 buffer_uint8 += hdr_bytes;
1880 while( i_read > 0 && ! eof )
1882 int tmp_length = read_chunk_data( (vlc_object_t*)s, buffer_uint8, i_read, stream, &eof );
1883 buffer_uint8 += tmp_length;
1884 i_read -= tmp_length;
1885 length += tmp_length;
1886 p_sys->playback_offset += tmp_length;
1892 static int Peek( stream_t *s, const uint8_t **pp_peek, unsigned i_peek )
1894 stream_sys_t *p_sys = s->p_sys;
1896 if ( vlc_array_count( p_sys->hds_streams ) == 0 )
1899 // TODO: change here for selectable stream
1900 hds_stream_t *stream = p_sys->hds_streams->pp_elems[0];
1902 if ( !p_sys->flv_header )
1904 initialize_header_and_metadata( p_sys, stream );
1907 if( header_unfinished( p_sys ) )
1909 *pp_peek = p_sys->flv_header + p_sys->flv_header_bytes_sent;
1910 return p_sys->flv_header_len - p_sys->flv_header_bytes_sent;
1913 if( stream->chunks_head && ! stream->chunks_head->failed && stream->chunks_head->data )
1915 // TODO: change here for selectable stream
1916 chunk_t* chunk = stream->chunks_head;
1917 *pp_peek = chunk->mdat_data + chunk->mdat_pos;
1918 if( chunk->mdat_len - chunk->mdat_pos < i_peek )
1920 return chunk->mdat_len - chunk->mdat_pos;
1932 static int Control( stream_t *s, int i_query, va_list args )
1936 case STREAM_CAN_SEEK:
1937 *(va_arg( args, bool * )) = false;
1939 case STREAM_CAN_FASTSEEK:
1940 case STREAM_CAN_PAUSE: /* TODO */
1941 *(va_arg( args, bool * )) = false;
1943 case STREAM_CAN_CONTROL_PACE:
1944 *(va_arg( args, bool * )) = true;
1946 case STREAM_GET_PTS_DELAY:
1947 *va_arg (args, int64_t *) = INT64_C(1000) *
1948 var_InheritInteger(s, "network-caching");
1950 case STREAM_GET_POSITION:
1951 *(va_arg (args, uint64_t *)) = s->p_sys->playback_offset;
1953 case STREAM_GET_SIZE:
1954 *(va_arg (args, uint64_t *)) = get_stream_size(s);
1957 return VLC_EGENERIC;