]> git.sesse.net Git - vlc/blob - modules/access_output/livehttp.c
Qt is GPLv2+
[vlc] / modules / access_output / livehttp.c
1 /*****************************************************************************
2  * livehttp.c: Live HTTP Streaming
3  *****************************************************************************
4  * Copyright © 2001, 2002, 2013 VLC authors and VideoLAN
5  * Copyright © 2009-2010 by Keary Griffin
6  *
7  * Authors: Keary Griffin <kearygriffin at gmail.com>
8  *          Ilkka Ollakka <ileoo at videolan dot org>
9  *
10  * This program is free software; you can redistribute it and/or modify it
11  * under the terms of the GNU Lesser General Public License as published by
12  * the Free Software Foundation; either version 2.1 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public License
21  * along with this program; if not, write to the Free Software Foundation,
22  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
32
33 #include <sys/types.h>
34 #include <time.h>
35 #include <fcntl.h>
36 #include <errno.h>
37 #include <unistd.h>
38
39 #include <vlc_common.h>
40 #include <vlc_plugin.h>
41 #include <vlc_sout.h>
42 #include <vlc_block.h>
43 #include <vlc_fs.h>
44 #include <vlc_strings.h>
45 #include <vlc_charset.h>
46
47 #include <gcrypt.h>
48 #include <vlc_gcrypt.h>
49
50 #include <vlc_rand.h>
51
52 #ifndef O_LARGEFILE
53 #   define O_LARGEFILE 0
54 #endif
55
56 #define STR_ENDLIST "#EXT-X-ENDLIST\n"
57
58 #define MAX_RENAME_RETRIES        10
59
60 /*****************************************************************************
61  * Module descriptor
62  *****************************************************************************/
63 static int  Open ( vlc_object_t * );
64 static void Close( vlc_object_t * );
65
66 #define SOUT_CFG_PREFIX "sout-livehttp-"
67 #define SEGLEN_TEXT N_("Segment length")
68 #define SEGLEN_LONGTEXT N_("Length of TS stream segments")
69
70 #define SPLITANYWHERE_TEXT N_("Split segments anywhere")
71 #define SPLITANYWHERE_LONGTEXT N_("Don't require a keyframe before splitting "\
72                                 "a segment. Needed for audio only.")
73
74 #define NUMSEGS_TEXT N_("Number of segments")
75 #define NUMSEGS_LONGTEXT N_("Number of segments to include in index")
76
77 #define NOCACHE_TEXT N_("Allow cache")
78 #define NOCACHE_LONGTEXT N_("Add EXT-X-ALLOW-CACHE:NO directive in playlist-file if this is disabled")
79
80 #define INDEX_TEXT N_("Index file")
81 #define INDEX_LONGTEXT N_("Path to the index file to create")
82
83 #define INDEXURL_TEXT N_("Full URL to put in index file")
84 #define INDEXURL_LONGTEXT N_("Full URL to put in index file. "\
85                           "Use #'s to represent segment number")
86
87 #define DELSEGS_TEXT N_("Delete segments")
88 #define DELSEGS_LONGTEXT N_("Delete segments when they are no longer needed")
89
90 #define RATECONTROL_TEXT N_("Use muxers rate control mechanism")
91
92 #define KEYURI_TEXT N_("AES key URI to place in playlist")
93
94 #define KEYFILE_TEXT N_("AES key file")
95 #define KEYFILE_LONGTEXT N_("File containing the 16 bytes encryption key")
96
97 #define KEYLOADFILE_TEXT N_("File where vlc reads key-uri and keyfile-location")
98 #define KEYLOADFILE_LONGTEXT N_("File is read when segment starts and is assumet to be in format: "\
99                                 "key-uri\\nkey-file. File is read on the segment opening and "\
100                                 "values are used on that segment.")
101
102 #define RANDOMIV_TEXT N_("Use randomized IV for encryption")
103 #define RANDOMIV_LONGTEXT N_("Generate IV instead using segment-number as IV")
104
105 #define INTITIAL_SEG_TEXT N_("Number of first segment")
106 #define INITIAL_SEG_LONGTEXT N_("The number of the first segment generated")
107
108 vlc_module_begin ()
109     set_description( N_("HTTP Live streaming output") )
110     set_shortname( N_("LiveHTTP" ))
111     add_shortcut( "livehttp" )
112     set_capability( "sout access", 0 )
113     set_category( CAT_SOUT )
114     set_subcategory( SUBCAT_SOUT_ACO )
115     add_integer( SOUT_CFG_PREFIX "seglen", 10, SEGLEN_TEXT, SEGLEN_LONGTEXT, false )
116     add_integer( SOUT_CFG_PREFIX "numsegs", 0, NUMSEGS_TEXT, NUMSEGS_LONGTEXT, false )
117     add_integer( SOUT_CFG_PREFIX "initial-segment-number", 1, INTITIAL_SEG_TEXT, INITIAL_SEG_LONGTEXT, false )
118     add_bool( SOUT_CFG_PREFIX "splitanywhere", false,
119               SPLITANYWHERE_TEXT, SPLITANYWHERE_LONGTEXT, true )
120     add_bool( SOUT_CFG_PREFIX "delsegs", true,
121               DELSEGS_TEXT, DELSEGS_LONGTEXT, true )
122     add_bool( SOUT_CFG_PREFIX "ratecontrol", false,
123               RATECONTROL_TEXT, RATECONTROL_TEXT, true )
124     add_bool( SOUT_CFG_PREFIX "caching", false,
125               NOCACHE_TEXT, NOCACHE_LONGTEXT, true )
126     add_bool( SOUT_CFG_PREFIX "generate-iv", false,
127               RANDOMIV_TEXT, RANDOMIV_LONGTEXT, true )
128     add_string( SOUT_CFG_PREFIX "index", NULL,
129                 INDEX_TEXT, INDEX_LONGTEXT, false )
130     add_string( SOUT_CFG_PREFIX "index-url", NULL,
131                 INDEXURL_TEXT, INDEXURL_LONGTEXT, false )
132     add_string( SOUT_CFG_PREFIX "key-uri", NULL,
133                 KEYURI_TEXT, KEYURI_TEXT, true )
134     add_loadfile( SOUT_CFG_PREFIX "key-file", NULL,
135                 KEYFILE_TEXT, KEYFILE_LONGTEXT, true )
136     add_loadfile( SOUT_CFG_PREFIX "key-loadfile", NULL,
137                 KEYLOADFILE_TEXT, KEYLOADFILE_LONGTEXT, true )
138     set_callbacks( Open, Close )
139 vlc_module_end ()
140
141
142 /*****************************************************************************
143  * Exported prototypes
144  *****************************************************************************/
145 static const char *const ppsz_sout_options[] = {
146     "seglen",
147     "splitanywhere",
148     "numsegs",
149     "delsegs",
150     "index",
151     "index-url",
152     "ratecontrol",
153     "caching",
154     "key-uri",
155     "key-file",
156     "key-loadfile",
157     "generate-iv",
158     "initial-segment-number",
159     NULL
160 };
161
162 static ssize_t Write( sout_access_out_t *, block_t * );
163 static int Seek ( sout_access_out_t *, off_t  );
164 static int Control( sout_access_out_t *, int, va_list );
165
166 typedef struct output_segment
167 {
168     char *psz_filename;
169     char *psz_uri;
170     char *psz_key_uri;
171     char *psz_duration;
172     float f_seglength;
173     uint32_t i_segment_number;
174     uint8_t aes_ivs[16];
175 } output_segment_t;
176
177 struct sout_access_out_sys_t
178 {
179     char *psz_cursegPath;
180     char *psz_indexPath;
181     char *psz_indexUrl;
182     char *psz_keyfile;
183     mtime_t i_keyfile_modification;
184     mtime_t i_opendts;
185     mtime_t i_dts_offset;
186     mtime_t  i_seglenm;
187     uint32_t i_segment;
188     size_t  i_seglen;
189     float   f_seglen;
190     block_t *block_buffer;
191     int i_handle;
192     unsigned i_numsegs;
193     unsigned i_initial_segment;
194     bool b_delsegs;
195     bool b_ratecontrol;
196     bool b_splitanywhere;
197     bool b_caching;
198     bool b_generate_iv;
199     bool b_segment_has_data;
200     uint8_t aes_ivs[16];
201     gcry_cipher_hd_t aes_ctx;
202     char *key_uri;
203     uint8_t stuffing_bytes[16];
204     ssize_t stuffing_size;
205     vlc_array_t *segments_t;
206 };
207
208 static int LoadCryptFile( sout_access_out_t *p_access);
209 static int CryptSetup( sout_access_out_t *p_access, char *keyfile );
210 static int CheckSegmentChange( sout_access_out_t *p_access, block_t *p_buffer );
211 static ssize_t writeSegment( sout_access_out_t *p_access );
212 static ssize_t openNextFile( sout_access_out_t *p_access, sout_access_out_sys_t *p_sys );
213 /*****************************************************************************
214  * Open: open the file
215  *****************************************************************************/
216 static int Open( vlc_object_t *p_this )
217 {
218     sout_access_out_t   *p_access = (sout_access_out_t*)p_this;
219     sout_access_out_sys_t *p_sys;
220     char *psz_idx;
221
222     config_ChainParse( p_access, SOUT_CFG_PREFIX, ppsz_sout_options, p_access->p_cfg );
223
224     if( !p_access->psz_path )
225     {
226         msg_Err( p_access, "no file name specified" );
227         return VLC_EGENERIC;
228     }
229
230     if( unlikely( !( p_sys = calloc ( 1, sizeof( *p_sys ) ) ) ) )
231         return VLC_ENOMEM;
232
233     p_sys->i_seglen = var_GetInteger( p_access, SOUT_CFG_PREFIX "seglen" );
234     /* Try to get within asked segment length */
235     p_sys->i_seglenm = CLOCK_FREQ * p_sys->i_seglen;
236     p_sys->block_buffer = NULL;
237
238     p_sys->i_numsegs = var_GetInteger( p_access, SOUT_CFG_PREFIX "numsegs" );
239     p_sys->i_initial_segment = var_GetInteger( p_access, SOUT_CFG_PREFIX "initial-segment-number" );
240     p_sys->b_splitanywhere = var_GetBool( p_access, SOUT_CFG_PREFIX "splitanywhere" );
241     p_sys->b_delsegs = var_GetBool( p_access, SOUT_CFG_PREFIX "delsegs" );
242     p_sys->b_ratecontrol = var_GetBool( p_access, SOUT_CFG_PREFIX "ratecontrol") ;
243     p_sys->b_caching = var_GetBool( p_access, SOUT_CFG_PREFIX "caching") ;
244     p_sys->b_generate_iv = var_GetBool( p_access, SOUT_CFG_PREFIX "generate-iv") ;
245     p_sys->b_segment_has_data = false;
246
247     p_sys->segments_t = vlc_array_new();
248
249     p_sys->stuffing_size = 0;
250     p_sys->i_opendts = VLC_TS_INVALID;
251     p_sys->i_dts_offset  = 0;
252
253     p_sys->psz_indexPath = NULL;
254     psz_idx = var_GetNonEmptyString( p_access, SOUT_CFG_PREFIX "index" );
255     if ( psz_idx )
256     {
257         char *psz_tmp;
258         psz_tmp = str_format_time( psz_idx );
259         free( psz_idx );
260         if ( !psz_tmp )
261         {
262             free( p_sys );
263             return VLC_ENOMEM;
264         }
265         path_sanitize( psz_tmp );
266         p_sys->psz_indexPath = psz_tmp;
267         if( p_sys->i_initial_segment != 1 )
268             vlc_unlink( p_sys->psz_indexPath );
269     }
270
271     p_sys->psz_indexUrl = var_GetNonEmptyString( p_access, SOUT_CFG_PREFIX "index-url" );
272     p_sys->psz_keyfile  = var_GetNonEmptyString( p_access, SOUT_CFG_PREFIX "key-loadfile" );
273     p_sys->key_uri      = var_GetNonEmptyString( p_access, SOUT_CFG_PREFIX "key-uri" );
274
275     p_access->p_sys = p_sys;
276
277     if( p_sys->psz_keyfile && ( LoadCryptFile( p_access ) < 0 ) )
278     {
279         free( p_sys->psz_indexUrl );
280         free( p_sys->psz_indexPath );
281         free( p_sys );
282         msg_Err( p_access, "Encryption init failed" );
283         return VLC_EGENERIC;
284     }
285     else if( !p_sys->psz_keyfile && ( CryptSetup( p_access, NULL ) < 0 ) )
286     {
287         free( p_sys->psz_indexUrl );
288         free( p_sys->psz_indexPath );
289         free( p_sys );
290         msg_Err( p_access, "Encryption init failed" );
291         return VLC_EGENERIC;
292     }
293
294     p_sys->i_handle = -1;
295     p_sys->i_segment = p_sys->i_initial_segment-1;
296     p_sys->psz_cursegPath = NULL;
297
298     p_access->pf_write = Write;
299     p_access->pf_seek  = Seek;
300     p_access->pf_control = Control;
301
302     return VLC_SUCCESS;
303 }
304
305 /************************************************************************
306  * CryptSetup: Initialize encryption
307  ************************************************************************/
308 static int CryptSetup( sout_access_out_t *p_access, char *key_file )
309 {
310     sout_access_out_sys_t *p_sys = p_access->p_sys;
311     uint8_t key[16];
312     char *keyfile = NULL;
313
314     if( !p_sys->key_uri ) /*No key uri, assume no encryption wanted*/
315     {
316         msg_Dbg( p_access, "No key uri, no encryption");
317         return VLC_SUCCESS;
318     }
319
320     if( key_file )
321         keyfile = strdup( key_file );
322     else
323         keyfile = var_InheritString( p_access, SOUT_CFG_PREFIX "key-file" );
324
325     if( unlikely(keyfile == NULL) )
326     {
327         msg_Err( p_access, "No key-file, no encryption" );
328         return VLC_EGENERIC;
329     }
330
331     vlc_gcrypt_init();
332
333     /*Setup encryption cipher*/
334     gcry_error_t err = gcry_cipher_open( &p_sys->aes_ctx, GCRY_CIPHER_AES,
335                                          GCRY_CIPHER_MODE_CBC, 0 );
336     if( err )
337     {
338         msg_Err( p_access, "Openin AES Cipher failed: %s", gpg_strerror(err));
339         free( keyfile );
340         return VLC_EGENERIC;
341     }
342
343     int keyfd = vlc_open( keyfile, O_RDONLY | O_NONBLOCK );
344     if( unlikely( keyfd == -1 ) )
345     {
346         msg_Err( p_access, "Unable to open keyfile %s: %s", keyfile,
347                  vlc_strerror_c(errno) );
348         free( keyfile );
349         gcry_cipher_close( p_sys->aes_ctx );
350         return VLC_EGENERIC;
351     }
352     free( keyfile );
353
354     ssize_t keylen = read( keyfd, key, 16 );
355
356     close( keyfd );
357     if( keylen < 16 )
358     {
359         msg_Err( p_access, "No key at least 16 octects (you provided %zd), no encryption", keylen );
360         gcry_cipher_close( p_sys->aes_ctx );
361         return VLC_EGENERIC;
362     }
363
364     err = gcry_cipher_setkey( p_sys->aes_ctx, key, 16 );
365     if(err)
366     {
367         msg_Err(p_access, "Setting AES key failed: %s", gpg_strerror(err));
368         gcry_cipher_close( p_sys->aes_ctx );
369         return VLC_EGENERIC;
370     }
371
372     if( p_sys->b_generate_iv )
373         vlc_rand_bytes( p_sys->aes_ivs, sizeof(uint8_t)*16);
374
375     return VLC_SUCCESS;
376 }
377
378
379 /************************************************************************
380  * LoadCryptFile: Try to parse key_uri and keyfile-location from file
381  ************************************************************************/
382 static int LoadCryptFile( sout_access_out_t *p_access )
383 {
384     sout_access_out_sys_t *p_sys = p_access->p_sys;
385
386     FILE *stream = vlc_fopen( p_sys->psz_keyfile, "rt" );
387     char *key_file=NULL,*key_uri=NULL;
388
389     if( unlikely( stream == NULL ) )
390     {
391         msg_Err( p_access, "Unable to open keyloadfile %s: %s",
392                  p_sys->psz_keyfile, vlc_strerror_c(errno) );
393         return VLC_EGENERIC;
394     }
395
396
397     //First read key_uri
398     ssize_t len = getline( &key_uri, &(size_t){0}, stream );
399     if( unlikely( len == -1 ) )
400     {
401         msg_Err( p_access, "Cannot read %s: %s", p_sys->psz_keyfile,
402                  vlc_strerror_c(errno) );
403         clearerr( stream );
404         fclose( stream );
405         free( key_uri );
406         return VLC_EGENERIC;
407     }
408     //Strip the newline from uri, maybe scanf would be better?
409     key_uri[len-1]='\0';
410
411     len = getline( &key_file, &(size_t){0}, stream );
412     if( unlikely( len == -1 ) )
413     {
414         msg_Err( p_access, "Cannot read %s: %s", p_sys->psz_keyfile,
415                  vlc_strerror_c(errno) );
416         clearerr( stream );
417         fclose( stream );
418
419         free( key_uri );
420         free( key_file );
421         return VLC_EGENERIC;
422     }
423     // Strip the last newline from filename
424     key_file[len-1]='\0';
425     fclose( stream );
426
427     int returncode = VLC_SUCCESS;
428     if( !p_sys->key_uri || strcmp( p_sys->key_uri, key_uri ) )
429     {
430         if( p_sys->key_uri )
431         {
432             free( p_sys->key_uri );
433             p_sys->key_uri = NULL;
434         }
435         p_sys->key_uri = strdup( key_uri );
436         returncode = CryptSetup( p_access, key_file );
437     }
438     free( key_file );
439     free( key_uri );
440     return returncode;
441 }
442
443 /************************************************************************
444  * CryptKey: Set encryption IV to current segment number
445  ************************************************************************/
446 static int CryptKey( sout_access_out_t *p_access, uint32_t i_segment )
447 {
448     sout_access_out_sys_t *p_sys = p_access->p_sys;
449
450     if( !p_sys->b_generate_iv )
451     {
452         /* Use segment number as IV if randomIV isn't selected*/
453         memset( p_sys->aes_ivs, 0, 16 * sizeof(uint8_t));
454         p_sys->aes_ivs[15] = i_segment & 0xff;
455         p_sys->aes_ivs[14] = (i_segment >> 8 ) & 0xff;
456         p_sys->aes_ivs[13] = (i_segment >> 16 ) & 0xff;
457         p_sys->aes_ivs[12] = (i_segment >> 24 ) & 0xff;
458     }
459
460     gcry_error_t err = gcry_cipher_setiv( p_sys->aes_ctx,
461                                           p_sys->aes_ivs, 16);
462     if( err )
463     {
464         msg_Err(p_access, "Setting AES IVs failed: %s", gpg_strerror(err) );
465         gcry_cipher_close( p_sys->aes_ctx);
466         return VLC_EGENERIC;
467     }
468     return VLC_SUCCESS;
469 }
470
471
472 #define SEG_NUMBER_PLACEHOLDER "#"
473 /*****************************************************************************
474  * formatSegmentPath: create segment path name based on seg #
475  *****************************************************************************/
476 static char *formatSegmentPath( char *psz_path, uint32_t i_seg, bool b_sanitize )
477 {
478     char *psz_result;
479     char *psz_firstNumSign;
480
481     if ( ! ( psz_result  = str_format_time( psz_path ) ) )
482         return NULL;
483
484     psz_firstNumSign = psz_result + strcspn( psz_result, SEG_NUMBER_PLACEHOLDER );
485     if ( *psz_firstNumSign )
486     {
487         char *psz_newResult;
488         int i_cnt = strspn( psz_firstNumSign, SEG_NUMBER_PLACEHOLDER );
489         int ret;
490
491         *psz_firstNumSign = '\0';
492         ret = asprintf( &psz_newResult, "%s%0*d%s", psz_result, i_cnt, i_seg, psz_firstNumSign + i_cnt );
493         free ( psz_result );
494         if ( ret < 0 )
495             return NULL;
496         psz_result = psz_newResult;
497     }
498
499     if ( b_sanitize )
500         path_sanitize( psz_result );
501
502     return psz_result;
503 }
504
505 static void destroySegment( output_segment_t *segment )
506 {
507     free( segment->psz_filename );
508     free( segment->psz_duration );
509     free( segment->psz_uri );
510     free( segment->psz_key_uri );
511     free( segment );
512 }
513
514 /************************************************************************
515  * segmentAmountNeeded: check that playlist has atleast 3*p_sys->i_seglength of segments
516  * return how many segments are needed for that (max of p_sys->i_segment )
517  ************************************************************************/
518 static uint32_t segmentAmountNeeded( sout_access_out_sys_t *p_sys )
519 {
520     float duration = .0f;
521     for( unsigned index = 1; (int)index <= vlc_array_count( p_sys->segments_t ); index++ )
522     {
523         output_segment_t* segment = vlc_array_item_at_index( p_sys->segments_t, vlc_array_count( p_sys->segments_t ) - index );
524         duration += segment->f_seglength;
525
526         if( duration >= (float)( 3 * p_sys->i_seglen ) )
527             return __MAX(index, p_sys->i_numsegs);
528     }
529     return vlc_array_count( p_sys->segments_t )-1;
530
531 }
532
533
534 /************************************************************************
535  * isFirstItemRemovable: Check for draft 11 section 6.2.2
536  * check that the first item has been around outside playlist
537  * segment->f_seglength + (p_sys->i_numsegs * p_sys->i_seglen) before it is removed.
538  ************************************************************************/
539 static bool isFirstItemRemovable( sout_access_out_sys_t *p_sys, uint32_t i_firstseg, uint32_t i_index_offset )
540 {
541     float duration = .0f;
542
543     /* Check that segment has been out of playlist for seglenght + (p_sys->i_numsegs * p_sys->i_seglen) amount
544      * We check this by calculating duration of the items that replaced first item in playlist
545      */
546     for( unsigned int index = 0; index < i_index_offset; index++ )
547     {
548         output_segment_t *segment = vlc_array_item_at_index( p_sys->segments_t, p_sys->i_segment - i_firstseg + index );
549         duration += segment->f_seglength;
550     }
551     output_segment_t *first = vlc_array_item_at_index( p_sys->segments_t, 0 );
552
553     return duration >= (first->f_seglength + (float)(p_sys->i_numsegs * p_sys->i_seglen));
554 }
555
556 /************************************************************************
557  * updateIndexAndDel: If necessary, update index file & delete old segments
558  ************************************************************************/
559 static int updateIndexAndDel( sout_access_out_t *p_access, sout_access_out_sys_t *p_sys, bool b_isend )
560 {
561
562     uint32_t i_firstseg;
563     unsigned i_index_offset = 0;
564
565     if ( p_sys->i_numsegs == 0 ||
566          p_sys->i_segment < ( p_sys->i_numsegs + p_sys->i_initial_segment ) )
567     {
568         i_firstseg = p_sys->i_initial_segment;
569     }
570     else
571     {
572         unsigned numsegs = segmentAmountNeeded( p_sys );
573         i_firstseg = ( p_sys->i_segment - numsegs ) + 1;
574         i_index_offset = vlc_array_count( p_sys->segments_t ) - numsegs;
575     }
576
577     // First update index
578     if ( p_sys->psz_indexPath )
579     {
580         int val;
581         FILE *fp;
582         char *psz_idxTmp;
583         if ( asprintf( &psz_idxTmp, "%s.tmp", p_sys->psz_indexPath ) < 0)
584             return -1;
585
586         fp = vlc_fopen( psz_idxTmp, "wt");
587         if ( !fp )
588         {
589             msg_Err( p_access, "cannot open index file `%s'", psz_idxTmp );
590             free( psz_idxTmp );
591             return -1;
592         }
593
594         if ( fprintf( fp, "#EXTM3U\n#EXT-X-TARGETDURATION:%zu\n#EXT-X-VERSION:3\n#EXT-X-ALLOW-CACHE:%s"
595                           "%s\n#EXT-X-MEDIA-SEQUENCE:%"PRIu32"\n%s", p_sys->i_seglen,
596                           p_sys->b_caching ? "YES" : "NO",
597                           p_sys->i_numsegs > 0 ? "" : b_isend ? "\n#EXT-X-PLAYLIST-TYPE:VOD" : "\n#EXT-X-PLAYLIST-TYPE:EVENT",
598                           i_firstseg, ((p_sys->i_initial_segment > 1) && (p_sys->i_initial_segment == i_firstseg)) ? "#EXT-X-DISCONTINUITY\n" : ""
599                           ) < 0 )
600         {
601             free( psz_idxTmp );
602             fclose( fp );
603             return -1;
604         }
605         char *psz_current_uri=NULL;
606
607
608         for ( uint32_t i = i_firstseg; i <= p_sys->i_segment; i++ )
609         {
610             //scale to i_index_offset..numsegs + i_index_offset
611             uint32_t index = i - i_firstseg + i_index_offset;
612
613             output_segment_t *segment = (output_segment_t *)vlc_array_item_at_index( p_sys->segments_t, index );
614             if( p_sys->key_uri &&
615                 ( !psz_current_uri ||  strcmp( psz_current_uri, segment->psz_key_uri ) )
616               )
617             {
618                 int ret = 0;
619                 free( psz_current_uri );
620                 psz_current_uri = strdup( segment->psz_key_uri );
621                 if( p_sys->b_generate_iv )
622                 {
623                     unsigned long long iv_hi = segment->aes_ivs[0];
624                     unsigned long long iv_lo = segment->aes_ivs[8];
625                     for( unsigned short i = 1; i < 8; i++ )
626                     {
627                         iv_hi <<= 8;
628                         iv_hi |= segment->aes_ivs[i] & 0xff;
629                         iv_lo <<= 8;
630                         iv_lo |= segment->aes_ivs[8+i] & 0xff;
631                     }
632                     ret = fprintf( fp, "#EXT-X-KEY:METHOD=AES-128,URI=\"%s\",IV=0X%16.16llx%16.16llx\n",
633                                    segment->psz_key_uri, iv_hi, iv_lo );
634
635                 } else {
636                     ret = fprintf( fp, "#EXT-X-KEY:METHOD=AES-128,URI=\"%s\"\n", segment->psz_key_uri );
637                 }
638                 if( ret < 0 )
639                 {
640                     free( psz_current_uri );
641                     free( psz_idxTmp );
642                     fclose( fp );
643                     return -1;
644                 }
645             }
646
647             val = fprintf( fp, "#EXTINF:%s,\n%s\n", segment->psz_duration, segment->psz_uri);
648             if ( val < 0 )
649             {
650                 free( psz_current_uri );
651                 free( psz_idxTmp );
652                 fclose( fp );
653                 return -1;
654             }
655         }
656         free( psz_current_uri );
657
658         if ( b_isend )
659         {
660             if ( fputs ( STR_ENDLIST, fp ) < 0)
661             {
662                 free( psz_idxTmp );
663                 fclose( fp ) ;
664                 return -1;
665             }
666
667         }
668         fclose( fp );
669
670         val = vlc_rename ( psz_idxTmp, p_sys->psz_indexPath);
671
672         if ( val < 0 )
673         {
674             vlc_unlink( psz_idxTmp );
675             msg_Err( p_access, "Error moving LiveHttp index file" );
676         }
677         else
678             msg_Dbg( p_access, "LiveHttpIndexComplete: %s" , p_sys->psz_indexPath );
679
680         free( psz_idxTmp );
681     }
682
683     // Then take care of deletion
684     // Try to follow pantos draft 11 section 6.2.2
685     while( p_sys->b_delsegs && p_sys->i_numsegs &&
686            isFirstItemRemovable( p_sys, i_firstseg, i_index_offset )
687          )
688     {
689          output_segment_t *segment = vlc_array_item_at_index( p_sys->segments_t, 0 );
690          msg_Dbg( p_access, "Removing segment number %d", segment->i_segment_number );
691          vlc_array_remove( p_sys->segments_t, 0 );
692
693          if ( segment->psz_filename )
694          {
695              vlc_unlink( segment->psz_filename );
696          }
697
698          destroySegment( segment );
699          i_index_offset -=1;
700     }
701
702
703     return 0;
704 }
705
706 /*****************************************************************************
707  * closeCurrentSegment: Close the segment file
708  *****************************************************************************/
709 static void closeCurrentSegment( sout_access_out_t *p_access, sout_access_out_sys_t *p_sys, bool b_isend )
710 {
711     if ( p_sys->i_handle >= 0 )
712     {
713         output_segment_t *segment = (output_segment_t *)vlc_array_item_at_index( p_sys->segments_t, vlc_array_count( p_sys->segments_t ) - 1 );
714
715         if( p_sys->key_uri )
716         {
717             size_t pad = 16 - p_sys->stuffing_size;
718             memset(&p_sys->stuffing_bytes[p_sys->stuffing_size], pad, pad);
719             gcry_error_t err = gcry_cipher_encrypt( p_sys->aes_ctx, p_sys->stuffing_bytes, 16, NULL, 0 );
720
721             if( err ) {
722                msg_Err( p_access, "Couldn't encrypt 16 bytes: %s", gpg_strerror(err) );
723             } else {
724             int ret = write( p_sys->i_handle, p_sys->stuffing_bytes, 16 );
725             if( ret != 16 )
726                 msg_Err( p_access, "Couldn't write 16 bytes" );
727             }
728             p_sys->stuffing_size = 0;
729         }
730
731
732         close( p_sys->i_handle );
733         p_sys->i_handle = -1;
734
735         if( ! ( us_asprintf( &segment->psz_duration, "%.2f", p_sys->f_seglen ) ) )
736         {
737             msg_Err( p_access, "Couldn't set duration on closed segment");
738             return;
739         }
740         segment->f_seglength = p_sys->f_seglen;
741
742         segment->i_segment_number = p_sys->i_segment;
743
744         if ( p_sys->psz_cursegPath )
745         {
746             msg_Dbg( p_access, "LiveHttpSegmentComplete: %s (%"PRIu32")" , p_sys->psz_cursegPath, p_sys->i_segment );
747             free( p_sys->psz_cursegPath );
748             p_sys->psz_cursegPath = 0;
749             updateIndexAndDel( p_access, p_sys, b_isend );
750         }
751     }
752 }
753
754 /*****************************************************************************
755  * Close: close the target
756  *****************************************************************************/
757 static void Close( vlc_object_t * p_this )
758 {
759     sout_access_out_t *p_access = (sout_access_out_t*)p_this;
760     sout_access_out_sys_t *p_sys = p_access->p_sys;
761     block_t *output_block = p_sys->block_buffer;
762     p_sys->block_buffer = NULL;
763
764     while( output_block )
765     {
766         block_t *p_next = output_block->p_next;
767         output_block->p_next = NULL;
768
769         /* Since we are flushing, check the segment change by hand and don't wait
770          * possible keyframe*/
771         if( p_sys->b_segment_has_data &&  (float)(output_block->i_length + p_sys->i_dts_offset +
772                      output_block->i_dts - p_sys->i_opendts) >= p_sys->i_seglenm )
773         {
774             closeCurrentSegment( p_access, p_sys, false );
775             p_sys->i_dts_offset = 0;
776             if( unlikely(openNextFile( p_access, p_sys ) < 0 ) )
777             {
778                 block_ChainRelease( output_block );
779                 output_block = NULL;
780                 block_ChainRelease( p_next );
781
782                 /* Jump out of the loop so we can close rest of the stuff*/
783                 continue;
784             }
785             p_sys->i_opendts = p_sys->block_buffer ? p_sys->block_buffer->i_dts : output_block->i_dts;
786         }
787         Write( p_access, output_block );
788         output_block = p_next;
789     }
790
791     ssize_t writevalue = writeSegment( p_access );
792     msg_Dbg( p_access, "Writing.. %zd", writevalue );
793     if( unlikely( writevalue < 0 ) )
794     {
795         block_ChainRelease( p_sys->block_buffer );
796         p_sys->block_buffer = NULL;
797     }
798
799     closeCurrentSegment( p_access, p_sys, true );
800
801     if( p_sys->key_uri )
802     {
803         gcry_cipher_close( p_sys->aes_ctx );
804         free( p_sys->key_uri );
805     }
806
807     while( vlc_array_count( p_sys->segments_t ) > 0 )
808     {
809         output_segment_t *segment = vlc_array_item_at_index( p_sys->segments_t, 0 );
810         vlc_array_remove( p_sys->segments_t, 0 );
811         if( p_sys->b_delsegs && p_sys->i_numsegs && segment->psz_filename )
812         {
813             msg_Dbg( p_access, "Removing segment number %d name %s", segment->i_segment_number, segment->psz_filename );
814             vlc_unlink( segment->psz_filename );
815         }
816
817         destroySegment( segment );
818     }
819     vlc_array_destroy( p_sys->segments_t );
820
821     free( p_sys->psz_indexUrl );
822     free( p_sys->psz_indexPath );
823     free( p_sys );
824
825     msg_Dbg( p_access, "livehttp access output closed" );
826 }
827
828 static int Control( sout_access_out_t *p_access, int i_query, va_list args )
829 {
830     sout_access_out_sys_t *p_sys = p_access->p_sys;
831
832     switch( i_query )
833     {
834         case ACCESS_OUT_CONTROLS_PACE:
835         {
836             bool *pb = va_arg( args, bool * );
837             *pb = !p_sys->b_ratecontrol;
838             //*pb = true;
839             break;
840         }
841
842         default:
843             return VLC_EGENERIC;
844     }
845     return VLC_SUCCESS;
846 }
847
848 /*****************************************************************************
849  * openNextFile: Open the segment file
850  *****************************************************************************/
851 static ssize_t openNextFile( sout_access_out_t *p_access, sout_access_out_sys_t *p_sys )
852 {
853     int fd;
854
855     uint32_t i_newseg = p_sys->i_segment + 1;
856
857     /* Create segment and fill it info that we can (everything excluding duration */
858     output_segment_t *segment = (output_segment_t*)calloc(1, sizeof(output_segment_t));
859     if( unlikely( !segment ) )
860         return -1;
861
862     segment->i_segment_number = i_newseg;
863     segment->psz_filename = formatSegmentPath( p_access->psz_path, i_newseg, true );
864     char *psz_idxFormat = p_sys->psz_indexUrl ? p_sys->psz_indexUrl : p_access->psz_path;
865     segment->psz_uri = formatSegmentPath( psz_idxFormat , i_newseg, false );
866
867     if ( unlikely( !segment->psz_filename ) )
868     {
869         msg_Err( p_access, "Format segmentpath failed");
870         destroySegment( segment );
871         return -1;
872     }
873
874     fd = vlc_open( segment->psz_filename, O_WRONLY | O_CREAT | O_LARGEFILE |
875                      O_TRUNC, 0666 );
876     if ( fd == -1 )
877     {
878         msg_Err( p_access, "cannot open `%s' (%s)", segment->psz_filename,
879                  vlc_strerror_c(errno) );
880         destroySegment( segment );
881         return -1;
882     }
883
884     vlc_array_append( p_sys->segments_t, segment);
885
886     if( p_sys->psz_keyfile )
887     {
888         LoadCryptFile( p_access );
889     }
890
891     if( p_sys->key_uri )
892     {
893         segment->psz_key_uri = strdup( p_sys->key_uri );
894         CryptKey( p_access, i_newseg );
895         if( p_sys->b_generate_iv )
896             memcpy( segment->aes_ivs, p_sys->aes_ivs, sizeof(uint8_t)*16 );
897     }
898     msg_Dbg( p_access, "Successfully opened livehttp file: %s (%"PRIu32")" , segment->psz_filename, i_newseg );
899
900     p_sys->psz_cursegPath = strdup(segment->psz_filename);
901     p_sys->i_handle = fd;
902     p_sys->i_segment = i_newseg;
903     p_sys->b_segment_has_data = false;
904     return fd;
905 }
906 /*****************************************************************************
907  * CheckSegmentChange: Check if segment needs to be closed and new opened
908  *****************************************************************************/
909 static int CheckSegmentChange( sout_access_out_t *p_access, block_t *p_buffer )
910 {
911     sout_access_out_sys_t *p_sys = p_access->p_sys;
912     block_t *output = p_sys->block_buffer;
913
914     /* let's check if we need to store offset to keep
915      * better count of actual duration */
916     if( unlikely( p_buffer->i_dts < p_sys->i_opendts ) )
917     {
918         block_t *last_buffer = p_sys->block_buffer;
919         while( last_buffer->p_next )
920             last_buffer = last_buffer->p_next;
921         p_sys->i_dts_offset += last_buffer->i_dts - p_sys->i_opendts;
922         p_sys->i_opendts    = p_buffer->i_dts;
923         msg_Dbg( p_access, "dts offset %"PRId64, p_sys->i_dts_offset );
924     }
925
926     if( p_sys->i_handle > 0 && p_sys->b_segment_has_data &&
927        (( p_buffer->i_length + p_buffer->i_dts - p_sys->i_opendts +
928           p_sys->i_dts_offset ) >= p_sys->i_seglenm ) )
929     {
930         closeCurrentSegment( p_access, p_sys, false );
931     }
932
933     if ( unlikely( p_sys->i_handle < 0 ) )
934     {
935         p_sys->i_dts_offset = 0;
936         p_sys->i_opendts = output ? output->i_dts : p_buffer->i_dts;
937         //For first segment we can get negative duration otherwise...?
938         if( ( p_sys->i_opendts != VLC_TS_INVALID ) &&
939             ( p_buffer->i_dts < p_sys->i_opendts ) )
940             p_sys->i_opendts = p_buffer->i_dts;
941
942         if ( openNextFile( p_access, p_sys ) < 0 )
943            return VLC_EGENERIC;
944     }
945     return VLC_SUCCESS;
946 }
947
948 static ssize_t writeSegment( sout_access_out_t *p_access )
949 {
950     sout_access_out_sys_t *p_sys = p_access->p_sys;
951     block_t *output = p_sys->block_buffer ? block_ChainGather( p_sys->block_buffer ) : NULL;
952     p_sys->block_buffer = NULL;
953     ssize_t i_write=0;
954     bool crypted = false;
955     while( output )
956     {
957         if( p_sys->key_uri && !crypted )
958         {
959             if( p_sys->stuffing_size )
960             {
961                 output = block_Realloc( output, p_sys->stuffing_size, output->i_buffer );
962                 if( unlikely(!output ) )
963                     return VLC_ENOMEM;
964                 memcpy( output->p_buffer, p_sys->stuffing_bytes, p_sys->stuffing_size );
965                 p_sys->stuffing_size = 0;
966             }
967             size_t original = output->i_buffer;
968             size_t padded = (output->i_buffer + 15 ) & ~15;
969             size_t pad = padded - original;
970             if( pad )
971             {
972                 p_sys->stuffing_size = 16-pad;
973                 output->i_buffer -= p_sys->stuffing_size;
974                 memcpy(p_sys->stuffing_bytes, &output->p_buffer[output->i_buffer], p_sys->stuffing_size);
975             }
976
977             gcry_error_t err = gcry_cipher_encrypt( p_sys->aes_ctx,
978                                 output->p_buffer, output->i_buffer, NULL, 0 );
979             if( err )
980             {
981                 msg_Err( p_access, "Encryption failure: %s ", gpg_strerror(err) );
982                 return -1;
983             }
984             crypted=true;
985
986         }
987         ssize_t val = write( p_sys->i_handle, output->p_buffer, output->i_buffer );
988         if ( val == -1 )
989         {
990            if ( errno == EINTR )
991               continue;
992            return -1;
993         }
994
995         p_sys->f_seglen =
996             (float)(output->i_length +
997                     output->i_dts - p_sys->i_opendts + p_sys->i_dts_offset) / CLOCK_FREQ;
998
999         if ( (size_t)val >= output->i_buffer )
1000         {
1001            block_t *p_next = output->p_next;
1002            block_Release (output);
1003            output = p_next;
1004            crypted=false;
1005         }
1006         else
1007         {
1008            output->p_buffer += val;
1009            output->i_buffer -= val;
1010         }
1011         i_write += val;
1012     }
1013     return i_write;
1014 }
1015
1016 /*****************************************************************************
1017  * Write: standard write on a file descriptor.
1018  *****************************************************************************/
1019 static ssize_t Write( sout_access_out_t *p_access, block_t *p_buffer )
1020 {
1021     size_t i_write = 0;
1022     sout_access_out_sys_t *p_sys = p_access->p_sys;
1023     block_t *p_temp;
1024     while( p_buffer )
1025     {
1026         if( ( p_sys->b_splitanywhere  || ( p_buffer->i_flags & BLOCK_FLAG_HEADER ) ) )
1027         {
1028             if( unlikely( CheckSegmentChange( p_access, p_buffer ) != VLC_SUCCESS ) )
1029             {
1030                 block_ChainRelease ( p_buffer );
1031                 return -1;
1032             }
1033
1034             ssize_t writevalue = writeSegment( p_access );
1035             if( unlikely( writevalue < 0 ) )
1036             {
1037                 block_ChainRelease ( p_buffer );
1038                 return -1;
1039             }
1040             p_sys->b_segment_has_data = true;
1041             i_write += writevalue;
1042         }
1043
1044         p_temp = p_buffer->p_next;
1045         p_buffer->p_next = NULL;
1046         block_ChainAppend( &p_sys->block_buffer, p_buffer );
1047         p_buffer = p_temp;
1048     }
1049
1050     return i_write;
1051 }
1052
1053 /*****************************************************************************
1054  * Seek: seek to a specific location in a file
1055  *****************************************************************************/
1056 static int Seek( sout_access_out_t *p_access, off_t i_pos )
1057 {
1058     (void) i_pos;
1059     msg_Err( p_access, "livehttp sout access cannot seek" );
1060     return -1;
1061 }