@ -164,6 +164,7 @@ typedef struct VariantStream {
char * agroup ; /* audio group name */
char * agroup ; /* audio group name */
char * ccgroup ; /* closed caption group name */
char * ccgroup ; /* closed caption group name */
char * baseurl ;
char * baseurl ;
char * varname ; // variant name
} VariantStream ;
} VariantStream ;
typedef struct ClosedCaptionsStream {
typedef struct ClosedCaptionsStream {
@ -340,6 +341,47 @@ fail:
return ;
return ;
}
}
static int replace_str_data_in_filename ( char * * s , const char * filename , char placeholder , const char * datastring )
{
const char * p ;
char * new_filename ;
char c ;
int addchar_count ;
int found_count = 0 ;
AVBPrint buf ;
av_bprint_init ( & buf , 0 , AV_BPRINT_SIZE_UNLIMITED ) ;
p = filename ;
for ( ; ; ) {
c = * p ;
if ( c = = ' \0 ' )
break ;
if ( c = = ' % ' & & * ( p + 1 ) = = ' % ' ) // %%
addchar_count = 2 ;
else if ( c = = ' % ' & & * ( p + 1 ) = = placeholder ) {
av_bprintf ( & buf , " %s " , datastring ) ;
p + = 2 ;
addchar_count = 0 ;
found_count + + ;
} else
addchar_count = 1 ;
if ( addchar_count > 0 ) {
av_bprint_append_data ( & buf , p , addchar_count ) ;
p + = addchar_count ;
}
}
if ( ! av_bprint_is_complete ( & buf ) ) {
av_bprint_finalize ( & buf , NULL ) ;
return - 1 ;
}
if ( av_bprint_finalize ( & buf , & new_filename ) < 0 | | ! new_filename )
return - 1 ;
* s = new_filename ;
return found_count ;
}
static int replace_int_data_in_filename ( char * * s , const char * filename , char placeholder , int64_t number )
static int replace_int_data_in_filename ( char * * s , const char * filename , char placeholder , int64_t number )
{
{
const char * p ;
const char * p ;
@ -474,20 +516,27 @@ static int hls_delete_old_segments(AVFormatContext *s, HLSContext *hls,
}
}
while ( segment ) {
/* if %v is present in the file's directory
* all segment belongs to the same variant , so do it only once before the loop */
if ( dirname & & av_stristr ( dirname , " %v " ) ) {
char * r_dirname = dirname ;
char * r_dirname = dirname ;
if ( ! vs - > varname ) {
/* if %v is present in the file's directory */
if ( dirname & & av_stristr ( dirname , " %v " ) ) {
if ( replace_int_data_in_filename ( & r_dirname , dirname , ' v ' , segment - > var_stream_idx ) < 1 ) {
if ( replace_int_data_in_filename ( & r_dirname , dirname , ' v ' , segment - > var_stream_idx ) < 1 ) {
ret = AVERROR ( EINVAL ) ;
ret = AVERROR ( EINVAL ) ;
goto fail ;
goto fail ;
}
}
av_free ( dirname ) ;
} else {
dirname = r_dirname ;
if ( replace_str_data_in_filename ( & r_dirname , dirname , ' v ' , vs - > varname ) < 1 ) {
ret = AVERROR ( EINVAL ) ;
goto fail ;
}
}
}
av_free ( dirname ) ;
dirname = r_dirname ;
}
while ( segment ) {
av_log ( hls , AV_LOG_DEBUG , " deleting old segment %s \n " ,
av_log ( hls , AV_LOG_DEBUG , " deleting old segment %s \n " ,
segment - > filename ) ;
segment - > filename ) ;
path_size = ( hls - > use_localtime_mkdir ? 0 : strlen ( dirname ) ) + strlen ( segment - > filename ) + 1 ;
path_size = ( hls - > use_localtime_mkdir ? 0 : strlen ( dirname ) ) + strlen ( segment - > filename ) + 1 ;
@ -1761,7 +1810,7 @@ fail:
return ret ;
return ret ;
}
}
static int format_name ( const char * buf , char * * s , int index )
static int format_name ( const char * buf , char * * s , int index , const char * varname )
{
{
const char * proto , * dir ;
const char * proto , * dir ;
char * orig_buf_dup = NULL , * mod_buf_dup = NULL ;
char * orig_buf_dup = NULL , * mod_buf_dup = NULL ;
@ -1778,9 +1827,16 @@ static int format_name(const char *buf, char **s, int index)
return ret ;
return ret ;
}
}
if ( replace_int_data_in_filename ( s , orig_buf_dup , ' v ' , index ) < 1 ) {
if ( ! varname ) {
ret = AVERROR ( EINVAL ) ;
if ( replace_int_data_in_filename ( s , orig_buf_dup , ' v ' , index ) < 1 ) {
goto fail ;
ret = AVERROR ( EINVAL ) ;
goto fail ;
}
} else {
if ( replace_str_data_in_filename ( s , orig_buf_dup , ' v ' , varname ) < 1 ) {
ret = AVERROR ( EINVAL ) ;
goto fail ;
}
}
}
proto = avio_find_protocol_name ( orig_buf_dup ) ;
proto = avio_find_protocol_name ( orig_buf_dup ) ;
@ -1898,6 +1954,11 @@ static int parse_variant_stream_mapstring(AVFormatContext *s)
( ! av_strncasecmp ( val , " 1 " , strlen ( " 1 " ) ) ) ) ;
( ! av_strncasecmp ( val , " 1 " , strlen ( " 1 " ) ) ) ) ;
hls - > has_default_key = 1 ;
hls - > has_default_key = 1 ;
continue ;
continue ;
} else if ( av_strstart ( keyval , " name: " , & val ) ) {
vs - > varname = av_strdup ( val ) ;
if ( ! vs - > varname )
return AVERROR ( ENOMEM ) ;
continue ;
} else if ( av_strstart ( keyval , " agroup: " , & val ) ) {
} else if ( av_strstart ( keyval , " agroup: " , & val ) ) {
vs - > agroup = av_strdup ( val ) ;
vs - > agroup = av_strdup ( val ) ;
if ( ! vs - > agroup )
if ( ! vs - > agroup )
@ -2417,6 +2478,7 @@ static void hls_free_variant_streams(struct HLSContext *hls)
av_freep ( & vs - > language ) ;
av_freep ( & vs - > language ) ;
av_freep ( & vs - > ccgroup ) ;
av_freep ( & vs - > ccgroup ) ;
av_freep ( & vs - > baseurl ) ;
av_freep ( & vs - > baseurl ) ;
av_freep ( & vs - > varname ) ;
}
}
}
}
@ -2629,12 +2691,7 @@ static int hls_init(AVFormatContext *s)
for ( i = 0 ; i < hls - > nb_varstreams ; i + + ) {
for ( i = 0 ; i < hls - > nb_varstreams ; i + + ) {
vs = & hls - > var_streams [ i ] ;
vs = & hls - > var_streams [ i ] ;
vs - > m3u8_name = av_strdup ( s - > url ) ;
ret = format_name ( s - > url , & vs - > m3u8_name , i , vs - > varname ) ;
if ( ! vs - > m3u8_name ) {
ret = AVERROR ( ENOMEM ) ;
goto fail ;
}
ret = format_name ( s - > url , i , vs - > m3u8_name ) ;
if ( ret < 0 )
if ( ret < 0 )
goto fail ;
goto fail ;
@ -2695,17 +2752,10 @@ static int hls_init(AVFormatContext *s)
}
}
}
}
if ( hls - > segment_filename ) {
if ( hls - > segment_filename ) {
basename_size = strlen ( hls - > segment_filename ) + 1 ;
ret = format_name ( hls - > segment_filename , & vs - > basename , i , vs - > varname ) ;
vs - > basename = av_malloc ( basename_size ) ;
if ( ! vs - > basename ) {
ret = AVERROR ( ENOMEM ) ;
goto fail ;
}
av_strlcpy ( vs - > basename , hls - > segment_filename , basename_size ) ;
ret = format_name ( vs - > basename , basename_size , i ) ;
if ( ret < 0 )
if ( ret < 0 )
goto fail ;
goto fail ;
basename_size = strlen ( vs - > basename ) + 1 ;
} else {
} else {
if ( hls - > flags & HLS_SINGLE_FILE ) {
if ( hls - > flags & HLS_SINGLE_FILE ) {
if ( hls - > segment_type = = SEGMENT_TYPE_FMP4 ) {
if ( hls - > segment_type = = SEGMENT_TYPE_FMP4 ) {
@ -2758,7 +2808,8 @@ static int hls_init(AVFormatContext *s)
fmp4_init_filename_len ) ;
fmp4_init_filename_len ) ;
if ( hls - > nb_varstreams > 1 ) {
if ( hls - > nb_varstreams > 1 ) {
if ( av_stristr ( vs - > fmp4_init_filename , " %v " ) ) {
if ( av_stristr ( vs - > fmp4_init_filename , " %v " ) ) {
format_name ( vs - > fmp4_init_filename , fmp4_init_filename_len , i ) ;
av_freep ( & vs - > fmp4_init_filename ) ;
format_name ( hls - > fmp4_init_filename , & vs - > fmp4_init_filename , i , vs - > varname ) ;
} else {
} else {
ret = append_postfix ( vs - > fmp4_init_filename , fmp4_init_filename_len , i ) ;
ret = append_postfix ( vs - > fmp4_init_filename , fmp4_init_filename_len , i ) ;
}
}
@ -2822,8 +2873,8 @@ static int hls_init(AVFormatContext *s)
* p = ' \0 ' ;
* p = ' \0 ' ;
if ( hls - > subtitle_filename ) {
if ( hls - > subtitle_filename ) {
strcpy ( vs - > vtt_m3u8_name , hls - > subtitle_file name) ;
av_freep ( & vs - > vtt_m3u8_ name) ;
ret = format_name ( vs - > vtt_m3u8_name , vtt_basename_size , i ) ;
ret = format_name ( hls - > subtitle_filename , & vs - > vtt_m3u8_name , i , vs - > varname ) ;
if ( ret < 0 )
if ( ret < 0 )
goto fail ;
goto fail ;
} else {
} else {
@ -2874,6 +2925,7 @@ fail:
av_freep ( & vs - > agroup ) ;
av_freep ( & vs - > agroup ) ;
av_freep ( & vs - > ccgroup ) ;
av_freep ( & vs - > ccgroup ) ;
av_freep ( & vs - > baseurl ) ;
av_freep ( & vs - > baseurl ) ;
av_freep ( & vs - > varname ) ;
if ( vs - > avf )
if ( vs - > avf )
avformat_free_context ( vs - > avf ) ;
avformat_free_context ( vs - > avf ) ;
if ( vs - > vtt_avf )
if ( vs - > vtt_avf )