2008-08-07 05:12:14 +03:00
/*
* MXF demuxer .
2009-01-19 17:46:40 +02:00
* Copyright ( c ) 2006 SmartJog S . A . , Baptiste Coudurier < baptiste dot coudurier at smartjog dot com >
2008-08-07 05:12:14 +03:00
*
* This file is part of FFmpeg .
*
* FFmpeg is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
* version 2.1 of the License , or ( at your option ) any later version .
*
* FFmpeg is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA
*/
/*
* References
* SMPTE 336 M KLV Data Encoding Protocol Using Key - Length - Value
* SMPTE 377 M MXF File Format Specifications
* SMPTE 378 M Operational Pattern 1 a
* SMPTE 379 M MXF Generic Container
* SMPTE 381 M Mapping MPEG Streams into the MXF Generic Container
* SMPTE 382 M Mapping AES3 and Broadcast Wave Audio into the MXF Generic Container
* SMPTE 383 M Mapping DV - DIF Data to the MXF Generic Container
*
* Principle
* Search for Track numbers which will identify essence element KLV packets .
* Search for SourcePackage which define tracks which contains Track numbers .
* Material Package contains tracks with reference to SourcePackage tracks .
* Search for Descriptors ( Picture , Sound ) which contains codec info and parameters .
* Assign Descriptors to correct Tracks .
*
* Metadata reading functions read Local Tags , get InstanceUID ( 0x3C0A ) then add MetaDataSet to MXFContext .
* Metadata parsing resolves Strong References to objects .
*
* Simple demuxer , only OP1A supported and some files might not work at all .
* Only tracks with associated descriptors will be decoded . " Highly Desirable " SMPTE 377 M D .1
*/
//#define DEBUG
# include "libavutil/aes.h"
2011-06-04 14:58:23 +03:00
# include "libavutil/mathematics.h"
2009-02-08 06:42:38 +02:00
# include "libavcodec/bytestream.h"
# include "avformat.h"
2011-10-16 16:03:30 +03:00
# include "internal.h"
2008-08-18 20:54:18 +03:00
# include "mxf.h"
2008-08-07 05:12:14 +03:00
2011-02-07 17:07:41 +02:00
typedef enum {
Header ,
BodyPartition ,
Footer
} MXFPartitionType ;
typedef enum {
OP1a ,
OP1b ,
OP1c ,
OP2a ,
OP2b ,
OP2c ,
OP3a ,
OP3b ,
OP3c ,
OPAtom ,
} MXFOP ;
typedef struct {
int closed ;
int complete ;
MXFPartitionType type ;
uint64_t previous_partition ;
int index_sid ;
int body_sid ;
2011-12-07 19:43:36 +03:00
int64_t this_partition ;
2011-02-07 17:07:41 +02:00
} MXFPartition ;
2008-08-07 05:12:14 +03:00
typedef struct {
UID uid ;
enum MXFMetadataSetType type ;
UID source_container_ul ;
} MXFCryptoContext ;
typedef struct {
UID uid ;
enum MXFMetadataSetType type ;
UID source_package_uid ;
UID data_definition_ul ;
int64_t duration ;
int64_t start_position ;
int source_track_id ;
} MXFStructuralComponent ;
typedef struct {
UID uid ;
enum MXFMetadataSetType type ;
UID data_definition_ul ;
UID * structural_components_refs ;
int structural_components_count ;
int64_t duration ;
} MXFSequence ;
typedef struct {
UID uid ;
enum MXFMetadataSetType type ;
MXFSequence * sequence ; /* mandatory, and only one */
UID sequence_ref ;
int track_id ;
uint8_t track_number [ 4 ] ;
AVRational edit_rate ;
} MXFTrack ;
typedef struct {
UID uid ;
enum MXFMetadataSetType type ;
UID essence_container_ul ;
UID essence_codec_ul ;
AVRational sample_rate ;
AVRational aspect_ratio ;
int width ;
int height ;
int channels ;
int bits_per_sample ;
UID * sub_descriptors_refs ;
int sub_descriptors_count ;
int linked_track_id ;
uint8_t * extradata ;
int extradata_size ;
2010-06-30 10:55:05 +03:00
enum PixelFormat pix_fmt ;
2008-08-07 05:12:14 +03:00
} MXFDescriptor ;
2009-01-08 04:54:43 +02:00
typedef struct {
UID uid ;
enum MXFMetadataSetType type ;
2011-11-09 13:47:57 +03:00
int edit_unit_byte_count ;
int index_sid ;
int body_sid ;
int slice_count ;
AVRational index_edit_rate ;
uint64_t index_start_position ;
uint64_t index_duration ;
int * slice ;
int * element_delta ;
int nb_delta_entries ;
int * flag_entries ;
uint64_t * stream_offset_entries ;
uint32_t * * slice_offset_entries ;
int nb_index_entries ;
2009-01-08 04:54:43 +02:00
} MXFIndexTableSegment ;
2008-08-07 05:12:14 +03:00
typedef struct {
UID uid ;
enum MXFMetadataSetType type ;
UID package_uid ;
UID * tracks_refs ;
int tracks_count ;
MXFDescriptor * descriptor ; /* only one */
UID descriptor_ref ;
} MXFPackage ;
typedef struct {
UID uid ;
enum MXFMetadataSetType type ;
} MXFMetadataSet ;
typedef struct {
2011-02-07 17:07:41 +02:00
MXFPartition * partitions ;
unsigned partitions_count ;
MXFOP op ;
2008-08-07 05:12:14 +03:00
UID * packages_refs ;
int packages_count ;
MXFMetadataSet * * metadata_sets ;
int metadata_sets_count ;
AVFormatContext * fc ;
struct AVAES * aesc ;
uint8_t * local_tags ;
int local_tags_count ;
2011-10-07 16:48:00 +03:00
uint64_t footer_partition ;
2011-11-11 17:01:34 +03:00
int system_item ;
2011-11-09 13:47:57 +03:00
int64_t essence_offset ;
int first_essence_kl_length ;
int64_t first_essence_length ;
KLVPacket current_klv_data ;
int current_klv_index ;
2011-03-14 18:00:21 +02:00
int run_in ;
MXFPartition * current_partition ;
int parsing_backward ;
int64_t last_forward_tell ;
2011-12-08 13:06:23 +03:00
int last_forward_partition ;
2008-08-07 05:12:14 +03:00
} MXFContext ;
enum MXFWrappingScheme {
Frame ,
Clip ,
} ;
2011-02-20 12:04:12 +02:00
typedef int MXFMetadataReadFunc ( void * arg , AVIOContext * pb , int tag , int size , UID uid ) ;
2010-07-01 20:10:31 +03:00
2008-08-07 05:12:14 +03:00
typedef struct {
const UID key ;
2010-07-01 20:10:31 +03:00
MXFMetadataReadFunc * read ;
2008-08-07 05:12:14 +03:00
int ctx_size ;
enum MXFMetadataSetType type ;
} MXFMetadataReadTableEntry ;
/* partial keys to match */
static const uint8_t mxf_header_partition_pack_key [ ] = { 0x06 , 0x0e , 0x2b , 0x34 , 0x02 , 0x05 , 0x01 , 0x01 , 0x0d , 0x01 , 0x02 , 0x01 , 0x01 , 0x02 } ;
static const uint8_t mxf_essence_element_key [ ] = { 0x06 , 0x0e , 0x2b , 0x34 , 0x01 , 0x02 , 0x01 , 0x01 , 0x0d , 0x01 , 0x03 , 0x01 } ;
2011-11-11 17:01:34 +03:00
static const uint8_t mxf_system_item_key [ ] = { 0x06 , 0x0E , 0x2B , 0x34 , 0x02 , 0x05 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x04 } ;
2008-08-07 05:12:14 +03:00
static const uint8_t mxf_klv_key [ ] = { 0x06 , 0x0e , 0x2b , 0x34 } ;
/* complete keys to match */
static const uint8_t mxf_crypto_source_container_ul [ ] = { 0x06 , 0x0e , 0x2b , 0x34 , 0x01 , 0x01 , 0x01 , 0x09 , 0x06 , 0x01 , 0x01 , 0x02 , 0x02 , 0x00 , 0x00 , 0x00 } ;
static const uint8_t mxf_encrypted_triplet_key [ ] = { 0x06 , 0x0e , 0x2b , 0x34 , 0x02 , 0x04 , 0x01 , 0x07 , 0x0d , 0x01 , 0x03 , 0x01 , 0x02 , 0x7e , 0x01 , 0x00 } ;
static const uint8_t mxf_encrypted_essence_container [ ] = { 0x06 , 0x0e , 0x2b , 0x34 , 0x04 , 0x01 , 0x01 , 0x07 , 0x0d , 0x01 , 0x03 , 0x01 , 0x02 , 0x0b , 0x01 , 0x00 } ;
static const uint8_t mxf_sony_mpeg4_extradata [ ] = { 0x06 , 0x0e , 0x2b , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x0e , 0x06 , 0x06 , 0x02 , 0x02 , 0x01 , 0x00 , 0x00 } ;
# define IS_KLV_KEY(x, y) (!memcmp(x, y, sizeof(y)))
2011-02-20 12:04:12 +02:00
static int64_t klv_decode_ber_length ( AVIOContext * pb )
2008-08-07 05:12:14 +03:00
{
2011-02-21 17:43:01 +02:00
uint64_t size = avio_r8 ( pb ) ;
2008-08-07 05:12:14 +03:00
if ( size & 0x80 ) { /* long form */
int bytes_num = size & 0x7f ;
/* SMPTE 379M 5.3.4 guarantee that bytes_num must not exceed 8 bytes */
if ( bytes_num > 8 )
return - 1 ;
size = 0 ;
while ( bytes_num - - )
2011-02-21 17:43:01 +02:00
size = size < < 8 | avio_r8 ( pb ) ;
2008-08-07 05:12:14 +03:00
}
return size ;
}
2011-02-20 12:04:12 +02:00
static int mxf_read_sync ( AVIOContext * pb , const uint8_t * key , unsigned size )
2008-08-07 05:12:14 +03:00
{
int i , b ;
for ( i = 0 ; i < size & & ! url_feof ( pb ) ; i + + ) {
2011-02-21 17:43:01 +02:00
b = avio_r8 ( pb ) ;
2008-08-07 05:12:14 +03:00
if ( b = = key [ 0 ] )
i = 0 ;
else if ( b ! = key [ i ] )
i = - 1 ;
}
return i = = size ;
}
2011-02-20 12:04:12 +02:00
static int klv_read_packet ( KLVPacket * klv , AVIOContext * pb )
2008-08-07 05:12:14 +03:00
{
if ( ! mxf_read_sync ( pb , mxf_klv_key , 4 ) )
return - 1 ;
2011-03-03 21:11:45 +02:00
klv - > offset = avio_tell ( pb ) - 4 ;
2008-08-07 05:12:14 +03:00
memcpy ( klv - > key , mxf_klv_key , 4 ) ;
2011-02-21 17:43:01 +02:00
avio_read ( pb , klv - > key + 4 , 12 ) ;
2008-08-07 05:12:14 +03:00
klv - > length = klv_decode_ber_length ( pb ) ;
return klv - > length = = - 1 ? - 1 : 0 ;
}
static int mxf_get_stream_index ( AVFormatContext * s , KLVPacket * klv )
{
int i ;
for ( i = 0 ; i < s - > nb_streams ; i + + ) {
MXFTrack * track = s - > streams [ i ] - > priv_data ;
/* SMPTE 379M 7.3 */
if ( ! memcmp ( klv - > key + sizeof ( mxf_essence_element_key ) , track - > track_number , sizeof ( track - > track_number ) ) )
return i ;
}
/* return 0 if only one stream, for OP Atom files with 0 as track number */
return s - > nb_streams = = 1 ? 0 : - 1 ;
}
/* XXX: use AVBitStreamFilter */
2011-02-20 12:04:12 +02:00
static int mxf_get_d10_aes3_packet ( AVIOContext * pb , AVStream * st , AVPacket * pkt , int64_t length )
2008-08-07 05:12:14 +03:00
{
const uint8_t * buf_ptr , * end_ptr ;
uint8_t * data_ptr ;
int i ;
if ( length > 61444 ) /* worst case PAL 1920 samples 8 channels */
return - 1 ;
2011-10-08 04:41:06 +03:00
length = av_get_packet ( pb , pkt , length ) ;
if ( length < 0 )
return length ;
2008-08-07 05:12:14 +03:00
data_ptr = pkt - > data ;
2009-11-21 01:12:55 +02:00
end_ptr = pkt - > data + length ;
buf_ptr = pkt - > data + 4 ; /* skip SMPTE 331M header */
2011-10-08 04:41:06 +03:00
for ( ; buf_ptr + st - > codec - > channels * 4 < end_ptr ; ) {
2008-08-07 05:12:14 +03:00
for ( i = 0 ; i < st - > codec - > channels ; i + + ) {
uint32_t sample = bytestream_get_le32 ( & buf_ptr ) ;
2008-09-08 17:24:59 +03:00
if ( st - > codec - > bits_per_coded_sample = = 24 )
2008-08-07 05:12:14 +03:00
bytestream_put_le24 ( & data_ptr , ( sample > > 4 ) & 0xffffff ) ;
else
bytestream_put_le16 ( & data_ptr , ( sample > > 12 ) & 0xffff ) ;
}
buf_ptr + = 32 - st - > codec - > channels * 4 ; // always 8 channels stored SMPTE 331M
}
2011-10-08 04:41:06 +03:00
av_shrink_packet ( pkt , data_ptr - pkt - > data ) ;
2008-08-07 05:12:14 +03:00
return 0 ;
}
static int mxf_decrypt_triplet ( AVFormatContext * s , AVPacket * pkt , KLVPacket * klv )
{
static const uint8_t checkv [ 16 ] = { 0x43 , 0x48 , 0x55 , 0x4b , 0x43 , 0x48 , 0x55 , 0x4b , 0x43 , 0x48 , 0x55 , 0x4b , 0x43 , 0x48 , 0x55 , 0x4b } ;
MXFContext * mxf = s - > priv_data ;
2011-02-20 12:04:12 +02:00
AVIOContext * pb = s - > pb ;
2011-03-03 21:11:45 +02:00
int64_t end = avio_tell ( pb ) + klv - > length ;
2011-11-07 21:14:54 +03:00
int64_t size ;
2008-08-07 05:12:14 +03:00
uint64_t orig_size ;
uint64_t plaintext_size ;
uint8_t ivec [ 16 ] ;
uint8_t tmpbuf [ 16 ] ;
int index ;
if ( ! mxf - > aesc & & s - > key & & s - > keylen = = 16 ) {
mxf - > aesc = av_malloc ( av_aes_size ) ;
if ( ! mxf - > aesc )
return - 1 ;
av_aes_init ( mxf - > aesc , s - > key , 128 , 1 ) ;
}
// crypto context
2011-03-15 10:14:38 +02:00
avio_skip ( pb , klv_decode_ber_length ( pb ) ) ;
2008-08-07 05:12:14 +03:00
// plaintext offset
klv_decode_ber_length ( pb ) ;
2011-02-21 17:43:01 +02:00
plaintext_size = avio_rb64 ( pb ) ;
2008-08-07 05:12:14 +03:00
// source klv key
klv_decode_ber_length ( pb ) ;
2011-02-21 17:43:01 +02:00
avio_read ( pb , klv - > key , 16 ) ;
2008-08-07 05:12:14 +03:00
if ( ! IS_KLV_KEY ( klv , mxf_essence_element_key ) )
return - 1 ;
index = mxf_get_stream_index ( s , klv ) ;
if ( index < 0 )
return - 1 ;
// source size
klv_decode_ber_length ( pb ) ;
2011-02-21 17:43:01 +02:00
orig_size = avio_rb64 ( pb ) ;
2008-08-07 05:12:14 +03:00
if ( orig_size < plaintext_size )
return - 1 ;
// enc. code
size = klv_decode_ber_length ( pb ) ;
if ( size < 32 | | size - 32 < orig_size )
return - 1 ;
2011-02-21 17:43:01 +02:00
avio_read ( pb , ivec , 16 ) ;
avio_read ( pb , tmpbuf , 16 ) ;
2008-08-07 05:12:14 +03:00
if ( mxf - > aesc )
av_aes_crypt ( mxf - > aesc , tmpbuf , tmpbuf , 1 , ivec , 1 ) ;
if ( memcmp ( tmpbuf , checkv , 16 ) )
av_log ( s , AV_LOG_ERROR , " probably incorrect decryption key \n " ) ;
size - = 32 ;
2011-10-08 04:41:06 +03:00
size = av_get_packet ( pb , pkt , size ) ;
if ( size < 0 )
return size ;
else if ( size < plaintext_size )
return AVERROR_INVALIDDATA ;
2008-08-07 05:12:14 +03:00
size - = plaintext_size ;
if ( mxf - > aesc )
av_aes_crypt ( mxf - > aesc , & pkt - > data [ plaintext_size ] ,
& pkt - > data [ plaintext_size ] , size > > 4 , ivec , 1 ) ;
2011-10-08 04:41:06 +03:00
av_shrink_packet ( pkt , orig_size ) ;
2008-08-07 05:12:14 +03:00
pkt - > stream_index = index ;
2011-03-15 10:14:38 +02:00
avio_skip ( pb , end - avio_tell ( pb ) ) ;
2008-08-07 05:12:14 +03:00
return 0 ;
}
static int mxf_read_packet ( AVFormatContext * s , AVPacket * pkt )
{
KLVPacket klv ;
while ( ! url_feof ( s - > pb ) ) {
if ( klv_read_packet ( & klv , s - > pb ) < 0 )
return - 1 ;
PRINT_KEY ( s , " read packet " , klv . key ) ;
2011-05-29 22:07:35 +03:00
av_dlog ( s , " size % " PRIu64 " offset %# " PRIx64 " \n " , klv . length , klv . offset ) ;
2008-08-07 05:12:14 +03:00
if ( IS_KLV_KEY ( klv . key , mxf_encrypted_triplet_key ) ) {
int res = mxf_decrypt_triplet ( s , pkt , & klv ) ;
if ( res < 0 ) {
av_log ( s , AV_LOG_ERROR , " invalid encoded triplet \n " ) ;
return - 1 ;
}
return 0 ;
}
if ( IS_KLV_KEY ( klv . key , mxf_essence_element_key ) ) {
int index = mxf_get_stream_index ( s , & klv ) ;
if ( index < 0 ) {
2008-09-09 05:56:13 +03:00
av_log ( s , AV_LOG_ERROR , " error getting stream index %d \n " , AV_RB32 ( klv . key + 12 ) ) ;
2008-08-07 05:12:14 +03:00
goto skip ;
}
if ( s - > streams [ index ] - > discard = = AVDISCARD_ALL )
goto skip ;
/* check for 8 channels AES3 element */
if ( klv . key [ 12 ] = = 0x06 & & klv . key [ 13 ] = = 0x01 & & klv . key [ 14 ] = = 0x10 ) {
if ( mxf_get_d10_aes3_packet ( s - > pb , s - > streams [ index ] , pkt , klv . length ) < 0 ) {
av_log ( s , AV_LOG_ERROR , " error reading D-10 aes3 frame \n " ) ;
return - 1 ;
}
2011-10-08 04:41:06 +03:00
} else {
int ret = av_get_packet ( s - > pb , pkt , klv . length ) ;
if ( ret < 0 )
return ret ;
}
2008-08-07 05:12:14 +03:00
pkt - > stream_index = index ;
pkt - > pos = klv . offset ;
return 0 ;
} else
skip :
2011-03-15 10:14:38 +02:00
avio_skip ( s - > pb , klv . length ) ;
2008-08-07 05:12:14 +03:00
}
2009-05-30 09:16:44 +03:00
return AVERROR_EOF ;
2008-08-07 05:12:14 +03:00
}
2011-02-20 12:04:12 +02:00
static int mxf_read_primer_pack ( void * arg , AVIOContext * pb , int tag , int size , UID uid )
2008-08-07 05:12:14 +03:00
{
2010-07-01 20:10:31 +03:00
MXFContext * mxf = arg ;
2011-02-21 17:43:01 +02:00
int item_num = avio_rb32 ( pb ) ;
int item_len = avio_rb32 ( pb ) ;
2008-08-07 05:12:14 +03:00
if ( item_len ! = 18 ) {
av_log ( mxf - > fc , AV_LOG_ERROR , " unsupported primer pack item length \n " ) ;
return - 1 ;
}
if ( item_num > UINT_MAX / item_len )
return - 1 ;
mxf - > local_tags_count = item_num ;
mxf - > local_tags = av_malloc ( item_num * item_len ) ;
if ( ! mxf - > local_tags )
return - 1 ;
2011-02-21 17:43:01 +02:00
avio_read ( pb , mxf - > local_tags , item_num * item_len ) ;
2008-08-07 05:12:14 +03:00
return 0 ;
}
2011-11-14 02:36:45 +03:00
static int mxf_read_partition_pack ( void * arg , AVIOContext * pb , int tag , int size , UID uid )
2011-02-07 17:07:41 +02:00
{
MXFContext * mxf = arg ;
MXFPartition * partition ;
UID op ;
2011-10-07 16:48:00 +03:00
uint64_t footer_partition ;
2011-02-07 17:07:41 +02:00
if ( mxf - > partitions_count + 1 > = UINT_MAX / sizeof ( * mxf - > partitions ) )
return AVERROR ( ENOMEM ) ;
mxf - > partitions = av_realloc ( mxf - > partitions , ( mxf - > partitions_count + 1 ) * sizeof ( * mxf - > partitions ) ) ;
if ( ! mxf - > partitions )
return AVERROR ( ENOMEM ) ;
2011-12-08 13:06:23 +03:00
if ( mxf - > parsing_backward ) {
/* insert the new partition pack in the middle
* this makes the entries in mxf - > partitions sorted by offset */
memmove ( & mxf - > partitions [ mxf - > last_forward_partition + 1 ] ,
& mxf - > partitions [ mxf - > last_forward_partition ] ,
( mxf - > partitions_count - mxf - > last_forward_partition ) * sizeof ( * mxf - > partitions ) ) ;
partition = mxf - > current_partition = & mxf - > partitions [ mxf - > last_forward_partition ] ;
} else {
mxf - > last_forward_partition + + ;
partition = mxf - > current_partition = & mxf - > partitions [ mxf - > partitions_count ] ;
}
memset ( partition , 0 , sizeof ( * partition ) ) ;
mxf - > partitions_count + + ;
2011-02-07 17:07:41 +02:00
switch ( uid [ 13 ] ) {
case 2 :
partition - > type = Header ;
break ;
case 3 :
partition - > type = BodyPartition ;
break ;
case 4 :
partition - > type = Footer ;
break ;
default :
av_log ( mxf - > fc , AV_LOG_ERROR , " unknown partition type %i \n " , uid [ 13 ] ) ;
return AVERROR_INVALIDDATA ;
}
/* consider both footers to be closed (there is only Footer and CompleteFooter) */
partition - > closed = partition - > type = = Footer | | ! ( uid [ 14 ] & 1 ) ;
partition - > complete = uid [ 14 ] > 2 ;
2011-12-07 19:43:36 +03:00
avio_skip ( pb , 8 ) ;
partition - > this_partition = avio_rb64 ( pb ) ;
2011-02-07 17:07:41 +02:00
partition - > previous_partition = avio_rb64 ( pb ) ;
2011-10-07 16:48:00 +03:00
footer_partition = avio_rb64 ( pb ) ;
2011-02-07 17:07:41 +02:00
avio_skip ( pb , 16 ) ;
partition - > index_sid = avio_rb32 ( pb ) ;
avio_skip ( pb , 8 ) ;
partition - > body_sid = avio_rb32 ( pb ) ;
avio_read ( pb , op , sizeof ( UID ) ) ;
2011-10-07 16:48:00 +03:00
/* some files don'thave FooterPartition set in every partition */
if ( footer_partition ) {
if ( mxf - > footer_partition & & mxf - > footer_partition ! = footer_partition ) {
av_log ( mxf - > fc , AV_LOG_ERROR , " inconsistent FooterPartition value: %li != %li \n " ,
mxf - > footer_partition , footer_partition ) ;
} else {
mxf - > footer_partition = footer_partition ;
}
}
2011-12-07 19:43:36 +03:00
av_dlog ( mxf - > fc , " PartitionPack: ThisPartition = 0x%lx, PreviousPartition = 0x%lx, "
2011-02-07 17:07:41 +02:00
" FooterPartition = 0x%lx, IndexSID = %i, BodySID = %i \n " ,
2011-12-07 19:43:36 +03:00
partition - > this_partition ,
2011-10-07 16:48:00 +03:00
partition - > previous_partition , footer_partition ,
2011-02-07 17:07:41 +02:00
partition - > index_sid , partition - > body_sid ) ;
if ( op [ 12 ] = = 1 & & op [ 13 ] = = 1 ) mxf - > op = OP1a ;
else if ( op [ 12 ] = = 1 & & op [ 13 ] = = 2 ) mxf - > op = OP1b ;
else if ( op [ 12 ] = = 1 & & op [ 13 ] = = 3 ) mxf - > op = OP1c ;
else if ( op [ 12 ] = = 2 & & op [ 13 ] = = 1 ) mxf - > op = OP2a ;
else if ( op [ 12 ] = = 2 & & op [ 13 ] = = 2 ) mxf - > op = OP2b ;
else if ( op [ 12 ] = = 2 & & op [ 13 ] = = 3 ) mxf - > op = OP2c ;
else if ( op [ 12 ] = = 3 & & op [ 13 ] = = 1 ) mxf - > op = OP3a ;
else if ( op [ 12 ] = = 3 & & op [ 13 ] = = 2 ) mxf - > op = OP3b ;
else if ( op [ 12 ] = = 3 & & op [ 13 ] = = 3 ) mxf - > op = OP3c ;
else if ( op [ 12 ] = = 0x10 ) mxf - > op = OPAtom ;
else
av_log ( mxf - > fc , AV_LOG_ERROR , " unknown operational pattern: %02xh %02xh \n " , op [ 12 ] , op [ 13 ] ) ;
return 0 ;
}
2008-08-07 05:12:14 +03:00
static int mxf_add_metadata_set ( MXFContext * mxf , void * metadata_set )
{
2009-03-21 02:50:51 +02:00
if ( mxf - > metadata_sets_count + 1 > = UINT_MAX / sizeof ( * mxf - > metadata_sets ) )
return AVERROR ( ENOMEM ) ;
2008-08-07 05:12:14 +03:00
mxf - > metadata_sets = av_realloc ( mxf - > metadata_sets , ( mxf - > metadata_sets_count + 1 ) * sizeof ( * mxf - > metadata_sets ) ) ;
if ( ! mxf - > metadata_sets )
return - 1 ;
mxf - > metadata_sets [ mxf - > metadata_sets_count ] = metadata_set ;
mxf - > metadata_sets_count + + ;
return 0 ;
}
2011-02-20 12:04:12 +02:00
static int mxf_read_cryptographic_context ( void * arg , AVIOContext * pb , int tag , int size , UID uid )
2008-08-07 05:12:14 +03:00
{
2010-07-01 20:10:31 +03:00
MXFCryptoContext * cryptocontext = arg ;
2008-08-07 05:12:14 +03:00
if ( size ! = 16 )
return - 1 ;
if ( IS_KLV_KEY ( uid , mxf_crypto_source_container_ul ) )
2011-02-21 17:43:01 +02:00
avio_read ( pb , cryptocontext - > source_container_ul , 16 ) ;
2008-08-07 05:12:14 +03:00
return 0 ;
}
2011-02-20 12:04:12 +02:00
static int mxf_read_content_storage ( void * arg , AVIOContext * pb , int tag , int size , UID uid )
2008-08-07 05:12:14 +03:00
{
2010-07-01 20:10:31 +03:00
MXFContext * mxf = arg ;
2008-08-07 05:12:14 +03:00
switch ( tag ) {
case 0x1901 :
2011-02-21 17:43:01 +02:00
mxf - > packages_count = avio_rb32 ( pb ) ;
2008-08-07 05:12:14 +03:00
if ( mxf - > packages_count > = UINT_MAX / sizeof ( UID ) )
return - 1 ;
mxf - > packages_refs = av_malloc ( mxf - > packages_count * sizeof ( UID ) ) ;
if ( ! mxf - > packages_refs )
return - 1 ;
2011-03-15 10:14:38 +02:00
avio_skip ( pb , 4 ) ; /* useless size of objects, always 16 according to specs */
2011-02-21 17:43:01 +02:00
avio_read ( pb , ( uint8_t * ) mxf - > packages_refs , mxf - > packages_count * sizeof ( UID ) ) ;
2008-08-07 05:12:14 +03:00
break ;
}
return 0 ;
}
2011-02-20 12:04:12 +02:00
static int mxf_read_source_clip ( void * arg , AVIOContext * pb , int tag , int size , UID uid )
2008-08-07 05:12:14 +03:00
{
2010-07-01 20:10:31 +03:00
MXFStructuralComponent * source_clip = arg ;
2008-08-07 05:12:14 +03:00
switch ( tag ) {
case 0x0202 :
2011-02-21 17:43:01 +02:00
source_clip - > duration = avio_rb64 ( pb ) ;
2008-08-07 05:12:14 +03:00
break ;
case 0x1201 :
2011-02-21 17:43:01 +02:00
source_clip - > start_position = avio_rb64 ( pb ) ;
2008-08-07 05:12:14 +03:00
break ;
case 0x1101 :
/* UMID, only get last 16 bytes */
2011-03-15 10:14:38 +02:00
avio_skip ( pb , 16 ) ;
2011-02-21 17:43:01 +02:00
avio_read ( pb , source_clip - > source_package_uid , 16 ) ;
2008-08-07 05:12:14 +03:00
break ;
case 0x1102 :
2011-02-21 17:43:01 +02:00
source_clip - > source_track_id = avio_rb32 ( pb ) ;
2008-08-07 05:12:14 +03:00
break ;
}
return 0 ;
}
2011-02-20 12:04:12 +02:00
static int mxf_read_material_package ( void * arg , AVIOContext * pb , int tag , int size , UID uid )
2008-08-07 05:12:14 +03:00
{
2010-07-01 20:10:31 +03:00
MXFPackage * package = arg ;
2008-08-07 05:12:14 +03:00
switch ( tag ) {
case 0x4403 :
2011-02-21 17:43:01 +02:00
package - > tracks_count = avio_rb32 ( pb ) ;
2008-08-07 05:12:14 +03:00
if ( package - > tracks_count > = UINT_MAX / sizeof ( UID ) )
return - 1 ;
package - > tracks_refs = av_malloc ( package - > tracks_count * sizeof ( UID ) ) ;
if ( ! package - > tracks_refs )
return - 1 ;
2011-03-15 10:14:38 +02:00
avio_skip ( pb , 4 ) ; /* useless size of objects, always 16 according to specs */
2011-02-21 17:43:01 +02:00
avio_read ( pb , ( uint8_t * ) package - > tracks_refs , package - > tracks_count * sizeof ( UID ) ) ;
2008-08-07 05:12:14 +03:00
break ;
}
return 0 ;
}
2011-02-20 12:04:12 +02:00
static int mxf_read_track ( void * arg , AVIOContext * pb , int tag , int size , UID uid )
2008-08-07 05:12:14 +03:00
{
2010-07-01 20:10:31 +03:00
MXFTrack * track = arg ;
2008-08-07 05:12:14 +03:00
switch ( tag ) {
case 0x4801 :
2011-02-21 17:43:01 +02:00
track - > track_id = avio_rb32 ( pb ) ;
2008-08-07 05:12:14 +03:00
break ;
case 0x4804 :
2011-02-21 17:43:01 +02:00
avio_read ( pb , track - > track_number , 4 ) ;
2008-08-07 05:12:14 +03:00
break ;
case 0x4B01 :
2011-02-21 17:43:01 +02:00
track - > edit_rate . den = avio_rb32 ( pb ) ;
track - > edit_rate . num = avio_rb32 ( pb ) ;
2008-08-07 05:12:14 +03:00
break ;
case 0x4803 :
2011-02-21 17:43:01 +02:00
avio_read ( pb , track - > sequence_ref , 16 ) ;
2008-08-07 05:12:14 +03:00
break ;
}
return 0 ;
}
2011-02-20 12:04:12 +02:00
static int mxf_read_sequence ( void * arg , AVIOContext * pb , int tag , int size , UID uid )
2008-08-07 05:12:14 +03:00
{
2010-07-01 20:10:31 +03:00
MXFSequence * sequence = arg ;
2008-08-07 05:12:14 +03:00
switch ( tag ) {
case 0x0202 :
2011-02-21 17:43:01 +02:00
sequence - > duration = avio_rb64 ( pb ) ;
2008-08-07 05:12:14 +03:00
break ;
case 0x0201 :
2011-02-21 17:43:01 +02:00
avio_read ( pb , sequence - > data_definition_ul , 16 ) ;
2008-08-07 05:12:14 +03:00
break ;
case 0x1001 :
2011-02-21 17:43:01 +02:00
sequence - > structural_components_count = avio_rb32 ( pb ) ;
2008-08-07 05:12:14 +03:00
if ( sequence - > structural_components_count > = UINT_MAX / sizeof ( UID ) )
return - 1 ;
sequence - > structural_components_refs = av_malloc ( sequence - > structural_components_count * sizeof ( UID ) ) ;
if ( ! sequence - > structural_components_refs )
return - 1 ;
2011-03-15 10:14:38 +02:00
avio_skip ( pb , 4 ) ; /* useless size of objects, always 16 according to specs */
2011-02-21 17:43:01 +02:00
avio_read ( pb , ( uint8_t * ) sequence - > structural_components_refs , sequence - > structural_components_count * sizeof ( UID ) ) ;
2008-08-07 05:12:14 +03:00
break ;
}
return 0 ;
}
2011-02-20 12:04:12 +02:00
static int mxf_read_source_package ( void * arg , AVIOContext * pb , int tag , int size , UID uid )
2008-08-07 05:12:14 +03:00
{
2010-07-01 20:10:31 +03:00
MXFPackage * package = arg ;
2008-08-07 05:12:14 +03:00
switch ( tag ) {
case 0x4403 :
2011-02-21 17:43:01 +02:00
package - > tracks_count = avio_rb32 ( pb ) ;
2008-08-07 05:12:14 +03:00
if ( package - > tracks_count > = UINT_MAX / sizeof ( UID ) )
return - 1 ;
package - > tracks_refs = av_malloc ( package - > tracks_count * sizeof ( UID ) ) ;
if ( ! package - > tracks_refs )
return - 1 ;
2011-03-15 10:14:38 +02:00
avio_skip ( pb , 4 ) ; /* useless size of objects, always 16 according to specs */
2011-02-21 17:43:01 +02:00
avio_read ( pb , ( uint8_t * ) package - > tracks_refs , package - > tracks_count * sizeof ( UID ) ) ;
2008-08-07 05:12:14 +03:00
break ;
case 0x4401 :
/* UMID, only get last 16 bytes */
2011-03-15 10:14:38 +02:00
avio_skip ( pb , 16 ) ;
2011-02-21 17:43:01 +02:00
avio_read ( pb , package - > package_uid , 16 ) ;
2008-08-07 05:12:14 +03:00
break ;
case 0x4701 :
2011-02-21 17:43:01 +02:00
avio_read ( pb , package - > descriptor_ref , 16 ) ;
2008-08-07 05:12:14 +03:00
break ;
}
return 0 ;
}
2011-11-09 13:47:57 +03:00
static int mxf_read_delta_entry_array ( AVIOContext * pb , MXFIndexTableSegment * segment )
{
int i , length ;
segment - > nb_delta_entries = avio_rb32 ( pb ) ;
length = avio_rb32 ( pb ) ;
if ( ! ( segment - > slice = av_calloc ( segment - > nb_delta_entries , sizeof ( * segment - > slice ) ) ) | |
! ( segment - > element_delta = av_calloc ( segment - > nb_delta_entries , sizeof ( * segment - > element_delta ) ) ) )
return AVERROR ( ENOMEM ) ;
for ( i = 0 ; i < segment - > nb_delta_entries ; i + + ) {
avio_r8 ( pb ) ; /* PosTableIndex */
segment - > slice [ i ] = avio_r8 ( pb ) ;
segment - > element_delta [ i ] = avio_rb32 ( pb ) ;
}
return 0 ;
}
static int mxf_read_index_entry_array ( AVIOContext * pb , MXFIndexTableSegment * segment )
{
int i , j , length ;
segment - > nb_index_entries = avio_rb32 ( pb ) ;
length = avio_rb32 ( pb ) ;
if ( ! ( segment - > flag_entries = av_calloc ( segment - > nb_index_entries , sizeof ( * segment - > flag_entries ) ) ) | |
! ( segment - > stream_offset_entries = av_calloc ( segment - > nb_index_entries , sizeof ( * segment - > stream_offset_entries ) ) ) )
return AVERROR ( ENOMEM ) ;
if ( segment - > slice_count & &
! ( segment - > slice_offset_entries = av_calloc ( segment - > nb_index_entries , sizeof ( * segment - > slice_offset_entries ) ) ) )
return AVERROR ( ENOMEM ) ;
for ( i = 0 ; i < segment - > nb_index_entries ; i + + ) {
avio_rb16 ( pb ) ; /* TemporalOffset and KeyFrameOffset */
segment - > flag_entries [ i ] = avio_r8 ( pb ) ;
segment - > stream_offset_entries [ i ] = avio_rb64 ( pb ) ;
if ( segment - > slice_count ) {
if ( ! ( segment - > slice_offset_entries [ i ] = av_calloc ( segment - > slice_count , sizeof ( * * segment - > slice_offset_entries ) ) ) )
return AVERROR ( ENOMEM ) ;
for ( j = 0 ; j < segment - > slice_count ; j + + )
segment - > slice_offset_entries [ i ] [ j ] = avio_rb32 ( pb ) ;
}
avio_skip ( pb , length - 11 - 4 * segment - > slice_count ) ;
}
return 0 ;
}
2011-02-20 12:04:12 +02:00
static int mxf_read_index_table_segment ( void * arg , AVIOContext * pb , int tag , int size , UID uid )
2009-01-08 04:54:43 +02:00
{
2011-11-09 13:47:57 +03:00
MXFIndexTableSegment * segment = arg ;
2009-01-08 04:54:43 +02:00
switch ( tag ) {
2011-11-09 13:47:57 +03:00
case 0x3F05 :
segment - > edit_unit_byte_count = avio_rb32 ( pb ) ;
av_dlog ( NULL , " EditUnitByteCount %d \n " , segment - > edit_unit_byte_count ) ;
break ;
case 0x3F06 :
segment - > index_sid = avio_rb32 ( pb ) ;
av_dlog ( NULL , " IndexSID %d \n " , segment - > index_sid ) ;
break ;
case 0x3F07 :
segment - > body_sid = avio_rb32 ( pb ) ;
av_dlog ( NULL , " BodySID %d \n " , segment - > body_sid ) ;
break ;
case 0x3F08 :
segment - > slice_count = avio_r8 ( pb ) ;
av_dlog ( NULL , " SliceCount %d \n " , segment - > slice_count ) ;
break ;
case 0x3F09 :
av_dlog ( NULL , " DeltaEntryArray found \n " ) ;
return mxf_read_delta_entry_array ( pb , segment ) ;
case 0x3F0A :
av_dlog ( NULL , " IndexEntryArray found \n " ) ;
return mxf_read_index_entry_array ( pb , segment ) ;
case 0x3F0B :
segment - > index_edit_rate . num = avio_rb32 ( pb ) ;
segment - > index_edit_rate . den = avio_rb32 ( pb ) ;
av_dlog ( NULL , " IndexEditRate %d/%d \n " , segment - > index_edit_rate . num ,
segment - > index_edit_rate . den ) ;
break ;
case 0x3F0C :
segment - > index_start_position = avio_rb64 ( pb ) ;
av_dlog ( NULL , " IndexStartPosition % " PRId64 " \n " , segment - > index_start_position ) ;
break ;
case 0x3F0D :
segment - > index_duration = avio_rb64 ( pb ) ;
av_dlog ( NULL , " IndexDuration % " PRId64 " \n " , segment - > index_duration ) ;
break ;
2009-01-08 04:54:43 +02:00
}
return 0 ;
}
2011-02-20 12:04:12 +02:00
static void mxf_read_pixel_layout ( AVIOContext * pb , MXFDescriptor * descriptor )
2008-08-07 05:12:14 +03:00
{
2010-06-30 10:55:05 +03:00
int code , value , ofs = 0 ;
2010-07-21 20:27:28 +03:00
char layout [ 16 ] = { 0 } ;
2008-08-07 05:12:14 +03:00
do {
2011-02-21 17:43:01 +02:00
code = avio_r8 ( pb ) ;
value = avio_r8 ( pb ) ;
2011-01-29 18:46:18 +02:00
av_dlog ( NULL , " pixel layout: code %#x \n " , code ) ;
2010-06-30 10:55:05 +03:00
if ( ofs < 16 ) {
layout [ ofs + + ] = code ;
layout [ ofs + + ] = value ;
2008-08-07 05:12:14 +03:00
}
} while ( code ! = 0 ) ; /* SMPTE 377M E.2.46 */
2010-06-30 10:55:05 +03:00
ff_mxf_decode_pixel_layout ( layout , & descriptor - > pix_fmt ) ;
2008-08-07 05:12:14 +03:00
}
2011-02-20 12:04:12 +02:00
static int mxf_read_generic_descriptor ( void * arg , AVIOContext * pb , int tag , int size , UID uid )
2008-08-07 05:12:14 +03:00
{
2010-07-01 20:10:31 +03:00
MXFDescriptor * descriptor = arg ;
2008-08-07 05:12:14 +03:00
switch ( tag ) {
case 0x3F01 :
2011-02-21 17:43:01 +02:00
descriptor - > sub_descriptors_count = avio_rb32 ( pb ) ;
2008-08-07 05:12:14 +03:00
if ( descriptor - > sub_descriptors_count > = UINT_MAX / sizeof ( UID ) )
return - 1 ;
descriptor - > sub_descriptors_refs = av_malloc ( descriptor - > sub_descriptors_count * sizeof ( UID ) ) ;
if ( ! descriptor - > sub_descriptors_refs )
return - 1 ;
2011-03-15 10:14:38 +02:00
avio_skip ( pb , 4 ) ; /* useless size of objects, always 16 according to specs */
2011-02-21 17:43:01 +02:00
avio_read ( pb , ( uint8_t * ) descriptor - > sub_descriptors_refs , descriptor - > sub_descriptors_count * sizeof ( UID ) ) ;
2008-08-07 05:12:14 +03:00
break ;
case 0x3004 :
2011-02-21 17:43:01 +02:00
avio_read ( pb , descriptor - > essence_container_ul , 16 ) ;
2008-08-07 05:12:14 +03:00
break ;
case 0x3006 :
2011-02-21 17:43:01 +02:00
descriptor - > linked_track_id = avio_rb32 ( pb ) ;
2008-08-07 05:12:14 +03:00
break ;
case 0x3201 : /* PictureEssenceCoding */
2011-02-21 17:43:01 +02:00
avio_read ( pb , descriptor - > essence_codec_ul , 16 ) ;
2008-08-07 05:12:14 +03:00
break ;
case 0x3203 :
2011-02-21 17:43:01 +02:00
descriptor - > width = avio_rb32 ( pb ) ;
2008-08-07 05:12:14 +03:00
break ;
case 0x3202 :
2011-02-21 17:43:01 +02:00
descriptor - > height = avio_rb32 ( pb ) ;
2008-08-07 05:12:14 +03:00
break ;
case 0x320E :
2011-02-21 17:43:01 +02:00
descriptor - > aspect_ratio . num = avio_rb32 ( pb ) ;
descriptor - > aspect_ratio . den = avio_rb32 ( pb ) ;
2008-08-07 05:12:14 +03:00
break ;
case 0x3D03 :
2011-02-21 17:43:01 +02:00
descriptor - > sample_rate . num = avio_rb32 ( pb ) ;
descriptor - > sample_rate . den = avio_rb32 ( pb ) ;
2008-08-07 05:12:14 +03:00
break ;
case 0x3D06 : /* SoundEssenceCompression */
2011-02-21 17:43:01 +02:00
avio_read ( pb , descriptor - > essence_codec_ul , 16 ) ;
2008-08-07 05:12:14 +03:00
break ;
case 0x3D07 :
2011-02-21 17:43:01 +02:00
descriptor - > channels = avio_rb32 ( pb ) ;
2008-08-07 05:12:14 +03:00
break ;
case 0x3D01 :
2011-02-21 17:43:01 +02:00
descriptor - > bits_per_sample = avio_rb32 ( pb ) ;
2008-08-07 05:12:14 +03:00
break ;
case 0x3401 :
mxf_read_pixel_layout ( pb , descriptor ) ;
break ;
default :
/* Private uid used by SONY C0023S01.mxf */
if ( IS_KLV_KEY ( uid , mxf_sony_mpeg4_extradata ) ) {
2011-07-30 01:27:36 +03:00
descriptor - > extradata = av_malloc ( size + FF_INPUT_BUFFER_PADDING_SIZE ) ;
2008-08-07 05:12:14 +03:00
if ( ! descriptor - > extradata )
return - 1 ;
descriptor - > extradata_size = size ;
2011-02-21 17:43:01 +02:00
avio_read ( pb , descriptor - > extradata , size ) ;
2008-08-07 05:12:14 +03:00
}
break ;
}
return 0 ;
}
/*
* Match an uid independently of the version byte and up to len common bytes
* Returns : boolean
*/
static int mxf_match_uid ( const UID key , const UID uid , int len )
{
int i ;
for ( i = 0 ; i < len ; i + + ) {
if ( i ! = 7 & & key [ i ] ! = uid [ i ] )
return 0 ;
}
return 1 ;
}
static const MXFCodecUL * mxf_get_codec_ul ( const MXFCodecUL * uls , UID * uid )
{
2009-02-08 07:12:30 +02:00
while ( uls - > uid [ 0 ] ) {
2008-08-07 05:12:14 +03:00
if ( mxf_match_uid ( uls - > uid , * uid , uls - > matching_len ) )
break ;
uls + + ;
}
return uls ;
}
static void * mxf_resolve_strong_ref ( MXFContext * mxf , UID * strong_ref , enum MXFMetadataSetType type )
{
int i ;
if ( ! strong_ref )
return NULL ;
for ( i = 0 ; i < mxf - > metadata_sets_count ; i + + ) {
if ( ! memcmp ( * strong_ref , mxf - > metadata_sets [ i ] - > uid , 16 ) & &
( type = = AnyType | | mxf - > metadata_sets [ i ] - > type = = type ) ) {
return mxf - > metadata_sets [ i ] ;
}
}
return NULL ;
}
2008-08-31 04:39:42 +03:00
static const MXFCodecUL mxf_essence_container_uls [ ] = {
// video essence container uls
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x02 , 0x0D , 0x01 , 0x03 , 0x01 , 0x02 , 0x04 , 0x60 , 0x01 } , 14 , CODEC_ID_MPEG2VIDEO } , /* MPEG-ES Frame wrapped */
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x02 , 0x02 , 0x41 , 0x01 } , 14 , CODEC_ID_DVVIDEO } , /* DV 625 25mbps */
// sound essence container uls
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x02 , 0x06 , 0x01 , 0x00 } , 14 , CODEC_ID_PCM_S16LE } , /* BWF Frame wrapped */
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x02 , 0x0D , 0x01 , 0x03 , 0x01 , 0x02 , 0x04 , 0x40 , 0x01 } , 14 , CODEC_ID_MP2 } , /* MPEG-ES Frame wrapped, 0x40 ??? stream id */
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x02 , 0x01 , 0x01 , 0x01 } , 14 , CODEC_ID_PCM_S16LE } , /* D-10 Mapping 50Mbps PAL Extended Template */
2011-11-28 11:53:10 +03:00
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0xFF , 0x4B , 0x46 , 0x41 , 0x41 , 0x00 , 0x0D , 0x4D , 0x4F } , 14 , CODEC_ID_PCM_S16LE } , /* 0001GL00.MXF.A1.mxf_opatom.mxf */
2008-08-31 04:39:42 +03:00
{ { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } , 0 , CODEC_ID_NONE } ,
} ;
2011-11-09 13:47:57 +03:00
static int mxf_get_sorted_table_segments ( MXFContext * mxf , int * nb_sorted_segments , MXFIndexTableSegment * * * sorted_segments )
{
int i , j , nb_segments = 0 ;
MXFIndexTableSegment * * unsorted_segments ;
int last_body_sid = - 1 , last_index_sid = - 1 , last_index_start = - 1 ;
/* count number of segments, allocate arrays and copy unsorted segments */
for ( i = 0 ; i < mxf - > metadata_sets_count ; i + + )
if ( mxf - > metadata_sets [ i ] - > type = = IndexTableSegment )
nb_segments + + ;
if ( ! ( unsorted_segments = av_calloc ( nb_segments , sizeof ( * unsorted_segments ) ) ) | |
! ( * sorted_segments = av_calloc ( nb_segments , sizeof ( * * sorted_segments ) ) ) ) {
av_free ( unsorted_segments ) ;
return AVERROR ( ENOMEM ) ;
}
for ( i = j = 0 ; i < mxf - > metadata_sets_count ; i + + )
if ( mxf - > metadata_sets [ i ] - > type = = IndexTableSegment )
unsorted_segments [ j + + ] = ( MXFIndexTableSegment * ) mxf - > metadata_sets [ i ] ;
* nb_sorted_segments = 0 ;
/* sort segments by {BodySID, IndexSID, IndexStartPosition}, remove duplicates while we're at it */
for ( i = 0 ; i < nb_segments ; i + + ) {
int best = - 1 , best_body_sid = - 1 , best_index_sid = - 1 , best_index_start = - 1 ;
for ( j = 0 ; j < nb_segments ; j + + ) {
MXFIndexTableSegment * s = unsorted_segments [ j ] ;
/* Require larger BosySID, IndexSID or IndexStartPosition then the previous entry. This removes duplicates.
* We want the smallest values for the keys than what we currently have , unless this is the first such entry this time around .
*/
if ( ( i = = 0 | | s - > body_sid > last_body_sid | | s - > index_sid > last_index_sid | | s - > index_start_position > last_index_start ) & &
( best = = - 1 | | s - > body_sid < best_body_sid | | s - > index_sid < best_index_sid | | s - > index_start_position < best_index_start ) ) {
best = j ;
best_body_sid = s - > body_sid ;
best_index_sid = s - > index_sid ;
best_index_start = s - > index_start_position ;
}
}
/* no suitable entry found -> we're done */
if ( best = = - 1 )
break ;
( * sorted_segments ) [ ( * nb_sorted_segments ) + + ] = unsorted_segments [ best ] ;
last_body_sid = best_body_sid ;
last_index_sid = best_index_sid ;
last_index_start = best_index_start ;
}
av_free ( unsorted_segments ) ;
return 0 ;
}
static int mxf_parse_index ( MXFContext * mxf , int i , AVStream * st )
{
int64_t accumulated_offset = 0 ;
int j , k , ret , nb_sorted_segments ;
MXFIndexTableSegment * * sorted_segments ;
if ( ( ret = mxf_get_sorted_table_segments ( mxf , & nb_sorted_segments , & sorted_segments ) ) )
return ret ;
for ( j = 0 ; j < nb_sorted_segments ; j + + ) {
int n_delta = i ;
int duration , sample_duration = 1 , last_sample_size = 0 ;
int64_t segment_size ;
MXFIndexTableSegment * tableseg = sorted_segments [ j ] ;
/* reset accumulated_offset on BodySID change */
if ( j > 0 & & tableseg - > body_sid ! = sorted_segments [ j - 1 ] - > body_sid )
accumulated_offset = 0 ;
/* HACK: How to correctly link between streams and slices? */
2011-11-11 17:01:34 +03:00
if ( i < mxf - > system_item + st - > index )
2011-11-09 13:47:57 +03:00
n_delta + + ;
if ( n_delta > = tableseg - > nb_delta_entries & & st - > index ! = 0 )
continue ;
duration = tableseg - > index_duration > 0 ? tableseg - > index_duration :
st - > duration - st - > nb_index_entries ;
segment_size = tableseg - > edit_unit_byte_count * duration ;
/* check small EditUnitByteCount for audio */
if ( tableseg - > edit_unit_byte_count & & tableseg - > edit_unit_byte_count < 32
& & ! tableseg - > index_duration ) {
/* duration might be prime relative to the new sample_duration,
* which means we need to handle the last frame differently */
sample_duration = 8192 ;
last_sample_size = ( duration % sample_duration ) * tableseg - > edit_unit_byte_count ;
tableseg - > edit_unit_byte_count * = sample_duration ;
duration / = sample_duration ;
if ( last_sample_size ) duration + + ;
}
for ( k = 0 ; k < duration ; k + + ) {
int64_t pos ;
int size , flags = 0 ;
if ( k < tableseg - > nb_index_entries ) {
pos = tableseg - > stream_offset_entries [ k ] ;
if ( n_delta < tableseg - > nb_delta_entries ) {
if ( n_delta < tableseg - > nb_delta_entries - 1 ) {
size =
tableseg - > slice_offset_entries [ k ] [ tableseg - > slice [ n_delta + 1 ] - 1 ] +
tableseg - > element_delta [ n_delta + 1 ] -
tableseg - > element_delta [ n_delta ] ;
if ( tableseg - > slice [ n_delta ] > 0 )
size - = tableseg - > slice_offset_entries [ k ] [ tableseg - > slice [ n_delta ] - 1 ] ;
} else if ( k < duration - 1 ) {
size = tableseg - > stream_offset_entries [ k + 1 ] -
tableseg - > stream_offset_entries [ k ] -
tableseg - > slice_offset_entries [ k ] [ tableseg - > slice [ tableseg - > nb_delta_entries - 1 ] - 1 ] -
tableseg - > element_delta [ tableseg - > nb_delta_entries - 1 ] ;
} else
size = 0 ;
if ( tableseg - > slice [ n_delta ] > 0 )
pos + = tableseg - > slice_offset_entries [ k ] [ tableseg - > slice [ n_delta ] - 1 ] ;
pos + = tableseg - > element_delta [ n_delta ] ;
} else
size = 0 ;
flags = ! ( tableseg - > flag_entries [ k ] & 0x30 ) ? AVINDEX_KEYFRAME : 0 ;
} else {
pos = ( int64_t ) k * tableseg - > edit_unit_byte_count + accumulated_offset ;
if ( n_delta < tableseg - > nb_delta_entries - 1 )
size = tableseg - > element_delta [ n_delta + 1 ] - tableseg - > element_delta [ n_delta ] ;
else {
/* use smaller size for last sample if we should */
if ( last_sample_size & & k = = duration - 1 )
size = last_sample_size ;
else
size = tableseg - > edit_unit_byte_count ;
if ( tableseg - > nb_delta_entries )
size - = tableseg - > element_delta [ tableseg - > nb_delta_entries - 1 ] ;
}
if ( n_delta < tableseg - > nb_delta_entries )
pos + = tableseg - > element_delta [ n_delta ] ;
flags = AVINDEX_KEYFRAME ;
}
if ( k > 0 & & pos < mxf - > first_essence_length & & accumulated_offset = = 0 )
pos + = mxf - > first_essence_kl_length ;
pos + = mxf - > essence_offset ;
av_dlog ( mxf - > fc , " Stream %d IndexEntry %d n_Delta %d Offset % " PRIx64 " Timestamp % " PRId64 " \n " ,
st - > index , st - > nb_index_entries , n_delta , pos , sample_duration * st - > nb_index_entries ) ;
if ( ( ret = av_add_index_entry ( st , pos , sample_duration * st - > nb_index_entries , size , 0 , flags ) ) < 0 )
return ret ;
}
accumulated_offset + = segment_size ;
}
av_free ( sorted_segments ) ;
return 0 ;
}
2008-08-07 05:12:14 +03:00
static int mxf_parse_structural_metadata ( MXFContext * mxf )
{
MXFPackage * material_package = NULL ;
MXFPackage * temp_package = NULL ;
2011-11-09 13:47:57 +03:00
int i , j , k , ret ;
2008-08-07 05:12:14 +03:00
2011-01-29 18:46:18 +02:00
av_dlog ( mxf - > fc , " metadata sets count %d \n " , mxf - > metadata_sets_count ) ;
2008-08-07 05:12:14 +03:00
/* TODO: handle multiple material packages (OP3x) */
for ( i = 0 ; i < mxf - > packages_count ; i + + ) {
material_package = mxf_resolve_strong_ref ( mxf , & mxf - > packages_refs [ i ] , MaterialPackage ) ;
if ( material_package ) break ;
}
if ( ! material_package ) {
av_log ( mxf - > fc , AV_LOG_ERROR , " no material package found \n " ) ;
return - 1 ;
}
for ( i = 0 ; i < material_package - > tracks_count ; i + + ) {
MXFPackage * source_package = NULL ;
MXFTrack * material_track = NULL ;
MXFTrack * source_track = NULL ;
MXFTrack * temp_track = NULL ;
MXFDescriptor * descriptor = NULL ;
MXFStructuralComponent * component = NULL ;
UID * essence_container_ul = NULL ;
const MXFCodecUL * codec_ul = NULL ;
const MXFCodecUL * container_ul = NULL ;
AVStream * st ;
if ( ! ( material_track = mxf_resolve_strong_ref ( mxf , & material_package - > tracks_refs [ i ] , Track ) ) ) {
av_log ( mxf - > fc , AV_LOG_ERROR , " could not resolve material track strong ref \n " ) ;
continue ;
}
if ( ! ( material_track - > sequence = mxf_resolve_strong_ref ( mxf , & material_track - > sequence_ref , Sequence ) ) ) {
av_log ( mxf - > fc , AV_LOG_ERROR , " could not resolve material track sequence strong ref \n " ) ;
2009-10-13 11:08:10 +03:00
continue ;
2008-08-07 05:12:14 +03:00
}
/* TODO: handle multiple source clips */
for ( j = 0 ; j < material_track - > sequence - > structural_components_count ; j + + ) {
/* TODO: handle timecode component */
component = mxf_resolve_strong_ref ( mxf , & material_track - > sequence - > structural_components_refs [ j ] , SourceClip ) ;
if ( ! component )
continue ;
for ( k = 0 ; k < mxf - > packages_count ; k + + ) {
temp_package = mxf_resolve_strong_ref ( mxf , & mxf - > packages_refs [ k ] , SourcePackage ) ;
if ( ! temp_package )
continue ;
if ( ! memcmp ( temp_package - > package_uid , component - > source_package_uid , 16 ) ) {
source_package = temp_package ;
break ;
}
}
if ( ! source_package ) {
av_log ( mxf - > fc , AV_LOG_ERROR , " material track %d: no corresponding source package found \n " , material_track - > track_id ) ;
break ;
}
for ( k = 0 ; k < source_package - > tracks_count ; k + + ) {
if ( ! ( temp_track = mxf_resolve_strong_ref ( mxf , & source_package - > tracks_refs [ k ] , Track ) ) ) {
av_log ( mxf - > fc , AV_LOG_ERROR , " could not resolve source track strong ref \n " ) ;
return - 1 ;
}
if ( temp_track - > track_id = = component - > source_track_id ) {
source_track = temp_track ;
break ;
}
}
if ( ! source_track ) {
av_log ( mxf - > fc , AV_LOG_ERROR , " material track %d: no corresponding source track found \n " , material_track - > track_id ) ;
break ;
}
}
if ( ! source_track )
continue ;
2011-11-28 12:51:00 +03:00
if ( ! ( source_track - > sequence = mxf_resolve_strong_ref ( mxf , & source_track - > sequence_ref , Sequence ) ) ) {
av_log ( mxf - > fc , AV_LOG_ERROR , " could not resolve source track sequence strong ref \n " ) ;
return - 1 ;
}
/* 0001GL00.MXF.A1.mxf_opatom.mxf has the same SourcePackageID as 0001GL.MXF.V1.mxf_opatom.mxf
* This would result in both files appearing to have two streams . Work around this by sanity checking DataDefinition */
if ( memcmp ( material_track - > sequence - > data_definition_ul , source_track - > sequence - > data_definition_ul , 16 ) ) {
av_log ( mxf - > fc , AV_LOG_ERROR , " material track %d: DataDefinition mismatch \n " , material_track - > track_id ) ;
continue ;
}
2011-06-18 12:43:24 +03:00
st = avformat_new_stream ( mxf - > fc , NULL ) ;
2008-08-07 05:12:14 +03:00
if ( ! st ) {
av_log ( mxf - > fc , AV_LOG_ERROR , " could not allocate stream \n " ) ;
return - 1 ;
}
2011-06-18 12:43:24 +03:00
st - > id = source_track - > track_id ;
2008-08-07 05:12:14 +03:00
st - > priv_data = source_track ;
st - > duration = component - > duration ;
if ( st - > duration = = - 1 )
st - > duration = AV_NOPTS_VALUE ;
st - > start_time = component - > start_position ;
2011-11-29 21:28:15 +03:00
avpriv_set_pts_info ( st , 64 , material_track - > edit_rate . num , material_track - > edit_rate . den ) ;
2008-08-07 05:12:14 +03:00
PRINT_KEY ( mxf - > fc , " data definition ul " , source_track - > sequence - > data_definition_ul ) ;
2009-02-08 07:12:30 +02:00
codec_ul = mxf_get_codec_ul ( ff_mxf_data_definition_uls , & source_track - > sequence - > data_definition_ul ) ;
st - > codec - > codec_type = codec_ul - > id ;
2008-08-07 05:12:14 +03:00
source_package - > descriptor = mxf_resolve_strong_ref ( mxf , & source_package - > descriptor_ref , AnyType ) ;
if ( source_package - > descriptor ) {
if ( source_package - > descriptor - > type = = MultipleDescriptor ) {
for ( j = 0 ; j < source_package - > descriptor - > sub_descriptors_count ; j + + ) {
MXFDescriptor * sub_descriptor = mxf_resolve_strong_ref ( mxf , & source_package - > descriptor - > sub_descriptors_refs [ j ] , Descriptor ) ;
if ( ! sub_descriptor ) {
av_log ( mxf - > fc , AV_LOG_ERROR , " could not resolve sub descriptor strong ref \n " ) ;
continue ;
}
if ( sub_descriptor - > linked_track_id = = source_track - > track_id ) {
descriptor = sub_descriptor ;
break ;
}
}
} else if ( source_package - > descriptor - > type = = Descriptor )
descriptor = source_package - > descriptor ;
}
if ( ! descriptor ) {
av_log ( mxf - > fc , AV_LOG_INFO , " source track %d: stream %d, no descriptor found \n " , source_track - > track_id , st - > index ) ;
continue ;
}
PRINT_KEY ( mxf - > fc , " essence codec ul " , descriptor - > essence_codec_ul ) ;
PRINT_KEY ( mxf - > fc , " essence container ul " , descriptor - > essence_container_ul ) ;
essence_container_ul = & descriptor - > essence_container_ul ;
/* HACK: replacing the original key with mxf_encrypted_essence_container
* is not allowed according to s429 - 6 , try to find correct information anyway */
if ( IS_KLV_KEY ( essence_container_ul , mxf_encrypted_essence_container ) ) {
av_log ( mxf - > fc , AV_LOG_INFO , " broken encrypted mxf file \n " ) ;
for ( k = 0 ; k < mxf - > metadata_sets_count ; k + + ) {
MXFMetadataSet * metadata = mxf - > metadata_sets [ k ] ;
if ( metadata - > type = = CryptoContext ) {
essence_container_ul = & ( ( MXFCryptoContext * ) metadata ) - > source_container_ul ;
break ;
}
}
}
/* TODO: drop PictureEssenceCoding and SoundEssenceCompression, only check EssenceContainer */
2008-08-18 20:54:18 +03:00
codec_ul = mxf_get_codec_ul ( ff_mxf_codec_uls , & descriptor - > essence_codec_ul ) ;
2008-08-07 05:12:14 +03:00
st - > codec - > codec_id = codec_ul - > id ;
if ( descriptor - > extradata ) {
st - > codec - > extradata = descriptor - > extradata ;
st - > codec - > extradata_size = descriptor - > extradata_size ;
}
2010-03-31 02:30:55 +03:00
if ( st - > codec - > codec_type = = AVMEDIA_TYPE_VIDEO ) {
2008-08-31 04:39:42 +03:00
container_ul = mxf_get_codec_ul ( mxf_essence_container_uls , essence_container_ul ) ;
2008-08-07 05:12:14 +03:00
if ( st - > codec - > codec_id = = CODEC_ID_NONE )
st - > codec - > codec_id = container_ul - > id ;
st - > codec - > width = descriptor - > width ;
st - > codec - > height = descriptor - > height ;
2010-06-30 10:55:05 +03:00
if ( st - > codec - > codec_id = = CODEC_ID_RAWVIDEO )
st - > codec - > pix_fmt = descriptor - > pix_fmt ;
2008-08-07 05:12:14 +03:00
st - > need_parsing = AVSTREAM_PARSE_HEADERS ;
2010-03-31 02:30:55 +03:00
} else if ( st - > codec - > codec_type = = AVMEDIA_TYPE_AUDIO ) {
2008-08-31 04:39:42 +03:00
container_ul = mxf_get_codec_ul ( mxf_essence_container_uls , essence_container_ul ) ;
2008-08-07 05:12:14 +03:00
if ( st - > codec - > codec_id = = CODEC_ID_NONE )
st - > codec - > codec_id = container_ul - > id ;
st - > codec - > channels = descriptor - > channels ;
2008-09-08 17:24:59 +03:00
st - > codec - > bits_per_coded_sample = descriptor - > bits_per_sample ;
2008-08-07 05:12:14 +03:00
st - > codec - > sample_rate = descriptor - > sample_rate . num / descriptor - > sample_rate . den ;
/* TODO: implement CODEC_ID_RAWAUDIO */
if ( st - > codec - > codec_id = = CODEC_ID_PCM_S16LE ) {
2011-09-27 12:14:59 +03:00
if ( descriptor - > bits_per_sample > 16 & & descriptor - > bits_per_sample < = 24 )
2008-08-07 05:12:14 +03:00
st - > codec - > codec_id = CODEC_ID_PCM_S24LE ;
else if ( descriptor - > bits_per_sample = = 32 )
st - > codec - > codec_id = CODEC_ID_PCM_S32LE ;
} else if ( st - > codec - > codec_id = = CODEC_ID_PCM_S16BE ) {
2011-09-27 12:14:59 +03:00
if ( descriptor - > bits_per_sample > 16 & & descriptor - > bits_per_sample < = 24 )
2008-08-07 05:12:14 +03:00
st - > codec - > codec_id = CODEC_ID_PCM_S24BE ;
else if ( descriptor - > bits_per_sample = = 32 )
st - > codec - > codec_id = CODEC_ID_PCM_S32BE ;
} else if ( st - > codec - > codec_id = = CODEC_ID_MP2 ) {
st - > need_parsing = AVSTREAM_PARSE_FULL ;
}
}
2010-03-31 02:30:55 +03:00
if ( st - > codec - > codec_type ! = AVMEDIA_TYPE_DATA & & ( * essence_container_ul ) [ 15 ] > 0x01 ) {
2008-08-07 05:12:14 +03:00
av_log ( mxf - > fc , AV_LOG_WARNING , " only frame wrapped mappings are correctly supported \n " ) ;
st - > need_parsing = AVSTREAM_PARSE_FULL ;
}
2011-11-09 13:47:57 +03:00
if ( ( ret = mxf_parse_index ( mxf , i , st ) ) )
return ret ;
2008-08-07 05:12:14 +03:00
}
return 0 ;
}
static const MXFMetadataReadTableEntry mxf_metadata_read_table [ ] = {
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x02 , 0x05 , 0x01 , 0x01 , 0x0d , 0x01 , 0x02 , 0x01 , 0x01 , 0x05 , 0x01 , 0x00 } , mxf_read_primer_pack } ,
2011-02-07 17:07:41 +02:00
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x02 , 0x05 , 0x01 , 0x01 , 0x0d , 0x01 , 0x02 , 0x01 , 0x01 , 0x02 , 0x01 , 0x00 } , mxf_read_partition_pack } ,
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x02 , 0x05 , 0x01 , 0x01 , 0x0d , 0x01 , 0x02 , 0x01 , 0x01 , 0x02 , 0x02 , 0x00 } , mxf_read_partition_pack } ,
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x02 , 0x05 , 0x01 , 0x01 , 0x0d , 0x01 , 0x02 , 0x01 , 0x01 , 0x02 , 0x03 , 0x00 } , mxf_read_partition_pack } ,
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x02 , 0x05 , 0x01 , 0x01 , 0x0d , 0x01 , 0x02 , 0x01 , 0x01 , 0x02 , 0x04 , 0x00 } , mxf_read_partition_pack } ,
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x02 , 0x05 , 0x01 , 0x01 , 0x0d , 0x01 , 0x02 , 0x01 , 0x01 , 0x03 , 0x01 , 0x00 } , mxf_read_partition_pack } ,
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x02 , 0x05 , 0x01 , 0x01 , 0x0d , 0x01 , 0x02 , 0x01 , 0x01 , 0x03 , 0x02 , 0x00 } , mxf_read_partition_pack } ,
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x02 , 0x05 , 0x01 , 0x01 , 0x0d , 0x01 , 0x02 , 0x01 , 0x01 , 0x03 , 0x03 , 0x00 } , mxf_read_partition_pack } ,
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x02 , 0x05 , 0x01 , 0x01 , 0x0d , 0x01 , 0x02 , 0x01 , 0x01 , 0x03 , 0x04 , 0x00 } , mxf_read_partition_pack } ,
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x02 , 0x05 , 0x01 , 0x01 , 0x0d , 0x01 , 0x02 , 0x01 , 0x01 , 0x04 , 0x02 , 0x00 } , mxf_read_partition_pack } ,
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x02 , 0x05 , 0x01 , 0x01 , 0x0d , 0x01 , 0x02 , 0x01 , 0x01 , 0x04 , 0x04 , 0x00 } , mxf_read_partition_pack } ,
2008-08-07 05:12:14 +03:00
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x02 , 0x53 , 0x01 , 0x01 , 0x0d , 0x01 , 0x01 , 0x01 , 0x01 , 0x01 , 0x18 , 0x00 } , mxf_read_content_storage , 0 , AnyType } ,
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x02 , 0x53 , 0x01 , 0x01 , 0x0d , 0x01 , 0x01 , 0x01 , 0x01 , 0x01 , 0x37 , 0x00 } , mxf_read_source_package , sizeof ( MXFPackage ) , SourcePackage } ,
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x02 , 0x53 , 0x01 , 0x01 , 0x0d , 0x01 , 0x01 , 0x01 , 0x01 , 0x01 , 0x36 , 0x00 } , mxf_read_material_package , sizeof ( MXFPackage ) , MaterialPackage } ,
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x02 , 0x53 , 0x01 , 0x01 , 0x0d , 0x01 , 0x01 , 0x01 , 0x01 , 0x01 , 0x0F , 0x00 } , mxf_read_sequence , sizeof ( MXFSequence ) , Sequence } ,
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x02 , 0x53 , 0x01 , 0x01 , 0x0d , 0x01 , 0x01 , 0x01 , 0x01 , 0x01 , 0x11 , 0x00 } , mxf_read_source_clip , sizeof ( MXFStructuralComponent ) , SourceClip } ,
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x02 , 0x53 , 0x01 , 0x01 , 0x0d , 0x01 , 0x01 , 0x01 , 0x01 , 0x01 , 0x44 , 0x00 } , mxf_read_generic_descriptor , sizeof ( MXFDescriptor ) , MultipleDescriptor } ,
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x02 , 0x53 , 0x01 , 0x01 , 0x0d , 0x01 , 0x01 , 0x01 , 0x01 , 0x01 , 0x42 , 0x00 } , mxf_read_generic_descriptor , sizeof ( MXFDescriptor ) , Descriptor } , /* Generic Sound */
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x02 , 0x53 , 0x01 , 0x01 , 0x0d , 0x01 , 0x01 , 0x01 , 0x01 , 0x01 , 0x28 , 0x00 } , mxf_read_generic_descriptor , sizeof ( MXFDescriptor ) , Descriptor } , /* CDCI */
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x02 , 0x53 , 0x01 , 0x01 , 0x0d , 0x01 , 0x01 , 0x01 , 0x01 , 0x01 , 0x29 , 0x00 } , mxf_read_generic_descriptor , sizeof ( MXFDescriptor ) , Descriptor } , /* RGBA */
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x02 , 0x53 , 0x01 , 0x01 , 0x0d , 0x01 , 0x01 , 0x01 , 0x01 , 0x01 , 0x51 , 0x00 } , mxf_read_generic_descriptor , sizeof ( MXFDescriptor ) , Descriptor } , /* MPEG 2 Video */
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x02 , 0x53 , 0x01 , 0x01 , 0x0d , 0x01 , 0x01 , 0x01 , 0x01 , 0x01 , 0x48 , 0x00 } , mxf_read_generic_descriptor , sizeof ( MXFDescriptor ) , Descriptor } , /* Wave */
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x02 , 0x53 , 0x01 , 0x01 , 0x0d , 0x01 , 0x01 , 0x01 , 0x01 , 0x01 , 0x47 , 0x00 } , mxf_read_generic_descriptor , sizeof ( MXFDescriptor ) , Descriptor } , /* AES3 */
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x02 , 0x53 , 0x01 , 0x01 , 0x0d , 0x01 , 0x01 , 0x01 , 0x01 , 0x01 , 0x3A , 0x00 } , mxf_read_track , sizeof ( MXFTrack ) , Track } , /* Static Track */
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x02 , 0x53 , 0x01 , 0x01 , 0x0d , 0x01 , 0x01 , 0x01 , 0x01 , 0x01 , 0x3B , 0x00 } , mxf_read_track , sizeof ( MXFTrack ) , Track } , /* Generic Track */
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x02 , 0x53 , 0x01 , 0x01 , 0x0d , 0x01 , 0x04 , 0x01 , 0x02 , 0x02 , 0x00 , 0x00 } , mxf_read_cryptographic_context , sizeof ( MXFCryptoContext ) , CryptoContext } ,
2009-01-08 04:54:43 +02:00
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x02 , 0x53 , 0x01 , 0x01 , 0x0d , 0x01 , 0x02 , 0x01 , 0x01 , 0x10 , 0x01 , 0x00 } , mxf_read_index_table_segment , sizeof ( MXFIndexTableSegment ) , IndexTableSegment } ,
2008-08-07 05:12:14 +03:00
{ { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } , NULL , 0 , AnyType } ,
} ;
2010-07-01 20:10:31 +03:00
static int mxf_read_local_tags ( MXFContext * mxf , KLVPacket * klv , MXFMetadataReadFunc * read_child , int ctx_size , enum MXFMetadataSetType type )
2008-08-07 05:12:14 +03:00
{
2011-02-20 12:04:12 +02:00
AVIOContext * pb = mxf - > fc - > pb ;
2008-08-07 05:12:14 +03:00
MXFMetadataSet * ctx = ctx_size ? av_mallocz ( ctx_size ) : mxf ;
2011-03-03 21:11:45 +02:00
uint64_t klv_end = avio_tell ( pb ) + klv - > length ;
2008-08-07 05:12:14 +03:00
if ( ! ctx )
return - 1 ;
2011-03-03 21:11:45 +02:00
while ( avio_tell ( pb ) + 4 < klv_end ) {
2011-02-21 17:43:01 +02:00
int tag = avio_rb16 ( pb ) ;
int size = avio_rb16 ( pb ) ; /* KLV specified by 0x53 */
2011-03-03 21:11:45 +02:00
uint64_t next = avio_tell ( pb ) + size ;
2008-08-07 05:12:14 +03:00
UID uid = { 0 } ;
2011-01-29 18:46:18 +02:00
av_dlog ( mxf - > fc , " local tag %#04x size %d \n " , tag , size ) ;
2008-08-07 05:12:14 +03:00
if ( ! size ) { /* ignore empty tag, needed for some files with empty UMID tag */
2009-01-08 04:57:21 +02:00
av_log ( mxf - > fc , AV_LOG_ERROR , " local tag %#04x with 0 size \n " , tag ) ;
2008-08-07 05:12:14 +03:00
continue ;
}
if ( tag > 0x7FFF ) { /* dynamic tag */
int i ;
for ( i = 0 ; i < mxf - > local_tags_count ; i + + ) {
int local_tag = AV_RB16 ( mxf - > local_tags + i * 18 ) ;
if ( local_tag = = tag ) {
memcpy ( uid , mxf - > local_tags + i * 18 + 2 , 16 ) ;
2011-01-29 18:46:18 +02:00
av_dlog ( mxf - > fc , " local tag %#04x \n " , local_tag ) ;
2008-08-07 05:12:14 +03:00
PRINT_KEY ( mxf - > fc , " uid " , uid ) ;
}
}
}
if ( ctx_size & & tag = = 0x3C0A )
2011-02-21 17:43:01 +02:00
avio_read ( pb , ctx - > uid , 16 ) ;
2008-08-07 05:12:14 +03:00
else if ( read_child ( ctx , pb , tag , size , uid ) < 0 )
return - 1 ;
2011-02-28 15:57:54 +02:00
avio_seek ( pb , next , SEEK_SET ) ;
2008-08-07 05:12:14 +03:00
}
if ( ctx_size ) ctx - > type = type ;
return ctx_size ? mxf_add_metadata_set ( mxf , ctx ) : 0 ;
}
2011-03-14 18:00:21 +02:00
/**
* 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 ;
}
2008-08-07 05:12:14 +03:00
static int mxf_read_header ( AVFormatContext * s , AVFormatParameters * ap )
{
MXFContext * mxf = s - > priv_data ;
KLVPacket klv ;
2011-03-14 18:00:21 +02:00
mxf - > last_forward_tell = INT64_MAX ;
2008-08-07 05:12:14 +03:00
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 ;
}
2011-02-28 15:57:54 +02:00
avio_seek ( s - > pb , - 14 , SEEK_CUR ) ;
2008-08-07 05:12:14 +03:00
mxf - > fc = s ;
2011-03-14 18:00:21 +02:00
mxf - > run_in = avio_tell ( s - > pb ) ;
2008-08-07 05:12:14 +03:00
while ( ! url_feof ( s - > pb ) ) {
const MXFMetadataReadTableEntry * metadata ;
2011-03-14 18:00:21 +02:00
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 ;
}
2008-08-07 05:12:14 +03:00
PRINT_KEY ( s , " read header " , klv . key ) ;
2011-05-31 22:23:45 +03:00
av_dlog ( s , " size % " PRIu64 " offset %# " PRIx64 " \n " , klv . length , klv . offset ) ;
2008-08-07 05:12:14 +03:00
if ( IS_KLV_KEY ( klv . key , mxf_encrypted_triplet_key ) | |
2011-03-14 18:00:21 +02:00
IS_KLV_KEY ( klv . key , mxf_essence_element_key ) | |
IS_KLV_KEY ( klv . key , mxf_system_item_key ) ) {
2011-11-11 17:01:34 +03:00
if ( IS_KLV_KEY ( klv . key , mxf_system_item_key ) ) {
mxf - > system_item = 1 ;
2011-03-14 18:00:21 +02:00
}
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 ;
2011-11-11 17:01:34 +03:00
continue ;
2011-03-14 18:00:21 +02:00
} 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 ;
2011-11-11 17:01:34 +03:00
}
2008-08-07 05:12:14 +03:00
for ( metadata = mxf_metadata_read_table ; metadata - > read ; metadata + + ) {
if ( IS_KLV_KEY ( klv . key , metadata - > key ) ) {
2010-07-01 20:10:31 +03:00
int res ;
if ( klv . key [ 5 ] = = 0x53 ) {
res = mxf_read_local_tags ( mxf , & klv , metadata - > read , metadata - > ctx_size , metadata - > type ) ;
2011-09-12 13:13:44 +03:00
} else {
uint64_t next = avio_tell ( s - > pb ) + klv . length ;
2011-02-07 17:07:41 +02:00
res = metadata - > read ( mxf , s - > pb , 0 , 0 , klv . key ) ;
2011-09-12 13:13:44 +03:00
avio_seek ( s - > pb , next , SEEK_SET ) ;
}
2010-07-01 20:10:31 +03:00
if ( res < 0 ) {
2008-08-07 05:12:14 +03:00
av_log ( s , AV_LOG_ERROR , " error reading header metadata \n " ) ;
return - 1 ;
}
break ;
}
}
if ( ! metadata - > read )
2011-03-15 10:14:38 +02:00
avio_skip ( s - > pb , klv . length ) ;
2008-08-07 05:12:14 +03:00
}
2011-03-14 18:00:21 +02:00
/* 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 ) ;
2008-08-07 05:12:14 +03:00
return mxf_parse_structural_metadata ( mxf ) ;
}
static int mxf_read_close ( AVFormatContext * s )
{
MXFContext * mxf = s - > priv_data ;
2011-11-09 13:47:57 +03:00
MXFIndexTableSegment * seg ;
int i , j ;
2008-08-07 05:12:14 +03:00
av_freep ( & mxf - > packages_refs ) ;
2009-05-15 08:33:05 +03:00
for ( i = 0 ; i < s - > nb_streams ; i + + )
s - > streams [ i ] - > priv_data = NULL ;
2008-08-07 05:12:14 +03:00
for ( i = 0 ; i < mxf - > metadata_sets_count ; i + + ) {
switch ( mxf - > metadata_sets [ i ] - > type ) {
case MultipleDescriptor :
av_freep ( & ( ( MXFDescriptor * ) mxf - > metadata_sets [ i ] ) - > sub_descriptors_refs ) ;
break ;
case Sequence :
av_freep ( & ( ( MXFSequence * ) mxf - > metadata_sets [ i ] ) - > structural_components_refs ) ;
break ;
case SourcePackage :
case MaterialPackage :
av_freep ( & ( ( MXFPackage * ) mxf - > metadata_sets [ i ] ) - > tracks_refs ) ;
break ;
2011-11-09 13:47:57 +03:00
case IndexTableSegment :
seg = ( MXFIndexTableSegment * ) mxf - > metadata_sets [ i ] ;
for ( j = 0 ; j < seg - > nb_index_entries ; j + + )
av_freep ( & seg - > slice_offset_entries [ j ] ) ;
av_freep ( & seg - > slice ) ;
av_freep ( & seg - > element_delta ) ;
av_freep ( & seg - > flag_entries ) ;
av_freep ( & seg - > stream_offset_entries ) ;
av_freep ( & seg - > slice_offset_entries ) ;
break ;
2008-08-07 05:12:14 +03:00
default :
break ;
}
av_freep ( & mxf - > metadata_sets [ i ] ) ;
}
2011-02-07 17:07:41 +02:00
av_freep ( & mxf - > partitions ) ;
2008-08-07 05:12:14 +03:00
av_freep ( & mxf - > metadata_sets ) ;
av_freep ( & mxf - > aesc ) ;
av_freep ( & mxf - > local_tags ) ;
return 0 ;
}
static int mxf_probe ( AVProbeData * p ) {
uint8_t * bufp = p - > buf ;
uint8_t * end = p - > buf + p - > buf_size ;
if ( p - > buf_size < sizeof ( mxf_header_partition_pack_key ) )
return 0 ;
/* Must skip Run-In Sequence and search for MXF header partition pack key SMPTE 377M 5.5 */
end - = sizeof ( mxf_header_partition_pack_key ) ;
for ( ; bufp < end ; bufp + + ) {
if ( IS_KLV_KEY ( bufp , mxf_header_partition_pack_key ) )
return AVPROBE_SCORE_MAX ;
}
return 0 ;
}
/* rudimentary byte seek */
/* XXX: use MXF Index */
static int mxf_read_seek ( AVFormatContext * s , int stream_index , int64_t sample_time , int flags )
{
AVStream * st = s - > streams [ stream_index ] ;
int64_t seconds ;
if ( ! s - > bit_rate )
return - 1 ;
if ( sample_time < 0 )
sample_time = 0 ;
seconds = av_rescale ( sample_time , st - > time_base . num , st - > time_base . den ) ;
2011-09-14 20:26:48 +03:00
if ( avio_seek ( s - > pb , ( s - > bit_rate * seconds ) > > 3 , SEEK_SET ) < 0 )
return - 1 ;
2011-10-16 16:03:30 +03:00
ff_update_cur_dts ( s , st , sample_time ) ;
2008-08-07 05:12:14 +03:00
return 0 ;
}
2011-01-26 00:03:28 +02:00
AVInputFormat ff_mxf_demuxer = {
2011-07-16 23:18:12 +03:00
. name = " mxf " ,
. long_name = NULL_IF_CONFIG_SMALL ( " Material eXchange Format " ) ,
. priv_data_size = sizeof ( MXFContext ) ,
. read_probe = mxf_probe ,
. read_header = mxf_read_header ,
. read_packet = mxf_read_packet ,
. read_close = mxf_read_close ,
. read_seek = mxf_read_seek ,
2008-08-07 05:12:14 +03:00
} ;