@ -49,7 +49,8 @@
# include "dash.h"
typedef enum {
SEGMENT_TYPE_MP4 = 0 ,
SEGMENT_TYPE_AUTO = 0 ,
SEGMENT_TYPE_MP4 ,
SEGMENT_TYPE_WEBM ,
SEGMENT_TYPE_NB
} SegmentType ;
@ -84,6 +85,8 @@ typedef struct OutputStream {
int64_t first_pts , start_pts , max_pts ;
int64_t last_dts , last_pts ;
int bit_rate ;
SegmentType segment_type ; /* segment type selected for this particular stream */
const char * format_name ;
char codec_str [ 100 ] ;
int written_len ;
@ -131,8 +134,7 @@ typedef struct DASHContext {
int64_t timeout ;
int index_correction ;
char * format_options_str ;
SegmentType segment_type ;
const char * format_name ;
SegmentType segment_type_option ; /* segment type as specified in options */
} DASHContext ;
static struct codec_string {
@ -151,6 +153,7 @@ static struct format_string {
SegmentType segment_type ;
const char * str ;
} formats [ ] = {
{ SEGMENT_TYPE_AUTO , " auto " } ,
{ SEGMENT_TYPE_MP4 , " mp4 " } ,
{ SEGMENT_TYPE_WEBM , " webm " } ,
{ 0 , NULL }
@ -197,6 +200,38 @@ static const char *get_format_str(SegmentType segment_type) {
return NULL ;
}
static inline SegmentType select_segment_type ( SegmentType segment_type , AVCodecID codec_id )
{
if ( segment_type = = SEGMENT_TYPE_AUTO ) {
if ( codec_id = = AV_CODEC_ID_OPUS | | codec_id = = AV_CODEC_ID_VORBIS | |
codec_id = = AV_CODEC_ID_VP8 | | codec_id = = AV_CODEC_ID_VP9 ) {
segment_type = SEGMENT_TYPE_WEBM ;
} else {
segment_type = SEGMENT_TYPE_MP4 ;
}
}
return segment_type ;
}
static int init_segment_types ( AVFormatContext * s )
{
DASHContext * c = s - > priv_data ;
for ( int i = 0 ; i < s - > nb_streams ; + + i ) {
OutputStream * os = & c - > streams [ i ] ;
SegmentType segment_type = select_segment_type (
c - > segment_type_option , s - > streams [ i ] - > codecpar - > codec_id ) ;
os - > segment_type = segment_type ;
os - > format_name = get_format_str ( segment_type ) ;
if ( ! os - > format_name ) {
av_log ( s , AV_LOG_ERROR , " Could not select DASH segment type for stream %d \n " , i ) ;
return AVERROR_MUXER_NOT_FOUND ;
}
}
return 0 ;
}
static int check_file_extension ( const char * filename , const char * extension ) {
char * dot ;
if ( ! filename | | ! extension )
@ -622,13 +657,13 @@ static int write_adaptation_set(AVFormatContext *s, AVIOContext *out, int as_ind
if ( as - > media_type = = AVMEDIA_TYPE_VIDEO ) {
AVStream * st = s - > streams [ i ] ;
avio_printf ( out , " \t \t \t <Representation id= \" %d \" mimeType= \" video/%s \" codecs= \" %s \" %s width= \" %d \" height= \" %d \" " ,
i , c - > format_name , os - > codec_str , bandwidth_str , s - > streams [ i ] - > codecpar - > width , s - > streams [ i ] - > codecpar - > height ) ;
i , os - > format_name , os - > codec_str , bandwidth_str , s - > streams [ i ] - > codecpar - > width , s - > streams [ i ] - > codecpar - > height ) ;
if ( st - > avg_frame_rate . num )
avio_printf ( out , " frameRate= \" %d/%d \" " , st - > avg_frame_rate . num , st - > avg_frame_rate . den ) ;
avio_printf ( out , " > \n " ) ;
} else {
avio_printf ( out , " \t \t \t <Representation id= \" %d \" mimeType= \" audio/%s \" codecs= \" %s \" %s audioSamplingRate= \" %d \" > \n " ,
i , c - > format_name , os - > codec_str , bandwidth_str , s - > streams [ i ] - > codecpar - > sample_rate ) ;
i , os - > format_name , os - > codec_str , bandwidth_str , s - > streams [ i ] - > codecpar - > sample_rate ) ;
avio_printf ( out , " \t \t \t \t <AudioChannelConfiguration schemeIdUri= \" urn:mpeg:dash:23003:3:audio_channel_configuration:2011 \" value= \" %d \" /> \n " ,
s - > streams [ i ] - > codecpar - > channels ) ;
}
@ -993,6 +1028,9 @@ static int dash_init(AVFormatContext *s)
if ( ( ret = parse_adaptation_sets ( s ) ) < 0 )
return ret ;
if ( ( ret = init_segment_types ( s ) ) < 0 )
return ret ;
for ( i = 0 ; i < s - > nb_streams ; i + + ) {
OutputStream * os = & c - > streams [ i ] ;
AdaptationSet * as = & c - > as [ os - > as_idx - 1 ] ;
@ -1018,13 +1056,10 @@ static int dash_init(AVFormatContext *s)
if ( ! ctx )
return AVERROR ( ENOMEM ) ;
c - > format_name = get_format_str ( c - > segment_type ) ;
if ( ! c - > format_name )
return AVERROR_MUXER_NOT_FOUND ;
if ( c - > segment_type = = SEGMENT_TYPE_WEBM ) {
if ( ( ! c - > single_file & & check_file_extension ( c - > init_seg_name , c - > format_name ) ! = 0 ) | |
( ! c - > single_file & & check_file_extension ( c - > media_seg_name , c - > format_name ) ! = 0 ) | |
( c - > single_file & & check_file_extension ( c - > single_file_name , c - > format_name ) ! = 0 ) ) {
if ( os - > segment_type = = SEGMENT_TYPE_WEBM ) {
if ( ( ! c - > single_file & & check_file_extension ( c - > init_seg_name , os - > format_name ) ! = 0 ) | |
( ! c - > single_file & & check_file_extension ( c - > media_seg_name , os - > format_name ) ! = 0 ) | |
( c - > single_file & & check_file_extension ( c - > single_file_name , os - > format_name ) ! = 0 ) ) {
av_log ( s , AV_LOG_WARNING ,
" One or many segment file names doesn't end with .webm. "
" Override -init_seg_name and/or -media_seg_name and/or "
@ -1032,7 +1067,7 @@ static int dash_init(AVFormatContext *s)
}
}
ctx - > oformat = av_guess_format ( c - > format_name , NULL , NULL ) ;
ctx - > oformat = av_guess_format ( os - > format_name , NULL , NULL ) ;
if ( ! ctx - > oformat )
return AVERROR_MUXER_NOT_FOUND ;
os - > ctx = ctx ;
@ -1076,7 +1111,7 @@ static int dash_init(AVFormatContext *s)
return ret ;
}
if ( c - > segment_type = = SEGMENT_TYPE_MP4 ) {
if ( os - > segment_type = = SEGMENT_TYPE_MP4 ) {
if ( c - > streaming )
av_dict_set ( & opts , " movflags " , " frag_every_frame+dash+delay_moov+global_sidx " , 0 ) ;
else
@ -1141,7 +1176,7 @@ static int dash_write_header(AVFormatContext *s)
// Flush init segment
// Only for WebM segment, since for mp4 delay_moov is set and
// the init segment is thus flushed after the first packets.
if ( c - > segment_type = = SEGMENT_TYPE_WEBM & &
if ( os - > segment_type = = SEGMENT_TYPE_WEBM & &
( ret = flush_init_segment ( s , os ) ) < 0 )
return ret ;
}
@ -1312,7 +1347,7 @@ static int dash_flush(AVFormatContext *s, int final, int stream)
}
if ( ! c - > single_file ) {
if ( c - > segment_type = = SEGMENT_TYPE_MP4 & & ! os - > written_len )
if ( os - > segment_type = = SEGMENT_TYPE_MP4 & & ! os - > written_len )
write_styp ( os - > ctx - > pb ) ;
} else {
snprintf ( os - > full_path , sizeof ( os - > full_path ) , " %s%s " , c - > dirname , os - > initfile ) ;
@ -1502,7 +1537,7 @@ static int dash_write_packet(AVFormatContext *s, AVPacket *pkt)
}
//write out the data immediately in streaming mode
if ( c - > streaming & & c - > segment_type = = SEGMENT_TYPE_MP4 ) {
if ( c - > streaming & & os - > segment_type = = SEGMENT_TYPE_MP4 ) {
int len = 0 ;
uint8_t * buf = NULL ;
if ( ! os - > written_len )
@ -1598,7 +1633,8 @@ static const AVOption options[] = {
{ " timeout " , " set timeout for socket I/O operations " , OFFSET ( timeout ) , AV_OPT_TYPE_DURATION , { . i64 = - 1 } , - 1 , INT_MAX , . flags = E } ,
{ " index_correction " , " Enable/Disable segment index correction logic " , OFFSET ( index_correction ) , AV_OPT_TYPE_BOOL , { . i64 = 0 } , 0 , 1 , E } ,
{ " format_options " , " set list of options for the container format (mp4/webm) used for dash " , OFFSET ( format_options_str ) , AV_OPT_TYPE_STRING , { . str = NULL } , 0 , 0 , E } ,
{ " dash_segment_type " , " set dash segment files type " , OFFSET ( segment_type ) , AV_OPT_TYPE_INT , { . i64 = SEGMENT_TYPE_MP4 } , 0 , SEGMENT_TYPE_NB - 1 , E , " segment_type " } ,
{ " dash_segment_type " , " set dash segment files type " , OFFSET ( segment_type_option ) , AV_OPT_TYPE_INT , { . i64 = SEGMENT_TYPE_AUTO } , 0 , SEGMENT_TYPE_NB - 1 , E , " segment_type " } ,
{ " auto " , " select segment file format based on codec " , 0 , AV_OPT_TYPE_CONST , { . i64 = SEGMENT_TYPE_AUTO } , 0 , UINT_MAX , E , " segment_type " } ,
{ " mp4 " , " make segment file in ISOBMFF format " , 0 , AV_OPT_TYPE_CONST , { . i64 = SEGMENT_TYPE_MP4 } , 0 , UINT_MAX , E , " segment_type " } ,
{ " webm " , " make segment file in WebM format " , 0 , AV_OPT_TYPE_CONST , { . i64 = SEGMENT_TYPE_WEBM } , 0 , UINT_MAX , E , " segment_type " } ,
{ NULL } ,