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_stream.h>
28 #include <vlc_charset.h>
30 #include "../../demux/mp4/libmp4.h"
32 static bool Replace( char **ppsz_string, off_t off, const char *psz_old,
35 const size_t i_oldlen = strlen( psz_old );
36 const size_t i_newlen = strlen( psz_new );
37 size_t i_stringlen = strlen( *ppsz_string );
39 if ( i_newlen > i_oldlen )
41 i_stringlen += i_newlen - i_oldlen;
42 char *psz_realloc = realloc( *ppsz_string, i_stringlen + 1 );
45 *ppsz_string = psz_realloc;
47 memmove( *ppsz_string + off + i_newlen,
48 *ppsz_string + off + i_oldlen,
49 i_stringlen - off - i_newlen );
50 strncpy( *ppsz_string + off, psz_new, i_newlen );
51 (*ppsz_string)[i_stringlen] = 0;
56 static char *ConstructUrl( const char *psz_template, const char *psz_base_url,
57 const quality_level_t *p_qlevel, const uint64_t i_start_time )
59 char *psz_path = strdup( psz_template );
66 if ( (psz_start = strstr( psz_path, "{bitrate}" )) )
68 char *psz_bitrate = NULL;
69 if ( us_asprintf( &psz_bitrate, "%u", p_qlevel->Bitrate ) < 0 ||
70 ! Replace( &psz_path, psz_start - psz_path, "{bitrate}", psz_bitrate ) )
78 else if ( (psz_start = strstr( psz_path, "{start time}" )) ||
79 (psz_start = strstr( psz_path, "{start_time}" )) )
82 char *psz_starttime = NULL;
83 if ( us_asprintf( &psz_starttime, "%"PRIu64, i_start_time ) < 0 ||
84 ! Replace( &psz_path, psz_start - psz_path, "{start time}", psz_starttime ) )
86 free( psz_starttime );
90 free( psz_starttime );
92 else if ( (psz_start = strstr( psz_path, "{CustomAttributes}" )) )
94 char *psz_attributes = NULL;
95 FOREACH_ARRAY( const custom_attrs_t *p_attrs, p_qlevel->custom_attrs )
96 if ( asprintf( &psz_attributes,
97 psz_attributes ? "%s,%s=%s" : "%s%s=%s",
98 psz_attributes ? psz_attributes : "",
99 p_attrs->psz_key, p_attrs->psz_value ) < 0 )
102 if ( !psz_attributes ||
103 ! Replace( &psz_path, psz_start - psz_path, "{CustomAttributes}", psz_attributes ) )
105 free( psz_attributes );
109 free( psz_attributes );
116 if( asprintf( &psz_url, "%s/%s", psz_base_url, psz_path ) < 0 )
125 static chunk_t * chunk_Get( sms_stream_t *sms, const uint64_t start_time )
127 chunk_t *p_chunk = sms->p_chunks;
130 if( p_chunk->start_time <= start_time &&
131 p_chunk->start_time + p_chunk->duration > start_time )
133 p_chunk = p_chunk->p_next;
138 static unsigned set_track_id( chunk_t *chunk, const unsigned tid )
141 if( !chunk->data || chunk->size < 32 )
143 uint8_t *slice = chunk->data;
147 SMS_GET4BYTES( size );
148 SMS_GETFOURCC( type );
149 assert( type == ATOM_moof );
151 SMS_GET4BYTES( size );
152 SMS_GETFOURCC( type );
153 assert( type == ATOM_mfhd );
156 SMS_GET4BYTES( size );
157 SMS_GETFOURCC( type );
158 assert( type == ATOM_traf );
160 SMS_GET4BYTES( size );
161 SMS_GETFOURCC( type );
162 if( type != ATOM_tfhd )
165 unsigned ret = bswap32( ((uint32_t *)slice)[1] );
166 ((uint32_t *)slice)[1] = bswap32( tid );
171 static int sms_Download( stream_t *s, chunk_t *chunk, char *url )
173 stream_t *p_ts = stream_UrlNew( s, url );
178 int64_t size = stream_Size( p_ts );
181 stream_Delete( p_ts );
185 uint8_t *p_data = malloc( size );
188 stream_Delete( p_ts );
192 int read = stream_Read( p_ts, p_data, size );
193 if( read < size && read > 0 )
195 msg_Warn( s, "sms_Download: I requested %"PRIi64" bytes, "\
196 "but I got only %i", size, read );
197 p_data = realloc( p_data, read );
200 chunk->data = p_data;
201 chunk->size = (uint64_t) (read > 0 ? read : 0);
203 stream_Delete( p_ts );
208 #ifdef DISABLE_BANDWIDTH_ADAPTATION
209 static quality_level_t *
210 BandwidthAdaptation( stream_t *s, sms_stream_t *sms,
211 uint64_t obw, uint64_t i_duration,
216 VLC_UNUSED(i_duration);
217 VLC_UNUSED(b_starved);
218 return sms->current_qlvl;
222 static quality_level_t *
223 BandwidthAdaptation( stream_t *s, sms_stream_t *sms,
224 uint64_t obw, uint64_t i_duration,
227 quality_level_t *ret = NULL;
229 assert( sms->current_qlvl );
230 if ( sms->qlevels.i_size < 2 )
231 return sms->qlevels.p_elems[0];
235 //TODO: do something on starvation post first buffering
236 // s->p_sys->i_probe_length *= 2;
240 quality_level_t *lowest = sms->qlevels.p_elems[0];
241 FOREACH_ARRAY( quality_level_t *qlevel, sms->qlevels );
242 if ( qlevel->Bitrate >= obw )
244 qlevel->i_validation_length -= i_duration;
245 qlevel->i_validation_length = __MAX(qlevel->i_validation_length, - s->p_sys->i_probe_length);
249 qlevel->i_validation_length += i_duration;
250 qlevel->i_validation_length = __MIN(qlevel->i_validation_length, s->p_sys->i_probe_length);
252 if ( qlevel->Bitrate < lowest->Bitrate )
257 if ( sms->current_qlvl->i_validation_length == s->p_sys->i_probe_length )
260 ret = sms->current_qlvl;
262 else if ( sms->current_qlvl->i_validation_length >= 0 )
265 ret = sms->current_qlvl;
266 msg_Dbg( s, "bw current:%uKB/s avg:%"PRIu64"KB/s qualified %"PRId64"%%",
267 (ret->Bitrate) / (8 * 1024),
269 ( ret->i_validation_length*1000 / s->p_sys->i_probe_length ) /10 );
279 FOREACH_ARRAY( quality_level_t *qlevel, sms->qlevels );
280 if( qlevel->Bitrate <= obw &&
281 ret->Bitrate <= qlevel->Bitrate &&
282 qlevel->i_validation_length >= 0 &&
283 qlevel->i_validation_length >= ret->i_validation_length )
289 msg_Dbg( s, "bw reselected:%uKB/s avg:%"PRIu64"KB/s qualified %"PRId64"%%",
290 (ret->Bitrate) / (8 * 1024),
292 ( ret->i_validation_length*1000 / s->p_sys->i_probe_length ) /10 );
298 static int get_new_chunks( stream_t *s, chunk_t *ck, sms_stream_t *sms )
300 stream_sys_t *p_sys = s->p_sys;
302 uint8_t *slice = ck->data;
305 uint8_t version, fragment_count;
306 uint32_t size, type, flags;
308 TfrfBoxDataFields_t *tfrf_df;
310 SMS_GET4BYTES( size );
311 SMS_GETFOURCC( type );
312 assert( type == ATOM_moof );
314 SMS_GET4BYTES( size );
315 SMS_GETFOURCC( type );
316 assert( type == ATOM_mfhd );
319 SMS_GET4BYTES( size );
320 SMS_GETFOURCC( type );
321 assert( type == ATOM_traf );
325 SMS_GET4BYTES( size );
327 SMS_GETFOURCC( type );
328 if( type == ATOM_mdat )
330 msg_Err( s, "No uuid box found :-(" );
333 else if( type == ATOM_uuid )
335 GetUUID( &uuid, slice);
336 if( !CmpUUID( &uuid, &TfrfBoxUUID ) )
343 SMS_GET1BYTE( version );
344 SMS_GET3BYTES( flags );
345 SMS_GET1BYTE( fragment_count );
347 tfrf_df = calloc( fragment_count, sizeof( TfrfBoxDataFields_t ) );
348 if( unlikely( tfrf_df == NULL ) )
351 for( uint8_t i = 0; i < fragment_count; i++ )
353 SMS_GET4or8BYTES( tfrf_df[i].i_fragment_abs_time );
354 SMS_GET4or8BYTES( tfrf_df[i].i_fragment_duration );
357 msg_Dbg( s, "read box: \"tfrf\" version %d, flags 0x%x, "\
358 "fragment count %"PRIu8, version, flags, fragment_count );
360 for( uint8_t i = 0; i < fragment_count; i++ )
362 uint64_t dur = tfrf_df[i].i_fragment_duration;
363 uint64_t stime = tfrf_df[i].i_fragment_abs_time;
364 msg_Dbg( s, "\"tfrf\" fragment duration %"PRIu64", "\
365 "fragment abs time %"PRIu64, dur, stime);
367 if( !chunk_Get( sms, stime + dur ) )
368 chunk_AppendNew( sms, dur, stime );
375 #define STRA_SIZE 334
376 //#define SMOO_SIZE (STRA_SIZE * 3 + 24) /* 1026 */
378 /* SmooBox is a very simple MP4 box, used only to pass information
379 * to the demux layer. As this box is not aimed to travel accross networks,
380 * simplicity of the design is better than compactness */
381 static int build_smoo_box( stream_t *s, chunk_t *p_chunk )
383 stream_sys_t *p_sys = s->p_sys;
387 assert(p_sys->sms_selected.i_size);
388 size_t i_size = p_sys->sms_selected.i_size * STRA_SIZE + 24;
389 p_chunk->data = calloc( 1, i_size );
390 if ( !p_chunk->data )
392 p_chunk->size = i_size;
393 uint8_t *smoo_box = p_chunk->data;
395 smoo_box[2] = (i_size & 0xff00)>>8;
396 smoo_box[3] = i_size & 0xff;
402 /* UUID is e1da72ba-24d7-43c3-a6a5-1b5759a1a92c */
403 ((uint32_t *)smoo_box)[2] = bswap32( 0xe1da72ba );
404 ((uint32_t *)smoo_box)[3] = bswap32( 0x24d743c3 );
405 ((uint32_t *)smoo_box)[4] = bswap32( 0xa6a51b57 );
406 ((uint32_t *)smoo_box)[5] = bswap32( 0x59a1a92c );
409 FOREACH_ARRAY( sms_stream_t *sms, p_sys->sms_selected );
410 uint8_t *stra_box = smoo_box + i++ * STRA_SIZE;
412 stra_box[26] = (STRA_SIZE & 0xff00)>>8;
413 stra_box[27] = STRA_SIZE & 0xff;
419 /* UUID is b03ef770-33bd-4bac-96c7-bf25f97e2447 */
420 ((uint32_t *)stra_box)[8] = bswap32( 0xb03ef770 );
421 ((uint32_t *)stra_box)[9] = bswap32( 0x33bd4bac );
422 ((uint32_t *)stra_box)[10] = bswap32( 0x96c7bf25 );
423 ((uint32_t *)stra_box)[11] = bswap32( 0xf97e2447 );
425 stra_box[48] = sms->type;
426 stra_box[49] = 0; /* reserved */
427 stra_box[50] = (sms->id & 0xff00)>>8;
428 stra_box[51] = sms->id & 0xff;
430 ((uint32_t *)stra_box)[13] = bswap32( sms->timescale );
431 ((uint64_t *)stra_box)[7] = bswap64( p_sys->vod_duration );
433 const quality_level_t *qlvl = sms->current_qlvl;
436 FourCC = qlvl->FourCC ? qlvl->FourCC : sms->default_FourCC;
437 ((uint32_t *)stra_box)[16] = bswap32( FourCC );
438 ((uint32_t *)stra_box)[17] = bswap32( qlvl->Bitrate );
439 ((uint32_t *)stra_box)[18] = bswap32( qlvl->MaxWidth );
440 ((uint32_t *)stra_box)[19] = bswap32( qlvl->MaxHeight );
441 ((uint32_t *)stra_box)[20] = bswap32( qlvl->SamplingRate );
442 ((uint32_t *)stra_box)[21] = bswap32( qlvl->Channels );
443 ((uint32_t *)stra_box)[22] = bswap32( qlvl->BitsPerSample );
444 ((uint32_t *)stra_box)[23] = bswap32( qlvl->AudioTag );
445 ((uint16_t *)stra_box)[48] = bswap16( qlvl->nBlockAlign );
447 if( !qlvl->CodecPrivateData )
449 stra_box[98] = stra_box[99] = stra_box[100] = 0; /* reserved */
450 stra_box[101] = strlen( qlvl->CodecPrivateData ) / 2;
451 if ( stra_box[101] > STRA_SIZE - 102 )
452 stra_box[101] = STRA_SIZE - 102;
453 uint8_t *binary_cpd = decode_string_hex_to_binary( qlvl->CodecPrivateData );
454 memcpy( stra_box + 102, binary_cpd, stra_box[101] );
462 static chunk_t *build_init_chunk( stream_t *s )
464 chunk_t *ret = calloc( 1, sizeof( chunk_t ) );
465 if( unlikely( ret == NULL ) )
466 goto build_init_chunk_error;
468 if( build_smoo_box( s, ret ) == VLC_SUCCESS )
471 build_init_chunk_error:
473 msg_Err( s, "build_init_chunk failed" );
477 static int Download( stream_t *s, sms_stream_t *sms )
479 stream_sys_t *p_sys = s->p_sys;
481 assert( sms->p_nextdownload );
482 assert( sms->p_nextdownload->data == NULL );
483 assert( sms->current_qlvl );
485 chunk_t *chunk = sms->p_nextdownload;
488 msg_Warn( s, "Could not find a chunk for stream %s", sms->name );
491 if( chunk->data != NULL )
493 /* Segment already downloaded */
494 msg_Warn( s, "Segment already downloaded" );
498 chunk->type = sms->type;
500 char *url = ConstructUrl( sms->url_template, p_sys->download.base_url,
501 sms->current_qlvl, chunk->start_time );
504 msg_Err( s, "ConstructUrl returned NULL" );
508 /* sanity check - can we download this chunk on time? */
509 if( (sms->i_obw > 0) && (sms->current_qlvl->Bitrate > 0) )
512 unsigned chunk_duration = chunk->duration * 1000 / sms->timescale;
513 uint64_t size = chunk_duration * sms->current_qlvl->Bitrate / 1000; /* bits */
514 unsigned estimated = size * 1000 / sms->i_obw;
515 if( estimated > chunk_duration )
517 msg_Warn( s,"downloading of chunk @%"PRIu64" would take %d ms, "
518 "which is longer than its playback (%d ms)",
519 chunk->start_time, estimated, chunk_duration );
523 mtime_t duration = mdate();
524 if( sms_Download( s, chunk, url ) != VLC_SUCCESS )
526 msg_Err( s, "downloaded chunk @%"PRIu64" from stream %s at quality"
527 " %u *failed*", chunk->start_time, sms->name, sms->current_qlvl->Bitrate );
530 duration = mdate() - duration;
532 unsigned real_id = set_track_id( chunk, sms->id );
535 msg_Err( s, "tfhd box not found or invalid chunk" );
541 get_new_chunks( s, chunk, sms );
544 msg_Info( s, "downloaded chunk @%"PRIu64" from stream %s at quality %u",
545 chunk->start_time, sms->name, sms->current_qlvl->Bitrate );
547 if (likely( duration ))
548 bw_stats_put( sms, chunk->size * 8 * CLOCK_FREQ / duration ); /* bits / s */
550 /* Track could get disabled in mp4 demux if we trigger adaption too soon.
551 And we don't need adaptation on last chunk */
552 if( sms->p_chunks == NULL || sms->p_chunks == sms->p_lastchunk )
555 bool b_starved = false;
556 vlc_mutex_lock( &p_sys->playback.lock );
557 if ( &p_sys->playback.b_underrun )
559 p_sys->playback.b_underrun = false;
560 bw_stats_underrun( sms );
563 vlc_mutex_unlock( &p_sys->playback.lock );
565 quality_level_t *new_qlevel = BandwidthAdaptation( s, sms, sms->i_obw,
566 duration, b_starved );
569 if( sms->qlevels.i_size < 2 )
571 assert(new_qlevel == sms->current_qlvl);
575 vlc_mutex_lock( &p_sys->playback.lock );
576 if ( p_sys->playback.init.p_datachunk == NULL && /* Don't chain/nest reinits */
577 new_qlevel != sms->current_qlvl )
579 msg_Warn( s, "detected %s bandwidth (%u) stream",
580 (new_qlevel->Bitrate >= sms->current_qlvl->Bitrate) ? "faster" : "lower",
581 new_qlevel->Bitrate );
583 quality_level_t *qlvl_backup = sms->current_qlvl;
584 sms->current_qlvl = new_qlevel;
585 chunk_t *new_init_ck = build_init_chunk( s );
588 p_sys->playback.init.p_datachunk = new_init_ck;
589 p_sys->playback.init.p_startchunk = chunk->p_next; /* to send before that one */
590 assert( chunk->p_next && chunk != sms->p_lastchunk );
593 sms->current_qlvl = qlvl_backup;
595 vlc_mutex_unlock( &p_sys->playback.lock );
600 static inline bool reached_download_limit( sms_stream_t *sms, unsigned int i_max_chunks,
601 uint64_t i_max_time )
603 if ( !sms->p_nextdownload )
606 if ( sms->p_playback == sms->p_nextdownload ) /* chunk can be > max_time */
609 const chunk_t *p_head = sms->p_playback;
613 unsigned int i_chunk_count = 0;
614 uint64_t i_total_time = 0;
615 const chunk_t *p_tail = sms->p_nextdownload;
618 i_total_time += p_head->duration * CLOCK_FREQ / sms->timescale;
619 if ( i_max_time && i_total_time >= i_max_time )
623 else if ( i_max_chunks && i_chunk_count >= i_max_chunks )
628 if ( p_head == p_tail )
631 p_head = p_head->p_next;
638 static bool all_reached_download_limit( stream_sys_t *p_sys, unsigned int i_max_chunks,
639 uint64_t i_max_time )
641 FOREACH_ARRAY( sms_stream_t *sms, p_sys->sms_selected );
642 vlc_mutex_lock( &sms->chunks_lock );
643 bool b_ret = reached_download_limit( sms, i_max_chunks, i_max_time );
644 vlc_mutex_unlock( &sms->chunks_lock );
651 /* Returns the first download chunk by time in the download queue */
652 static sms_stream_t *next_download_stream( stream_sys_t *p_sys )
654 sms_stream_t *p_candidate = NULL;
655 FOREACH_ARRAY( sms_stream_t *sms, p_sys->sms_selected );
656 vlc_mutex_lock( &sms->chunks_lock );
657 if ( !sms->p_nextdownload )
659 vlc_mutex_unlock( &sms->chunks_lock );
662 if ( p_candidate == NULL ||
663 sms->p_nextdownload->start_time < p_candidate->p_nextdownload->start_time )
665 vlc_mutex_unlock( &sms->chunks_lock );
670 void* sms_Thread( void *p_this )
672 stream_t *s = (stream_t *)p_this;
673 stream_sys_t *p_sys = s->p_sys;
675 int canc = vlc_savecancel();
677 chunk_t *init_ck = build_init_chunk( s );
681 vlc_mutex_lock( &p_sys->playback.lock );
682 p_sys->playback.init.p_datachunk = init_ck;
683 p_sys->playback.init.p_startchunk = NULL; /* before any */
684 vlc_mutex_unlock( &p_sys->playback.lock );
685 vlc_cond_signal( &p_sys->playback.wait ); /* demuxer in Open() can start reading */
687 int64_t i_pts_delay = 0;
689 /* Buffer up first chunks */
690 int i_initial_buffering = p_sys->download.lookahead_count;
691 if ( !i_initial_buffering )
692 i_initial_buffering = 3;
693 for( int i = 0; i < i_initial_buffering; i++ )
695 FOREACH_ARRAY( sms_stream_t *sms, p_sys->sms_selected );
696 vlc_mutex_lock( &sms->chunks_lock );
697 if ( sms->p_nextdownload )
699 mtime_t duration = mdate();
700 if( Download( s, sms ) != VLC_SUCCESS )
702 vlc_mutex_unlock( &sms->chunks_lock );
705 duration = mdate() - duration;
706 if (likely( duration ))
707 bw_stats_put( sms, sms->p_nextdownload->size * 8 * CLOCK_FREQ / duration ); /* bits / s */
708 sms->p_nextdownload = sms->p_nextdownload->p_next;
710 vlc_mutex_unlock( &sms->chunks_lock );
713 vlc_cond_signal( &p_sys->playback.wait );
715 while( !p_sys->b_close )
717 if ( !p_sys->b_live || !p_sys->download.lookahead_count )
718 stream_Control( s, STREAM_GET_PTS_DELAY, &i_pts_delay );
720 vlc_mutex_lock( &p_sys->lock );
721 while( all_reached_download_limit( p_sys,
722 p_sys->download.lookahead_count,
725 vlc_cond_wait( &p_sys->download.wait, &p_sys->lock );
732 vlc_mutex_unlock( &p_sys->lock );
736 sms_stream_t *sms = next_download_stream( p_sys );
739 vlc_mutex_lock( &sms->chunks_lock );
740 vlc_mutex_unlock( &p_sys->lock );
742 if( Download( s, sms ) != VLC_SUCCESS )
744 vlc_mutex_unlock( &sms->chunks_lock );
747 vlc_cond_signal( &p_sys->playback.wait );
749 if ( sms->p_nextdownload ) /* could have been modified by seek */
750 sms->p_nextdownload = sms->p_nextdownload->p_next;
752 vlc_mutex_unlock( &sms->chunks_lock );
755 vlc_mutex_unlock( &p_sys->lock );
761 p_sys->b_error = true;
762 msg_Dbg(s, "Canceling download thread!");
763 vlc_restorecancel( canc );