@ -67,6 +67,7 @@ static const AVOption options[] = {
{ " dash " , " Write DASH compatible fragmented MP4 " , 0 , AV_OPT_TYPE_CONST , { . i64 = FF_MOV_FLAG_DASH } , INT_MIN , INT_MAX , AV_OPT_FLAG_ENCODING_PARAM , " movflags " } ,
{ " frag_discont " , " Signal that the next fragment is discontinuous from earlier ones " , 0 , AV_OPT_TYPE_CONST , { . i64 = FF_MOV_FLAG_FRAG_DISCONT } , INT_MIN , INT_MAX , AV_OPT_FLAG_ENCODING_PARAM , " movflags " } ,
{ " delay_moov " , " Delay writing the initial moov until the first fragment is cut, or until the first fragment flush " , 0 , AV_OPT_TYPE_CONST , { . i64 = FF_MOV_FLAG_DELAY_MOOV } , INT_MIN , INT_MAX , AV_OPT_FLAG_ENCODING_PARAM , " movflags " } ,
{ " write_colr " , " Write colr atom " , 0 , AV_OPT_TYPE_CONST , { . i64 = FF_MOV_FLAG_WRITE_COLR } , INT_MIN , INT_MAX , AV_OPT_FLAG_ENCODING_PARAM , " movflags " } ,
FF_RTP_FLAG_OPTS ( MOVMuxContext , rtp_flags ) ,
{ " skip_iods " , " Skip writing iods atom. " , offsetof ( MOVMuxContext , iods_skip ) , AV_OPT_TYPE_INT , { . i64 = 1 } , 0 , 1 , AV_OPT_FLAG_ENCODING_PARAM } ,
{ " iods_audio_profile " , " iods audio profile atom. " , offsetof ( MOVMuxContext , iods_audio_profile ) , AV_OPT_TYPE_INT , { . i64 = - 1 } , - 1 , 255 , AV_OPT_FLAG_ENCODING_PARAM } ,
@ -1499,6 +1500,66 @@ static int mov_write_pasp_tag(AVIOContext *pb, MOVTrack *track)
return 16 ;
}
static int mov_write_colr_tag ( AVIOContext * pb , MOVTrack * track )
{
// Ref: https://developer.apple.com/library/mac/technotes/tn2162/_index.html#//apple_ref/doc/uid/DTS40013070-CH1-TNTAG9
if ( track - > enc - > color_primaries = = AVCOL_PRI_UNSPECIFIED & &
track - > enc - > color_trc = = AVCOL_TRC_UNSPECIFIED & &
track - > enc - > colorspace = = AVCOL_SPC_UNSPECIFIED ) {
if ( ( track - > enc - > width > = 1920 & & track - > enc - > height > = 1080 )
| | ( track - > enc - > width = = 1280 & & track - > enc - > height = = 720 ) ) {
av_log ( NULL , AV_LOG_WARNING , " color primaries unspecified, assuming bt709 \n " ) ;
track - > enc - > color_primaries = AVCOL_PRI_BT709 ;
} else if ( track - > enc - > width = = 720 & & track - > height = = 576 ) {
av_log ( NULL , AV_LOG_WARNING , " color primaries unspecified, assuming bt470bg \n " ) ;
track - > enc - > color_primaries = AVCOL_PRI_BT470BG ;
} else if ( track - > enc - > width = = 720 & &
( track - > height = = 486 | | track - > height = = 480 ) ) {
av_log ( NULL , AV_LOG_WARNING , " color primaries unspecified, assuming smpte170 \n " ) ;
track - > enc - > color_primaries = AVCOL_PRI_SMPTE170M ;
} else {
av_log ( NULL , AV_LOG_WARNING , " color primaries unspecified, unable to assume anything \n " ) ;
}
switch ( track - > enc - > color_primaries ) {
case AVCOL_PRI_BT709 :
track - > enc - > color_trc = AVCOL_TRC_BT709 ;
track - > enc - > colorspace = AVCOL_SPC_BT709 ;
break ;
case AVCOL_PRI_SMPTE170M :
case AVCOL_PRI_BT470BG :
track - > enc - > color_trc = AVCOL_TRC_BT709 ;
track - > enc - > colorspace = AVCOL_SPC_SMPTE170M ;
break ;
}
}
avio_wb32 ( pb , 18 ) ;
ffio_wfourcc ( pb , " colr " ) ;
ffio_wfourcc ( pb , " nclc " ) ;
switch ( track - > enc - > color_primaries ) {
case AVCOL_PRI_BT709 : avio_wb16 ( pb , 1 ) ; break ;
case AVCOL_PRI_SMPTE170M :
case AVCOL_PRI_SMPTE240M : avio_wb16 ( pb , 6 ) ; break ;
case AVCOL_PRI_BT470BG : avio_wb16 ( pb , 5 ) ; break ;
default : avio_wb16 ( pb , 2 ) ;
}
switch ( track - > enc - > color_trc ) {
case AVCOL_TRC_BT709 : avio_wb16 ( pb , 1 ) ; break ;
case AVCOL_TRC_SMPTE170M : avio_wb16 ( pb , 1 ) ; break ; // remapped
case AVCOL_TRC_SMPTE240M : avio_wb16 ( pb , 7 ) ; break ;
default : avio_wb16 ( pb , 2 ) ;
}
switch ( track - > enc - > colorspace ) {
case AVCOL_TRC_BT709 : avio_wb16 ( pb , 1 ) ; break ;
case AVCOL_PRI_SMPTE170M : avio_wb16 ( pb , 6 ) ; break ;
case AVCOL_PRI_SMPTE240M : avio_wb16 ( pb , 7 ) ; break ;
default : avio_wb16 ( pb , 2 ) ;
}
return 18 ;
}
static void find_compressor ( char * compressor_name , int len , MOVTrack * track )
{
AVDictionaryEntry * encoder ;
@ -1527,7 +1588,7 @@ static void find_compressor(char * compressor_name, int len, MOVTrack *track)
}
}
static int mov_write_video_tag ( AVIOContext * pb , MOVTrack * track )
static int mov_write_video_tag ( AVIOContext * pb , MOVMuxContext * mov , MOV Track * track )
{
int64_t pos = avio_tell ( pb ) ;
char compressor_name [ 32 ] = { 0 } ;
@ -1605,6 +1666,9 @@ static int mov_write_video_tag(AVIOContext *pb, MOVTrack *track)
if ( track - > enc - > field_order ! = AV_FIELD_UNKNOWN )
mov_write_fiel_tag ( pb , track ) ;
if ( mov - > flags & FF_MOV_FLAG_WRITE_COLR )
mov_write_colr_tag ( pb , track ) ;
if ( track - > enc - > sample_aspect_ratio . den & & track - > enc - > sample_aspect_ratio . num & &
track - > enc - > sample_aspect_ratio . den ! = track - > enc - > sample_aspect_ratio . num ) {
mov_write_pasp_tag ( pb , track ) ;
@ -1695,7 +1759,7 @@ static int mov_write_tmcd_tag(AVIOContext *pb, MOVTrack *track)
return update_size ( pb , pos ) ;
}
static int mov_write_stsd_tag ( AVIOContext * pb , MOVTrack * track )
static int mov_write_stsd_tag ( AVIOContext * pb , MOVMuxContext * mov , MOV Track * track )
{
int64_t pos = avio_tell ( pb ) ;
avio_wb32 ( pb , 0 ) ; /* size */
@ -1703,7 +1767,7 @@ static int mov_write_stsd_tag(AVIOContext *pb, MOVTrack *track)
avio_wb32 ( pb , 0 ) ; /* version & flags */
avio_wb32 ( pb , 1 ) ; /* entry count */
if ( track - > enc - > codec_type = = AVMEDIA_TYPE_VIDEO )
mov_write_video_tag ( pb , track ) ;
mov_write_video_tag ( pb , mov , track ) ;
else if ( track - > enc - > codec_type = = AVMEDIA_TYPE_AUDIO )
mov_write_audio_tag ( pb , track ) ;
else if ( track - > enc - > codec_type = = AVMEDIA_TYPE_SUBTITLE )
@ -1807,14 +1871,14 @@ static int mov_write_dref_tag(AVIOContext *pb)
return 28 ;
}
static int mov_write_stbl_tag ( AVIOContext * pb , MOVTrack * track )
static int mov_write_stbl_tag ( AVIOContext * pb , MOVMuxContext * mov , MOV Track * track )
{
int64_t pos = avio_tell ( pb ) ;
int ret ;
avio_wb32 ( pb , 0 ) ; /* size */
ffio_wfourcc ( pb , " stbl " ) ;
mov_write_stsd_tag ( pb , track ) ;
mov_write_stsd_tag ( pb , mov , track ) ;
mov_write_stts_tag ( pb , track ) ;
if ( ( track - > enc - > codec_type = = AVMEDIA_TYPE_VIDEO | |
track - > enc - > codec_tag = = MKTAG ( ' r ' , ' t ' , ' p ' , ' ' ) ) & &
@ -2032,7 +2096,7 @@ static int mov_write_hmhd_tag(AVIOContext *pb)
return 28 ;
}
static int mov_write_minf_tag ( AVIOContext * pb , MOVTrack * track )
static int mov_write_minf_tag ( AVIOContext * pb , MOVMuxContext * mov , MOV Track * track )
{
int64_t pos = avio_tell ( pb ) ;
int ret ;
@ -2057,7 +2121,7 @@ static int mov_write_minf_tag(AVIOContext *pb, MOVTrack *track)
if ( track - > mode = = MODE_MOV ) /* FIXME: Why do it for MODE_MOV only ? */
mov_write_hdlr_tag ( pb , NULL ) ;
mov_write_dinf_tag ( pb ) ;
if ( ( ret = mov_write_stbl_tag ( pb , track ) ) < 0 )
if ( ( ret = mov_write_stbl_tag ( pb , mov , track ) ) < 0 )
return ret ;
return update_size ( pb , pos ) ;
}
@ -2111,7 +2175,7 @@ static int mov_write_mdia_tag(AVIOContext *pb, MOVMuxContext *mov,
ffio_wfourcc ( pb , " mdia " ) ;
mov_write_mdhd_tag ( pb , mov , track ) ;
mov_write_hdlr_tag ( pb , track ) ;
if ( ( ret = mov_write_minf_tag ( pb , track ) ) < 0 )
if ( ( ret = mov_write_minf_tag ( pb , mov , track ) ) < 0 )
return ret ;
return update_size ( pb , pos ) ;
}