@ -73,6 +73,7 @@ static const AVOption options[] = {
{ " brand " , " Override major brand " , offsetof ( MOVMuxContext , major_brand ) , AV_OPT_TYPE_STRING , { . str = NULL } , . flags = AV_OPT_FLAG_ENCODING_PARAM } ,
{ " brand " , " Override major brand " , offsetof ( MOVMuxContext , major_brand ) , AV_OPT_TYPE_STRING , { . str = NULL } , . flags = AV_OPT_FLAG_ENCODING_PARAM } ,
{ " use_editlist " , " use edit list " , offsetof ( MOVMuxContext , use_editlist ) , AV_OPT_TYPE_INT , { . i64 = - 1 } , - 1 , 1 , AV_OPT_FLAG_ENCODING_PARAM } ,
{ " use_editlist " , " use edit list " , offsetof ( MOVMuxContext , use_editlist ) , AV_OPT_TYPE_INT , { . i64 = - 1 } , - 1 , 1 , AV_OPT_FLAG_ENCODING_PARAM } ,
{ " fragment_index " , " Fragment number of the next fragment " , offsetof ( MOVMuxContext , fragments ) , AV_OPT_TYPE_INT , { . i64 = 1 } , 1 , INT_MAX , AV_OPT_FLAG_ENCODING_PARAM } ,
{ " fragment_index " , " Fragment number of the next fragment " , offsetof ( MOVMuxContext , fragments ) , AV_OPT_TYPE_INT , { . i64 = 1 } , 1 , INT_MAX , AV_OPT_FLAG_ENCODING_PARAM } ,
{ " frag_interleave " , " Interleave samples within fragments (max number of consecutive samples, lower is tighter interleaving, but with more overhead) " , offsetof ( MOVMuxContext , frag_interleave ) , AV_OPT_TYPE_INT , { . i64 = 0 } , 0 , INT_MAX , AV_OPT_FLAG_ENCODING_PARAM } ,
{ NULL } ,
{ NULL } ,
} ;
} ;
@ -3118,6 +3119,32 @@ static void mov_parse_vc1_frame(AVPacket *pkt, MOVTrack *trk)
}
}
}
}
static int mov_flush_fragment_interleaving ( AVFormatContext * s , MOVTrack * track )
{
MOVMuxContext * mov = s - > priv_data ;
int ret , buf_size ;
uint8_t * buf ;
int i , offset ;
if ( ! track - > mdat_buf )
return 0 ;
if ( ! mov - > mdat_buf ) {
if ( ( ret = avio_open_dyn_buf ( & mov - > mdat_buf ) ) < 0 )
return ret ;
}
buf_size = avio_close_dyn_buf ( track - > mdat_buf , & buf ) ;
track - > mdat_buf = NULL ;
offset = avio_tell ( mov - > mdat_buf ) ;
avio_write ( mov - > mdat_buf , buf , buf_size ) ;
av_free ( buf ) ;
for ( i = track - > entries_flushed ; i < track - > entry ; i + + )
track - > cluster [ i ] . pos + = offset ;
track - > entries_flushed = track - > entry ;
return 0 ;
}
static int mov_flush_fragment ( AVFormatContext * s )
static int mov_flush_fragment ( AVFormatContext * s )
{
{
MOVMuxContext * mov = s - > priv_data ;
MOVMuxContext * mov = s - > priv_data ;
@ -3180,14 +3207,28 @@ static int mov_flush_fragment(AVFormatContext *s)
return 0 ;
return 0 ;
}
}
if ( mov - > frag_interleave ) {
for ( i = 0 ; i < mov - > nb_streams ; i + + ) {
MOVTrack * track = & mov - > tracks [ i ] ;
int ret ;
if ( ( ret = mov_flush_fragment_interleaving ( s , track ) ) < 0 )
return ret ;
}
if ( ! mov - > mdat_buf )
return 0 ;
mdat_size = avio_tell ( mov - > mdat_buf ) ;
}
for ( i = 0 ; i < mov - > nb_streams ; i + + ) {
for ( i = 0 ; i < mov - > nb_streams ; i + + ) {
MOVTrack * track = & mov - > tracks [ i ] ;
MOVTrack * track = & mov - > tracks [ i ] ;
if ( mov - > flags & FF_MOV_FLAG_SEPARATE_MOOF )
if ( mov - > flags & FF_MOV_FLAG_SEPARATE_MOOF | | mov - > frag_interleave )
track - > data_offset = 0 ;
track - > data_offset = 0 ;
else
else
track - > data_offset = mdat_size ;
track - > data_offset = mdat_size ;
if ( ! track - > mdat_buf )
if ( ! track - > entry )
continue ;
continue ;
if ( track - > mdat_buf )
mdat_size + = avio_tell ( track - > mdat_buf ) ;
mdat_size + = avio_tell ( track - > mdat_buf ) ;
if ( first_track < 0 )
if ( first_track < 0 )
first_track = i ;
first_track = i ;
@ -3227,10 +3268,18 @@ static int mov_flush_fragment(AVFormatContext *s)
if ( track - > entry )
if ( track - > entry )
track - > frag_start + = duration ;
track - > frag_start + = duration ;
track - > entry = 0 ;
track - > entry = 0 ;
track - > entries_flushed = 0 ;
if ( ! mov - > frag_interleave ) {
if ( ! track - > mdat_buf )
if ( ! track - > mdat_buf )
continue ;
continue ;
buf_size = avio_close_dyn_buf ( track - > mdat_buf , & buf ) ;
buf_size = avio_close_dyn_buf ( track - > mdat_buf , & buf ) ;
track - > mdat_buf = NULL ;
track - > mdat_buf = NULL ;
} else {
if ( ! mov - > mdat_buf )
continue ;
buf_size = avio_close_dyn_buf ( mov - > mdat_buf , & buf ) ;
mov - > mdat_buf = NULL ;
}
avio_write ( s - > pb , buf , buf_size ) ;
avio_write ( s - > pb , buf , buf_size ) ;
av_free ( buf ) ;
av_free ( buf ) ;
@ -3269,6 +3318,13 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
if ( mov - > flags & FF_MOV_FLAG_FRAGMENT ) {
if ( mov - > flags & FF_MOV_FLAG_FRAGMENT ) {
int ret ;
int ret ;
if ( mov - > moov_written | | mov - > flags & FF_MOV_FLAG_EMPTY_MOOV ) {
if ( mov - > moov_written | | mov - > flags & FF_MOV_FLAG_EMPTY_MOOV ) {
if ( mov - > frag_interleave & & mov - > fragments > 0 ) {
if ( trk - > entry - trk - > entries_flushed > = mov - > frag_interleave ) {
if ( ( ret = mov_flush_fragment_interleaving ( s , trk ) ) < 0 )
return ret ;
}
}
if ( ! trk - > mdat_buf ) {
if ( ! trk - > mdat_buf ) {
if ( ( ret = avio_open_dyn_buf ( & trk - > mdat_buf ) ) < 0 )
if ( ( ret = avio_open_dyn_buf ( & trk - > mdat_buf ) ) < 0 )
return ret ;
return ret ;
@ -3741,6 +3797,21 @@ static int mov_write_header(AVFormatContext *s)
if ( ! mov - > use_editlist & & s - > avoid_negative_ts = = AVFMT_AVOID_NEG_TS_AUTO )
if ( ! mov - > use_editlist & & s - > avoid_negative_ts = = AVFMT_AVOID_NEG_TS_AUTO )
s - > avoid_negative_ts = AVFMT_AVOID_NEG_TS_MAKE_ZERO ;
s - > avoid_negative_ts = AVFMT_AVOID_NEG_TS_MAKE_ZERO ;
/* Clear the omit_tfhd_offset flag if default_base_moof is set;
* if the latter is set that ' s enough and omit_tfhd_offset doesn ' t
* add anything extra on top of that . */
if ( mov - > flags & FF_MOV_FLAG_OMIT_TFHD_OFFSET & &
mov - > flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF )
mov - > flags & = ~ FF_MOV_FLAG_OMIT_TFHD_OFFSET ;
if ( mov - > frag_interleave & &
mov - > flags & ( FF_MOV_FLAG_OMIT_TFHD_OFFSET | FF_MOV_FLAG_SEPARATE_MOOF ) ) {
av_log ( s , AV_LOG_ERROR ,
" Sample interleaving in fragments is mutually exclusive with "
" omit_tfhd_offset and separate_moof \n " ) ;
return AVERROR ( EINVAL ) ;
}
/* Non-seekable output is ok if using fragmentation. If ism_lookahead
/* Non-seekable output is ok if using fragmentation. If ism_lookahead
* is enabled , we don ' t support non - seekable output at all . */
* is enabled , we don ' t support non - seekable output at all . */
if ( ! s - > pb - > seekable & &
if ( ! s - > pb - > seekable & &