@ -572,6 +572,45 @@ static void get_aac_sample_rates(AVFormatContext *s, AVCodecContext *codec,
* output_sample_rate = mp4ac . ext_sample_rate ;
}
static int mkv_write_native_codecprivate ( AVFormatContext * s ,
AVCodecContext * codec ,
AVIOContext * dyn_cp )
{
switch ( codec - > codec_id ) {
case AV_CODEC_ID_VORBIS :
case AV_CODEC_ID_THEORA :
return put_xiph_codecpriv ( s , dyn_cp , codec ) ;
case AV_CODEC_ID_FLAC :
return put_flac_codecpriv ( s , dyn_cp , codec ) ;
case AV_CODEC_ID_WAVPACK :
return put_wv_codecpriv ( dyn_cp , codec ) ;
case AV_CODEC_ID_H264 :
return ff_isom_write_avcc ( dyn_cp , codec - > extradata ,
codec - > extradata_size ) ;
case AV_CODEC_ID_HEVC :
return ff_isom_write_hvcc ( dyn_cp , codec - > extradata ,
codec - > extradata_size , 0 ) ;
case AV_CODEC_ID_ALAC :
if ( codec - > extradata_size < 36 ) {
av_log ( s , AV_LOG_ERROR ,
" Invalid extradata found, ALAC expects a 36-byte "
" QuickTime atom. " ) ;
return AVERROR_INVALIDDATA ;
} else
avio_write ( dyn_cp , codec - > extradata + 12 ,
codec - > extradata_size - 12 ) ;
break ;
default :
if ( codec - > codec_id = = AV_CODEC_ID_PRORES & &
ff_codec_get_id ( ff_codec_movvideo_tags , codec - > codec_tag ) = = AV_CODEC_ID_PRORES ) {
avio_wl32 ( dyn_cp , codec - > codec_tag ) ;
} else if ( codec - > extradata_size & & codec - > codec_id ! = AV_CODEC_ID_TTA )
avio_write ( dyn_cp , codec - > extradata , codec - > extradata_size ) ;
}
return 0 ;
}
static int mkv_write_codecprivate ( AVFormatContext * s , AVIOContext * pb ,
AVCodecContext * codec , int native_id ,
int qt_id )
@ -585,33 +624,7 @@ static int mkv_write_codecprivate(AVFormatContext *s, AVIOContext *pb,
return ret ;
if ( native_id ) {
if ( codec - > codec_id = = AV_CODEC_ID_VORBIS | |
codec - > codec_id = = AV_CODEC_ID_THEORA )
ret = put_xiph_codecpriv ( s , dyn_cp , codec ) ;
else if ( codec - > codec_id = = AV_CODEC_ID_FLAC )
ret = put_flac_codecpriv ( s , dyn_cp , codec ) ;
else if ( codec - > codec_id = = AV_CODEC_ID_WAVPACK )
ret = put_wv_codecpriv ( dyn_cp , codec ) ;
else if ( codec - > codec_id = = AV_CODEC_ID_H264 )
ret = ff_isom_write_avcc ( dyn_cp , codec - > extradata ,
codec - > extradata_size ) ;
else if ( codec - > codec_id = = AV_CODEC_ID_HEVC )
ret = ff_isom_write_hvcc ( dyn_cp , codec - > extradata ,
codec - > extradata_size , 0 ) ;
else if ( codec - > codec_id = = AV_CODEC_ID_ALAC ) {
if ( codec - > extradata_size < 36 ) {
av_log ( s , AV_LOG_ERROR ,
" Invalid extradata found, ALAC expects a 36-byte "
" QuickTime atom. " ) ;
ret = AVERROR_INVALIDDATA ;
} else
avio_write ( dyn_cp , codec - > extradata + 12 ,
codec - > extradata_size - 12 ) ;
} else if ( codec - > codec_id = = AV_CODEC_ID_PRORES & &
ff_codec_get_id ( ff_codec_movvideo_tags , codec - > codec_tag ) = = AV_CODEC_ID_PRORES ) {
avio_wl32 ( dyn_cp , codec - > codec_tag ) ;
} else if ( codec - > extradata_size & & codec - > codec_id ! = AV_CODEC_ID_TTA )
avio_write ( dyn_cp , codec - > extradata , codec - > extradata_size ) ;
ret = mkv_write_native_codecprivate ( s , codec , dyn_cp ) ;
} else if ( codec - > codec_type = = AVMEDIA_TYPE_VIDEO ) {
if ( qt_id ) {
if ( ! codec - > codec_tag )
@ -667,258 +680,269 @@ static int mkv_write_codecprivate(AVFormatContext *s, AVIOContext *pb,
return ret ;
}
static int mkv_write_tracks ( AVFormatContext * s )
static int mkv_write_track ( AVFormatContext * s , MatroskaMuxContext * mkv ,
int i , AVIOContext * pb , int default_stream_exists )
{
MatroskaMuxContext * mkv = s - > priv_data ;
AVIOContext * pb = s - > pb ;
ebml_master tracks ;
int i , j , ret , default_stream_exists = 0 ;
AVStream * st = s - > streams [ i ] ;
AVCodecContext * codec = st - > codec ;
ebml_master subinfo , track ;
int native_id = 0 ;
int qt_id = 0 ;
int bit_depth = av_get_bits_per_sample ( codec - > codec_id ) ;
int sample_rate = codec - > sample_rate ;
int output_sample_rate = 0 ;
int display_width_div = 1 ;
int display_height_div = 1 ;
int j , ret ;
AVDictionaryEntry * tag ;
ret = mkv_add_seekhead_entry ( mkv - > main_seekhead , MATROSKA_ID_TRACKS , avio_tell ( pb ) ) ;
if ( ret < 0 )
return ret ;
// ms precision is the de-facto standard timescale for mkv files
avpriv_set_pts_info ( st , 64 , 1 , 1000 ) ;
tracks = start_ebml_master ( pb , MATROSKA_ID_TRACKS , 0 ) ;
for ( i = 0 ; i < s - > nb_streams ; i + + ) {
AVStream * st = s - > streams [ i ] ;
default_stream_exists | = st - > disposition & AV_DISPOSITION_DEFAULT ;
if ( codec - > codec_type = = AVMEDIA_TYPE_ATTACHMENT ) {
mkv - > have_attachments = 1 ;
return 0 ;
}
for ( i = 0 ; i < s - > nb_streams ; i + + ) {
AVStream * st = s - > streams [ i ] ;
AVCodecContext * codec = st - > codec ;
ebml_master subinfo , track ;
int native_id = 0 ;
int qt_id = 0 ;
int bit_depth = av_get_bits_per_sample ( codec - > codec_id ) ;
int sample_rate = codec - > sample_rate ;
int output_sample_rate = 0 ;
int display_width_div = 1 ;
int display_height_div = 1 ;
AVDictionaryEntry * tag ;
// ms precision is the de-facto standard timescale for mkv files
avpriv_set_pts_info ( st , 64 , 1 , 1000 ) ;
if ( codec - > codec_type = = AVMEDIA_TYPE_ATTACHMENT ) {
mkv - > have_attachments = 1 ;
continue ;
}
if ( ! bit_depth & & codec - > codec_id ! = AV_CODEC_ID_ADPCM_G726 )
bit_depth = av_get_bytes_per_sample ( codec - > sample_fmt ) < < 3 ;
if ( ! bit_depth )
bit_depth = codec - > bits_per_coded_sample ;
if ( codec - > codec_id = = AV_CODEC_ID_AAC )
get_aac_sample_rates ( s , codec , & sample_rate , & output_sample_rate ) ;
track = start_ebml_master ( pb , MATROSKA_ID_TRACKENTRY , 0 ) ;
put_ebml_uint ( pb , MATROSKA_ID_TRACKNUMBER ,
mkv - > is_dash ? mkv - > dash_track_number : i + 1 ) ;
put_ebml_uint ( pb , MATROSKA_ID_TRACKUID ,
mkv - > is_dash ? mkv - > dash_track_number : i + 1 ) ;
put_ebml_uint ( pb , MATROSKA_ID_TRACKFLAGLACING , 0 ) ; // no lacing (yet)
if ( ( tag = av_dict_get ( st - > metadata , " title " , NULL , 0 ) ) )
put_ebml_string ( pb , MATROSKA_ID_TRACKNAME , tag - > value ) ;
tag = av_dict_get ( st - > metadata , " language " , NULL , 0 ) ;
if ( mkv - > mode ! = MODE_WEBM | | codec - > codec_id ! = AV_CODEC_ID_WEBVTT ) {
put_ebml_string ( pb , MATROSKA_ID_TRACKLANGUAGE , tag ? tag - > value : " und " ) ;
} else if ( tag & & tag - > value ) {
put_ebml_string ( pb , MATROSKA_ID_TRACKLANGUAGE , tag - > value ) ;
}
if ( ! bit_depth & & codec - > codec_id ! = AV_CODEC_ID_ADPCM_G726 )
bit_depth = av_get_bytes_per_sample ( codec - > sample_fmt ) < < 3 ;
if ( ! bit_depth )
bit_depth = codec - > bits_per_coded_sample ;
if ( codec - > codec_id = = AV_CODEC_ID_AAC )
get_aac_sample_rates ( s , codec , & sample_rate , & output_sample_rate ) ;
track = start_ebml_master ( pb , MATROSKA_ID_TRACKENTRY , 0 ) ;
put_ebml_uint ( pb , MATROSKA_ID_TRACKNUMBER ,
mkv - > is_dash ? mkv - > dash_track_number : i + 1 ) ;
put_ebml_uint ( pb , MATROSKA_ID_TRACKUID ,
mkv - > is_dash ? mkv - > dash_track_number : i + 1 ) ;
put_ebml_uint ( pb , MATROSKA_ID_TRACKFLAGLACING , 0 ) ; // no lacing (yet)
if ( ( tag = av_dict_get ( st - > metadata , " title " , NULL , 0 ) ) )
put_ebml_string ( pb , MATROSKA_ID_TRACKNAME , tag - > value ) ;
tag = av_dict_get ( st - > metadata , " language " , NULL , 0 ) ;
if ( mkv - > mode ! = MODE_WEBM | | codec - > codec_id ! = AV_CODEC_ID_WEBVTT ) {
put_ebml_string ( pb , MATROSKA_ID_TRACKLANGUAGE , tag ? tag - > value : " und " ) ;
} else if ( tag & & tag - > value ) {
put_ebml_string ( pb , MATROSKA_ID_TRACKLANGUAGE , tag - > value ) ;
}
// The default value for TRACKFLAGDEFAULT is 1, so add element
// if we need to clear it.
if ( default_stream_exists & & ! ( st - > disposition & AV_DISPOSITION_DEFAULT ) )
put_ebml_uint ( pb , MATROSKA_ID_TRACKFLAGDEFAULT , ! ! ( st - > disposition & AV_DISPOSITION_DEFAULT ) ) ;
if ( st - > disposition & AV_DISPOSITION_FORCED )
put_ebml_uint ( pb , MATROSKA_ID_TRACKFLAGFORCED , 1 ) ;
if ( mkv - > mode = = MODE_WEBM & & codec - > codec_id = = AV_CODEC_ID_WEBVTT ) {
const char * codec_id ;
if ( st - > disposition & AV_DISPOSITION_CAPTIONS ) {
codec_id = " D_WEBVTT/CAPTIONS " ;
native_id = MATROSKA_TRACK_TYPE_SUBTITLE ;
} else if ( st - > disposition & AV_DISPOSITION_DESCRIPTIONS ) {
codec_id = " D_WEBVTT/DESCRIPTIONS " ;
native_id = MATROSKA_TRACK_TYPE_METADATA ;
} else if ( st - > disposition & AV_DISPOSITION_METADATA ) {
codec_id = " D_WEBVTT/METADATA " ;
native_id = MATROSKA_TRACK_TYPE_METADATA ;
} else {
codec_id = " D_WEBVTT/SUBTITLES " ;
native_id = MATROSKA_TRACK_TYPE_SUBTITLE ;
}
put_ebml_string ( pb , MATROSKA_ID_CODECID , codec_id ) ;
// The default value for TRACKFLAGDEFAULT is 1, so add element
// if we need to clear it.
if ( default_stream_exists & & ! ( st - > disposition & AV_DISPOSITION_DEFAULT ) )
put_ebml_uint ( pb , MATROSKA_ID_TRACKFLAGDEFAULT , ! ! ( st - > disposition & AV_DISPOSITION_DEFAULT ) ) ;
if ( st - > disposition & AV_DISPOSITION_FORCED )
put_ebml_uint ( pb , MATROSKA_ID_TRACKFLAGFORCED , 1 ) ;
if ( mkv - > mode = = MODE_WEBM & & codec - > codec_id = = AV_CODEC_ID_WEBVTT ) {
const char * codec_id ;
if ( st - > disposition & AV_DISPOSITION_CAPTIONS ) {
codec_id = " D_WEBVTT/CAPTIONS " ;
native_id = MATROSKA_TRACK_TYPE_SUBTITLE ;
} else if ( st - > disposition & AV_DISPOSITION_DESCRIPTIONS ) {
codec_id = " D_WEBVTT/DESCRIPTIONS " ;
native_id = MATROSKA_TRACK_TYPE_METADATA ;
} else if ( st - > disposition & AV_DISPOSITION_METADATA ) {
codec_id = " D_WEBVTT/METADATA " ;
native_id = MATROSKA_TRACK_TYPE_METADATA ;
} else {
// look for a codec ID string specific to mkv to use,
// if none are found, use AVI codes
for ( j = 0 ; ff_mkv_codec_tags [ j ] . id ! = AV_CODEC_ID_NONE ; j + + ) {
if ( ff_mkv_codec_tags [ j ] . id = = codec - > codec_id ) {
put_ebml_string ( pb , MATROSKA_ID_CODECID , ff_mkv_codec_tags [ j ] . str ) ;
native_id = 1 ;
break ;
}
codec_id = " D_WEBVTT/SUBTITLES " ;
native_id = MATROSKA_TRACK_TYPE_SUBTITLE ;
}
put_ebml_string ( pb , MATROSKA_ID_CODECID , codec_id ) ;
} else {
// look for a codec ID string specific to mkv to use,
// if none are found, use AVI codes
for ( j = 0 ; ff_mkv_codec_tags [ j ] . id ! = AV_CODEC_ID_NONE ; j + + ) {
if ( ff_mkv_codec_tags [ j ] . id = = codec - > codec_id ) {
put_ebml_string ( pb , MATROSKA_ID_CODECID , ff_mkv_codec_tags [ j ] . str ) ;
native_id = 1 ;
break ;
}
}
}
if ( codec - > codec_type = = AVMEDIA_TYPE_AUDIO & & codec - > delay & & codec - > codec_id = = AV_CODEC_ID_OPUS ) {
// mkv->tracks[i].ts_offset = av_rescale_q(codec->delay,
// (AVRational){ 1, codec->sample_rate },
// st->time_base);
if ( codec - > codec_type = = AVMEDIA_TYPE_AUDIO & & codec - > delay & & codec - > codec_id = = AV_CODEC_ID_OPUS ) {
// mkv->tracks[i].ts_offset = av_rescale_q(codec->delay,
// (AVRational){ 1, codec->sample_rate },
// st->time_base);
put_ebml_uint ( pb , MATROSKA_ID_CODECDELAY ,
av_rescale_q ( codec - > delay , ( AVRational ) { 1 , codec - > sample_rate } ,
( AVRational ) { 1 , 1000000000 } ) ) ;
}
if ( codec - > codec_id = = AV_CODEC_ID_OPUS ) {
put_ebml_uint ( pb , MATROSKA_ID_SEEKPREROLL , OPUS_SEEK_PREROLL ) ;
}
put_ebml_uint ( pb , MATROSKA_ID_CODECDELAY ,
av_rescale_q ( codec - > delay , ( AVRational ) { 1 , codec - > sample_rate } ,
( AVRational ) { 1 , 1000000000 } ) ) ;
}
if ( codec - > codec_id = = AV_CODEC_ID_OPUS ) {
put_ebml_uint ( pb , MATROSKA_ID_SEEKPREROLL , OPUS_SEEK_PREROLL ) ;
}
if ( mkv - > mode = = MODE_WEBM & & ! ( codec - > codec_id = = AV_CODEC_ID_VP8 | |
codec - > codec_id = = AV_CODEC_ID_VP9 | |
codec - > codec_id = = AV_CODEC_ID_OPUS | |
codec - > codec_id = = AV_CODEC_ID_VORBIS | |
codec - > codec_id = = AV_CODEC_ID_WEBVTT ) ) {
av_log ( s , AV_LOG_ERROR ,
" Only VP8 or VP9 video and Vorbis or Opus audio and WebVTT subtitles are supported for WebM. \n " ) ;
return AVERROR ( EINVAL ) ;
}
if ( mkv - > mode = = MODE_WEBM & & ! ( codec - > codec_id = = AV_CODEC_ID_VP8 | |
codec - > codec_id = = AV_CODEC_ID_VP9 | |
codec - > codec_id = = AV_CODEC_ID_OPUS | |
codec - > codec_id = = AV_CODEC_ID_VORBIS | |
codec - > codec_id = = AV_CODEC_ID_WEBVTT ) ) {
av_log ( s , AV_LOG_ERROR ,
" Only VP8 or VP9 video and Vorbis or Opus audio and WebVTT subtitles are supported for WebM. \n " ) ;
return AVERROR ( EINVAL ) ;
}
switch ( codec - > codec_type ) {
case AVMEDIA_TYPE_VIDEO :
put_ebml_uint ( pb , MATROSKA_ID_TRACKTYPE , MATROSKA_TRACK_TYPE_VIDEO ) ;
if ( st - > avg_frame_rate . num > 0 & & st - > avg_frame_rate . den > 0
& & 1.0 / av_q2d ( st - > avg_frame_rate ) > av_q2d ( codec - > time_base ) )
put_ebml_uint ( pb , MATROSKA_ID_TRACKDEFAULTDURATION , 1E9 / av_q2d ( st - > avg_frame_rate ) ) ;
else
put_ebml_uint ( pb , MATROSKA_ID_TRACKDEFAULTDURATION , av_q2d ( codec - > time_base ) * 1E9 ) ;
if ( ! native_id & &
ff_codec_get_tag ( ff_codec_movvideo_tags , codec - > codec_id ) & &
( ! ff_codec_get_tag ( ff_codec_bmp_tags , codec - > codec_id ) | |
codec - > codec_id = = AV_CODEC_ID_SVQ1 | |
codec - > codec_id = = AV_CODEC_ID_SVQ3 | |
codec - > codec_id = = AV_CODEC_ID_CINEPAK ) )
qt_id = 1 ;
if ( qt_id )
put_ebml_string ( pb , MATROSKA_ID_CODECID , " V_QUICKTIME " ) ;
else if ( ! native_id ) {
// if there is no mkv-specific codec ID, use VFW mode
put_ebml_string ( pb , MATROSKA_ID_CODECID , " V_MS/VFW/FOURCC " ) ;
mkv - > tracks [ i ] . write_dts = 1 ;
}
switch ( codec - > codec_type ) {
case AVMEDIA_TYPE_VIDEO :
put_ebml_uint ( pb , MATROSKA_ID_TRACKTYPE , MATROSKA_TRACK_TYPE_VIDEO ) ;
subinfo = start_ebml_master ( pb , MATROSKA_ID_TRACKVIDEO , 0 ) ;
// XXX: interlace flag?
put_ebml_uint ( pb , MATROSKA_ID_VIDEOPIXELWIDTH , codec - > width ) ;
put_ebml_uint ( pb , MATROSKA_ID_VIDEOPIXELHEIGHT , codec - > height ) ;
if ( st - > avg_frame_rate . num > 0 & & st - > avg_frame_rate . den > 0
& & 1.0 / av_q2d ( st - > avg_frame_rate ) > av_q2d ( codec - > time_base ) )
put_ebml_uint ( pb , MATROSKA_ID_TRACKDEFAULTDURATION , 1E9 / av_q2d ( st - > avg_frame_rate ) ) ;
else
put_ebml_uint ( pb , MATROSKA_ID_TRACKDEFAULTDURATION , av_q2d ( codec - > time_base ) * 1E9 ) ;
if ( ! native_id & &
ff_codec_get_tag ( ff_codec_movvideo_tags , codec - > codec_id ) & &
( ! ff_codec_get_tag ( ff_codec_bmp_tags , codec - > codec_id ) | |
codec - > codec_id = = AV_CODEC_ID_SVQ1 | |
codec - > codec_id = = AV_CODEC_ID_SVQ3 | |
codec - > codec_id = = AV_CODEC_ID_CINEPAK ) )
qt_id = 1 ;
if ( qt_id )
put_ebml_string ( pb , MATROSKA_ID_CODECID , " V_QUICKTIME " ) ;
else if ( ! native_id ) {
// if there is no mkv-specific codec ID, use VFW mode
put_ebml_string ( pb , MATROSKA_ID_CODECID , " V_MS/VFW/FOURCC " ) ;
mkv - > tracks [ i ] . write_dts = 1 ;
}
if ( ( tag = av_dict_get ( st - > metadata , " stereo_mode " , NULL , 0 ) ) | |
( tag = av_dict_get ( s - > metadata , " stereo_mode " , NULL , 0 ) ) ) {
// save stereo mode flag
uint64_t st_mode = MATROSKA_VIDEO_STEREO_MODE_COUNT ;
subinfo = start_ebml_master ( pb , MATROSKA_ID_TRACKVIDEO , 0 ) ;
// XXX: interlace flag?
put_ebml_uint ( pb , MATROSKA_ID_VIDEOPIXELWIDTH , codec - > width ) ;
put_ebml_uint ( pb , MATROSKA_ID_VIDEOPIXELHEIGHT , codec - > height ) ;
for ( j = 0 ; j < MATROSKA_VIDEO_STEREO_MODE_COUNT ; j + + )
if ( ! strcmp ( tag - > value , ff_matroska_video_stereo_mode [ j ] ) ) {
st_mode = j ;
break ;
}
if ( ( tag = av_dict_get ( st - > metadata , " stereo_mode " , NULL , 0 ) ) | |
( tag = av_dict_get ( s - > metadata , " stereo_mode " , NULL , 0 ) ) ) {
// save stereo mode flag
uint64_t st_mode = MATROSKA_VIDEO_STEREO_MODE_COUNT ;
if ( ( mkv - > mode = = MODE_WEBM & & st_mode > 3 & & st_mode ! = 11 )
| | st_mode > = MATROSKA_VIDEO_STEREO_MODE_COUNT ) {
av_log ( s , AV_LOG_ERROR ,
" The specified stereo mode is not valid. \n " ) ;
return AVERROR ( EINVAL ) ;
} else
put_ebml_uint ( pb , MATROSKA_ID_VIDEOSTEREOMODE , st_mode ) ;
switch ( st_mode ) {
case 1 :
case 8 :
case 9 :
case 11 :
display_width_div = 2 ;
break ;
case 2 :
case 3 :
case 6 :
case 7 :
display_height_div = 2 ;
for ( j = 0 ; j < MATROSKA_VIDEO_STEREO_MODE_COUNT ; j + + )
if ( ! strcmp ( tag - > value , ff_matroska_video_stereo_mode [ j ] ) ) {
st_mode = j ;
break ;
}
}
if ( ( tag = av_dict_get ( st - > metadata , " alpha_mode " , NULL , 0 ) ) | |
( tag = av_dict_get ( s - > metadata , " alpha_mode " , NULL , 0 ) ) | |
( codec - > pix_fmt = = AV_PIX_FMT_YUVA420P ) ) {
put_ebml_uint ( pb , MATROSKA_ID_VIDEOALPHAMODE , 1 ) ;
if ( ( mkv - > mode = = MODE_WEBM & & st_mode > 3 & & st_mode ! = 11 )
| | st_mode > = MATROSKA_VIDEO_STEREO_MODE_COUNT ) {
av_log ( s , AV_LOG_ERROR ,
" The specified stereo mode is not valid. \n " ) ;
return AVERROR ( EINVAL ) ;
} else
put_ebml_uint ( pb , MATROSKA_ID_VIDEOSTEREOMODE , st_mode ) ;
switch ( st_mode ) {
case 1 :
case 8 :
case 9 :
case 11 :
display_width_div = 2 ;
break ;
case 2 :
case 3 :
case 6 :
case 7 :
display_height_div = 2 ;
break ;
}
}
if ( st - > sample_aspect_ratio . num ) {
int64_t d_width = av_rescale ( codec - > width , st - > sample_aspect_ratio . num , st - > sample_aspect_ratio . den ) ;
if ( d_width > INT_MAX ) {
av_log ( s , AV_LOG_ERROR , " Overflow in display width \n " ) ;
return AVERROR ( EINVAL ) ;
}
put_ebml_uint ( pb , MATROSKA_ID_VIDEODISPLAYWIDTH , d_width / display_width_div ) ;
put_ebml_uint ( pb , MATROSKA_ID_VIDEODISPLAYHEIGHT , codec - > height / display_height_div ) ;
} else if ( display_width_div ! = 1 | | display_height_div ! = 1 ) {
put_ebml_uint ( pb , MATROSKA_ID_VIDEODISPLAYWIDTH , codec - > width / display_width_div ) ;
put_ebml_uint ( pb , MATROSKA_ID_VIDEODISPLAYHEIGHT , codec - > height / display_height_div ) ;
}
if ( ( tag = av_dict_get ( st - > metadata , " alpha_mode " , NULL , 0 ) ) | |
( tag = av_dict_get ( s - > metadata , " alpha_mode " , NULL , 0 ) ) | |
( codec - > pix_fmt = = AV_PIX_FMT_YUVA420P ) ) {
put_ebml_uint ( pb , MATROSKA_ID_VIDEOALPHAMODE , 1 ) ;
}
if ( codec - > codec_id = = AV_CODEC_ID_RAWVIDEO ) {
uint32_t color_space = av_le2ne32 ( codec - > codec_tag ) ;
put_ebml_binary ( pb , MATROSKA_ID_VIDEOCOLORSPACE , & color_space , sizeof ( color_space ) ) ;
}
end_ebml_master ( pb , subinfo ) ;
break ;
case AVMEDIA_TYPE_AUDIO :
put_ebml_uint ( pb , MATROSKA_ID_TRACKTYPE , MATROSKA_TRACK_TYPE_AUDIO ) ;
if ( ! native_id )
// no mkv-specific ID, use ACM mode
put_ebml_string ( pb , MATROSKA_ID_CODECID , " A_MS/ACM " ) ;
subinfo = start_ebml_master ( pb , MATROSKA_ID_TRACKAUDIO , 0 ) ;
put_ebml_uint ( pb , MATROSKA_ID_AUDIOCHANNELS , codec - > channels ) ;
put_ebml_float ( pb , MATROSKA_ID_AUDIOSAMPLINGFREQ , sample_rate ) ;
if ( output_sample_rate )
put_ebml_float ( pb , MATROSKA_ID_AUDIOOUTSAMPLINGFREQ , output_sample_rate ) ;
if ( bit_depth )
put_ebml_uint ( pb , MATROSKA_ID_AUDIOBITDEPTH , bit_depth ) ;
end_ebml_master ( pb , subinfo ) ;
break ;
case AVMEDIA_TYPE_SUBTITLE :
if ( ! native_id ) {
av_log ( s , AV_LOG_ERROR , " Subtitle codec %d is not supported. \n " , codec - > codec_id ) ;
return AVERROR ( ENOSYS ) ;
if ( st - > sample_aspect_ratio . num ) {
int64_t d_width = av_rescale ( codec - > width , st - > sample_aspect_ratio . num , st - > sample_aspect_ratio . den ) ;
if ( d_width > INT_MAX ) {
av_log ( s , AV_LOG_ERROR , " Overflow in display width \n " ) ;
return AVERROR ( EINVAL ) ;
}
if ( mkv - > mode ! = MODE_WEBM | | codec - > codec_id ! = AV_CODEC_ID_WEBVTT )
native_id = MATROSKA_TRACK_TYPE_SUBTITLE ;
put_ebml_uint ( pb , MATROSKA_ID_TRACKTYPE , native_id ) ;
break ;
default :
av_log ( s , AV_LOG_ERROR , " Only audio, video, and subtitles are supported for Matroska. \n " ) ;
return AVERROR ( EINVAL ) ;
put_ebml_uint ( pb , MATROSKA_ID_VIDEODISPLAYWIDTH , d_width / display_width_div ) ;
put_ebml_uint ( pb , MATROSKA_ID_VIDEODISPLAYHEIGHT , codec - > height / display_height_div ) ;
} else if ( display_width_div ! = 1 | | display_height_div ! = 1 ) {
put_ebml_uint ( pb , MATROSKA_ID_VIDEODISPLAYWIDTH , codec - > width / display_width_div ) ;
put_ebml_uint ( pb , MATROSKA_ID_VIDEODISPLAYHEIGHT , codec - > height / display_height_div ) ;
}
if ( mkv - > mode ! = MODE_WEBM | | codec - > codec_id ! = AV_CODEC_ID_WEBVTT ) {
ret = mkv_write_codecprivate ( s , pb , codec , native_id , qt_id ) ;
if ( ret < 0 )
return ret ;
if ( codec - > codec_id = = AV_CODEC_ID_RAWVIDEO ) {
uint32_t color_space = av_le2ne32 ( codec - > codec_tag ) ;
put_ebml_binary ( pb , MATROSKA_ID_VIDEOCOLORSPACE , & color_space , sizeof ( color_space ) ) ;
}
end_ebml_master ( pb , subinfo ) ;
break ;
case AVMEDIA_TYPE_AUDIO :
put_ebml_uint ( pb , MATROSKA_ID_TRACKTYPE , MATROSKA_TRACK_TYPE_AUDIO ) ;
if ( ! native_id )
// no mkv-specific ID, use ACM mode
put_ebml_string ( pb , MATROSKA_ID_CODECID , " A_MS/ACM " ) ;
subinfo = start_ebml_master ( pb , MATROSKA_ID_TRACKAUDIO , 0 ) ;
put_ebml_uint ( pb , MATROSKA_ID_AUDIOCHANNELS , codec - > channels ) ;
put_ebml_float ( pb , MATROSKA_ID_AUDIOSAMPLINGFREQ , sample_rate ) ;
if ( output_sample_rate )
put_ebml_float ( pb , MATROSKA_ID_AUDIOOUTSAMPLINGFREQ , output_sample_rate ) ;
if ( bit_depth )
put_ebml_uint ( pb , MATROSKA_ID_AUDIOBITDEPTH , bit_depth ) ;
end_ebml_master ( pb , subinfo ) ;
break ;
case AVMEDIA_TYPE_SUBTITLE :
if ( ! native_id ) {
av_log ( s , AV_LOG_ERROR , " Subtitle codec %d is not supported. \n " , codec - > codec_id ) ;
return AVERROR ( ENOSYS ) ;
}
if ( mkv - > mode ! = MODE_WEBM | | codec - > codec_id ! = AV_CODEC_ID_WEBVTT )
native_id = MATROSKA_TRACK_TYPE_SUBTITLE ;
put_ebml_uint ( pb , MATROSKA_ID_TRACKTYPE , native_id ) ;
break ;
default :
av_log ( s , AV_LOG_ERROR , " Only audio, video, and subtitles are supported for Matroska. \n " ) ;
return AVERROR ( EINVAL ) ;
}
end_ebml_master ( pb , track ) ;
if ( mkv - > mode ! = MODE_WEBM | | codec - > codec_id ! = AV_CODEC_ID_WEBVTT ) {
ret = mkv_write_codecprivate ( s , pb , codec , native_id , qt_id ) ;
if ( ret < 0 )
return ret ;
}
end_ebml_master ( pb , track ) ;
return 0 ;
}
static int mkv_write_tracks ( AVFormatContext * s )
{
MatroskaMuxContext * mkv = s - > priv_data ;
AVIOContext * pb = s - > pb ;
ebml_master tracks ;
int i , ret , default_stream_exists = 0 ;
ret = mkv_add_seekhead_entry ( mkv - > main_seekhead , MATROSKA_ID_TRACKS , avio_tell ( pb ) ) ;
if ( ret < 0 )
return ret ;
tracks = start_ebml_master ( pb , MATROSKA_ID_TRACKS , 0 ) ;
for ( i = 0 ; i < s - > nb_streams ; i + + ) {
AVStream * st = s - > streams [ i ] ;
default_stream_exists | = st - > disposition & AV_DISPOSITION_DEFAULT ;
}
for ( i = 0 ; i < s - > nb_streams ; i + + ) {
ret = mkv_write_track ( s , mkv , i , pb , default_stream_exists ) ;
if ( ret < 0 )
return ret ;
}
end_ebml_master ( pb , tracks ) ;
return 0 ;