@ -187,6 +187,10 @@ typedef struct {
int64_t first_essence_length ;
KLVPacket current_klv_data ;
int current_klv_index ;
int run_in ;
MXFPartition * current_partition ;
int parsing_backward ;
int64_t last_forward_tell ;
} MXFContext ;
enum MXFWrappingScheme {
@ -441,7 +445,7 @@ static int mxf_read_partition_pack(void *arg, AVIOContext *pb, int tag, int size
if ( ! mxf - > partitions )
return AVERROR ( ENOMEM ) ;
partition = & mxf - > partitions [ mxf - > partitions_count + + ] ;
partition = mxf - > current_partition = & mxf - > partitions [ mxf - > partitions_count + + ] ;
switch ( uid [ 13 ] ) {
case 2 :
@ -1304,34 +1308,134 @@ static int mxf_read_local_tags(MXFContext *mxf, KLVPacket *klv, MXFMetadataReadF
return ctx_size ? mxf_add_metadata_set ( mxf , ctx ) : 0 ;
}
/**
* Seeks to the previous partition , if possible
* @ return < = 0 if we should stop parsing , > 0 if we should keep going
*/
static int mxf_seek_to_previous_partition ( MXFContext * mxf )
{
AVIOContext * pb = mxf - > fc - > pb ;
if ( ! mxf - > current_partition | |
mxf - > run_in + mxf - > current_partition - > previous_partition < = mxf - > last_forward_tell )
return 0 ; /* we've parsed all partitions */
/* seek to previous partition */
avio_seek ( pb , mxf - > run_in + mxf - > current_partition - > previous_partition , SEEK_SET ) ;
mxf - > current_partition = NULL ;
av_dlog ( mxf - > fc , " seeking to previous partition \n " ) ;
return 1 ;
}
/**
* Called when essence is encountered
* @ return < = 0 if we should stop parsing , > 0 if we should keep going
*/
static int mxf_parse_handle_essence ( MXFContext * mxf )
{
AVIOContext * pb = mxf - > fc - > pb ;
int64_t ret ;
if ( ! mxf - > current_partition ) {
av_log ( mxf - > fc , AV_LOG_ERROR , " found essence prior to PartitionPack \n " ) ;
return AVERROR_INVALIDDATA ;
}
if ( mxf - > parsing_backward ) {
return mxf_seek_to_previous_partition ( mxf ) ;
} else {
if ( ! mxf - > footer_partition ) {
av_dlog ( mxf - > fc , " no footer \n " ) ;
return 0 ;
}
av_dlog ( mxf - > fc , " seeking to footer \n " ) ;
/* remember where we were so we don't end up seeking further back than this */
mxf - > last_forward_tell = avio_tell ( pb ) ;
if ( ! pb - > seekable ) {
av_log ( mxf - > fc , AV_LOG_INFO , " file is not seekable - not parsing footer \n " ) ;
return - 1 ;
}
/* seek to footer partition and parse backward */
if ( ( ret = avio_seek ( pb , mxf - > run_in + mxf - > footer_partition , SEEK_SET ) ) < 0 ) {
av_log ( mxf - > fc , AV_LOG_ERROR , " failed to seek to footer @ 0x% " PRIx64 " (% " PRId64 " ) - partial file? \n " ,
mxf - > run_in + mxf - > footer_partition , ret ) ;
return ret ;
}
mxf - > current_partition = NULL ;
mxf - > parsing_backward = 1 ;
}
return 1 ;
}
/**
* Called when the next partition or EOF is encountered
* @ return < = 0 if we should stop parsing , > 0 if we should keep going
*/
static int mxf_parse_handle_partition_or_eof ( MXFContext * mxf )
{
return mxf - > parsing_backward ? mxf_seek_to_previous_partition ( mxf ) : 1 ;
}
static int mxf_read_header ( AVFormatContext * s , AVFormatParameters * ap )
{
MXFContext * mxf = s - > priv_data ;
KLVPacket klv ;
mxf - > last_forward_tell = INT64_MAX ;
if ( ! mxf_read_sync ( s - > pb , mxf_header_partition_pack_key , 14 ) ) {
av_log ( s , AV_LOG_ERROR , " could not find header partition pack key \n " ) ;
return - 1 ;
}
avio_seek ( s - > pb , - 14 , SEEK_CUR ) ;
mxf - > fc = s ;
mxf - > run_in = avio_tell ( s - > pb ) ;
while ( ! url_feof ( s - > pb ) ) {
const MXFMetadataReadTableEntry * metadata ;
if ( klv_read_packet ( & klv , s - > pb ) < 0 )
return - 1 ;
if ( klv_read_packet ( & klv , s - > pb ) < 0 ) {
/* EOF - seek to previous partition or stop */
if ( mxf_parse_handle_partition_or_eof ( mxf ) < = 0 )
break ;
else
continue ;
}
PRINT_KEY ( s , " read header " , klv . key ) ;
av_dlog ( s , " size % " PRIu64 " offset %# " PRIx64 " \n " , klv . length , klv . offset ) ;
if ( IS_KLV_KEY ( klv . key , mxf_encrypted_triplet_key ) | |
IS_KLV_KEY ( klv . key , mxf_essence_element_key ) ) {
/* FIXME avoid seek */
avio_seek ( s - > pb , klv . offset , SEEK_SET ) ;
break ;
}
IS_KLV_KEY ( klv . key , mxf_essence_element_key ) | |
IS_KLV_KEY ( klv . key , mxf_system_item_key ) ) {
if ( IS_KLV_KEY ( klv . key , mxf_system_item_key ) ) {
mxf - > system_item = 1 ;
avio_skip ( s - > pb , klv . length ) ;
}
if ( ! mxf - > essence_offset )
mxf - > essence_offset = klv . offset ;
if ( ! mxf - > first_essence_kl_length & & IS_KLV_KEY ( klv . key , mxf_essence_element_key ) ) {
mxf - > first_essence_kl_length = avio_tell ( s - > pb ) - klv . offset ;
mxf - > first_essence_length = klv . length ;
}
/* seek to footer, previous partition or stop */
if ( mxf_parse_handle_essence ( mxf ) < = 0 )
break ;
continue ;
} else if ( ! memcmp ( klv . key , mxf_header_partition_pack_key , 13 ) & &
klv . key [ 13 ] > = 2 & & klv . key [ 13 ] < = 4 & & mxf - > current_partition ) {
/* next partition pack - keep going, seek to previous partition or stop */
if ( mxf_parse_handle_partition_or_eof ( mxf ) < = 0 )
break ;
}
for ( metadata = mxf_metadata_read_table ; metadata - > read ; metadata + + ) {
@ -1354,6 +1458,12 @@ static int mxf_read_header(AVFormatContext *s, AVFormatParameters *ap)
if ( ! metadata - > read )
avio_skip ( s - > pb , klv . length ) ;
}
/* FIXME avoid seek */
if ( ! mxf - > essence_offset ) {
av_log ( s , AV_LOG_ERROR , " no essence \n " ) ;
return AVERROR_INVALIDDATA ;
}
avio_seek ( s - > pb , mxf - > essence_offset , SEEK_SET ) ;
return mxf_parse_structural_metadata ( mxf ) ;
}