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 int res = build_smoo_box( s, ret->data );
367 if( res != VLC_SUCCESS )
368 goto build_init_chunk_error;
372 build_init_chunk_error:
373 msg_Err( s, "build_init_chunk failed" );
377 static int Download( stream_t *s, sms_stream_t *sms )
379 stream_sys_t *p_sys = s->p_sys;
381 int index = es_cat_to_index( sms->type );
382 int64_t start_time = p_sys->download.lead[index];
384 quality_level_t *qlevel = get_qlevel( sms, sms->download_qlvl );
385 if( unlikely( !qlevel ) )
387 msg_Err( s, "Could not get quality level id %u", sms->download_qlvl );
392 chunk_t *chunk = chunk_Get( sms, start_time );
395 msg_Warn( s, "Could not find a chunk for stream %s, "\
396 "start time = %"PRIu64"", sms->name, start_time );
399 if( chunk->data != NULL )
401 /* Segment already downloaded */
402 msg_Warn( s, "Segment already downloaded" );
406 chunk->type = sms->type;
408 char *url = ConstructUrl( sms->url_template, p_sys->base_url,
409 qlevel->Bitrate, chunk->start_time );
412 msg_Err( s, "ConstructUrl returned NULL" );
416 /* sanity check - can we download this chunk on time? */
417 uint64_t avg_bw = sms_queue_avg( p_sys->bws );
418 if( (avg_bw > 0) && (qlevel->Bitrate > 0) )
421 unsigned chunk_duration = chunk->duration * 1000 / sms->timescale;
422 uint64_t size = chunk_duration * qlevel->Bitrate / 1000; /* bits */
423 unsigned estimated = size * 1000 / avg_bw;
424 if( estimated > chunk_duration )
426 msg_Warn( s,"downloading of chunk %d would take %d ms, "\
427 "which is longer than its playback (%d ms)",
428 chunk->sequence, estimated, chunk_duration );
432 mtime_t start = mdate();
433 if( sms_Download( s, chunk, url ) != VLC_SUCCESS )
435 msg_Err( s, "downloaded chunk %u from stream %s at quality\
436 %u failed", chunk->sequence, sms->name, qlevel->Bitrate );
439 mtime_t duration = mdate() - start;
441 unsigned real_id = set_track_id( chunk, sms->id );
444 msg_Err( s, "tfhd box not found or invalid chunk" );
448 //msg_Dbg( s, "chunk ID was %i and is now %i", real_id, sms->id );
451 get_new_chunks( s, chunk );
453 vlc_mutex_lock( &p_sys->download.lock_wait );
454 vlc_array_append( p_sys->download.chunks, chunk );
455 vlc_cond_signal( &p_sys->download.wait );
456 vlc_mutex_unlock( &p_sys->download.lock_wait );
458 msg_Info( s, "downloaded chunk %d from stream %s at quality %u",
459 chunk->sequence, sms->name, qlevel->Bitrate );
461 uint64_t actual_lead = chunk->start_time + chunk->duration;
462 int ind = es_cat_to_index( sms->type );
463 p_sys->download.ck_index[ind] = chunk->sequence;
464 p_sys->download.lead[ind] = __MIN( p_sys->download.lead[ind], actual_lead );
466 if( sms->type == VIDEO_ES ||
467 ( !SMS_GET_SELECTED_ST( VIDEO_ES ) && sms->type == AUDIO_ES ) )
469 p_sys->playback.toffset = __MIN( p_sys->playback.toffset,
470 (uint64_t)chunk->start_time );
473 unsigned dur_ms = __MAX( 1, duration / 1000 );
474 uint64_t bw = chunk->size * 8 * 1000 / dur_ms; /* bits / s */
475 if( sms_queue_put( p_sys->bws, bw ) != VLC_SUCCESS )
477 avg_bw = sms_queue_avg( p_sys->bws );
479 if( sms->type != VIDEO_ES )
482 /* Track could get disabled in mp4 demux if we trigger adaption too soon. */
483 if( chunk->sequence <= 1 )
486 unsigned new_qlevel_id = BandwidthAdaptation( s, sms, avg_bw );
487 quality_level_t *new_qlevel = get_qlevel( sms, new_qlevel_id );
488 if( unlikely( !new_qlevel ) )
490 msg_Err( s, "Could not get quality level id %u", new_qlevel_id );
494 if( new_qlevel->Bitrate != qlevel->Bitrate )
496 msg_Warn( s, "detected %s bandwidth (%u) stream",
497 (new_qlevel->Bitrate >= qlevel->Bitrate) ? "faster" : "lower",
498 new_qlevel->Bitrate );
500 sms->download_qlvl = new_qlevel_id;
503 if( new_qlevel->MaxWidth != qlevel->MaxWidth ||
504 new_qlevel->MaxHeight != qlevel->MaxHeight )
506 chunk_t *new_init_ck = build_init_chunk( s );
512 new_init_ck->offset = p_sys->download.next_chunk_offset;
513 p_sys->download.next_chunk_offset += new_init_ck->size;
515 vlc_mutex_lock( &p_sys->download.lock_wait );
516 vlc_array_append( p_sys->download.chunks, new_init_ck );
517 vlc_array_append( p_sys->init_chunks, new_init_ck );
518 vlc_mutex_unlock( &p_sys->download.lock_wait );
523 static inline int64_t get_lead( stream_t *s )
525 stream_sys_t *p_sys = s->p_sys;
527 int64_t alead = p_sys->download.lead[es_cat_to_index( AUDIO_ES )];
528 int64_t vlead = p_sys->download.lead[es_cat_to_index( VIDEO_ES )];
529 bool video = SMS_GET_SELECTED_ST( VIDEO_ES ) ? true : false;
530 bool audio = SMS_GET_SELECTED_ST( AUDIO_ES ) ? true : false;
533 lead = __MIN( vlead, alead );
539 lead -= p_sys->playback.toffset;
543 static int next_track( stream_t *s )
545 stream_sys_t *p_sys = s->p_sys;
546 uint64_t tmp, min = 0;
547 int cat, ret = UNKNOWN_ES;
548 for( int i = 0; i < 3; i++ )
550 tmp = p_sys->download.lead[i];
551 cat = index_to_es_cat( i );
552 if( (!min || tmp < min) && SMS_GET_SELECTED_ST( cat ) )
561 void* sms_Thread( void *p_this )
563 stream_t *s = (stream_t *)p_this;
564 stream_sys_t *p_sys = s->p_sys;
565 sms_stream_t *sms = NULL;
568 int canc = vlc_savecancel();
570 /* We compute the average bandwidth of the 4 last downloaded
571 * chunks, but feel free to replace '4' by whatever you wish */
572 p_sys->bws = sms_queue_init( 4 );
576 chunk_t *init_ck = build_init_chunk( s );
580 vlc_mutex_lock( &p_sys->download.lock_wait );
581 vlc_array_append( p_sys->download.chunks, init_ck );
582 vlc_array_append( p_sys->init_chunks, init_ck );
583 vlc_mutex_unlock( &p_sys->download.lock_wait );
585 p_sys->download.next_chunk_offset = init_ck->size;
587 /* XXX Sometimes, the video stream is cut into pieces of one exact length,
588 * while the audio stream fragments can't be made to match exactly,
589 * and for some reason the n^th advertised video fragment is related to
590 * the n+1^th advertised audio chunk or vice versa */
592 int64_t start_time = 0, lead = 0;
594 for( int i = 0; i < 3; i++ )
596 sms = SMS_GET_SELECTED_ST( index_to_es_cat( i ) );
599 chunk = vlc_array_item_at_index( sms->chunks, 0 );
600 p_sys->download.lead[i] = chunk->start_time + p_sys->timescale / 1000;
602 start_time = chunk->start_time;
604 if( Download( s, sms ) != VLC_SUCCESS )
611 /* XXX replace magic number 10 by a value depending on
612 * LookAheadFragmentCount and DVRWindowLength */
613 vlc_mutex_lock( &p_sys->download.lock_wait );
617 vlc_mutex_unlock( &p_sys->download.lock_wait );
621 lead = get_lead( s );
623 while( lead > 10 * p_sys->timescale + start_time || NO_MORE_CHUNKS )
625 vlc_cond_wait( &p_sys->download.wait, &p_sys->download.lock_wait );
626 lead = get_lead( s );
634 int count = vlc_array_count( p_sys->download.chunks );
636 for( int i = 0; i < count; i++ )
638 ck = vlc_array_item_at_index( p_sys->download.chunks, i );
639 if( unlikely( !ck ) )
642 if( ck->data == NULL )
644 FREENULL( ck->data );
647 vlc_array_destroy( p_sys->download.chunks );
648 p_sys->download.chunks = vlc_array_new();
650 p_sys->playback.toffset = p_sys->time_pos;
651 for( int i = 0; i < 3; i++ )
653 p_sys->download.lead[i] = p_sys->time_pos;
654 p_sys->download.ck_index[i] = 0;
656 p_sys->download.next_chunk_offset = 0;
658 p_sys->playback.boffset = 0;
659 p_sys->playback.index = 0;
661 chunk_t *new_init_ck = build_init_chunk( s );
665 new_init_ck->offset = p_sys->download.next_chunk_offset;
666 p_sys->download.next_chunk_offset += new_init_ck->size;
668 vlc_array_append( p_sys->download.chunks, new_init_ck );
669 vlc_array_append( p_sys->init_chunks, new_init_ck );
670 p_sys->b_tseek = false;
672 vlc_mutex_unlock( &p_sys->download.lock_wait );
674 sms = SMS_GET_SELECTED_ST( next_track( s ) );
675 if( Download( s, sms ) != VLC_SUCCESS )
680 p_sys->b_error = true;
681 msg_Warn(s, "Canceling download thread!");
682 vlc_restorecancel( canc );