@ -119,7 +119,7 @@ static int setup_encryption(AVFormatContext *s)
AVIOContext * out = NULL ;
int len , ret ;
uint8_t buf [ 16 ] ;
uint8_t * k ;
uint8_t * k = NULL ;
len = strlen ( hls - > basename ) + 4 + 1 ;
hls - > key_basename = av_mallocz ( len ) ;
@ -141,9 +141,22 @@ static int setup_encryption(AVFormatContext *s)
return ret ;
k = hls - > key ;
} else {
if ( ( ret = randomize ( buf , sizeof ( buf ) ) ) < 0 ) {
av_log ( s , AV_LOG_ERROR , " Cannot generate a strong random key \n " ) ;
return ret ;
if ( hls - > start_sequence < 0 ) {
ret = s - > io_open ( s , & out , hls - > key_basename , AVIO_FLAG_READ , NULL ) ;
if ( ret < 0 ) {
av_log ( s , AV_LOG_WARNING ,
" Cannot recover the key, generating a new one. \n " ) ;
} else {
avio_read ( out , buf , 16 ) ;
k = buf ;
avio_close ( out ) ;
}
}
if ( ! k ) {
if ( ( ret = randomize ( buf , sizeof ( buf ) ) ) < 0 ) {
av_log ( s , AV_LOG_ERROR , " Cannot generate a strong random key \n " ) ;
return ret ;
}
}
if ( ( ret = dict_set_bin ( & hls - > enc_opts , " key " , buf , sizeof ( buf ) ) ) < 0 )
@ -201,14 +214,14 @@ static int hls_mux_init(AVFormatContext *s)
return 0 ;
}
static int append_entry ( HLSContext * hls , int64_t duration )
static int append_entry ( HLSContext * hls , int64_t duration , const char * name )
{
ListEntry * en = av_malloc ( sizeof ( * en ) ) ;
if ( ! en )
return AVERROR ( ENOMEM ) ;
av_strlcpy ( en - > name , av_base name( hls - > avf - > filename ) , sizeof ( en - > name ) ) ;
av_strlcpy ( en - > name , name , sizeof ( en - > name ) ) ;
en - > duration = duration ;
en - > next = NULL ;
@ -356,12 +369,67 @@ fail:
return err ;
}
static int read_chomp_line ( AVIOContext * s , char * buf , int maxlen )
{
int len = ff_get_line ( s , buf , maxlen ) ;
while ( len > 0 & & av_isspace ( buf [ len - 1 ] ) )
buf [ - - len ] = ' \0 ' ;
return len ;
}
static int hls_recover ( AVFormatContext * s )
{
HLSContext * hls = s - > priv_data ;
char line [ 1024 ] ;
AVIOContext * io ;
const char * ptr ;
int ret , is_segment = 0 ;
int64_t duration = 0 ;
ret = s - > io_open ( s , & io , s - > filename , AVIO_FLAG_READ , NULL ) ;
if ( ret < 0 ) {
av_log ( s , AV_LOG_WARNING ,
" Cannot recover the playlist, generating a new one. \n " ) ;
hls - > start_sequence = 0 ;
hls - > sequence = 0 ;
return 0 ;
}
read_chomp_line ( io , line , sizeof ( line ) ) ;
if ( strcmp ( line , " #EXTM3U " ) ) {
av_log ( s , AV_LOG_ERROR ,
" The playlist file is present but unparsable. "
" Please remove it. \n " ) ;
return AVERROR_INVALIDDATA ;
}
while ( ! io - > eof_reached ) {
read_chomp_line ( io , line , sizeof ( line ) ) ;
if ( av_strstart ( line , " #EXT-X-MEDIA-SEQUENCE: " , & ptr ) ) {
hls - > sequence = hls - > start_sequence = atoi ( ptr ) ;
} else if ( av_strstart ( line , " #EXTINF: " , & ptr ) ) {
is_segment = 1 ;
duration = atof ( ptr ) * AV_TIME_BASE ;
} else if ( av_strstart ( line , " # " , NULL ) ) {
continue ;
} else if ( line [ 0 ] ) {
if ( is_segment ) {
append_entry ( hls , duration , av_basename ( line ) ) ;
is_segment = 0 ;
}
}
}
return 0 ;
}
static int hls_setup ( AVFormatContext * s )
{
HLSContext * hls = s - > priv_data ;
const char * pattern = " %d.ts " ;
int basename_size = strlen ( s - > filename ) + strlen ( pattern ) + 1 ;
char * p ;
int ret ;
if ( hls - > encrypt )
basename_size + = 7 ;
@ -382,7 +450,13 @@ static int hls_setup(AVFormatContext *s)
* p = ' \0 ' ;
if ( hls - > encrypt ) {
int ret = setup_encryption ( s ) ;
ret = setup_encryption ( s ) ;
if ( ret < 0 )
return ret ;
}
if ( hls - > start_sequence < 0 ) {
ret = hls_recover ( s ) ;
if ( ret < 0 )
return ret ;
}
@ -465,7 +539,7 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt)
hls - > duration = pts - hls - > end_pts ;
if ( can_split & & pts - hls - > start_pts > = end_pts ) {
ret = append_entry ( hls , hls - > duration ) ;
ret = append_entry ( hls , hls - > duration , av_basename ( hls - > avf - > filename ) ) ;
if ( ret )
return ret ;
@ -500,7 +574,7 @@ static int hls_write_trailer(struct AVFormatContext *s)
ff_format_io_close ( s , & oc - > pb ) ;
avformat_free_context ( oc ) ;
av_free ( hls - > basename ) ;
append_entry ( hls , hls - > duration ) ;
append_entry ( hls , hls - > duration , av_basename ( hls - > avf - > filename ) ) ;
hls_window ( s , 1 ) ;
free_entries ( hls ) ;
@ -511,7 +585,8 @@ static int hls_write_trailer(struct AVFormatContext *s)
# define OFFSET(x) offsetof(HLSContext, x)
# define E AV_OPT_FLAG_ENCODING_PARAM
static const AVOption options [ ] = {
{ " start_number " , " first number in the sequence " , OFFSET ( start_sequence ) , AV_OPT_TYPE_INT64 , { . i64 = 0 } , 0 , INT64_MAX , E } ,
{ " start_number " , " first number in the sequence " , OFFSET ( start_sequence ) , AV_OPT_TYPE_INT64 , { . i64 = 0 } , - 1 , INT64_MAX , E , " start_number " } ,
{ " recover " , " If there is already a m3u8 file in the path, populate the sequence from it " , 0 , AV_OPT_TYPE_CONST , { . i64 = - 1 } , 0 , 0 , E , " start_number " } ,
{ " hls_time " , " segment length in seconds " , OFFSET ( time ) , AV_OPT_TYPE_FLOAT , { . dbl = 2 } , 0 , FLT_MAX , E } ,
{ " hls_list_size " , " maximum number of playlist entries " , OFFSET ( size ) , AV_OPT_TYPE_INT , { . i64 = 5 } , 0 , INT_MAX , E } ,
{ " hls_wrap " , " number after which the index wraps " , OFFSET ( wrap ) , AV_OPT_TYPE_INT , { . i64 = 0 } , 0 , INT_MAX , E } ,