]> git.sesse.net Git - vlc/blob - modules/stream_filter/smooth/downloader.c
LGPL
[vlc] / modules / stream_filter / smooth / downloader.c
1 /*****************************************************************************
2  * downloader.c: download thread
3  *****************************************************************************
4  * Copyright (C) 1996-2012 VLC authors and VideoLAN
5  * $Id$
6  *
7  * Author: Frédéric Yhuel <fyhuel _AT_ viotech _DOT_ net>
8  *
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.
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  * Lesser General Public License for more details.
18  *
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  *****************************************************************************/
23
24 #ifdef HAVE_CONFIG_H
25 # include "config.h"
26 #endif
27 #include <vlc_common.h>
28 #include <assert.h>
29 #include <vlc_stream.h>
30 #include <vlc_es.h>
31
32 #include "smooth.h"
33 #include "../../demux/mp4/libmp4.h"
34
35 static char *ConstructUrl( const char *template, const char *base_url,
36         const uint64_t bandwidth, const uint64_t start_time )
37 {
38     char *frag, *end, *qual;
39     char *url_template = strdup( template );
40     char *saveptr = NULL;
41
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 );
47     char *url = NULL;
48
49     if( asprintf( &url, "%s/%s%"PRIu64"%s%"PRIu64"%s", base_url, qual,
50                 bandwidth, frag, start_time, end) < 0 )
51     {
52        return NULL;
53     }
54
55     free( url_template );
56     return url;
57 }
58
59 static chunk_t * chunk_Get( sms_stream_t *sms, const int64_t start_time )
60 {
61     int len = vlc_array_count( sms->chunks );
62     for( int i = 0; i < len; i++ )
63     {
64         chunk_t * chunk = vlc_array_item_at_index( sms->chunks, i );
65         if( !chunk ) return NULL;
66
67         if( chunk->start_time <= start_time &&
68                 chunk->start_time + chunk->duration > start_time )
69         {
70             return chunk;
71         }
72     }
73     return NULL;
74 }
75
76 static unsigned set_track_id( chunk_t *chunk, const unsigned tid )
77 {
78     uint32_t size, type;
79     if( !chunk->data )
80         return 0;
81     uint8_t *slice = chunk->data;
82     if( !slice )
83         return 0;
84
85     SMS_GET4BYTES( size );
86     SMS_GETFOURCC( type );
87     assert( type == ATOM_moof );
88
89     SMS_GET4BYTES( size );
90     SMS_GETFOURCC( type );
91     assert( type == ATOM_mfhd );
92     slice += size - 8;
93
94     SMS_GET4BYTES( size );
95     SMS_GETFOURCC( type );
96     assert( type == ATOM_traf );
97
98     SMS_GET4BYTES( size );
99     SMS_GETFOURCC( type );
100     if( type != ATOM_tfhd )
101         return 0;
102
103     unsigned ret = bswap32( ((uint32_t *)slice)[1] );
104     ((uint32_t *)slice)[1] = bswap32( tid );
105
106     return ret;
107 }
108
109 static int sms_Download( stream_t *s, chunk_t *chunk, char *url )
110 {
111     stream_sys_t *p_sys = s->p_sys;
112
113     stream_t *p_ts = stream_UrlNew( s, url );
114     free( url );
115     if( p_ts == NULL )
116         return VLC_EGENERIC;
117
118     int64_t size = stream_Size( p_ts );
119
120     chunk->size = size;
121     chunk->offset = p_sys->download.next_chunk_offset;
122     p_sys->download.next_chunk_offset += chunk->size;
123
124     chunk->data = malloc( size );
125
126     if( chunk->data == NULL )
127     {
128         stream_Delete( p_ts );
129         return VLC_ENOMEM;
130     }
131
132     int read = stream_Read( p_ts, chunk->data, size );
133     if( read < size )
134     {
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 );
138     }
139
140     stream_Delete( p_ts );
141
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 );
146
147     return VLC_SUCCESS;
148 }
149
150 #ifdef DISABLE_BANDWIDTH_ADAPTATION
151 static unsigned BandwidthAdaptation( stream_t *s,
152         sms_stream_t *sms, uint64_t *bandwidth )
153 {
154     return sms->download_qlvl;
155 }
156 #else
157
158 static unsigned BandwidthAdaptation( stream_t *s,
159         sms_stream_t *sms, uint64_t bandwidth )
160 {
161     if( sms->type != VIDEO_ES )
162         return sms->download_qlvl;
163
164     uint64_t bw_candidate = 0;
165     quality_level_t *qlevel;
166     unsigned ret = sms->download_qlvl;
167
168     for( unsigned i = 0; i < sms->qlevel_nb; i++ )
169     {
170         qlevel = vlc_array_item_at_index( sms->qlevels, i );
171         if( unlikely( !qlevel ) )
172         {
173             msg_Err( s, "Could no get %uth quality level", i );
174             return 0;
175         }
176
177         if( qlevel->Bitrate < (bandwidth - bandwidth / 3) &&
178                 qlevel->Bitrate > bw_candidate )
179         {
180             bw_candidate = qlevel->Bitrate;
181             ret = qlevel->id;
182         }
183     }
184
185     return ret;
186 }
187 #endif
188
189 static int get_new_chunks( stream_t *s, chunk_t *ck )
190 {
191     stream_sys_t *p_sys = s->p_sys;
192
193     uint8_t *slice = ck->data;
194     if( !slice )
195         return VLC_EGENERIC;
196     uint8_t version, fragment_count;
197     uint32_t size, type, flags;
198     sms_stream_t *sms;
199     UUID_t uuid;
200     TfrfBoxDataFields_t *tfrf_df;
201
202     sms = SMS_GET_SELECTED_ST( ck->type );
203
204     SMS_GET4BYTES( size );
205     SMS_GETFOURCC( type );
206     assert( type == ATOM_moof );
207
208     SMS_GET4BYTES( size );
209     SMS_GETFOURCC( type );
210     assert( type == ATOM_mfhd );
211     slice += size - 8;
212
213     SMS_GET4BYTES( size );
214     SMS_GETFOURCC( type );
215     assert( type == ATOM_traf );
216
217     for(;;)
218     {
219         SMS_GET4BYTES( size );
220         assert( size > 1 );
221         SMS_GETFOURCC( type );
222         if( type == ATOM_mdat )
223         {
224             msg_Err( s, "No uuid box found :-(" );
225             return VLC_EGENERIC;
226         }
227         else if( type == ATOM_uuid )
228         {
229             GetUUID( &uuid, slice);
230             if( !CmpUUID( &uuid, &TfrfBoxUUID ) )
231                 break;
232         }
233         slice += size - 8;
234     }
235
236     slice += 16;
237     SMS_GET1BYTE( version );
238     SMS_GET3BYTES( flags );
239     SMS_GET1BYTE( fragment_count );
240
241     tfrf_df = calloc( fragment_count, sizeof( TfrfBoxDataFields_t ) );
242     if( unlikely( tfrf_df == NULL ) )
243         return VLC_EGENERIC;
244
245     for( uint8_t i = 0; i < fragment_count; i++ )
246     {
247         SMS_GET4or8BYTES( tfrf_df[i].i_fragment_abs_time );
248         SMS_GET4or8BYTES( tfrf_df[i].i_fragment_duration );
249     }
250
251     msg_Dbg( s, "read box: \"tfrf\" version %d, flags 0x%x, "\
252             "fragment count %"PRIu8, version, flags, fragment_count );
253
254     for( uint8_t i = 0; i < fragment_count; i++ )
255     {
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);
260
261         if( !chunk_Get( sms, stime + dur ) )
262             chunk_New( sms, dur, stime );
263     }
264     free( tfrf_df );
265
266     return VLC_SUCCESS;
267 }
268
269 #define STRA_SIZE 334
270 #define SMOO_SIZE (STRA_SIZE * 3 + 24) /* 1026 */
271
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 )
276 {
277     stream_sys_t *p_sys = s->p_sys;
278     sms_stream_t *sms = NULL;
279     uint32_t FourCC;
280
281     /* smoo */
282     memset( smoo_box, 0, SMOO_SIZE );
283     smoo_box[2] = (SMOO_SIZE & 0xff00)>>8;
284     smoo_box[3] = SMOO_SIZE & 0xff;
285     smoo_box[4] = 'u';
286     smoo_box[5] = 'u';
287     smoo_box[6] = 'i';
288     smoo_box[7] = 'd';
289
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 );
295
296     uint8_t *stra_box;
297     for( int i = 0; i < 3; i++ )
298     {
299         sms = NULL;
300         int cat = UNKNOWN_ES;
301         stra_box = smoo_box + i * STRA_SIZE;
302
303         stra_box[26] = (STRA_SIZE & 0xff00)>>8;
304         stra_box[27] = STRA_SIZE & 0xff;
305         stra_box[28] = 'u';
306         stra_box[29] = 'u';
307         stra_box[30] = 'i';
308         stra_box[31] = 'd';
309
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 );
315
316         cat = index_to_es_cat( i );
317         stra_box[48] = cat;
318         sms = SMS_GET_SELECTED_ST( cat );
319
320         stra_box[49] = 0; /* reserved */
321         if( sms == NULL )
322             continue;
323         stra_box[50] = (sms->id & 0xff00)>>8;
324         stra_box[51] = sms->id & 0xff;
325
326         ((uint32_t *)stra_box)[13] = bswap32( sms->timescale );
327         ((uint64_t *)stra_box)[7] = bswap64( p_sys->vod_duration );
328
329         quality_level_t * qlvl = get_qlevel( sms, sms->download_qlvl );
330
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 );
341
342         if( !qlvl->CodecPrivateData )
343             continue;
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] );
349         free( binary_cpd );
350     }
351
352     return VLC_SUCCESS;
353 }
354
355 static chunk_t *build_init_chunk( stream_t *s )
356 {
357     chunk_t *ret = calloc( 1, sizeof( chunk_t ) );
358     if( unlikely( ret == NULL ) )
359         goto build_init_chunk_error;
360
361     ret->size = SMOO_SIZE;
362     ret->data = malloc( SMOO_SIZE );
363     if( !ret->data )
364         goto build_init_chunk_error;
365
366     int res = build_smoo_box( s, ret->data );
367     if( res != VLC_SUCCESS )
368         goto build_init_chunk_error;
369
370     return ret;
371
372 build_init_chunk_error:
373     msg_Err( s, "build_init_chunk failed" );
374     return NULL;
375 }
376
377 static int Download( stream_t *s, sms_stream_t *sms )
378 {
379     stream_sys_t *p_sys = s->p_sys;
380
381     int index = es_cat_to_index( sms->type );
382     int64_t start_time = p_sys->download.lead[index];
383
384     quality_level_t *qlevel = get_qlevel( sms, sms->download_qlvl );
385     if( unlikely( !qlevel ) )
386     {
387         msg_Err( s, "Could not get quality level id %u", sms->download_qlvl );
388         return VLC_EGENERIC;
389     }
390
391
392     chunk_t *chunk = chunk_Get( sms, start_time );
393     if( !chunk )
394     {
395         msg_Warn( s, "Could not find a chunk for stream %s, "\
396                 "start time = %"PRIu64"", sms->name, start_time );
397         return VLC_EGENERIC;
398     }
399     if( chunk->data != NULL )
400     {
401         /* Segment already downloaded */
402         msg_Warn( s, "Segment already downloaded" );
403         return VLC_SUCCESS;
404     }
405
406     chunk->type = sms->type;
407
408     char *url = ConstructUrl( sms->url_template, p_sys->base_url,
409                                   qlevel->Bitrate, chunk->start_time );
410     if( !url )
411     {
412         msg_Err( s, "ConstructUrl returned NULL" );
413         return VLC_EGENERIC;
414     }
415
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) )
419     {
420         /* duration in ms */
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 )
425         {
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 );
429         }
430     }
431
432     mtime_t start = mdate();
433     if( sms_Download( s, chunk, url ) != VLC_SUCCESS )
434     {
435         msg_Err( s, "downloaded chunk %u from stream %s at quality\
436             %u failed", chunk->sequence, sms->name, qlevel->Bitrate );
437         return VLC_EGENERIC;
438     }
439     mtime_t duration = mdate() - start;
440
441     unsigned real_id = set_track_id( chunk, sms->id );
442     if( real_id == 0)
443     {
444         msg_Err( s, "tfhd box not found or invalid chunk" );
445         return VLC_EGENERIC;
446     }
447
448     //msg_Dbg( s, "chunk ID was %i and is now %i", real_id, sms->id );
449
450     if( p_sys->b_live )
451         get_new_chunks( s, chunk );
452
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 );
457
458     msg_Info( s, "downloaded chunk %d from stream %s at quality %u",
459                 chunk->sequence, sms->name, qlevel->Bitrate );
460
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 );
465
466     if( sms->type == VIDEO_ES ||
467             ( !SMS_GET_SELECTED_ST( VIDEO_ES ) && sms->type == AUDIO_ES ) )
468     {
469         p_sys->playback.toffset = __MIN( p_sys->playback.toffset,
470                                             (uint64_t)chunk->start_time );
471     }
472
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 )
476         return VLC_EGENERIC;
477     avg_bw = sms_queue_avg( p_sys->bws );
478
479     if( sms->type != VIDEO_ES )
480         return VLC_SUCCESS;
481
482     /* Track could get disabled in mp4 demux if we trigger adaption too soon. */
483     if( chunk->sequence <= 1 )
484         return VLC_SUCCESS;
485
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 ) )
489     {
490         msg_Err( s, "Could not get quality level id %u", new_qlevel_id );
491         return VLC_EGENERIC;
492     }
493
494     if( new_qlevel->Bitrate != qlevel->Bitrate )
495     {
496         msg_Warn( s, "detected %s bandwidth (%u) stream",
497                  (new_qlevel->Bitrate >= qlevel->Bitrate) ? "faster" : "lower",
498                  new_qlevel->Bitrate );
499
500         sms->download_qlvl = new_qlevel_id;
501     }
502
503     if( new_qlevel->MaxWidth != qlevel->MaxWidth ||
504         new_qlevel->MaxHeight != qlevel->MaxHeight )
505     {
506         chunk_t *new_init_ck = build_init_chunk( s );
507         if( !new_init_ck )
508         {
509             return VLC_EGENERIC;
510         }
511
512         new_init_ck->offset = p_sys->download.next_chunk_offset;
513         p_sys->download.next_chunk_offset += new_init_ck->size;
514
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 );
519     }
520     return VLC_SUCCESS;
521 }
522
523 static inline int64_t get_lead( stream_t *s )
524 {
525     stream_sys_t *p_sys = s->p_sys;
526     int64_t lead = 0;
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;
531
532     if( video && audio )
533         lead = __MIN( vlead, alead );
534     else if( video )
535         lead = vlead;
536     else
537         lead = alead;
538
539     lead -= p_sys->playback.toffset;
540     return lead;
541 }
542
543 static int next_track( stream_t *s )
544 {
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++ )
549     {
550         tmp = p_sys->download.lead[i];
551         cat = index_to_es_cat( i );
552         if( (!min || tmp < min) && SMS_GET_SELECTED_ST( cat ) )
553         {
554             min = tmp;
555             ret = cat;
556         }
557     }
558     return ret;
559 }
560
561 void* sms_Thread( void *p_this )
562 {
563     stream_t *s = (stream_t *)p_this;
564     stream_sys_t *p_sys = s->p_sys;
565     sms_stream_t *sms = NULL;
566     chunk_t *chunk;
567
568     int canc = vlc_savecancel();
569
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 );
573     if( !p_sys->bws )
574         goto cancel;
575
576     chunk_t *init_ck = build_init_chunk( s );
577     if( !init_ck )
578         goto cancel;
579
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 );
584
585     p_sys->download.next_chunk_offset = init_ck->size;
586
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 */
591
592     int64_t start_time = 0, lead = 0;
593
594     for( int i = 0; i < 3; i++ )
595     {
596         sms = SMS_GET_SELECTED_ST( index_to_es_cat( i ) );
597         if( sms )
598         {
599             chunk = vlc_array_item_at_index( sms->chunks, 0 );
600             p_sys->download.lead[i] = chunk->start_time + p_sys->timescale / 1000;
601             if( !start_time )
602                 start_time = chunk->start_time;
603
604             if( Download( s, sms ) != VLC_SUCCESS )
605                 goto cancel;
606         }
607     }
608
609     while( 1 )
610     {
611         /* XXX replace magic number 10 by a value depending on
612          * LookAheadFragmentCount and DVRWindowLength */
613         vlc_mutex_lock( &p_sys->download.lock_wait );
614
615         if( p_sys->b_close )
616         {
617             vlc_mutex_unlock( &p_sys->download.lock_wait );
618             break;
619         }
620
621         lead = get_lead( s );
622
623         while( lead > 10 * p_sys->timescale + start_time || NO_MORE_CHUNKS )
624         {
625             vlc_cond_wait( &p_sys->download.wait, &p_sys->download.lock_wait );
626             lead = get_lead( s );
627
628             if( p_sys->b_close )
629                 break;
630         }
631
632         if( p_sys->b_tseek )
633         {
634             int count = vlc_array_count( p_sys->download.chunks );
635             chunk_t *ck = NULL;
636             for( int i = 0; i < count; i++ )
637             {
638                 ck = vlc_array_item_at_index( p_sys->download.chunks, i );
639                 if( unlikely( !ck ) )
640                     goto cancel;
641                 ck->read_pos = 0;
642                 if( ck->data == NULL )
643                     continue;
644                 FREENULL( ck->data );
645             }
646
647             vlc_array_destroy( p_sys->download.chunks );
648             p_sys->download.chunks = vlc_array_new();
649
650             p_sys->playback.toffset = p_sys->time_pos;
651             for( int i = 0; i < 3; i++ )
652             {
653                 p_sys->download.lead[i] = p_sys->time_pos;
654                 p_sys->download.ck_index[i] = 0;
655             }
656             p_sys->download.next_chunk_offset = 0;
657
658             p_sys->playback.boffset = 0;
659             p_sys->playback.index = 0;
660
661             chunk_t *new_init_ck = build_init_chunk( s );
662             if( !new_init_ck )
663                 goto cancel;
664
665             new_init_ck->offset = p_sys->download.next_chunk_offset;
666             p_sys->download.next_chunk_offset += new_init_ck->size;
667
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;
671         }
672         vlc_mutex_unlock( &p_sys->download.lock_wait );
673
674         sms = SMS_GET_SELECTED_ST( next_track( s ) );
675         if( Download( s, sms ) != VLC_SUCCESS )
676             goto cancel;
677     }
678
679 cancel:
680     p_sys->b_error = true;
681     msg_Warn(s, "Canceling download thread!");
682     vlc_restorecancel( canc );
683     return NULL;
684 }