1 /*****************************************************************************
2 * downloader.c: download thread
3 *****************************************************************************
4 * Copyright (C) 1996-2012 VLC authors and VideoLAN
7 * Author: Frédéric Yhuel <fyhuel _AT_ viotech _DOT_ net>
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
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 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 *****************************************************************************/
27 #include <vlc_common.h>
29 #include <vlc_stream.h>
33 #include "../../demux/mp4/libmp4.h"
35 static char *ConstructUrl( const char *template, const char *base_url,
36 const uint64_t bandwidth, const uint64_t start_time )
38 char *frag, *end, *qual;
39 char *url_template = strdup( template );
42 qual = strtok_r( url_template, "{", &saveptr );
43 strtok_r( NULL, "}", &saveptr );
44 frag = strtok_r( NULL, "{", &saveptr );
45 strtok_r( NULL, "}", &saveptr );
46 end = strtok_r( NULL, "", &saveptr );
49 if( asprintf( &url, "%s/%s%"PRIu64"%s%"PRIu64"%s", base_url, qual,
50 bandwidth, frag, start_time, end) < 0 )
59 static chunk_t * chunk_Get( sms_stream_t *sms, const int64_t start_time )
61 int len = vlc_array_count( sms->chunks );
62 for( int i = 0; i < len; i++ )
64 chunk_t * chunk = vlc_array_item_at_index( sms->chunks, i );
65 if( !chunk ) return NULL;
67 if( chunk->start_time <= start_time &&
68 chunk->start_time + chunk->duration > start_time )
76 static unsigned set_track_id( chunk_t *chunk, const unsigned tid )
81 uint8_t *slice = chunk->data;
85 SMS_GET4BYTES( size );
86 SMS_GETFOURCC( type );
87 assert( type == ATOM_moof );
89 SMS_GET4BYTES( size );
90 SMS_GETFOURCC( type );
91 assert( type == ATOM_mfhd );
94 SMS_GET4BYTES( size );
95 SMS_GETFOURCC( type );
96 assert( type == ATOM_traf );
98 SMS_GET4BYTES( size );
99 SMS_GETFOURCC( type );
100 if( type != ATOM_tfhd )
103 unsigned ret = bswap32( ((uint32_t *)slice)[1] );
104 ((uint32_t *)slice)[1] = bswap32( tid );
109 static int sms_Download( stream_t *s, chunk_t *chunk, char *url )
111 stream_sys_t *p_sys = s->p_sys;
113 stream_t *p_ts = stream_UrlNew( s, url );
118 int64_t size = stream_Size( p_ts );
121 chunk->offset = p_sys->download.next_chunk_offset;
122 p_sys->download.next_chunk_offset += chunk->size;
124 chunk->data = malloc( size );
126 if( chunk->data == NULL )
128 stream_Delete( p_ts );
132 int read = stream_Read( p_ts, chunk->data, size );
135 msg_Warn( s, "sms_Download: I requested %"PRIi64" bytes, "\
136 "but I got only %i", size, read );
137 chunk->data = realloc( chunk->data, read );
140 stream_Delete( p_ts );
142 vlc_mutex_lock( &p_sys->download.lock_wait );
143 int index = es_cat_to_index( chunk->type );
144 p_sys->download.lead[index] += chunk->duration;
145 vlc_mutex_unlock( &p_sys->download.lock_wait );
150 #ifdef DISABLE_BANDWIDTH_ADAPTATION
151 static unsigned BandwidthAdaptation( stream_t *s,
152 sms_stream_t *sms, uint64_t *bandwidth )
154 return sms->download_qlvl;
158 static unsigned BandwidthAdaptation( stream_t *s,
159 sms_stream_t *sms, uint64_t bandwidth )
161 if( sms->type != VIDEO_ES )
162 return sms->download_qlvl;
164 uint64_t bw_candidate = 0;
165 quality_level_t *qlevel;
166 unsigned ret = sms->download_qlvl;
168 for( unsigned i = 0; i < sms->qlevel_nb; i++ )
170 qlevel = vlc_array_item_at_index( sms->qlevels, i );
171 if( unlikely( !qlevel ) )
173 msg_Err( s, "Could no get %uth quality level", i );
177 if( qlevel->Bitrate < (bandwidth - bandwidth / 3) &&
178 qlevel->Bitrate > bw_candidate )
180 bw_candidate = qlevel->Bitrate;
189 static int get_new_chunks( stream_t *s, chunk_t *ck )
191 stream_sys_t *p_sys = s->p_sys;
193 uint8_t *slice = ck->data;
196 uint8_t version, fragment_count;
197 uint32_t size, type, flags;
200 TfrfBoxDataFields_t *tfrf_df;
202 sms = SMS_GET_SELECTED_ST( ck->type );
204 SMS_GET4BYTES( size );
205 SMS_GETFOURCC( type );
206 assert( type == ATOM_moof );
208 SMS_GET4BYTES( size );
209 SMS_GETFOURCC( type );
210 assert( type == ATOM_mfhd );
213 SMS_GET4BYTES( size );
214 SMS_GETFOURCC( type );
215 assert( type == ATOM_traf );
219 SMS_GET4BYTES( size );
221 SMS_GETFOURCC( type );
222 if( type == ATOM_mdat )
224 msg_Err( s, "No uuid box found :-(" );
227 else if( type == ATOM_uuid )
229 GetUUID( &uuid, slice);
230 if( !CmpUUID( &uuid, &TfrfBoxUUID ) )
237 SMS_GET1BYTE( version );
238 SMS_GET3BYTES( flags );
239 SMS_GET1BYTE( fragment_count );
241 tfrf_df = calloc( fragment_count, sizeof( TfrfBoxDataFields_t ) );
242 if( unlikely( tfrf_df == NULL ) )
245 for( uint8_t i = 0; i < fragment_count; i++ )
247 SMS_GET4or8BYTES( tfrf_df[i].i_fragment_abs_time );
248 SMS_GET4or8BYTES( tfrf_df[i].i_fragment_duration );
251 msg_Dbg( s, "read box: \"tfrf\" version %d, flags 0x%x, "\
252 "fragment count %"PRIu8, version, flags, fragment_count );
254 for( uint8_t i = 0; i < fragment_count; i++ )
256 int64_t dur = tfrf_df[i].i_fragment_duration;
257 int64_t stime = tfrf_df[i].i_fragment_abs_time;
258 msg_Dbg( s, "\"tfrf\" fragment duration %"PRIu64", "\
259 "fragment abs time %"PRIu64, dur, stime);
261 if( !chunk_Get( sms, stime + dur ) )
262 chunk_New( sms, dur, stime );
269 #define STRA_SIZE 334
270 #define SMOO_SIZE (STRA_SIZE * 3 + 24) /* 1026 */
272 /* SmooBox is a very simple MP4 box, used only to pass information
273 * to the demux layer. As this box is not aimed to travel accross networks,
274 * simplicity of the design is better than compactness */
275 static int build_smoo_box( stream_t *s, uint8_t *smoo_box )
277 stream_sys_t *p_sys = s->p_sys;
278 sms_stream_t *sms = NULL;
282 memset( smoo_box, 0, SMOO_SIZE );
283 smoo_box[2] = (SMOO_SIZE & 0xff00)>>8;
284 smoo_box[3] = SMOO_SIZE & 0xff;
290 /* UUID is e1da72ba-24d7-43c3-a6a5-1b5759a1a92c */
291 ((uint32_t *)smoo_box)[2] = bswap32( 0xe1da72ba );
292 ((uint32_t *)smoo_box)[3] = bswap32( 0x24d743c3 );
293 ((uint32_t *)smoo_box)[4] = bswap32( 0xa6a51b57 );
294 ((uint32_t *)smoo_box)[5] = bswap32( 0x59a1a92c );
297 for( int i = 0; i < 3; i++ )
300 int cat = UNKNOWN_ES;
301 stra_box = smoo_box + i * STRA_SIZE;
303 stra_box[26] = (STRA_SIZE & 0xff00)>>8;
304 stra_box[27] = STRA_SIZE & 0xff;
310 /* UUID is b03ef770-33bd-4bac-96c7-bf25f97e2447 */
311 ((uint32_t *)stra_box)[8] = bswap32( 0xb03ef770 );
312 ((uint32_t *)stra_box)[9] = bswap32( 0x33bd4bac );
313 ((uint32_t *)stra_box)[10] = bswap32( 0x96c7bf25 );
314 ((uint32_t *)stra_box)[11] = bswap32( 0xf97e2447 );
316 cat = index_to_es_cat( i );
318 sms = SMS_GET_SELECTED_ST( cat );
320 stra_box[49] = 0; /* reserved */
323 stra_box[50] = (sms->id & 0xff00)>>8;
324 stra_box[51] = sms->id & 0xff;
326 ((uint32_t *)stra_box)[13] = bswap32( sms->timescale );
327 ((uint64_t *)stra_box)[7] = bswap64( p_sys->vod_duration );
329 quality_level_t * qlvl = get_qlevel( sms, sms->download_qlvl );
331 FourCC = qlvl->FourCC ? qlvl->FourCC : sms->default_FourCC;
332 ((uint32_t *)stra_box)[16] = bswap32( FourCC );
333 ((uint32_t *)stra_box)[17] = bswap32( qlvl->Bitrate );
334 ((uint32_t *)stra_box)[18] = bswap32( qlvl->MaxWidth );
335 ((uint32_t *)stra_box)[19] = bswap32( qlvl->MaxHeight );
336 ((uint32_t *)stra_box)[20] = bswap32( qlvl->SamplingRate );
337 ((uint32_t *)stra_box)[21] = bswap32( qlvl->Channels );
338 ((uint32_t *)stra_box)[22] = bswap32( qlvl->BitsPerSample );
339 ((uint32_t *)stra_box)[23] = bswap32( qlvl->AudioTag );
340 ((uint16_t *)stra_box)[48] = bswap16( qlvl->nBlockAlign );
342 if( !qlvl->CodecPrivateData )
344 stra_box[98] = stra_box[99] = stra_box[100] = 0; /* reserved */
345 assert( strlen( qlvl->CodecPrivateData ) < 512 );
346 stra_box[101] = strlen( qlvl->CodecPrivateData ) / 2;
347 uint8_t *binary_cpd = decode_string_hex_to_binary( qlvl->CodecPrivateData );
348 memcpy( stra_box + 102, binary_cpd, stra_box[101] );
355 static chunk_t *build_init_chunk( stream_t *s )
357 chunk_t *ret = calloc( 1, sizeof( chunk_t ) );
358 if( unlikely( ret == NULL ) )
359 goto build_init_chunk_error;
361 ret->size = SMOO_SIZE;
362 ret->data = malloc( SMOO_SIZE );
364 goto build_init_chunk_error;
366 if( build_smoo_box( s, ret->data ) == VLC_SUCCESS)
370 build_init_chunk_error:
372 msg_Err( s, "build_init_chunk failed" );
376 static int Download( stream_t *s, sms_stream_t *sms )
378 stream_sys_t *p_sys = s->p_sys;
380 int index = es_cat_to_index( sms->type );
381 int64_t start_time = p_sys->download.lead[index];
383 quality_level_t *qlevel = get_qlevel( sms, sms->download_qlvl );
384 if( unlikely( !qlevel ) )
386 msg_Err( s, "Could not get quality level id %u", sms->download_qlvl );
391 chunk_t *chunk = chunk_Get( sms, start_time );
394 msg_Warn( s, "Could not find a chunk for stream %s, "\
395 "start time = %"PRIu64"", sms->name, start_time );
398 if( chunk->data != NULL )
400 /* Segment already downloaded */
401 msg_Warn( s, "Segment already downloaded" );
405 chunk->type = sms->type;
407 char *url = ConstructUrl( sms->url_template, p_sys->base_url,
408 qlevel->Bitrate, chunk->start_time );
411 msg_Err( s, "ConstructUrl returned NULL" );
415 /* sanity check - can we download this chunk on time? */
416 uint64_t avg_bw = sms_queue_avg( p_sys->bws );
417 if( (avg_bw > 0) && (qlevel->Bitrate > 0) )
420 unsigned chunk_duration = chunk->duration * 1000 / sms->timescale;
421 uint64_t size = chunk_duration * qlevel->Bitrate / 1000; /* bits */
422 unsigned estimated = size * 1000 / avg_bw;
423 if( estimated > chunk_duration )
425 msg_Warn( s,"downloading of chunk %d would take %d ms, "\
426 "which is longer than its playback (%d ms)",
427 chunk->sequence, estimated, chunk_duration );
431 mtime_t start = mdate();
432 if( sms_Download( s, chunk, url ) != VLC_SUCCESS )
434 msg_Err( s, "downloaded chunk %u from stream %s at quality\
435 %u failed", chunk->sequence, sms->name, qlevel->Bitrate );
438 mtime_t duration = mdate() - start;
440 unsigned real_id = set_track_id( chunk, sms->id );
443 msg_Err( s, "tfhd box not found or invalid chunk" );
447 //msg_Dbg( s, "chunk ID was %i and is now %i", real_id, sms->id );
450 get_new_chunks( s, chunk );
452 vlc_mutex_lock( &p_sys->download.lock_wait );
453 vlc_array_append( p_sys->download.chunks, chunk );
454 vlc_cond_signal( &p_sys->download.wait );
455 vlc_mutex_unlock( &p_sys->download.lock_wait );
457 msg_Info( s, "downloaded chunk %d from stream %s at quality %u",
458 chunk->sequence, sms->name, qlevel->Bitrate );
460 uint64_t actual_lead = chunk->start_time + chunk->duration;
461 int ind = es_cat_to_index( sms->type );
462 p_sys->download.ck_index[ind] = chunk->sequence;
463 p_sys->download.lead[ind] = __MIN( p_sys->download.lead[ind], actual_lead );
465 if( sms->type == VIDEO_ES ||
466 ( !SMS_GET_SELECTED_ST( VIDEO_ES ) && sms->type == AUDIO_ES ) )
468 p_sys->playback.toffset = __MIN( p_sys->playback.toffset,
469 (uint64_t)chunk->start_time );
472 unsigned dur_ms = __MAX( 1, duration / 1000 );
473 uint64_t bw = chunk->size * 8 * 1000 / dur_ms; /* bits / s */
474 if( sms_queue_put( p_sys->bws, bw ) != VLC_SUCCESS )
476 avg_bw = sms_queue_avg( p_sys->bws );
478 if( sms->type != VIDEO_ES )
481 /* Track could get disabled in mp4 demux if we trigger adaption too soon. */
482 if( chunk->sequence <= 1 )
485 unsigned new_qlevel_id = BandwidthAdaptation( s, sms, avg_bw );
486 quality_level_t *new_qlevel = get_qlevel( sms, new_qlevel_id );
487 if( unlikely( !new_qlevel ) )
489 msg_Err( s, "Could not get quality level id %u", new_qlevel_id );
493 if( new_qlevel->Bitrate != qlevel->Bitrate )
495 msg_Warn( s, "detected %s bandwidth (%u) stream",
496 (new_qlevel->Bitrate >= qlevel->Bitrate) ? "faster" : "lower",
497 new_qlevel->Bitrate );
499 sms->download_qlvl = new_qlevel_id;
502 if( new_qlevel->MaxWidth != qlevel->MaxWidth ||
503 new_qlevel->MaxHeight != qlevel->MaxHeight )
505 chunk_t *new_init_ck = build_init_chunk( s );
511 new_init_ck->offset = p_sys->download.next_chunk_offset;
512 p_sys->download.next_chunk_offset += new_init_ck->size;
514 vlc_mutex_lock( &p_sys->download.lock_wait );
515 vlc_array_append( p_sys->download.chunks, new_init_ck );
516 vlc_array_append( p_sys->init_chunks, new_init_ck );
517 vlc_mutex_unlock( &p_sys->download.lock_wait );
522 static inline int64_t get_lead( stream_t *s )
524 stream_sys_t *p_sys = s->p_sys;
526 int64_t alead = p_sys->download.lead[es_cat_to_index( AUDIO_ES )];
527 int64_t vlead = p_sys->download.lead[es_cat_to_index( VIDEO_ES )];
528 bool video = SMS_GET_SELECTED_ST( VIDEO_ES ) ? true : false;
529 bool audio = SMS_GET_SELECTED_ST( AUDIO_ES ) ? true : false;
532 lead = __MIN( vlead, alead );
538 lead -= p_sys->playback.toffset;
542 static int next_track( stream_t *s )
544 stream_sys_t *p_sys = s->p_sys;
545 uint64_t tmp, min = 0;
546 int cat, ret = UNKNOWN_ES;
547 for( int i = 0; i < 3; i++ )
549 tmp = p_sys->download.lead[i];
550 cat = index_to_es_cat( i );
551 if( (!min || tmp < min) && SMS_GET_SELECTED_ST( cat ) )
560 void* sms_Thread( void *p_this )
562 stream_t *s = (stream_t *)p_this;
563 stream_sys_t *p_sys = s->p_sys;
564 sms_stream_t *sms = NULL;
567 int canc = vlc_savecancel();
569 /* We compute the average bandwidth of the 4 last downloaded
570 * chunks, but feel free to replace '4' by whatever you wish */
571 p_sys->bws = sms_queue_init( 4 );
575 chunk_t *init_ck = build_init_chunk( s );
579 vlc_mutex_lock( &p_sys->download.lock_wait );
580 vlc_array_append( p_sys->download.chunks, init_ck );
581 vlc_array_append( p_sys->init_chunks, init_ck );
582 vlc_mutex_unlock( &p_sys->download.lock_wait );
584 p_sys->download.next_chunk_offset = init_ck->size;
586 /* XXX Sometimes, the video stream is cut into pieces of one exact length,
587 * while the audio stream fragments can't be made to match exactly,
588 * and for some reason the n^th advertised video fragment is related to
589 * the n+1^th advertised audio chunk or vice versa */
591 int64_t start_time = 0, lead = 0;
593 for( int i = 0; i < 3; i++ )
595 sms = SMS_GET_SELECTED_ST( index_to_es_cat( i ) );
598 chunk = vlc_array_item_at_index( sms->chunks, 0 );
599 p_sys->download.lead[i] = chunk->start_time + p_sys->timescale / 1000;
601 start_time = chunk->start_time;
603 if( Download( s, sms ) != VLC_SUCCESS )
610 /* XXX replace magic number 10 by a value depending on
611 * LookAheadFragmentCount and DVRWindowLength */
612 vlc_mutex_lock( &p_sys->download.lock_wait );
616 vlc_mutex_unlock( &p_sys->download.lock_wait );
620 lead = get_lead( s );
622 while( lead > 10 * p_sys->timescale + start_time || NO_MORE_CHUNKS )
624 vlc_cond_wait( &p_sys->download.wait, &p_sys->download.lock_wait );
625 lead = get_lead( s );
633 int count = vlc_array_count( p_sys->download.chunks );
635 for( int i = 0; i < count; i++ )
637 ck = vlc_array_item_at_index( p_sys->download.chunks, i );
638 if( unlikely( !ck ) )
641 if( ck->data == NULL )
643 FREENULL( ck->data );
646 vlc_array_destroy( p_sys->download.chunks );
647 p_sys->download.chunks = vlc_array_new();
649 p_sys->playback.toffset = p_sys->time_pos;
650 for( int i = 0; i < 3; i++ )
652 p_sys->download.lead[i] = p_sys->time_pos;
653 p_sys->download.ck_index[i] = 0;
655 p_sys->download.next_chunk_offset = 0;
657 p_sys->playback.boffset = 0;
658 p_sys->playback.index = 0;
660 chunk_t *new_init_ck = build_init_chunk( s );
664 new_init_ck->offset = p_sys->download.next_chunk_offset;
665 p_sys->download.next_chunk_offset += new_init_ck->size;
667 vlc_array_append( p_sys->download.chunks, new_init_ck );
668 vlc_array_append( p_sys->init_chunks, new_init_ck );
669 p_sys->b_tseek = false;
671 vlc_mutex_unlock( &p_sys->download.lock_wait );
673 sms = SMS_GET_SELECTED_ST( next_track( s ) );
674 if( Download( s, sms ) != VLC_SUCCESS )
679 p_sys->b_error = true;
680 msg_Warn(s, "Canceling download thread!");
681 vlc_restorecancel( canc );