2008-08-07 02:12:14 +00:00
/*
* MXF demuxer .
2009-01-19 15:46:40 +00:00
* Copyright ( c ) 2006 SmartJog S . A . , Baptiste Coudurier < baptiste dot coudurier at smartjog dot com >
2008-08-07 02:12:14 +00: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
*/
2014-03-10 14:35:59 +00:00
# include <inttypes.h>
2013-11-23 20:32:55 +00:00
2008-08-07 02:12:14 +00:00
# include "libavutil/aes.h"
2012-09-13 19:15:48 +00:00
# include "libavutil/avassert.h"
2011-06-04 11:58:23 +00:00
# include "libavutil/mathematics.h"
2009-02-08 04:42:38 +00:00
# include "libavcodec/bytestream.h"
2013-11-08 20:43:27 +00:00
# include "libavutil/intreadwrite.h"
2012-02-23 15:58:01 +00:00
# include "libavutil/timecode.h"
2009-02-08 04:42:38 +00:00
# include "avformat.h"
2011-10-16 13:03:30 +00:00
# include "internal.h"
2008-08-18 17:54:18 +00:00
# include "mxf.h"
2008-08-07 02:12:14 +00:00
2011-02-07 15:07:41 +00:00
typedef enum {
Header ,
BodyPartition ,
Footer
} MXFPartitionType ;
typedef enum {
2012-01-11 10:29:57 +00:00
OP1a = 1 ,
2011-02-07 15:07:41 +00:00
OP1b ,
OP1c ,
OP2a ,
OP2b ,
OP2c ,
OP3a ,
OP3b ,
OP3c ,
OPAtom ,
2011-12-08 16:45:35 +00:00
OPSONYOpt , /* FATE sample, violates the spec in places */
2011-02-07 15:07:41 +00:00
} MXFOP ;
2014-09-22 07:19:33 +00:00
typedef struct MXFPartition {
2011-02-07 15:07:41 +00:00
int closed ;
int complete ;
MXFPartitionType type ;
uint64_t previous_partition ;
int index_sid ;
int body_sid ;
2011-12-07 16:43:36 +00:00
int64_t this_partition ;
2011-12-08 10:21:58 +00:00
int64_t essence_offset ; ///< absolute offset of essence
2011-12-08 10:18:21 +00:00
int64_t essence_length ;
2011-12-08 16:45:35 +00:00
int32_t kag_size ;
int64_t header_byte_count ;
int64_t index_byte_count ;
int pack_length ;
2014-10-28 12:38:18 +00:00
int64_t pack_ofs ; ///< absolute offset of pack in file, including run-in
2011-02-07 15:07:41 +00:00
} MXFPartition ;
2014-09-22 07:19:33 +00:00
typedef struct MXFCryptoContext {
2008-08-07 02:12:14 +00:00
UID uid ;
enum MXFMetadataSetType type ;
UID source_container_ul ;
} MXFCryptoContext ;
2014-09-22 07:19:33 +00:00
typedef struct MXFStructuralComponent {
2008-08-07 02:12:14 +00:00
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 ;
2014-09-22 07:19:33 +00:00
typedef struct MXFSequence {
2008-08-07 02:12:14 +00:00
UID uid ;
enum MXFMetadataSetType type ;
UID data_definition_ul ;
UID * structural_components_refs ;
int structural_components_count ;
int64_t duration ;
2014-07-22 16:08:04 +00:00
uint8_t origin ;
2008-08-07 02:12:14 +00:00
} MXFSequence ;
2014-09-22 07:19:33 +00:00
typedef struct MXFTrack {
2012-02-23 15:58:01 +00:00
UID uid ;
enum MXFMetadataSetType type ;
int drop_frame ;
int start_frame ;
struct AVRational rate ;
AVTimecode tc ;
} MXFTimecodeComponent ;
2014-10-25 00:31:24 +00:00
typedef struct {
UID uid ;
enum MXFMetadataSetType type ;
UID input_segment_ref ;
} MXFPulldownComponent ;
2014-11-30 20:16:27 +00:00
typedef struct {
UID uid ;
enum MXFMetadataSetType type ;
UID * structural_components_refs ;
int structural_components_count ;
int64_t duration ;
} MXFEssenceGroup ;
2015-03-14 01:58:38 +00:00
typedef struct {
UID uid ;
enum MXFMetadataSetType type ;
char * name ;
char * value ;
} MXFTaggedValue ;
2008-08-07 02:12:14 +00:00
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 ;
2012-03-07 09:52:39 +00:00
int intra_only ;
2012-09-13 19:15:48 +00:00
uint64_t sample_count ;
2012-09-13 19:15:48 +00:00
int64_t original_duration ; /* st->duration in SampleRate/EditRate units */
2008-08-07 02:12:14 +00:00
} MXFTrack ;
2014-09-22 07:19:33 +00:00
typedef struct MXFDescriptor {
2008-08-07 02:12:14 +00:00
UID uid ;
enum MXFMetadataSetType type ;
UID essence_container_ul ;
UID essence_codec_ul ;
AVRational sample_rate ;
AVRational aspect_ratio ;
int width ;
2012-02-07 10:48:43 +00:00
int height ; /* Field height, not frame height */
int frame_layout ; /* See MXFFrameLayout enum */
2013-02-16 12:52:29 +00:00
# define MXF_TFF 1
# define MXF_BFF 2
int field_dominance ;
2008-08-07 02:12:14 +00:00
int channels ;
int bits_per_sample ;
2014-11-30 20:16:27 +00:00
int64_t duration ; /* ContainerDuration optional property */
2012-02-28 14:16:39 +00:00
unsigned int component_depth ;
unsigned int horiz_subsampling ;
unsigned int vert_subsampling ;
2008-08-07 02:12:14 +00:00
UID * sub_descriptors_refs ;
int sub_descriptors_count ;
int linked_track_id ;
uint8_t * extradata ;
int extradata_size ;
2012-10-06 10:10:34 +00:00
enum AVPixelFormat pix_fmt ;
2008-08-07 02:12:14 +00:00
} MXFDescriptor ;
2014-09-22 07:19:33 +00:00
typedef struct MXFIndexTableSegment {
2009-01-08 02:54:43 +00:00
UID uid ;
enum MXFMetadataSetType type ;
2011-11-09 10:47:57 +00:00
int edit_unit_byte_count ;
int index_sid ;
int body_sid ;
AVRational index_edit_rate ;
uint64_t index_start_position ;
uint64_t index_duration ;
2011-12-08 10:39:59 +00:00
int8_t * temporal_offset_entries ;
2011-11-09 10:47:57 +00:00
int * flag_entries ;
uint64_t * stream_offset_entries ;
int nb_index_entries ;
2009-01-08 02:54:43 +00:00
} MXFIndexTableSegment ;
2014-09-22 07:19:33 +00:00
typedef struct MXFPackage {
2008-08-07 02:12:14 +00:00
UID uid ;
enum MXFMetadataSetType type ;
UID package_uid ;
2015-01-10 02:05:27 +00:00
UID package_ul ;
2008-08-07 02:12:14 +00:00
UID * tracks_refs ;
int tracks_count ;
MXFDescriptor * descriptor ; /* only one */
UID descriptor_ref ;
2014-10-05 00:42:51 +00:00
char * name ;
2015-03-14 01:58:38 +00:00
UID * comment_refs ;
int comment_count ;
2008-08-07 02:12:14 +00:00
} MXFPackage ;
2014-09-22 07:19:33 +00:00
typedef struct MXFMetadataSet {
2008-08-07 02:12:14 +00:00
UID uid ;
enum MXFMetadataSetType type ;
} MXFMetadataSet ;
2011-12-15 15:47:49 +00:00
/* decoded index table */
2014-09-22 07:19:33 +00:00
typedef struct MXFIndexTable {
2011-12-15 15:47:49 +00:00
int index_sid ;
int body_sid ;
int nb_ptses ; /* number of PTSes or total duration of index */
int64_t first_dts ; /* DTS = EditUnit + first_dts */
int64_t * ptses ; /* maps EditUnit -> PTS */
int nb_segments ;
MXFIndexTableSegment * * segments ; /* sorted by IndexStartPosition */
2011-12-16 08:42:52 +00:00
AVIndexEntry * fake_index ; /* used for calling ff_index_search_timestamp() */
2011-12-15 15:47:49 +00:00
} MXFIndexTable ;
2014-09-22 07:19:33 +00:00
typedef struct MXFContext {
2011-02-07 15:07:41 +00:00
MXFPartition * partitions ;
unsigned partitions_count ;
MXFOP op ;
2008-08-07 02:12:14 +00: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 13:48:00 +00:00
uint64_t footer_partition ;
2011-11-09 10:47:57 +00:00
KLVPacket current_klv_data ;
int current_klv_index ;
2011-03-14 16:00:21 +00:00
int run_in ;
MXFPartition * current_partition ;
int parsing_backward ;
int64_t last_forward_tell ;
2011-12-08 10:06:23 +00:00
int last_forward_partition ;
2011-12-08 19:28:49 +00:00
int current_edit_unit ;
2011-12-15 15:47:49 +00:00
int nb_index_tables ;
MXFIndexTable * index_tables ;
2012-01-24 10:36:39 +00:00
int edit_units_per_packet ; ///< how many edit units to read at a time (PCM, OPAtom)
2008-08-07 02:12:14 +00:00
} MXFContext ;
enum MXFWrappingScheme {
Frame ,
Clip ,
} ;
2011-12-08 16:45:35 +00:00
/* NOTE: klv_offset is not set (-1) for local keys */
typedef int MXFMetadataReadFunc ( void * arg , AVIOContext * pb , int tag , int size , UID uid , int64_t klv_offset ) ;
2010-07-01 17:10:31 +00:00
2014-09-22 07:19:33 +00:00
typedef struct MXFMetadataReadTableEntry {
2008-08-07 02:12:14 +00:00
const UID key ;
2010-07-01 17:10:31 +00:00
MXFMetadataReadFunc * read ;
2008-08-07 02:12:14 +00:00
int ctx_size ;
enum MXFMetadataSetType type ;
} MXFMetadataReadTableEntry ;
2012-11-11 01:13:31 +00:00
static int mxf_read_close ( AVFormatContext * s ) ;
2008-08-07 02:12:14 +00:00
/* 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-12-10 11:11:11 +00:00
static const uint8_t mxf_avid_essence_element_key [ ] = { 0x06 , 0x0e , 0x2b , 0x34 , 0x01 , 0x02 , 0x01 , 0x01 , 0x0e , 0x04 , 0x03 , 0x01 } ;
2014-03-13 12:34:16 +00: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 02:12:14 +00: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 } ;
2014-03-13 12:34:16 +00:00
static const uint8_t mxf_random_index_pack_key [ ] = { 0x06 , 0x0e , 0x2b , 0x34 , 0x02 , 0x05 , 0x01 , 0x01 , 0x0d , 0x01 , 0x02 , 0x01 , 0x01 , 0x11 , 0x01 , 0x00 } ;
2008-08-07 02:12:14 +00:00
static const uint8_t mxf_sony_mpeg4_extradata [ ] = { 0x06 , 0x0e , 0x2b , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x0e , 0x06 , 0x06 , 0x02 , 0x02 , 0x01 , 0x00 , 0x00 } ;
2015-01-06 00:53:05 +00:00
static const uint8_t mxf_avid_project_name [ ] = { 0xa5 , 0xfb , 0x7b , 0x25 , 0xf6 , 0x15 , 0x94 , 0xb9 , 0x62 , 0xfc , 0x37 , 0x17 , 0x49 , 0x2d , 0x42 , 0xbf } ;
2015-03-04 22:36:50 +00:00
static const uint8_t mxf_jp2k_rsiz [ ] = { 0x06 , 0x0e , 0x2b , 0x34 , 0x02 , 0x05 , 0x01 , 0x01 , 0x0d , 0x01 , 0x02 , 0x01 , 0x01 , 0x02 , 0x01 , 0x00 } ;
2015-03-14 01:58:38 +00:00
static const uint8_t mxf_indirect_value_utf16le [ ] = { 0x4c , 0x00 , 0x02 , 0x10 , 0x01 , 0x00 , 0x00 , 0x00 , 0x00 , 0x06 , 0x0e , 0x2b , 0x34 , 0x01 , 0x04 , 0x01 , 0x01 } ;
static const uint8_t mxf_indirect_value_utf16be [ ] = { 0x42 , 0x01 , 0x10 , 0x02 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x06 , 0x0e , 0x2b , 0x34 , 0x01 , 0x04 , 0x01 , 0x01 } ;
2008-08-07 02:12:14 +00:00
# define IS_KLV_KEY(x, y) (!memcmp(x, y, sizeof(y)))
2015-01-28 01:59:03 +00:00
static void mxf_free_metadataset ( MXFMetadataSet * * ctx , int freectx )
2014-12-15 00:31:12 +00:00
{
MXFIndexTableSegment * seg ;
switch ( ( * ctx ) - > type ) {
case Descriptor :
av_freep ( & ( ( MXFDescriptor * ) * ctx ) - > extradata ) ;
break ;
case MultipleDescriptor :
av_freep ( & ( ( MXFDescriptor * ) * ctx ) - > sub_descriptors_refs ) ;
break ;
case Sequence :
av_freep ( & ( ( MXFSequence * ) * ctx ) - > structural_components_refs ) ;
break ;
case EssenceGroup :
av_freep ( & ( ( MXFEssenceGroup * ) * ctx ) - > structural_components_refs ) ;
break ;
case SourcePackage :
case MaterialPackage :
av_freep ( & ( ( MXFPackage * ) * ctx ) - > tracks_refs ) ;
av_freep ( & ( ( MXFPackage * ) * ctx ) - > name ) ;
2015-03-15 21:43:32 +00:00
av_freep ( & ( ( MXFPackage * ) * ctx ) - > comment_refs ) ;
2014-12-15 00:31:12 +00:00
break ;
2015-03-14 01:58:38 +00:00
case TaggedValue :
av_freep ( & ( ( MXFTaggedValue * ) * ctx ) - > name ) ;
av_freep ( & ( ( MXFTaggedValue * ) * ctx ) - > value ) ;
break ;
2014-12-15 00:31:12 +00:00
case IndexTableSegment :
seg = ( MXFIndexTableSegment * ) * ctx ;
av_freep ( & seg - > temporal_offset_entries ) ;
av_freep ( & seg - > flag_entries ) ;
av_freep ( & seg - > stream_offset_entries ) ;
default :
break ;
}
2015-01-28 01:59:03 +00:00
if ( freectx )
2014-12-15 00:31:12 +00:00
av_freep ( ctx ) ;
}
2011-02-20 10:04:12 +00:00
static int64_t klv_decode_ber_length ( AVIOContext * pb )
2008-08-07 02:12:14 +00:00
{
2011-02-21 15:43:01 +00:00
uint64_t size = avio_r8 ( pb ) ;
2008-08-07 02:12:14 +00: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 )
2012-01-14 21:25:12 +00:00
return AVERROR_INVALIDDATA ;
2008-08-07 02:12:14 +00:00
size = 0 ;
while ( bytes_num - - )
2011-02-21 15:43:01 +00:00
size = size < < 8 | avio_r8 ( pb ) ;
2008-08-07 02:12:14 +00:00
}
return size ;
}
2011-02-20 10:04:12 +00:00
static int mxf_read_sync ( AVIOContext * pb , const uint8_t * key , unsigned size )
2008-08-07 02:12:14 +00:00
{
int i , b ;
2014-08-07 20:12:41 +00:00
for ( i = 0 ; i < size & & ! avio_feof ( pb ) ; i + + ) {
2011-02-21 15:43:01 +00:00
b = avio_r8 ( pb ) ;
2008-08-07 02:12:14 +00:00
if ( b = = key [ 0 ] )
i = 0 ;
else if ( b ! = key [ i ] )
i = - 1 ;
}
return i = = size ;
}
2011-02-20 10:04:12 +00:00
static int klv_read_packet ( KLVPacket * klv , AVIOContext * pb )
2008-08-07 02:12:14 +00:00
{
if ( ! mxf_read_sync ( pb , mxf_klv_key , 4 ) )
2012-01-14 21:25:12 +00:00
return AVERROR_INVALIDDATA ;
2011-03-03 19:11:45 +00:00
klv - > offset = avio_tell ( pb ) - 4 ;
2008-08-07 02:12:14 +00:00
memcpy ( klv - > key , mxf_klv_key , 4 ) ;
2011-02-21 15:43:01 +00:00
avio_read ( pb , klv - > key + 4 , 12 ) ;
2008-08-07 02:12:14 +00: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 10:04:12 +00:00
static int mxf_get_d10_aes3_packet ( AVIOContext * pb , AVStream * st , AVPacket * pkt , int64_t length )
2008-08-07 02:12:14 +00:00
{
const uint8_t * buf_ptr , * end_ptr ;
uint8_t * data_ptr ;
int i ;
if ( length > 61444 ) /* worst case PAL 1920 samples 8 channels */
2012-01-14 21:25:12 +00:00
return AVERROR_INVALIDDATA ;
2011-10-08 01:41:06 +00:00
length = av_get_packet ( pb , pkt , length ) ;
if ( length < 0 )
return length ;
2008-08-07 02:12:14 +00:00
data_ptr = pkt - > data ;
2009-11-20 23:12:55 +00:00
end_ptr = pkt - > data + length ;
buf_ptr = pkt - > data + 4 ; /* skip SMPTE 331M header */
2012-07-18 23:23:20 +00:00
for ( ; end_ptr - buf_ptr > = st - > codec - > channels * 4 ; ) {
2008-08-07 02:12:14 +00:00
for ( i = 0 ; i < st - > codec - > channels ; i + + ) {
uint32_t sample = bytestream_get_le32 ( & buf_ptr ) ;
2008-09-08 14:24:59 +00:00
if ( st - > codec - > bits_per_coded_sample = = 24 )
2008-08-07 02:12:14 +00: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 01:41:06 +00:00
av_shrink_packet ( pkt , data_ptr - pkt - > data ) ;
2008-08-07 02:12:14 +00: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 10:04:12 +00:00
AVIOContext * pb = s - > pb ;
2011-03-03 19:11:45 +00:00
int64_t end = avio_tell ( pb ) + klv - > length ;
2011-11-07 18:14:54 +00:00
int64_t size ;
2008-08-07 02:12:14 +00: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 ) {
2012-10-11 12:10:45 +00:00
mxf - > aesc = av_aes_alloc ( ) ;
2008-08-07 02:12:14 +00:00
if ( ! mxf - > aesc )
2012-01-14 21:25:12 +00:00
return AVERROR ( ENOMEM ) ;
2008-08-07 02:12:14 +00:00
av_aes_init ( mxf - > aesc , s - > key , 128 , 1 ) ;
}
// crypto context
2011-03-15 08:14:38 +00:00
avio_skip ( pb , klv_decode_ber_length ( pb ) ) ;
2008-08-07 02:12:14 +00:00
// plaintext offset
klv_decode_ber_length ( pb ) ;
2011-02-21 15:43:01 +00:00
plaintext_size = avio_rb64 ( pb ) ;
2008-08-07 02:12:14 +00:00
// source klv key
klv_decode_ber_length ( pb ) ;
2011-02-21 15:43:01 +00:00
avio_read ( pb , klv - > key , 16 ) ;
2008-08-07 02:12:14 +00:00
if ( ! IS_KLV_KEY ( klv , mxf_essence_element_key ) )
2012-01-14 21:25:12 +00:00
return AVERROR_INVALIDDATA ;
2008-08-07 02:12:14 +00:00
index = mxf_get_stream_index ( s , klv ) ;
if ( index < 0 )
2012-01-14 21:25:12 +00:00
return AVERROR_INVALIDDATA ;
2008-08-07 02:12:14 +00:00
// source size
klv_decode_ber_length ( pb ) ;
2011-02-21 15:43:01 +00:00
orig_size = avio_rb64 ( pb ) ;
2008-08-07 02:12:14 +00:00
if ( orig_size < plaintext_size )
2012-01-14 21:25:12 +00:00
return AVERROR_INVALIDDATA ;
2008-08-07 02:12:14 +00:00
// enc. code
size = klv_decode_ber_length ( pb ) ;
if ( size < 32 | | size - 32 < orig_size )
2012-01-14 21:25:12 +00:00
return AVERROR_INVALIDDATA ;
2011-02-21 15:43:01 +00:00
avio_read ( pb , ivec , 16 ) ;
avio_read ( pb , tmpbuf , 16 ) ;
2008-08-07 02:12:14 +00: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 01:41:06 +00:00
size = av_get_packet ( pb , pkt , size ) ;
if ( size < 0 )
return size ;
else if ( size < plaintext_size )
return AVERROR_INVALIDDATA ;
2008-08-07 02:12:14 +00: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 01:41:06 +00:00
av_shrink_packet ( pkt , orig_size ) ;
2008-08-07 02:12:14 +00:00
pkt - > stream_index = index ;
2011-03-15 08:14:38 +00:00
avio_skip ( pb , end - avio_tell ( pb ) ) ;
2008-08-07 02:12:14 +00:00
return 0 ;
}
2011-12-08 16:45:35 +00:00
static int mxf_read_primer_pack ( void * arg , AVIOContext * pb , int tag , int size , UID uid , int64_t klv_offset )
2008-08-07 02:12:14 +00:00
{
2010-07-01 17:10:31 +00:00
MXFContext * mxf = arg ;
2011-02-21 15:43:01 +00:00
int item_num = avio_rb32 ( pb ) ;
int item_len = avio_rb32 ( pb ) ;
2008-08-07 02:12:14 +00:00
if ( item_len ! = 18 ) {
2013-02-25 22:54:28 +00:00
avpriv_request_sample ( pb , " Primer pack item length %d " , item_len ) ;
2012-01-14 21:25:12 +00:00
return AVERROR_PATCHWELCOME ;
2008-08-07 02:12:14 +00:00
}
2012-02-01 05:05:12 +00:00
if ( item_num > 65536 ) {
av_log ( mxf - > fc , AV_LOG_ERROR , " item_num %d is too large \n " , item_num ) ;
2012-01-14 21:25:12 +00:00
return AVERROR_INVALIDDATA ;
2012-02-01 05:05:12 +00:00
}
2014-10-15 00:16:18 +00:00
if ( mxf - > local_tags )
av_log ( mxf - > fc , AV_LOG_VERBOSE , " Multiple primer packs \n " ) ;
av_free ( mxf - > local_tags ) ;
mxf - > local_tags_count = 0 ;
2012-02-01 05:05:12 +00:00
mxf - > local_tags = av_calloc ( item_num , item_len ) ;
2008-08-07 02:12:14 +00:00
if ( ! mxf - > local_tags )
2012-01-14 21:25:12 +00:00
return AVERROR ( ENOMEM ) ;
2012-02-01 05:05:12 +00:00
mxf - > local_tags_count = item_num ;
2011-02-21 15:43:01 +00:00
avio_read ( pb , mxf - > local_tags , item_num * item_len ) ;
2008-08-07 02:12:14 +00:00
return 0 ;
}
2011-12-08 16:45:35 +00:00
static int mxf_read_partition_pack ( void * arg , AVIOContext * pb , int tag , int size , UID uid , int64_t klv_offset )
2011-02-07 15:07:41 +00:00
{
MXFContext * mxf = arg ;
2013-09-11 10:13:44 +00:00
MXFPartition * partition , * tmp_part ;
2011-02-07 15:07:41 +00:00
UID op ;
2011-10-07 13:48:00 +00:00
uint64_t footer_partition ;
2012-01-11 10:29:57 +00:00
uint32_t nb_essence_containers ;
2011-02-07 15:07:41 +00:00
2013-09-11 11:34:25 +00:00
tmp_part = av_realloc_array ( mxf - > partitions , mxf - > partitions_count + 1 , sizeof ( * mxf - > partitions ) ) ;
2013-09-11 10:13:44 +00:00
if ( ! tmp_part )
return AVERROR ( ENOMEM ) ;
mxf - > partitions = tmp_part ;
2011-02-07 15:07:41 +00:00
2011-12-08 10:06:23 +00: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-12-08 16:45:35 +00:00
partition - > pack_length = avio_tell ( pb ) - klv_offset + size ;
2014-10-28 12:38:18 +00:00
partition - > pack_ofs = klv_offset ;
2011-02-07 15:07:41 +00: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-08 16:45:35 +00:00
avio_skip ( pb , 4 ) ;
partition - > kag_size = avio_rb32 ( pb ) ;
2011-12-07 16:43:36 +00:00
partition - > this_partition = avio_rb64 ( pb ) ;
2011-02-07 15:07:41 +00:00
partition - > previous_partition = avio_rb64 ( pb ) ;
2011-10-07 13:48:00 +00:00
footer_partition = avio_rb64 ( pb ) ;
2011-12-08 16:45:35 +00:00
partition - > header_byte_count = avio_rb64 ( pb ) ;
partition - > index_byte_count = avio_rb64 ( pb ) ;
2011-02-07 15:07:41 +00:00
partition - > index_sid = avio_rb32 ( pb ) ;
avio_skip ( pb , 8 ) ;
partition - > body_sid = avio_rb32 ( pb ) ;
2014-01-10 01:11:20 +00:00
if ( avio_read ( pb , op , sizeof ( UID ) ) ! = sizeof ( UID ) ) {
av_log ( mxf - > fc , AV_LOG_ERROR , " Failed reading UID \n " ) ;
return AVERROR_INVALIDDATA ;
}
2012-01-11 10:29:57 +00:00
nb_essence_containers = avio_rb32 ( pb ) ;
2011-02-07 15:07:41 +00:00
2014-03-13 15:12:05 +00:00
if ( partition - > this_partition & &
partition - > previous_partition = = partition - > this_partition ) {
av_log ( mxf - > fc , AV_LOG_ERROR ,
" PreviousPartition equal to ThisPartition % " PRIx64 " \n " ,
partition - > previous_partition ) ;
/* override with the actual previous partition offset */
if ( ! mxf - > parsing_backward & & mxf - > last_forward_partition > 1 ) {
MXFPartition * prev =
mxf - > partitions + mxf - > last_forward_partition - 2 ;
partition - > previous_partition = prev - > this_partition ;
}
/* if no previous body partition are found point to the header
* partition */
2014-04-03 13:52:13 +00:00
if ( partition - > previous_partition = = partition - > this_partition )
2014-03-13 15:12:05 +00:00
partition - > previous_partition = 0 ;
av_log ( mxf - > fc , AV_LOG_ERROR ,
" Overriding PreviousPartition with % " PRIx64 " \n " ,
partition - > previous_partition ) ;
}
2011-10-07 13:48:00 +00:00
/* some files don'thave FooterPartition set in every partition */
if ( footer_partition ) {
if ( mxf - > footer_partition & & mxf - > footer_partition ! = footer_partition ) {
2012-01-26 12:21:42 +00:00
av_log ( mxf - > fc , AV_LOG_ERROR ,
" inconsistent FooterPartition value: % " PRIu64 " != % " PRIu64 " \n " ,
2011-10-07 13:48:00 +00:00
mxf - > footer_partition , footer_partition ) ;
} else {
mxf - > footer_partition = footer_partition ;
}
}
2015-03-16 08:57:35 +00:00
av_log ( mxf - > fc , AV_LOG_TRACE ,
2012-01-26 12:21:42 +00:00
" PartitionPack: ThisPartition = 0x% " PRIX64
" , PreviousPartition = 0x% " PRIX64 " , "
" FooterPartition = 0x% " PRIX64 " , IndexSID = %i, BodySID = %i \n " ,
2011-12-07 16:43:36 +00:00
partition - > this_partition ,
2011-10-07 13:48:00 +00:00
partition - > previous_partition , footer_partition ,
2011-02-07 15:07:41 +00:00
partition - > index_sid , partition - > body_sid ) ;
2011-12-21 09:56:59 +00:00
/* sanity check PreviousPartition if set */
2014-10-28 12:38:18 +00:00
//NOTE: this isn't actually enough, see mxf_seek_to_previous_partition()
2011-12-21 09:56:59 +00:00
if ( partition - > previous_partition & &
mxf - > run_in + partition - > previous_partition > = klv_offset ) {
2012-01-26 12:21:39 +00:00
av_log ( mxf - > fc , AV_LOG_ERROR ,
" PreviousPartition points to this partition or forward \n " ) ;
2011-12-21 09:56:59 +00:00
return AVERROR_INVALIDDATA ;
}
2011-02-07 15:07:41 +00:00
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 ;
2011-12-08 16:45:35 +00:00
else if ( op [ 12 ] = = 64 & & op [ 13 ] = = 1 ) mxf - > op = OPSONYOpt ;
2012-01-11 10:29:57 +00:00
else if ( op [ 12 ] = = 0x10 ) {
/* SMPTE 390m: "There shall be exactly one essence container"
2012-03-02 10:33:28 +00:00
* The following block deals with files that violate this , namely :
* 2011 _DCPTEST_24FPS . V . mxf - two ECs , OP1a
* abcdefghiv016f56415e . mxf - zero ECs , OPAtom , output by Avid AirSpeed */
2012-01-11 10:29:57 +00:00
if ( nb_essence_containers ! = 1 ) {
2012-03-02 10:33:28 +00:00
MXFOP op = nb_essence_containers ? OP1a : OPAtom ;
2012-01-11 10:29:57 +00:00
/* only nag once */
if ( ! mxf - > op )
2012-01-26 12:21:43 +00:00
av_log ( mxf - > fc , AV_LOG_WARNING ,
2014-03-10 14:35:59 +00:00
" \" OPAtom \" with % " PRIu32 " ECs - assuming %s \n " ,
2012-03-02 10:33:28 +00:00
nb_essence_containers ,
op = = OP1a ? " OP1a " : " OPAtom " ) ;
2012-01-11 10:29:57 +00:00
2012-03-02 10:33:28 +00:00
mxf - > op = op ;
2012-01-11 10:29:57 +00:00
} else
mxf - > op = OPAtom ;
} else {
2011-12-08 16:45:35 +00:00
av_log ( mxf - > fc , AV_LOG_ERROR , " unknown operational pattern: %02xh %02xh - guessing OP1a \n " , op [ 12 ] , op [ 13 ] ) ;
mxf - > op = OP1a ;
}
if ( partition - > kag_size < = 0 | | partition - > kag_size > ( 1 < < 20 ) ) {
2014-03-10 14:35:59 +00:00
av_log ( mxf - > fc , AV_LOG_WARNING , " invalid KAGSize % " PRId32 " - guessing " ,
partition - > kag_size ) ;
2011-12-08 16:45:35 +00:00
if ( mxf - > op = = OPSONYOpt )
partition - > kag_size = 512 ;
else
partition - > kag_size = 1 ;
2014-03-10 14:35:59 +00:00
av_log ( mxf - > fc , AV_LOG_WARNING , " % " PRId32 " \n " , partition - > kag_size ) ;
2011-12-08 16:45:35 +00:00
}
2011-02-07 15:07:41 +00:00
return 0 ;
}
2008-08-07 02:12:14 +00:00
static int mxf_add_metadata_set ( MXFContext * mxf , void * metadata_set )
{
2013-09-11 10:13:44 +00:00
MXFMetadataSet * * tmp ;
2013-09-11 11:34:25 +00:00
tmp = av_realloc_array ( mxf - > metadata_sets , mxf - > metadata_sets_count + 1 , sizeof ( * mxf - > metadata_sets ) ) ;
2013-09-11 10:13:44 +00:00
if ( ! tmp )
return AVERROR ( ENOMEM ) ;
mxf - > metadata_sets = tmp ;
2008-08-07 02:12:14 +00:00
mxf - > metadata_sets [ mxf - > metadata_sets_count ] = metadata_set ;
mxf - > metadata_sets_count + + ;
return 0 ;
}
2011-12-08 16:45:35 +00:00
static int mxf_read_cryptographic_context ( void * arg , AVIOContext * pb , int tag , int size , UID uid , int64_t klv_offset )
2008-08-07 02:12:14 +00:00
{
2010-07-01 17:10:31 +00:00
MXFCryptoContext * cryptocontext = arg ;
2008-08-07 02:12:14 +00:00
if ( size ! = 16 )
2012-01-14 21:25:12 +00:00
return AVERROR_INVALIDDATA ;
2008-08-07 02:12:14 +00:00
if ( IS_KLV_KEY ( uid , mxf_crypto_source_container_ul ) )
2011-02-21 15:43:01 +00:00
avio_read ( pb , cryptocontext - > source_container_ul , 16 ) ;
2008-08-07 02:12:14 +00:00
return 0 ;
}
2015-03-02 02:33:10 +00:00
static int mxf_read_strong_ref_array ( AVIOContext * pb , UID * * refs , int * count )
{
* count = avio_rb32 ( pb ) ;
* refs = av_calloc ( * count , sizeof ( UID ) ) ;
if ( ! * refs ) {
* count = 0 ;
return AVERROR ( ENOMEM ) ;
}
avio_skip ( pb , 4 ) ; /* useless size of objects, always 16 according to specs */
avio_read ( pb , ( uint8_t * ) * refs , * count * sizeof ( UID ) ) ;
return 0 ;
}
2011-12-08 16:45:35 +00:00
static int mxf_read_content_storage ( void * arg , AVIOContext * pb , int tag , int size , UID uid , int64_t klv_offset )
2008-08-07 02:12:14 +00:00
{
2010-07-01 17:10:31 +00:00
MXFContext * mxf = arg ;
2008-08-07 02:12:14 +00:00
switch ( tag ) {
case 0x1901 :
2014-10-15 00:16:18 +00:00
if ( mxf - > packages_refs )
av_log ( mxf - > fc , AV_LOG_VERBOSE , " Multiple packages_refs \n " ) ;
av_free ( mxf - > packages_refs ) ;
2015-03-02 02:33:10 +00:00
return mxf_read_strong_ref_array ( pb , & mxf - > packages_refs , & mxf - > packages_count ) ;
2008-08-07 02:12:14 +00:00
}
return 0 ;
}
2011-12-08 16:45:35 +00:00
static int mxf_read_source_clip ( void * arg , AVIOContext * pb , int tag , int size , UID uid , int64_t klv_offset )
2008-08-07 02:12:14 +00:00
{
2010-07-01 17:10:31 +00:00
MXFStructuralComponent * source_clip = arg ;
2008-08-07 02:12:14 +00:00
switch ( tag ) {
case 0x0202 :
2011-02-21 15:43:01 +00:00
source_clip - > duration = avio_rb64 ( pb ) ;
2008-08-07 02:12:14 +00:00
break ;
case 0x1201 :
2011-02-21 15:43:01 +00:00
source_clip - > start_position = avio_rb64 ( pb ) ;
2008-08-07 02:12:14 +00:00
break ;
case 0x1101 :
/* UMID, only get last 16 bytes */
2011-03-15 08:14:38 +00:00
avio_skip ( pb , 16 ) ;
2011-02-21 15:43:01 +00:00
avio_read ( pb , source_clip - > source_package_uid , 16 ) ;
2008-08-07 02:12:14 +00:00
break ;
case 0x1102 :
2011-02-21 15:43:01 +00:00
source_clip - > source_track_id = avio_rb32 ( pb ) ;
2008-08-07 02:12:14 +00:00
break ;
}
return 0 ;
}
2012-02-23 15:58:01 +00:00
static int mxf_read_timecode_component ( void * arg , AVIOContext * pb , int tag , int size , UID uid , int64_t klv_offset )
{
MXFTimecodeComponent * mxf_timecode = arg ;
switch ( tag ) {
case 0x1501 :
mxf_timecode - > start_frame = avio_rb64 ( pb ) ;
break ;
case 0x1502 :
mxf_timecode - > rate = ( AVRational ) { avio_rb16 ( pb ) , 1 } ;
break ;
case 0x1503 :
mxf_timecode - > drop_frame = avio_r8 ( pb ) ;
break ;
}
return 0 ;
}
2014-10-25 00:31:24 +00:00
static int mxf_read_pulldown_component ( void * arg , AVIOContext * pb , int tag , int size , UID uid , int64_t klv_offset )
{
MXFPulldownComponent * mxf_pulldown = arg ;
switch ( tag ) {
case 0x0d01 :
avio_read ( pb , mxf_pulldown - > input_segment_ref , 16 ) ;
break ;
}
return 0 ;
}
2011-12-08 16:45:35 +00:00
static int mxf_read_track ( void * arg , AVIOContext * pb , int tag , int size , UID uid , int64_t klv_offset )
2008-08-07 02:12:14 +00:00
{
2010-07-01 17:10:31 +00:00
MXFTrack * track = arg ;
2008-08-07 02:12:14 +00:00
switch ( tag ) {
case 0x4801 :
2011-02-21 15:43:01 +00:00
track - > track_id = avio_rb32 ( pb ) ;
2008-08-07 02:12:14 +00:00
break ;
case 0x4804 :
2011-02-21 15:43:01 +00:00
avio_read ( pb , track - > track_number , 4 ) ;
2008-08-07 02:12:14 +00:00
break ;
2014-03-13 12:34:16 +00:00
case 0x4b01 :
2011-02-21 15:43:01 +00:00
track - > edit_rate . num = avio_rb32 ( pb ) ;
2012-02-28 14:16:36 +00:00
track - > edit_rate . den = avio_rb32 ( pb ) ;
2008-08-07 02:12:14 +00:00
break ;
case 0x4803 :
2011-02-21 15:43:01 +00:00
avio_read ( pb , track - > sequence_ref , 16 ) ;
2008-08-07 02:12:14 +00:00
break ;
}
return 0 ;
}
2011-12-08 16:45:35 +00:00
static int mxf_read_sequence ( void * arg , AVIOContext * pb , int tag , int size , UID uid , int64_t klv_offset )
2008-08-07 02:12:14 +00:00
{
2010-07-01 17:10:31 +00:00
MXFSequence * sequence = arg ;
2008-08-07 02:12:14 +00:00
switch ( tag ) {
case 0x0202 :
2011-02-21 15:43:01 +00:00
sequence - > duration = avio_rb64 ( pb ) ;
2008-08-07 02:12:14 +00:00
break ;
case 0x0201 :
2011-02-21 15:43:01 +00:00
avio_read ( pb , sequence - > data_definition_ul , 16 ) ;
2008-08-07 02:12:14 +00:00
break ;
2014-07-22 16:08:04 +00:00
case 0x4b02 :
sequence - > origin = avio_r8 ( pb ) ;
break ;
2008-08-07 02:12:14 +00:00
case 0x1001 :
2015-03-02 02:33:10 +00:00
return mxf_read_strong_ref_array ( pb , & sequence - > structural_components_refs ,
& sequence - > structural_components_count ) ;
2008-08-07 02:12:14 +00:00
}
return 0 ;
}
2014-11-30 20:16:27 +00:00
static int mxf_read_essence_group ( void * arg , AVIOContext * pb , int tag , int size , UID uid , int64_t klv_offset )
{
MXFEssenceGroup * essence_group = arg ;
switch ( tag ) {
case 0x0202 :
essence_group - > duration = avio_rb64 ( pb ) ;
break ;
case 0x0501 :
2015-03-02 02:33:10 +00:00
return mxf_read_strong_ref_array ( pb , & essence_group - > structural_components_refs ,
& essence_group - > structural_components_count ) ;
2014-11-30 20:16:27 +00:00
}
return 0 ;
}
2015-03-14 01:58:38 +00:00
static inline int mxf_read_utf16_string ( AVIOContext * pb , int size , char * * str , int be )
2014-10-05 00:42:51 +00:00
{
int ret ;
size_t buf_size ;
if ( size < 0 )
return AVERROR ( EINVAL ) ;
buf_size = size + size / 2 + 1 ;
* str = av_malloc ( buf_size ) ;
if ( ! * str )
return AVERROR ( ENOMEM ) ;
2015-03-14 01:58:38 +00:00
if ( be )
ret = avio_get_str16be ( pb , size , * str , buf_size ) ;
else
ret = avio_get_str16le ( pb , size , * str , buf_size ) ;
if ( ret < 0 ) {
2014-10-05 00:42:51 +00:00
av_freep ( str ) ;
return ret ;
}
return ret ;
}
2015-03-14 01:58:38 +00:00
# define READ_STR16(type, big_endian) \
static int mxf_read_utf16 # # type # # _string ( AVIOContext * pb , int size , char * * str ) \
{ \
return mxf_read_utf16_string ( pb , size , str , big_endian ) ; \
}
READ_STR16 ( be , 1 )
READ_STR16 ( le , 0 )
# undef READ_STR16
2014-11-22 01:43:09 +00:00
static int mxf_read_package ( void * arg , AVIOContext * pb , int tag , int size , UID uid , int64_t klv_offset )
2008-08-07 02:12:14 +00:00
{
2010-07-01 17:10:31 +00:00
MXFPackage * package = arg ;
2008-08-07 02:12:14 +00:00
switch ( tag ) {
case 0x4403 :
2015-03-02 02:33:10 +00:00
return mxf_read_strong_ref_array ( pb , & package - > tracks_refs ,
& package - > tracks_count ) ;
2008-08-07 02:12:14 +00:00
case 0x4401 :
2015-01-10 02:05:27 +00:00
/* UMID */
avio_read ( pb , package - > package_ul , 16 ) ;
2011-02-21 15:43:01 +00:00
avio_read ( pb , package - > package_uid , 16 ) ;
2008-08-07 02:12:14 +00:00
break ;
case 0x4701 :
2011-02-21 15:43:01 +00:00
avio_read ( pb , package - > descriptor_ref , 16 ) ;
2008-08-07 02:12:14 +00:00
break ;
2014-10-05 00:42:51 +00:00
case 0x4402 :
2015-03-14 01:58:38 +00:00
return mxf_read_utf16be_string ( pb , size , & package - > name ) ;
case 0x4406 :
return mxf_read_strong_ref_array ( pb , & package - > comment_refs ,
& package - > comment_count ) ;
2008-08-07 02:12:14 +00:00
}
return 0 ;
}
2011-11-09 10:47:57 +00:00
static int mxf_read_index_entry_array ( AVIOContext * pb , MXFIndexTableSegment * segment )
{
2011-12-20 08:59:29 +00:00
int i , length ;
2011-11-09 10:47:57 +00:00
segment - > nb_index_entries = avio_rb32 ( pb ) ;
2011-11-09 10:47:57 +00:00
2011-11-09 10:47:57 +00:00
length = avio_rb32 ( pb ) ;
2011-12-08 10:39:59 +00:00
if ( ! ( segment - > temporal_offset_entries = av_calloc ( segment - > nb_index_entries , sizeof ( * segment - > temporal_offset_entries ) ) ) | |
! ( segment - > flag_entries = av_calloc ( segment - > nb_index_entries , sizeof ( * segment - > flag_entries ) ) ) | |
2014-12-15 00:33:13 +00:00
! ( segment - > stream_offset_entries = av_calloc ( segment - > nb_index_entries , sizeof ( * segment - > stream_offset_entries ) ) ) ) {
av_freep ( & segment - > temporal_offset_entries ) ;
av_freep ( & segment - > flag_entries ) ;
2011-11-09 10:47:57 +00:00
return AVERROR ( ENOMEM ) ;
2014-12-15 00:33:13 +00:00
}
2011-11-09 10:47:57 +00:00
for ( i = 0 ; i < segment - > nb_index_entries ; i + + ) {
2011-12-08 10:39:59 +00:00
segment - > temporal_offset_entries [ i ] = avio_r8 ( pb ) ;
avio_r8 ( pb ) ; /* KeyFrameOffset */
2011-11-09 10:47:57 +00:00
segment - > flag_entries [ i ] = avio_r8 ( pb ) ;
segment - > stream_offset_entries [ i ] = avio_rb64 ( pb ) ;
2011-12-16 10:02:04 +00:00
avio_skip ( pb , length - 11 ) ;
2011-11-09 10:47:57 +00:00
}
return 0 ;
}
2011-12-08 16:45:35 +00:00
static int mxf_read_index_table_segment ( void * arg , AVIOContext * pb , int tag , int size , UID uid , int64_t klv_offset )
2009-01-08 02:54:43 +00:00
{
2011-11-09 10:47:57 +00:00
MXFIndexTableSegment * segment = arg ;
2009-01-08 02:54:43 +00:00
switch ( tag ) {
2011-11-09 10:47:57 +00:00
case 0x3F05 :
segment - > edit_unit_byte_count = avio_rb32 ( pb ) ;
2015-03-16 08:57:35 +00:00
av_log ( NULL , AV_LOG_TRACE , " EditUnitByteCount %d \n " , segment - > edit_unit_byte_count ) ;
2011-11-09 10:47:57 +00:00
break ;
case 0x3F06 :
segment - > index_sid = avio_rb32 ( pb ) ;
2015-03-16 08:57:35 +00:00
av_log ( NULL , AV_LOG_TRACE , " IndexSID %d \n " , segment - > index_sid ) ;
2011-11-09 10:47:57 +00:00
break ;
case 0x3F07 :
segment - > body_sid = avio_rb32 ( pb ) ;
2015-03-16 08:57:35 +00:00
av_log ( NULL , AV_LOG_TRACE , " BodySID %d \n " , segment - > body_sid ) ;
2011-11-09 10:47:57 +00:00
break ;
case 0x3F0A :
2015-03-16 08:57:35 +00:00
av_log ( NULL , AV_LOG_TRACE , " IndexEntryArray found \n " ) ;
2011-11-09 10:47:57 +00:00
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 ) ;
2015-03-16 08:57:35 +00:00
av_log ( NULL , AV_LOG_TRACE , " IndexEditRate %d/%d \n " , segment - > index_edit_rate . num ,
2011-11-09 10:47:57 +00:00
segment - > index_edit_rate . den ) ;
break ;
case 0x3F0C :
segment - > index_start_position = avio_rb64 ( pb ) ;
2015-03-16 08:57:35 +00:00
av_log ( NULL , AV_LOG_TRACE , " IndexStartPosition % " PRId64 " \n " , segment - > index_start_position ) ;
2011-11-09 10:47:57 +00:00
break ;
case 0x3F0D :
segment - > index_duration = avio_rb64 ( pb ) ;
2015-03-16 08:57:35 +00:00
av_log ( NULL , AV_LOG_TRACE , " IndexDuration % " PRId64 " \n " , segment - > index_duration ) ;
2011-11-09 10:47:57 +00:00
break ;
2009-01-08 02:54:43 +00:00
}
return 0 ;
}
2011-02-20 10:04:12 +00:00
static void mxf_read_pixel_layout ( AVIOContext * pb , MXFDescriptor * descriptor )
2008-08-07 02:12:14 +00:00
{
2010-06-30 07:55:05 +00:00
int code , value , ofs = 0 ;
2012-10-24 14:50:26 +00:00
char layout [ 16 ] = { 0 } ; /* not for printing, may end up not terminated on purpose */
2008-08-07 02:12:14 +00:00
do {
2011-02-21 15:43:01 +00:00
code = avio_r8 ( pb ) ;
value = avio_r8 ( pb ) ;
2015-03-16 08:57:35 +00:00
av_log ( NULL , AV_LOG_TRACE , " pixel layout: code %#x \n " , code ) ;
2010-06-30 07:55:05 +00:00
2012-10-24 14:50:26 +00:00
if ( ofs < = 14 ) {
2010-06-30 07:55:05 +00:00
layout [ ofs + + ] = code ;
layout [ ofs + + ] = value ;
2012-10-24 14:51:41 +00:00
} else
break ; /* don't read byte by byte on sneaky files filled with lots of non-zeroes */
2008-08-07 02:12:14 +00:00
} while ( code ! = 0 ) ; /* SMPTE 377M E.2.46 */
2010-06-30 07:55:05 +00:00
ff_mxf_decode_pixel_layout ( layout , & descriptor - > pix_fmt ) ;
2008-08-07 02:12:14 +00:00
}
2011-12-08 16:45:35 +00:00
static int mxf_read_generic_descriptor ( void * arg , AVIOContext * pb , int tag , int size , UID uid , int64_t klv_offset )
2008-08-07 02:12:14 +00:00
{
2010-07-01 17:10:31 +00:00
MXFDescriptor * descriptor = arg ;
2008-08-07 02:12:14 +00:00
switch ( tag ) {
case 0x3F01 :
2015-03-02 02:33:10 +00:00
return mxf_read_strong_ref_array ( pb , & descriptor - > sub_descriptors_refs ,
& descriptor - > sub_descriptors_count ) ;
2014-11-30 20:16:27 +00:00
case 0x3002 : /* ContainerDuration */
descriptor - > duration = avio_rb64 ( pb ) ;
break ;
2008-08-07 02:12:14 +00:00
case 0x3004 :
2011-02-21 15:43:01 +00:00
avio_read ( pb , descriptor - > essence_container_ul , 16 ) ;
2008-08-07 02:12:14 +00:00
break ;
case 0x3006 :
2011-02-21 15:43:01 +00:00
descriptor - > linked_track_id = avio_rb32 ( pb ) ;
2008-08-07 02:12:14 +00:00
break ;
case 0x3201 : /* PictureEssenceCoding */
2011-02-21 15:43:01 +00:00
avio_read ( pb , descriptor - > essence_codec_ul , 16 ) ;
2008-08-07 02:12:14 +00:00
break ;
case 0x3203 :
2011-02-21 15:43:01 +00:00
descriptor - > width = avio_rb32 ( pb ) ;
2008-08-07 02:12:14 +00:00
break ;
case 0x3202 :
2011-02-21 15:43:01 +00:00
descriptor - > height = avio_rb32 ( pb ) ;
2008-08-07 02:12:14 +00:00
break ;
2012-02-07 10:48:43 +00:00
case 0x320C :
descriptor - > frame_layout = avio_r8 ( pb ) ;
break ;
2008-08-07 02:12:14 +00:00
case 0x320E :
2011-02-21 15:43:01 +00:00
descriptor - > aspect_ratio . num = avio_rb32 ( pb ) ;
descriptor - > aspect_ratio . den = avio_rb32 ( pb ) ;
2008-08-07 02:12:14 +00:00
break ;
2013-02-16 12:52:29 +00:00
case 0x3212 :
descriptor - > field_dominance = avio_r8 ( pb ) ;
break ;
2012-02-28 14:16:39 +00:00
case 0x3301 :
descriptor - > component_depth = avio_rb32 ( pb ) ;
break ;
case 0x3302 :
descriptor - > horiz_subsampling = avio_rb32 ( pb ) ;
break ;
case 0x3308 :
descriptor - > vert_subsampling = avio_rb32 ( pb ) ;
break ;
2008-08-07 02:12:14 +00:00
case 0x3D03 :
2011-02-21 15:43:01 +00:00
descriptor - > sample_rate . num = avio_rb32 ( pb ) ;
descriptor - > sample_rate . den = avio_rb32 ( pb ) ;
2008-08-07 02:12:14 +00:00
break ;
case 0x3D06 : /* SoundEssenceCompression */
2011-02-21 15:43:01 +00:00
avio_read ( pb , descriptor - > essence_codec_ul , 16 ) ;
2008-08-07 02:12:14 +00:00
break ;
case 0x3D07 :
2011-02-21 15:43:01 +00:00
descriptor - > channels = avio_rb32 ( pb ) ;
2008-08-07 02:12:14 +00:00
break ;
case 0x3D01 :
2011-02-21 15:43:01 +00:00
descriptor - > bits_per_sample = avio_rb32 ( pb ) ;
2008-08-07 02:12:14 +00: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 ) ) {
2012-12-11 13:43:47 +00:00
if ( descriptor - > extradata )
av_log ( NULL , AV_LOG_WARNING , " Duplicate sony_mpeg4_extradata \n " ) ;
av_free ( descriptor - > extradata ) ;
descriptor - > extradata_size = 0 ;
2012-12-11 13:47:40 +00:00
descriptor - > extradata = av_malloc ( size ) ;
2008-08-07 02:12:14 +00:00
if ( ! descriptor - > extradata )
2012-01-14 21:25:12 +00:00
return AVERROR ( ENOMEM ) ;
2008-08-07 02:12:14 +00:00
descriptor - > extradata_size = size ;
2011-02-21 15:43:01 +00:00
avio_read ( pb , descriptor - > extradata , size ) ;
2008-08-07 02:12:14 +00:00
}
2015-03-04 22:36:50 +00:00
if ( IS_KLV_KEY ( uid , mxf_jp2k_rsiz ) ) {
uint32_t rsiz = avio_rb16 ( pb ) ;
if ( rsiz = = FF_PROFILE_JPEG2000_DCINEMA_2K | |
rsiz = = FF_PROFILE_JPEG2000_DCINEMA_4K )
descriptor - > pix_fmt = AV_PIX_FMT_XYZ12 ;
}
2008-08-07 02:12:14 +00:00
break ;
}
return 0 ;
}
2015-03-14 01:58:38 +00:00
static int mxf_read_indirect_value ( void * arg , AVIOContext * pb , int size )
{
MXFTaggedValue * tagged_value = arg ;
uint8_t key [ 17 ] ;
if ( size < = 17 )
return 0 ;
avio_read ( pb , key , 17 ) ;
/* TODO: handle other types of of indirect values */
if ( memcmp ( key , mxf_indirect_value_utf16le , 17 ) = = 0 ) {
return mxf_read_utf16le_string ( pb , size - 17 , & tagged_value - > value ) ;
} else if ( memcmp ( key , mxf_indirect_value_utf16be , 17 ) = = 0 ) {
return mxf_read_utf16be_string ( pb , size - 17 , & tagged_value - > value ) ;
}
return 0 ;
}
static int mxf_read_tagged_value ( void * arg , AVIOContext * pb , int tag , int size , UID uid , int64_t klv_offset )
{
MXFTaggedValue * tagged_value = arg ;
switch ( tag ) {
case 0x5001 :
return mxf_read_utf16be_string ( pb , size , & tagged_value - > name ) ;
case 0x5003 :
return mxf_read_indirect_value ( tagged_value , pb , size ) ;
}
return 0 ;
}
2008-08-07 02:12:14 +00:00
/*
* 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 05:12:30 +00:00
while ( uls - > uid [ 0 ] ) {
2008-08-07 02:12:14 +00: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 ;
}
2011-12-10 13:58:57 +00:00
static const MXFCodecUL mxf_picture_essence_container_uls [ ] = {
2008-08-31 01:39:42 +00:00
// video essence container uls
2014-03-13 12:34:16 +00:00
{ { 0x06 , 0x0e , 0x2b , 0x34 , 0x04 , 0x01 , 0x01 , 0x02 , 0x0d , 0x01 , 0x03 , 0x01 , 0x02 , 0x04 , 0x60 , 0x01 } , 14 , AV_CODEC_ID_MPEG2VIDEO } , /* MPEG-ES Frame wrapped */
{ { 0x06 , 0x0e , 0x2b , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x0d , 0x01 , 0x03 , 0x01 , 0x02 , 0x02 , 0x41 , 0x01 } , 14 , AV_CODEC_ID_DVVIDEO } , /* DV 625 25mbps */
{ { 0x06 , 0x0e , 0x2b , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x0d , 0x01 , 0x03 , 0x01 , 0x02 , 0x05 , 0x00 , 0x00 } , 14 , AV_CODEC_ID_RAWVIDEO } , /* Uncompressed Picture */
2014-11-30 20:16:27 +00:00
{ { 0x06 , 0x0e , 0x2b , 0x34 , 0x01 , 0x01 , 0x01 , 0xff , 0x4b , 0x46 , 0x41 , 0x41 , 0x00 , 0x0d , 0x4d , 0x4f } , 14 , AV_CODEC_ID_RAWVIDEO } , /* Legacy ?? Uncompressed Picture */
2012-08-05 09:11:04 +00:00
{ { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } , 0 , AV_CODEC_ID_NONE } ,
2011-12-10 13:58:57 +00:00
} ;
2012-03-07 09:52:39 +00:00
/* EC ULs for intra-only formats */
static const MXFCodecUL mxf_intra_only_essence_container_uls [ ] = {
2014-03-13 12:34:16 +00:00
{ { 0x06 , 0x0e , 0x2b , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x0d , 0x01 , 0x03 , 0x01 , 0x02 , 0x01 , 0x00 , 0x00 } , 14 , AV_CODEC_ID_MPEG2VIDEO } , /* MXF-GC SMPTE D-10 Mappings */
2012-08-05 09:11:04 +00:00
{ { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } , 0 , AV_CODEC_ID_NONE } ,
2012-03-07 09:52:39 +00:00
} ;
/* intra-only PictureEssenceCoding ULs, where no corresponding EC UL exists */
static const MXFCodecUL mxf_intra_only_picture_essence_coding_uls [ ] = {
2014-03-13 12:34:16 +00:00
{ { 0x06 , 0x0e , 0x2b , 0x34 , 0x04 , 0x01 , 0x01 , 0x0A , 0x04 , 0x01 , 0x02 , 0x02 , 0x01 , 0x32 , 0x00 , 0x00 } , 14 , AV_CODEC_ID_H264 } , /* H.264/MPEG-4 AVC Intra Profiles */
{ { 0x06 , 0x0e , 0x2b , 0x34 , 0x04 , 0x01 , 0x01 , 0x07 , 0x04 , 0x01 , 0x02 , 0x02 , 0x03 , 0x01 , 0x01 , 0x00 } , 14 , AV_CODEC_ID_JPEG2000 } , /* JPEG2000 Codestream */
2012-08-05 09:11:04 +00:00
{ { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } , 0 , AV_CODEC_ID_NONE } ,
2012-03-07 09:52:39 +00:00
} ;
2011-12-10 13:58:57 +00:00
static const MXFCodecUL mxf_sound_essence_container_uls [ ] = {
2008-08-31 01:39:42 +00:00
// sound essence container uls
2014-03-13 12:34:16 +00:00
{ { 0x06 , 0x0e , 0x2b , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x0d , 0x01 , 0x03 , 0x01 , 0x02 , 0x06 , 0x01 , 0x00 } , 14 , AV_CODEC_ID_PCM_S16LE } , /* BWF Frame wrapped */
{ { 0x06 , 0x0e , 0x2b , 0x34 , 0x04 , 0x01 , 0x01 , 0x02 , 0x0d , 0x01 , 0x03 , 0x01 , 0x02 , 0x04 , 0x40 , 0x01 } , 14 , AV_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 , AV_CODEC_ID_PCM_S16LE } , /* D-10 Mapping 50Mbps PAL Extended Template */
{ { 0x06 , 0x0e , 0x2b , 0x34 , 0x01 , 0x01 , 0x01 , 0xff , 0x4b , 0x46 , 0x41 , 0x41 , 0x00 , 0x0d , 0x4d , 0x4F } , 14 , AV_CODEC_ID_PCM_S16LE } , /* 0001GL00.MXF.A1.mxf_opatom.mxf */
2014-08-12 16:58:52 +00:00
{ { 0x06 , 0x0e , 0x2b , 0x34 , 0x04 , 0x01 , 0x01 , 0x03 , 0x04 , 0x02 , 0x02 , 0x02 , 0x03 , 0x03 , 0x01 , 0x00 } , 14 , AV_CODEC_ID_AAC } , /* MPEG2 AAC ADTS (legacy) */
2012-08-05 09:11:04 +00:00
{ { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } , 0 , AV_CODEC_ID_NONE } ,
2008-08-31 01:39:42 +00:00
} ;
2014-07-22 14:08:52 +00:00
static const MXFCodecUL mxf_data_essence_container_uls [ ] = {
{ { 0x06 , 0x0e , 0x2b , 0x34 , 0x04 , 0x01 , 0x01 , 0x09 , 0x0d , 0x01 , 0x03 , 0x01 , 0x02 , 0x0e , 0x00 , 0x00 } , 16 , 0 } ,
2014-10-14 23:36:04 +00:00
{ { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } , 0 , AV_CODEC_ID_NONE } ,
2014-07-22 14:08:52 +00:00
} ;
2014-07-29 18:17:28 +00:00
static const char * const mxf_data_essence_descriptor [ ] = {
2014-07-22 14:08:52 +00:00
" vbi_vanc_smpte_436M " ,
} ;
2011-11-09 10:47:57 +00: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 + + ;
2012-10-09 19:45:23 +00:00
if ( ! nb_segments )
return AVERROR_INVALIDDATA ;
2011-11-09 10:47:57 +00:00
if ( ! ( unsorted_segments = av_calloc ( nb_segments , sizeof ( * unsorted_segments ) ) ) | |
! ( * sorted_segments = av_calloc ( nb_segments , sizeof ( * * sorted_segments ) ) ) ) {
2011-11-09 10:47:57 +00:00
av_freep ( sorted_segments ) ;
2011-11-09 10:47:57 +00:00
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 ;
mxfdec: Fix regression on files from Pinnacle Thunder
The reason for this is that such files have IndexTableSegments which when parsed
cover EditUnit ranges like this:
[0,1)
[249,250)
[249,377)
[0,249)
where each interval is [IndexStartPosition,IndexStartPosition+IndexDuration).
This would be reduced to a sparse index like:
[0,1), [249,250)
instead of the full range:
[0,249), [249,377)
See TimeCode_HD.mxf, UMID =
060a2b340101010101010410130000000004001aa0e59175025b2a5600da4101.
Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
2012-04-04 12:24:49 +00:00
uint64_t best_index_duration = 0 ;
2011-11-09 10:47:57 +00:00
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 .
mxfdec: Fix regression on files from Pinnacle Thunder
The reason for this is that such files have IndexTableSegments which when parsed
cover EditUnit ranges like this:
[0,1)
[249,250)
[249,377)
[0,249)
where each interval is [IndexStartPosition,IndexStartPosition+IndexDuration).
This would be reduced to a sparse index like:
[0,1), [249,250)
instead of the full range:
[0,249), [249,377)
See TimeCode_HD.mxf, UMID =
060a2b340101010101010410130000000004001aa0e59175025b2a5600da4101.
Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
2012-04-04 12:24:49 +00:00
* If we come across an entry with the same IndexStartPosition but larger IndexDuration , then we ' ll prefer it over the one we currently have .
2011-11-09 10:47:57 +00:00
*/
if ( ( i = = 0 | | s - > body_sid > last_body_sid | | s - > index_sid > last_index_sid | | s - > index_start_position > last_index_start ) & &
mxfdec: Fix regression on files from Pinnacle Thunder
The reason for this is that such files have IndexTableSegments which when parsed
cover EditUnit ranges like this:
[0,1)
[249,250)
[249,377)
[0,249)
where each interval is [IndexStartPosition,IndexStartPosition+IndexDuration).
This would be reduced to a sparse index like:
[0,1), [249,250)
instead of the full range:
[0,249), [249,377)
See TimeCode_HD.mxf, UMID =
060a2b340101010101010410130000000004001aa0e59175025b2a5600da4101.
Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
2012-04-04 12:24:49 +00:00
( best = = - 1 | | s - > body_sid < best_body_sid | | s - > index_sid < best_index_sid | | s - > index_start_position < best_index_start | |
( s - > index_start_position = = best_index_start & & s - > index_duration > best_index_duration ) ) ) {
2011-11-09 10:47:57 +00:00
best = j ;
best_body_sid = s - > body_sid ;
best_index_sid = s - > index_sid ;
best_index_start = s - > index_start_position ;
mxfdec: Fix regression on files from Pinnacle Thunder
The reason for this is that such files have IndexTableSegments which when parsed
cover EditUnit ranges like this:
[0,1)
[249,250)
[249,377)
[0,249)
where each interval is [IndexStartPosition,IndexStartPosition+IndexDuration).
This would be reduced to a sparse index like:
[0,1), [249,250)
instead of the full range:
[0,249), [249,377)
See TimeCode_HD.mxf, UMID =
060a2b340101010101010410130000000004001aa0e59175025b2a5600da4101.
Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
2012-04-04 12:24:49 +00:00
best_index_duration = s - > index_duration ;
2011-11-09 10:47:57 +00:00
}
}
/* 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 ;
}
2011-12-08 11:23:36 +00:00
/**
* Computes the absolute file offset of the given essence container offset
*/
static int mxf_absolute_bodysid_offset ( MXFContext * mxf , int body_sid , int64_t offset , int64_t * offset_out )
{
int x ;
int64_t offset_in = offset ; /* for logging */
for ( x = 0 ; x < mxf - > partitions_count ; x + + ) {
MXFPartition * p = & mxf - > partitions [ x ] ;
if ( p - > body_sid ! = body_sid )
continue ;
if ( offset < p - > essence_length | | ! p - > essence_length ) {
* offset_out = p - > essence_offset + offset ;
return 0 ;
}
offset - = p - > essence_length ;
}
2012-01-26 12:21:42 +00:00
av_log ( mxf - > fc , AV_LOG_ERROR ,
" failed to find absolute offset of % " PRIX64 " in BodySID %i - partial file? \n " ,
2011-12-08 11:23:36 +00:00
offset_in , body_sid ) ;
return AVERROR_INVALIDDATA ;
}
2011-12-16 09:53:41 +00:00
/**
* Returns the end position of the essence container with given BodySID , or zero if unknown
*/
static int64_t mxf_essence_container_end ( MXFContext * mxf , int body_sid )
{
int x ;
int64_t ret = 0 ;
for ( x = 0 ; x < mxf - > partitions_count ; x + + ) {
MXFPartition * p = & mxf - > partitions [ x ] ;
if ( p - > body_sid ! = body_sid )
continue ;
if ( ! p - > essence_length )
return 0 ;
ret = p - > essence_offset + p - > essence_length ;
}
return ret ;
}
2011-12-15 15:53:38 +00:00
/* EditUnit -> absolute offset */
static int mxf_edit_unit_absolute_offset ( MXFContext * mxf , MXFIndexTable * index_table , int64_t edit_unit , int64_t * edit_unit_out , int64_t * offset_out , int nag )
{
int i ;
2012-01-24 11:24:24 +00:00
int64_t offset_temp = 0 ;
2011-12-15 15:53:38 +00:00
for ( i = 0 ; i < index_table - > nb_segments ; i + + ) {
MXFIndexTableSegment * s = index_table - > segments [ i ] ;
edit_unit = FFMAX ( edit_unit , s - > index_start_position ) ; /* clamp if trying to seek before start */
if ( edit_unit < s - > index_start_position + s - > index_duration ) {
int64_t index = edit_unit - s - > index_start_position ;
if ( s - > edit_unit_byte_count )
offset_temp + = s - > edit_unit_byte_count * index ;
else if ( s - > nb_index_entries ) {
if ( s - > nb_index_entries = = 2 * s - > index_duration + 1 )
index * = 2 ; /* Avid index */
2012-03-26 13:05:02 +00:00
if ( index < 0 | | index > = s - > nb_index_entries ) {
2011-12-15 15:53:38 +00:00
av_log ( mxf - > fc , AV_LOG_ERROR , " IndexSID %i segment at % " PRId64 " IndexEntryArray too small \n " ,
index_table - > index_sid , s - > index_start_position ) ;
return AVERROR_INVALIDDATA ;
}
offset_temp = s - > stream_offset_entries [ index ] ;
} else {
av_log ( mxf - > fc , AV_LOG_ERROR , " IndexSID %i segment at % " PRId64 " missing EditUnitByteCount and IndexEntryArray \n " ,
index_table - > index_sid , s - > index_start_position ) ;
return AVERROR_INVALIDDATA ;
}
if ( edit_unit_out )
* edit_unit_out = edit_unit ;
return mxf_absolute_bodysid_offset ( mxf , index_table - > body_sid , offset_temp , offset_out ) ;
} else {
/* EditUnitByteCount == 0 for VBR indexes, which is fine since they use explicit StreamOffsets */
offset_temp + = s - > edit_unit_byte_count * s - > index_duration ;
}
}
if ( nag )
av_log ( mxf - > fc , AV_LOG_ERROR , " failed to map EditUnit % " PRId64 " in IndexSID %i to an offset \n " , edit_unit , index_table - > index_sid ) ;
return AVERROR_INVALIDDATA ;
}
2011-12-16 08:42:52 +00:00
static int mxf_compute_ptses_fake_index ( MXFContext * mxf , MXFIndexTable * index_table )
2011-12-09 16:56:46 +00:00
{
2011-12-16 08:42:52 +00:00
int i , j , x ;
2011-12-09 16:56:46 +00:00
int8_t max_temporal_offset = - 128 ;
/* first compute how many entries we have */
2011-12-16 08:42:52 +00:00
for ( i = 0 ; i < index_table - > nb_segments ; i + + ) {
MXFIndexTableSegment * s = index_table - > segments [ i ] ;
2011-12-09 16:56:46 +00:00
2011-12-21 10:58:01 +00:00
if ( ! s - > nb_index_entries ) {
index_table - > nb_ptses = 0 ;
2011-12-09 16:56:46 +00:00
return 0 ; /* no TemporalOffsets */
2011-12-21 10:58:01 +00:00
}
2011-12-09 16:56:46 +00:00
2011-12-16 08:42:52 +00:00
index_table - > nb_ptses + = s - > index_duration ;
2011-12-09 16:56:46 +00:00
}
/* paranoid check */
2011-12-16 08:42:52 +00:00
if ( index_table - > nb_ptses < = 0 )
2011-12-09 16:56:46 +00:00
return 0 ;
2011-12-16 08:42:52 +00:00
if ( ! ( index_table - > ptses = av_calloc ( index_table - > nb_ptses , sizeof ( int64_t ) ) ) | |
! ( index_table - > fake_index = av_calloc ( index_table - > nb_ptses , sizeof ( AVIndexEntry ) ) ) ) {
av_freep ( & index_table - > ptses ) ;
2011-12-09 16:56:46 +00:00
return AVERROR ( ENOMEM ) ;
2011-12-16 08:42:52 +00:00
}
2011-12-09 16:56:46 +00:00
/* we may have a few bad TemporalOffsets
* make sure the corresponding PTSes don ' t have the bogus value 0 */
2011-12-16 08:42:52 +00:00
for ( x = 0 ; x < index_table - > nb_ptses ; x + + )
index_table - > ptses [ x ] = AV_NOPTS_VALUE ;
2011-12-09 16:56:46 +00:00
/**
* We have this :
*
* x TemporalOffset
* 0 : 0
* 1 : 1
* 2 : 1
* 3 : - 2
* 4 : 1
* 5 : 1
* 6 : - 2
*
* We want to transform it into this :
*
* x DTS PTS
* 0 : - 1 0
* 1 : 0 3
* 2 : 1 1
* 3 : 2 2
* 4 : 3 6
* 5 : 4 4
* 6 : 5 5
*
* We do this by bucket sorting x by x + TemporalOffset [ x ] into mxf - > ptses ,
* then settings mxf - > first_dts = - max ( TemporalOffset [ x ] ) .
* The latter makes DTS < = PTS .
*/
2011-12-16 08:42:52 +00:00
for ( i = x = 0 ; i < index_table - > nb_segments ; i + + ) {
MXFIndexTableSegment * s = index_table - > segments [ i ] ;
2011-12-09 16:56:46 +00:00
int index_delta = 1 ;
2011-12-19 10:00:14 +00:00
int n = s - > nb_index_entries ;
2011-12-09 16:56:46 +00:00
2011-12-19 10:00:14 +00:00
if ( s - > nb_index_entries = = 2 * s - > index_duration + 1 ) {
2011-12-09 16:56:46 +00:00
index_delta = 2 ; /* Avid index */
2011-12-19 10:00:14 +00:00
/* ignore the last entry - it's the size of the essence container */
n - - ;
}
for ( j = 0 ; j < n ; j + = index_delta , x + + ) {
2011-12-09 16:56:46 +00:00
int offset = s - > temporal_offset_entries [ j ] / index_delta ;
int index = x + offset ;
2011-12-20 08:57:07 +00:00
if ( x > = index_table - > nb_ptses ) {
2012-01-26 12:21:31 +00:00
av_log ( mxf - > fc , AV_LOG_ERROR ,
" x >= nb_ptses - IndexEntryCount %i < IndexDuration % " PRId64 " ? \n " ,
2011-12-20 08:57:07 +00:00
s - > nb_index_entries , s - > index_duration ) ;
break ;
}
2011-12-16 08:42:52 +00:00
index_table - > fake_index [ x ] . timestamp = x ;
index_table - > fake_index [ x ] . flags = ! ( s - > flag_entries [ j ] & 0x30 ) ? AVINDEX_KEYFRAME : 0 ;
if ( index < 0 | | index > = index_table - > nb_ptses ) {
2011-12-09 16:56:46 +00:00
av_log ( mxf - > fc , AV_LOG_ERROR ,
" index entry %i + TemporalOffset %i = %i, which is out of bounds \n " ,
x , offset , index ) ;
continue ;
}
2011-12-16 08:42:52 +00:00
index_table - > ptses [ index ] = x ;
2011-12-09 16:56:46 +00:00
max_temporal_offset = FFMAX ( max_temporal_offset , offset ) ;
}
}
2011-12-16 08:42:52 +00:00
index_table - > first_dts = - max_temporal_offset ;
2011-12-09 16:56:46 +00:00
return 0 ;
}
2011-12-15 15:47:49 +00:00
/**
* Sorts and collects index table segments into index tables .
* Also computes PTSes if possible .
*/
static int mxf_compute_index_tables ( MXFContext * mxf )
{
2011-12-16 08:50:58 +00:00
int i , j , k , ret , nb_sorted_segments ;
2011-12-15 15:47:49 +00:00
MXFIndexTableSegment * * sorted_segments = NULL ;
if ( ( ret = mxf_get_sorted_table_segments ( mxf , & nb_sorted_segments , & sorted_segments ) ) | |
nb_sorted_segments < = 0 ) {
av_log ( mxf - > fc , AV_LOG_WARNING , " broken or empty index \n " ) ;
return 0 ;
}
/* sanity check and count unique BodySIDs/IndexSIDs */
for ( i = 0 ; i < nb_sorted_segments ; i + + ) {
if ( i = = 0 | | sorted_segments [ i - 1 ] - > index_sid ! = sorted_segments [ i ] - > index_sid )
mxf - > nb_index_tables + + ;
else if ( sorted_segments [ i - 1 ] - > body_sid ! = sorted_segments [ i ] - > body_sid ) {
av_log ( mxf - > fc , AV_LOG_ERROR , " found inconsistent BodySID \n " ) ;
ret = AVERROR_INVALIDDATA ;
goto finish_decoding_index ;
}
}
2014-01-07 22:54:09 +00:00
mxf - > index_tables = av_mallocz_array ( mxf - > nb_index_tables ,
sizeof ( * mxf - > index_tables ) ) ;
if ( ! mxf - > index_tables ) {
2011-12-15 15:47:49 +00:00
av_log ( mxf - > fc , AV_LOG_ERROR , " failed to allocate index tables \n " ) ;
ret = AVERROR ( ENOMEM ) ;
goto finish_decoding_index ;
}
/* distribute sorted segments to index tables */
for ( i = j = 0 ; i < nb_sorted_segments ; i + + ) {
if ( i ! = 0 & & sorted_segments [ i - 1 ] - > index_sid ! = sorted_segments [ i ] - > index_sid ) {
/* next IndexSID */
j + + ;
}
mxf - > index_tables [ j ] . nb_segments + + ;
}
for ( i = j = 0 ; j < mxf - > nb_index_tables ; i + = mxf - > index_tables [ j + + ] . nb_segments ) {
MXFIndexTable * t = & mxf - > index_tables [ j ] ;
2014-01-07 22:54:09 +00:00
t - > segments = av_mallocz_array ( t - > nb_segments ,
sizeof ( * t - > segments ) ) ;
if ( ! t - > segments ) {
2011-12-08 19:28:49 +00:00
av_log ( mxf - > fc , AV_LOG_ERROR , " failed to allocate IndexTableSegment "
" pointer array \n " ) ;
2011-12-15 15:47:49 +00:00
ret = AVERROR ( ENOMEM ) ;
goto finish_decoding_index ;
}
if ( sorted_segments [ i ] - > index_start_position )
av_log ( mxf - > fc , AV_LOG_WARNING , " IndexSID %i starts at EditUnit % " PRId64 " - seeking may not work as expected \n " ,
sorted_segments [ i ] - > index_sid , sorted_segments [ i ] - > index_start_position ) ;
memcpy ( t - > segments , & sorted_segments [ i ] , t - > nb_segments * sizeof ( MXFIndexTableSegment * ) ) ;
t - > index_sid = sorted_segments [ i ] - > index_sid ;
t - > body_sid = sorted_segments [ i ] - > body_sid ;
2011-12-16 08:42:52 +00:00
if ( ( ret = mxf_compute_ptses_fake_index ( mxf , t ) ) < 0 )
goto finish_decoding_index ;
2011-12-16 08:50:58 +00:00
/* fix zero IndexDurations */
for ( k = 0 ; k < t - > nb_segments ; k + + ) {
if ( t - > segments [ k ] - > index_duration )
continue ;
if ( t - > nb_segments > 1 )
av_log ( mxf - > fc , AV_LOG_WARNING , " IndexSID %i segment %i has zero IndexDuration and there's more than one segment \n " ,
t - > index_sid , k ) ;
if ( mxf - > fc - > nb_streams < = 0 ) {
av_log ( mxf - > fc , AV_LOG_WARNING , " no streams? \n " ) ;
break ;
}
/* assume the first stream's duration is reasonable
* leave index_duration = 0 on further segments in case we have any ( unlikely )
*/
t - > segments [ k ] - > index_duration = mxf - > fc - > streams [ 0 ] - > duration ;
break ;
}
2011-12-15 15:47:49 +00:00
}
ret = 0 ;
finish_decoding_index :
av_free ( sorted_segments ) ;
return ret ;
}
2012-03-07 09:52:39 +00:00
static int mxf_is_intra_only ( MXFDescriptor * descriptor )
{
return mxf_get_codec_ul ( mxf_intra_only_essence_container_uls ,
2012-08-07 20:45:46 +00:00
& descriptor - > essence_container_ul ) - > id ! = AV_CODEC_ID_NONE | |
2012-03-07 09:52:39 +00:00
mxf_get_codec_ul ( mxf_intra_only_picture_essence_coding_uls ,
2012-08-07 20:45:46 +00:00
& descriptor - > essence_codec_ul ) - > id ! = AV_CODEC_ID_NONE ;
2012-03-07 09:52:39 +00:00
}
2014-11-22 01:43:09 +00:00
static int mxf_uid_to_str ( UID uid , char * * str )
{
int i ;
char * p ;
p = * str = av_mallocz ( sizeof ( UID ) * 2 + 4 + 1 ) ;
if ( ! p )
return AVERROR ( ENOMEM ) ;
for ( i = 0 ; i < sizeof ( UID ) ; i + + ) {
snprintf ( p , 2 + 1 , " %.2x " , uid [ i ] ) ;
p + = 2 ;
if ( i = = 3 | | i = = 5 | | i = = 7 | | i = = 9 ) {
snprintf ( p , 1 + 1 , " - " ) ;
p + + ;
}
}
return 0 ;
}
2015-01-10 02:05:27 +00:00
static int mxf_umid_to_str ( UID ul , UID uid , char * * str )
{
int i ;
char * p ;
p = * str = av_mallocz ( sizeof ( UID ) * 4 + 2 + 1 ) ;
if ( ! p )
return AVERROR ( ENOMEM ) ;
snprintf ( p , 2 + 1 , " 0x " ) ;
p + = 2 ;
for ( i = 0 ; i < sizeof ( UID ) ; i + + ) {
snprintf ( p , 2 + 1 , " %.2X " , ul [ i ] ) ;
p + = 2 ;
}
for ( i = 0 ; i < sizeof ( UID ) ; i + + ) {
snprintf ( p , 2 + 1 , " %.2X " , uid [ i ] ) ;
p + = 2 ;
}
return 0 ;
}
static int mxf_add_umid_metadata ( AVDictionary * * pm , const char * key , MXFPackage * package )
2014-11-22 01:43:09 +00:00
{
char * str ;
int ret ;
2015-01-10 02:05:27 +00:00
if ( ! package )
return 0 ;
if ( ( ret = mxf_umid_to_str ( package - > package_ul , package - > package_uid , & str ) ) < 0 )
2014-11-22 01:43:09 +00:00
return ret ;
av_dict_set ( pm , key , str , AV_DICT_DONT_STRDUP_VAL ) ;
return 0 ;
}
2012-02-23 15:58:01 +00:00
static int mxf_add_timecode_metadata ( AVDictionary * * pm , const char * key , AVTimecode * tc )
{
char buf [ AV_TIMECODE_STR_SIZE ] ;
av_dict_set ( pm , key , av_timecode_make_string ( tc , buf , 0 ) , 0 ) ;
return 0 ;
}
2014-11-12 20:15:21 +00:00
static MXFTimecodeComponent * mxf_resolve_timecode_component ( MXFContext * mxf , UID * strong_ref )
{
MXFStructuralComponent * component = NULL ;
MXFPulldownComponent * pulldown = NULL ;
component = mxf_resolve_strong_ref ( mxf , strong_ref , AnyType ) ;
if ( ! component )
return NULL ;
switch ( component - > type ) {
case TimecodeComponent :
return ( MXFTimecodeComponent * ) component ;
case PulldownComponent : /* timcode component may be located on a pulldown component */
pulldown = ( MXFPulldownComponent * ) component ;
return mxf_resolve_strong_ref ( mxf , & pulldown - > input_segment_ref , TimecodeComponent ) ;
default :
break ;
}
return NULL ;
}
2014-11-30 20:16:27 +00:00
static MXFPackage * mxf_resolve_source_package ( MXFContext * mxf , UID package_uid )
{
MXFPackage * package = NULL ;
int i ;
for ( i = 0 ; i < mxf - > packages_count ; i + + ) {
package = mxf_resolve_strong_ref ( mxf , & mxf - > packages_refs [ i ] , SourcePackage ) ;
if ( ! package )
continue ;
if ( ! memcmp ( package - > package_uid , package_uid , 16 ) )
return package ;
}
return NULL ;
}
2014-12-03 00:43:52 +00:00
static MXFDescriptor * mxf_resolve_multidescriptor ( MXFContext * mxf , MXFDescriptor * descriptor , int track_id )
{
MXFDescriptor * sub_descriptor = NULL ;
int i ;
if ( ! descriptor )
return NULL ;
if ( descriptor - > type = = MultipleDescriptor ) {
for ( i = 0 ; i < descriptor - > sub_descriptors_count ; i + + ) {
sub_descriptor = mxf_resolve_strong_ref ( mxf , & descriptor - > sub_descriptors_refs [ i ] , 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 = = track_id ) {
return sub_descriptor ;
}
}
} else if ( descriptor - > type = = Descriptor )
return descriptor ;
return NULL ;
}
2014-11-30 20:16:27 +00:00
static MXFStructuralComponent * mxf_resolve_essence_group_choice ( MXFContext * mxf , MXFEssenceGroup * essence_group )
{
MXFStructuralComponent * component = NULL ;
MXFPackage * package = NULL ;
MXFDescriptor * descriptor = NULL ;
int i ;
if ( ! essence_group | | ! essence_group - > structural_components_count )
return NULL ;
/* essence groups contains multiple representations of the same media,
this return the first components with a valid Descriptor typically index 0 */
for ( i = 0 ; i < essence_group - > structural_components_count ; i + + ) {
component = mxf_resolve_strong_ref ( mxf , & essence_group - > structural_components_refs [ i ] , SourceClip ) ;
if ( ! component )
continue ;
if ( ! ( package = mxf_resolve_source_package ( mxf , component - > source_package_uid ) ) )
continue ;
descriptor = mxf_resolve_strong_ref ( mxf , & package - > descriptor_ref , Descriptor ) ;
2014-12-03 00:43:52 +00:00
if ( descriptor )
2014-11-30 20:16:27 +00:00
return component ;
}
return NULL ;
}
static MXFStructuralComponent * mxf_resolve_sourceclip ( MXFContext * mxf , UID * strong_ref )
{
MXFStructuralComponent * component = NULL ;
component = mxf_resolve_strong_ref ( mxf , strong_ref , AnyType ) ;
if ( ! component )
return NULL ;
switch ( component - > type ) {
case SourceClip :
return component ;
case EssenceGroup :
return mxf_resolve_essence_group_choice ( mxf , ( MXFEssenceGroup * ) component ) ;
default :
break ;
}
return NULL ;
}
2015-03-14 01:58:38 +00:00
static int mxf_parse_package_comments ( MXFContext * mxf , AVDictionary * * pm , MXFPackage * package )
{
MXFTaggedValue * tag ;
int size , i ;
char * key = NULL ;
for ( i = 0 ; i < package - > comment_count ; i + + ) {
tag = mxf_resolve_strong_ref ( mxf , & package - > comment_refs [ i ] , TaggedValue ) ;
if ( ! tag | | ! tag - > name | | ! tag - > value )
continue ;
size = strlen ( tag - > name ) + 8 + 1 ;
key = av_mallocz ( size ) ;
if ( ! key )
return AVERROR ( ENOMEM ) ;
snprintf ( key , size , " comment_%s " , tag - > name ) ;
av_dict_set ( pm , key , tag - > value , AV_DICT_DONT_STRDUP_KEY ) ;
}
return 0 ;
}
2014-10-05 00:42:51 +00:00
static int mxf_parse_physical_source_package ( MXFContext * mxf , MXFTrack * source_track , AVStream * st )
{
MXFPackage * physical_package = NULL ;
MXFTrack * physical_track = NULL ;
MXFStructuralComponent * sourceclip = NULL ;
MXFTimecodeComponent * mxf_tc = NULL ;
int i , j , k ;
AVTimecode tc ;
int flags ;
int64_t start_position ;
for ( i = 0 ; i < source_track - > sequence - > structural_components_count ; i + + ) {
2014-11-30 20:16:27 +00:00
sourceclip = mxf_resolve_strong_ref ( mxf , & source_track - > sequence - > structural_components_refs [ i ] , SourceClip ) ;
if ( ! sourceclip )
2014-10-05 00:42:51 +00:00
continue ;
2014-11-30 20:16:27 +00:00
if ( ! ( physical_package = mxf_resolve_source_package ( mxf , sourceclip - > source_package_uid ) ) )
2014-10-05 00:42:51 +00:00
break ;
2015-01-10 02:05:27 +00:00
mxf_add_umid_metadata ( & st - > metadata , " reel_umid " , physical_package ) ;
2014-11-22 01:43:09 +00:00
2014-10-05 00:42:51 +00:00
/* the name of physical source package is name of the reel or tape */
2014-10-29 02:54:06 +00:00
if ( physical_package - > name & & physical_package - > name [ 0 ] )
2014-10-05 00:42:51 +00:00
av_dict_set ( & st - > metadata , " reel_name " , physical_package - > name , 0 ) ;
/* the source timecode is calculated by adding the start_position of the sourceclip from the file source package track
* to the start_frame of the timecode component located on one of the tracks of the physical source package .
*/
for ( j = 0 ; j < physical_package - > tracks_count ; j + + ) {
if ( ! ( physical_track = mxf_resolve_strong_ref ( mxf , & physical_package - > tracks_refs [ j ] , Track ) ) ) {
av_log ( mxf - > fc , AV_LOG_ERROR , " could not resolve source track strong ref \n " ) ;
continue ;
}
if ( ! ( physical_track - > sequence = mxf_resolve_strong_ref ( mxf , & physical_track - > sequence_ref , Sequence ) ) ) {
av_log ( mxf - > fc , AV_LOG_ERROR , " could not resolve source track sequence strong ref \n " ) ;
continue ;
}
for ( k = 0 ; k < physical_track - > sequence - > structural_components_count ; k + + ) {
2014-11-12 20:15:21 +00:00
if ( ! ( mxf_tc = mxf_resolve_timecode_component ( mxf , & physical_track - > sequence - > structural_components_refs [ k ] ) ) )
continue ;
2014-10-05 00:42:51 +00:00
flags = mxf_tc - > drop_frame = = 1 ? AV_TIMECODE_FLAG_DROPFRAME : 0 ;
/* scale sourceclip start_position to match physical track edit rate */
start_position = av_rescale_q ( sourceclip - > start_position ,
physical_track - > edit_rate ,
source_track - > edit_rate ) ;
if ( av_timecode_init ( & tc , mxf_tc - > rate , flags , start_position + mxf_tc - > start_frame , mxf - > fc ) = = 0 ) {
mxf_add_timecode_metadata ( & st - > metadata , " timecode " , & tc ) ;
return 0 ;
}
}
}
}
return 0 ;
}
2008-08-07 02:12:14 +00:00
static int mxf_parse_structural_metadata ( MXFContext * mxf )
{
MXFPackage * material_package = NULL ;
2011-12-16 09:58:46 +00:00
int i , j , k , ret ;
2008-08-07 02:12:14 +00:00
2015-03-16 08:57:35 +00:00
av_log ( mxf - > fc , AV_LOG_TRACE , " metadata sets count %d \n " , mxf - > metadata_sets_count ) ;
2008-08-07 02:12:14 +00: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 " ) ;
2012-01-14 21:25:12 +00:00
return AVERROR_INVALIDDATA ;
2008-08-07 02:12:14 +00:00
}
2015-01-10 02:05:27 +00:00
mxf_add_umid_metadata ( & mxf - > fc - > metadata , " material_package_umid " , material_package ) ;
2014-11-22 01:43:09 +00:00
if ( material_package - > name & & material_package - > name [ 0 ] )
av_dict_set ( & mxf - > fc - > metadata , " material_package_name " , material_package - > name , 0 ) ;
2015-03-14 01:58:38 +00:00
mxf_parse_package_comments ( mxf , & mxf - > fc - > metadata , material_package ) ;
2014-11-22 01:43:09 +00:00
2008-08-07 02:12:14 +00:00
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 ;
2012-02-23 15:58:01 +00:00
MXFTimecodeComponent * mxf_tc = NULL ;
2008-08-07 02:12:14 +00:00
UID * essence_container_ul = NULL ;
const MXFCodecUL * codec_ul = NULL ;
const MXFCodecUL * container_ul = NULL ;
2012-02-28 14:16:39 +00:00
const MXFCodecUL * pix_fmt_ul = NULL ;
2008-08-07 02:12:14 +00:00
AVStream * st ;
2012-02-23 15:58:01 +00:00
AVTimecode tc ;
int flags ;
2008-08-07 02:12:14 +00:00
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 ;
}
2012-02-23 15:58:01 +00:00
if ( ( component = mxf_resolve_strong_ref ( mxf , & material_track - > sequence_ref , TimecodeComponent ) ) ) {
mxf_tc = ( MXFTimecodeComponent * ) component ;
flags = mxf_tc - > drop_frame = = 1 ? AV_TIMECODE_FLAG_DROPFRAME : 0 ;
2012-03-26 01:03:02 +00:00
if ( av_timecode_init ( & tc , mxf_tc - > rate , flags , mxf_tc - > start_frame , mxf - > fc ) = = 0 ) {
2012-02-23 15:58:01 +00:00
mxf_add_timecode_metadata ( & mxf - > fc - > metadata , " timecode " , & tc ) ;
}
}
2008-08-07 02:12:14 +00:00
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 08:08:10 +00:00
continue ;
2008-08-07 02:12:14 +00:00
}
2012-02-23 15:58:01 +00:00
for ( j = 0 ; j < material_track - > sequence - > structural_components_count ; j + + ) {
component = mxf_resolve_strong_ref ( mxf , & material_track - > sequence - > structural_components_refs [ j ] , TimecodeComponent ) ;
if ( ! component )
continue ;
mxf_tc = ( MXFTimecodeComponent * ) component ;
flags = mxf_tc - > drop_frame = = 1 ? AV_TIMECODE_FLAG_DROPFRAME : 0 ;
2012-03-26 01:03:02 +00:00
if ( av_timecode_init ( & tc , mxf_tc - > rate , flags , mxf_tc - > start_frame , mxf - > fc ) = = 0 ) {
2012-02-23 15:58:01 +00:00
mxf_add_timecode_metadata ( & mxf - > fc - > metadata , " timecode " , & tc ) ;
break ;
}
}
2008-08-07 02:12:14 +00:00
/* TODO: handle multiple source clips */
for ( j = 0 ; j < material_track - > sequence - > structural_components_count ; j + + ) {
2014-11-30 20:16:27 +00:00
component = mxf_resolve_sourceclip ( mxf , & material_track - > sequence - > structural_components_refs [ j ] ) ;
2008-08-07 02:12:14 +00:00
if ( ! component )
continue ;
2014-11-30 20:16:27 +00:00
source_package = mxf_resolve_source_package ( mxf , component - > source_package_uid ) ;
2008-08-07 02:12:14 +00:00
if ( ! source_package ) {
2015-03-16 08:57:35 +00:00
av_log ( mxf - > fc , AV_LOG_TRACE , " material track %d: no corresponding source package found \n " , material_track - > track_id ) ;
2008-08-07 02:12:14 +00:00
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 " ) ;
2012-01-16 00:20:32 +00:00
ret = AVERROR_INVALIDDATA ;
2011-12-09 16:17:33 +00:00
goto fail_and_free ;
2008-08-07 02:12:14 +00:00
}
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 ;
}
}
2011-12-20 16:38:27 +00:00
if ( ! source_track | | ! component )
2008-08-07 02:12:14 +00:00
continue ;
2011-11-28 09:51:00 +00: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 " ) ;
2011-12-08 19:28:49 +00:00
ret = AVERROR_INVALIDDATA ;
2011-12-09 16:17:33 +00:00
goto fail_and_free ;
2011-11-28 09:51:00 +00:00
}
/* 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 09:43:24 +00:00
st = avformat_new_stream ( mxf - > fc , NULL ) ;
2008-08-07 02:12:14 +00:00
if ( ! st ) {
av_log ( mxf - > fc , AV_LOG_ERROR , " could not allocate stream \n " ) ;
2011-12-09 16:17:33 +00:00
ret = AVERROR ( ENOMEM ) ;
goto fail_and_free ;
2008-08-07 02:12:14 +00:00
}
2011-06-18 09:43:24 +00:00
st - > id = source_track - > track_id ;
2008-08-07 02:12:14 +00:00
st - > priv_data = source_track ;
2014-12-03 00:43:52 +00:00
source_package - > descriptor = mxf_resolve_strong_ref ( mxf , & source_package - > descriptor_ref , AnyType ) ;
descriptor = mxf_resolve_multidescriptor ( mxf , source_package - > descriptor , source_track - > track_id ) ;
/* A SourceClip from a EssenceGroup may only be a single frame of essence data. The clips duration is then how many
* frames its suppose to repeat for . Descriptor - > duration , if present , contains the real duration of the essence data */
if ( descriptor & & descriptor - > duration ! = AV_NOPTS_VALUE )
source_track - > original_duration = st - > duration = FFMIN ( descriptor - > duration , component - > duration ) ;
else
source_track - > original_duration = st - > duration = component - > duration ;
2008-08-07 02:12:14 +00:00
if ( st - > duration = = - 1 )
st - > duration = AV_NOPTS_VALUE ;
st - > start_time = component - > start_position ;
2014-01-08 00:20:00 +00:00
if ( material_track - > edit_rate . num < = 0 | |
material_track - > edit_rate . den < = 0 ) {
2012-09-13 19:15:48 +00:00
av_log ( mxf - > fc , AV_LOG_WARNING ,
2014-01-08 00:20:00 +00:00
" Invalid edit rate (%d/%d) found on stream #%d, "
" defaulting to 25/1 \n " ,
material_track - > edit_rate . num ,
material_track - > edit_rate . den , st - > index ) ;
2012-09-13 19:15:48 +00:00
material_track - > edit_rate = ( AVRational ) { 25 , 1 } ;
}
2012-02-28 14:16:36 +00:00
avpriv_set_pts_info ( st , 64 , material_track - > edit_rate . den , material_track - > edit_rate . num ) ;
2008-08-07 02:12:14 +00:00
2012-09-13 19:15:48 +00:00
/* ensure SourceTrack EditRate == MaterialTrack EditRate since only
* the former is accessible via st - > priv_data */
2012-12-14 14:39:16 +00:00
source_track - > edit_rate = material_track - > edit_rate ;
2008-08-07 02:12:14 +00:00
PRINT_KEY ( mxf - > fc , " data definition ul " , source_track - > sequence - > data_definition_ul ) ;
2009-02-08 05:12:30 +00: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 02:12:14 +00:00
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 ;
}
}
}
2011-12-08 19:28:49 +00:00
2008-08-07 02:12:14 +00:00
/* TODO: drop PictureEssenceCoding and SoundEssenceCompression, only check EssenceContainer */
2008-08-18 17:54:18 +00:00
codec_ul = mxf_get_codec_ul ( ff_mxf_codec_uls , & descriptor - > essence_codec_ul ) ;
2012-10-24 14:30:06 +00:00
st - > codec - > codec_id = ( enum AVCodecID ) codec_ul - > id ;
2013-02-11 12:11:16 +00:00
av_log ( mxf - > fc , AV_LOG_VERBOSE , " %s: Universal Label: " ,
avcodec_get_name ( st - > codec - > codec_id ) ) ;
2013-02-21 08:11:22 +00:00
for ( k = 0 ; k < 16 ; k + + ) {
2013-02-11 12:11:16 +00:00
av_log ( mxf - > fc , AV_LOG_VERBOSE , " %.2x " ,
descriptor - > essence_codec_ul [ k ] ) ;
2013-02-21 08:11:22 +00:00
if ( ! ( k + 1 & 19 ) | | k = = 5 )
av_log ( mxf - > fc , AV_LOG_VERBOSE , " . " ) ;
}
2013-02-11 12:11:16 +00:00
av_log ( mxf - > fc , AV_LOG_VERBOSE , " \n " ) ;
2012-09-26 10:13:53 +00:00
2015-01-10 02:05:27 +00:00
mxf_add_umid_metadata ( & st - > metadata , " file_package_umid " , source_package ) ;
2014-11-22 01:43:09 +00:00
if ( source_package - > name & & source_package - > name [ 0 ] )
av_dict_set ( & st - > metadata , " file_package_name " , source_package - > name , 0 ) ;
2014-10-05 00:42:51 +00:00
mxf_parse_physical_source_package ( mxf , source_track , st ) ;
2010-03-30 23:30:55 +00:00
if ( st - > codec - > codec_type = = AVMEDIA_TYPE_VIDEO ) {
2012-03-07 09:52:39 +00:00
source_track - > intra_only = mxf_is_intra_only ( descriptor ) ;
2011-12-10 13:58:57 +00:00
container_ul = mxf_get_codec_ul ( mxf_picture_essence_container_uls , essence_container_ul ) ;
2012-08-05 09:11:04 +00:00
if ( st - > codec - > codec_id = = AV_CODEC_ID_NONE )
2008-08-07 02:12:14 +00:00
st - > codec - > codec_id = container_ul - > id ;
st - > codec - > width = descriptor - > width ;
2012-02-07 10:48:43 +00:00
st - > codec - > height = descriptor - > height ; /* Field height, not frame height */
switch ( descriptor - > frame_layout ) {
case SegmentedFrame :
/* This one is a weird layout I don't fully understand. */
av_log ( mxf - > fc , AV_LOG_INFO , " SegmentedFrame layout isn't currently supported \n " ) ;
break ;
case FullFrame :
2013-01-03 20:42:35 +00:00
st - > codec - > field_order = AV_FIELD_PROGRESSIVE ;
2012-02-07 10:48:43 +00:00
break ;
case OneField :
/* Every other line is stored and needs to be duplicated. */
av_log ( mxf - > fc , AV_LOG_INFO , " OneField frame layout isn't currently supported \n " ) ;
break ; /* The correct thing to do here is fall through, but by breaking we might be
able to decode some streams at half the vertical resolution , rather than not al all .
It ' s also for compatibility with the old behavior . */
case MixedFields :
2012-05-21 11:05:01 +00:00
break ;
case SeparateFields :
2013-02-16 12:52:29 +00:00
switch ( descriptor - > field_dominance ) {
case MXF_TFF :
st - > codec - > field_order = AV_FIELD_TT ;
break ;
case MXF_BFF :
st - > codec - > field_order = AV_FIELD_BB ;
break ;
default :
avpriv_request_sample ( mxf - > fc ,
" Field dominance %d support " ,
descriptor - > field_dominance ) ;
2014-11-26 01:07:57 +00:00
case 0 : // we already have many samples with field_dominance == unknown
2013-02-16 12:52:29 +00:00
break ;
}
2012-02-07 10:48:43 +00:00
/* Turn field height into frame height. */
st - > codec - > height * = 2 ;
2012-04-13 13:32:55 +00:00
break ;
2012-02-07 10:48:43 +00:00
default :
av_log ( mxf - > fc , AV_LOG_INFO , " Unknown frame layout type: %d \n " , descriptor - > frame_layout ) ;
}
2012-08-05 09:11:04 +00:00
if ( st - > codec - > codec_id = = AV_CODEC_ID_RAWVIDEO ) {
2010-06-30 07:55:05 +00:00
st - > codec - > pix_fmt = descriptor - > pix_fmt ;
2012-10-06 10:10:34 +00:00
if ( st - > codec - > pix_fmt = = AV_PIX_FMT_NONE ) {
2012-02-28 14:16:39 +00:00
pix_fmt_ul = mxf_get_codec_ul ( ff_mxf_pixel_format_uls ,
& descriptor - > essence_codec_ul ) ;
2012-10-24 14:30:06 +00:00
st - > codec - > pix_fmt = ( enum AVPixelFormat ) pix_fmt_ul - > id ;
2012-10-06 10:10:34 +00:00
if ( st - > codec - > pix_fmt = = AV_PIX_FMT_NONE ) {
2012-02-28 14:16:39 +00:00
/* support files created before RP224v10 by defaulting to UYVY422
if subsampling is 4 : 2 : 2 and component depth is 8 - bit */
if ( descriptor - > horiz_subsampling = = 2 & &
descriptor - > vert_subsampling = = 1 & &
descriptor - > component_depth = = 8 ) {
2012-10-06 10:10:34 +00:00
st - > codec - > pix_fmt = AV_PIX_FMT_UYVY422 ;
2012-02-28 14:16:39 +00:00
}
}
}
}
2008-08-07 02:12:14 +00:00
st - > need_parsing = AVSTREAM_PARSE_HEADERS ;
2014-07-22 16:08:04 +00:00
if ( material_track - > sequence - > origin ) {
2014-07-29 19:10:39 +00:00
av_dict_set_int ( & st - > metadata , " material_track_origin " , material_track - > sequence - > origin , 0 ) ;
2014-07-22 16:08:04 +00:00
}
if ( source_track - > sequence - > origin ) {
2014-07-29 19:10:39 +00:00
av_dict_set_int ( & st - > metadata , " source_track_origin " , source_track - > sequence - > origin , 0 ) ;
2014-07-22 16:08:04 +00:00
}
2014-11-17 16:54:32 +00:00
if ( descriptor - > aspect_ratio . num & & descriptor - > aspect_ratio . den )
st - > display_aspect_ratio = descriptor - > aspect_ratio ;
2010-03-30 23:30:55 +00:00
} else if ( st - > codec - > codec_type = = AVMEDIA_TYPE_AUDIO ) {
2011-12-10 13:58:57 +00:00
container_ul = mxf_get_codec_ul ( mxf_sound_essence_container_uls , essence_container_ul ) ;
2012-09-26 22:24:46 +00:00
/* Only overwrite existing codec ID if it is unset or A-law, which is the default according to SMPTE RP 224. */
2012-10-24 14:30:06 +00:00
if ( st - > codec - > codec_id = = AV_CODEC_ID_NONE | | ( st - > codec - > codec_id = = AV_CODEC_ID_PCM_ALAW & & ( enum AVCodecID ) container_ul - > id ! = AV_CODEC_ID_NONE ) )
st - > codec - > codec_id = ( enum AVCodecID ) container_ul - > id ;
2008-08-07 02:12:14 +00:00
st - > codec - > channels = descriptor - > channels ;
2008-09-08 14:24:59 +00:00
st - > codec - > bits_per_coded_sample = descriptor - > bits_per_sample ;
2012-01-26 13:12:50 +00:00
2012-09-13 19:15:48 +00:00
if ( descriptor - > sample_rate . den > 0 ) {
2012-01-26 13:12:50 +00:00
st - > codec - > sample_rate = descriptor - > sample_rate . num / descriptor - > sample_rate . den ;
2013-09-28 14:56:54 +00:00
avpriv_set_pts_info ( st , 64 , descriptor - > sample_rate . den , descriptor - > sample_rate . num ) ;
2012-09-13 19:15:48 +00:00
} else {
2013-09-28 14:56:54 +00:00
av_log ( mxf - > fc , AV_LOG_WARNING , " invalid sample rate (%d/%d) "
2013-10-01 11:43:48 +00:00
" found for stream #%d, time base forced to 1/48000 \n " ,
2013-09-28 14:56:54 +00:00
descriptor - > sample_rate . num , descriptor - > sample_rate . den ,
st - > index ) ;
2012-09-13 19:15:48 +00:00
avpriv_set_pts_info ( st , 64 , 1 , 48000 ) ;
}
2012-01-26 13:12:50 +00:00
2012-12-14 14:39:16 +00:00
/* if duration is set, rescale it from EditRate to SampleRate */
if ( st - > duration ! = AV_NOPTS_VALUE )
2012-09-13 19:15:48 +00:00
st - > duration = av_rescale_q ( st - > duration ,
av_inv_q ( material_track - > edit_rate ) ,
st - > time_base ) ;
2012-12-14 14:39:16 +00:00
2012-08-05 09:11:04 +00:00
/* TODO: implement AV_CODEC_ID_RAWAUDIO */
if ( st - > codec - > codec_id = = AV_CODEC_ID_PCM_S16LE ) {
2011-09-27 09:14:59 +00:00
if ( descriptor - > bits_per_sample > 16 & & descriptor - > bits_per_sample < = 24 )
2012-08-05 09:11:04 +00:00
st - > codec - > codec_id = AV_CODEC_ID_PCM_S24LE ;
2008-08-07 02:12:14 +00:00
else if ( descriptor - > bits_per_sample = = 32 )
2012-08-05 09:11:04 +00:00
st - > codec - > codec_id = AV_CODEC_ID_PCM_S32LE ;
} else if ( st - > codec - > codec_id = = AV_CODEC_ID_PCM_S16BE ) {
2011-09-27 09:14:59 +00:00
if ( descriptor - > bits_per_sample > 16 & & descriptor - > bits_per_sample < = 24 )
2012-08-05 09:11:04 +00:00
st - > codec - > codec_id = AV_CODEC_ID_PCM_S24BE ;
2008-08-07 02:12:14 +00:00
else if ( descriptor - > bits_per_sample = = 32 )
2012-08-05 09:11:04 +00:00
st - > codec - > codec_id = AV_CODEC_ID_PCM_S32BE ;
} else if ( st - > codec - > codec_id = = AV_CODEC_ID_MP2 ) {
2008-08-07 02:12:14 +00:00
st - > need_parsing = AVSTREAM_PARSE_FULL ;
}
2014-07-22 14:08:52 +00:00
} else if ( st - > codec - > codec_type = = AVMEDIA_TYPE_DATA ) {
int codec_id = mxf_get_codec_ul ( mxf_data_essence_container_uls ,
essence_container_ul ) - > id ;
if ( codec_id > = 0 & &
codec_id < FF_ARRAY_ELEMS ( mxf_data_essence_descriptor ) ) {
av_dict_set ( & st - > metadata , " data_type " ,
mxf_data_essence_descriptor [ codec_id ] , 0 ) ;
}
2008-08-07 02:12:14 +00:00
}
2012-09-26 10:13:53 +00:00
if ( descriptor - > extradata ) {
2013-10-13 10:30:59 +00:00
if ( ! ff_alloc_extradata ( st - > codec , descriptor - > extradata_size ) ) {
2012-09-26 10:13:53 +00:00
memcpy ( st - > codec - > extradata , descriptor - > extradata , descriptor - > extradata_size ) ;
2013-06-27 11:28:43 +00:00
}
2012-09-26 10:13:53 +00:00
} else if ( st - > codec - > codec_id = = AV_CODEC_ID_H264 ) {
ret = ff_generate_avci_extradata ( st ) ;
if ( ret < 0 )
return ret ;
2012-09-26 10:13:53 +00:00
}
2010-03-30 23:30:55 +00:00
if ( st - > codec - > codec_type ! = AVMEDIA_TYPE_DATA & & ( * essence_container_ul ) [ 15 ] > 0x01 ) {
2011-12-08 19:28:49 +00:00
/* TODO: decode timestamps */
st - > need_parsing = AVSTREAM_PARSE_TIMESTAMPS ;
2008-08-07 02:12:14 +00:00
}
}
2011-12-09 16:17:33 +00:00
2011-12-16 08:42:52 +00:00
ret = 0 ;
2011-12-09 16:17:33 +00:00
fail_and_free :
return ret ;
2008-08-07 02:12:14 +00:00
}
2013-03-29 13:09:31 +00:00
static int mxf_timestamp_to_str ( uint64_t timestamp , char * * str )
{
2013-03-29 13:09:31 +00:00
struct tm time = { 0 } ;
2013-03-29 13:09:31 +00:00
time . tm_year = ( timestamp > > 48 ) - 1900 ;
2013-04-13 15:12:20 +00:00
time . tm_mon = ( timestamp > > 40 & 0xFF ) - 1 ;
time . tm_mday = ( timestamp > > 32 & 0xFF ) ;
time . tm_hour = ( timestamp > > 24 & 0xFF ) ;
time . tm_min = ( timestamp > > 16 & 0xFF ) ;
time . tm_sec = ( timestamp > > 8 & 0xFF ) ;
2013-03-29 13:09:31 +00:00
2014-03-09 20:44:10 +00:00
/* msvcrt versions of strftime calls the invalid parameter handler
* ( aborting the process if one isn ' t set ) if the parameters are out
* of range . */
time . tm_mon = av_clip ( time . tm_mon , 0 , 11 ) ;
time . tm_mday = av_clip ( time . tm_mday , 1 , 31 ) ;
time . tm_hour = av_clip ( time . tm_hour , 0 , 23 ) ;
time . tm_min = av_clip ( time . tm_min , 0 , 59 ) ;
time . tm_sec = av_clip ( time . tm_sec , 0 , 59 ) ;
2013-04-13 13:45:57 +00:00
2013-03-29 13:09:31 +00:00
* str = av_mallocz ( 32 ) ;
if ( ! * str )
return AVERROR ( ENOMEM ) ;
2014-10-24 07:43:20 +00:00
if ( ! strftime ( * str , 32 , " %Y-%m-%d %H:%M:%S " , & time ) )
2015-03-07 22:19:45 +00:00
( * str ) [ 0 ] = ' \0 ' ;
2013-03-29 13:09:31 +00:00
return 0 ;
}
# define SET_STR_METADATA(pb, name, str) do { \
2015-03-14 01:58:38 +00:00
if ( ( ret = mxf_read_utf16be_string ( pb , size , & str ) ) < 0 ) \
2013-03-29 13:09:31 +00:00
return ret ; \
av_dict_set ( & s - > metadata , name , str , AV_DICT_DONT_STRDUP_VAL ) ; \
} while ( 0 )
# define SET_UID_METADATA(pb, name, var, str) do { \
avio_read ( pb , var , 16 ) ; \
if ( ( ret = mxf_uid_to_str ( var , & str ) ) < 0 ) \
return ret ; \
av_dict_set ( & s - > metadata , name , str , AV_DICT_DONT_STRDUP_VAL ) ; \
} while ( 0 )
# define SET_TS_METADATA(pb, name, var, str) do { \
var = avio_rb64 ( pb ) ; \
if ( ( ret = mxf_timestamp_to_str ( var , & str ) ) < 0 ) \
return ret ; \
av_dict_set ( & s - > metadata , name , str , AV_DICT_DONT_STRDUP_VAL ) ; \
} while ( 0 )
static int mxf_read_identification_metadata ( void * arg , AVIOContext * pb , int tag , int size , UID _uid , int64_t klv_offset )
{
MXFContext * mxf = arg ;
AVFormatContext * s = mxf - > fc ;
int ret ;
UID uid = { 0 } ;
char * str = NULL ;
uint64_t ts ;
switch ( tag ) {
case 0x3C01 :
SET_STR_METADATA ( pb , " company_name " , str ) ;
break ;
case 0x3C02 :
SET_STR_METADATA ( pb , " product_name " , str ) ;
break ;
case 0x3C04 :
SET_STR_METADATA ( pb , " product_version " , str ) ;
break ;
case 0x3C05 :
SET_UID_METADATA ( pb , " product_uid " , uid , str ) ;
break ;
case 0x3C06 :
SET_TS_METADATA ( pb , " modification_date " , ts , str ) ;
break ;
case 0x3C08 :
SET_STR_METADATA ( pb , " application_platform " , str ) ;
break ;
case 0x3C09 :
SET_UID_METADATA ( pb , " generation_uid " , uid , str ) ;
break ;
case 0x3C0A :
SET_UID_METADATA ( pb , " uid " , uid , str ) ;
break ;
}
return 0 ;
}
2015-01-06 00:53:05 +00:00
static int mxf_read_preface_metadata ( void * arg , AVIOContext * pb , int tag , int size , UID uid , int64_t klv_offset )
{
MXFContext * mxf = arg ;
AVFormatContext * s = mxf - > fc ;
int ret ;
char * str = NULL ;
if ( tag > = 0x8000 & & ( IS_KLV_KEY ( uid , mxf_avid_project_name ) ) ) {
SET_STR_METADATA ( pb , " project_name " , str ) ;
}
return 0 ;
}
2008-08-07 02:12:14 +00:00
static const MXFMetadataReadTableEntry mxf_metadata_read_table [ ] = {
2014-03-13 12:34:16 +00:00
{ { 0x06 , 0x0e , 0x2b , 0x34 , 0x02 , 0x05 , 0x01 , 0x01 , 0x0d , 0x01 , 0x02 , 0x01 , 0x01 , 0x05 , 0x01 , 0x00 } , mxf_read_primer_pack } ,
{ { 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 } ,
2015-01-06 00:53:05 +00:00
{ { 0x06 , 0x0e , 0x2b , 0x34 , 0x02 , 0x53 , 0x01 , 0x01 , 0x0d , 0x01 , 0x01 , 0x01 , 0x01 , 0x01 , 0x2f , 0x00 } , mxf_read_preface_metadata } ,
2014-03-13 12:34:16 +00:00
{ { 0x06 , 0x0e , 0x2b , 0x34 , 0x02 , 0x53 , 0x01 , 0x01 , 0x0d , 0x01 , 0x01 , 0x01 , 0x01 , 0x01 , 0x30 , 0x00 } , mxf_read_identification_metadata } ,
{ { 0x06 , 0x0e , 0x2b , 0x34 , 0x02 , 0x53 , 0x01 , 0x01 , 0x0d , 0x01 , 0x01 , 0x01 , 0x01 , 0x01 , 0x18 , 0x00 } , mxf_read_content_storage , 0 , AnyType } ,
2014-11-22 01:43:09 +00:00
{ { 0x06 , 0x0e , 0x2b , 0x34 , 0x02 , 0x53 , 0x01 , 0x01 , 0x0d , 0x01 , 0x01 , 0x01 , 0x01 , 0x01 , 0x37 , 0x00 } , mxf_read_package , sizeof ( MXFPackage ) , SourcePackage } ,
{ { 0x06 , 0x0e , 0x2b , 0x34 , 0x02 , 0x53 , 0x01 , 0x01 , 0x0d , 0x01 , 0x01 , 0x01 , 0x01 , 0x01 , 0x36 , 0x00 } , mxf_read_package , sizeof ( MXFPackage ) , MaterialPackage } ,
2014-03-19 20:09:16 +00:00
{ { 0x06 , 0x0e , 0x2b , 0x34 , 0x02 , 0x53 , 0x01 , 0x01 , 0x0d , 0x01 , 0x01 , 0x01 , 0x01 , 0x01 , 0x0f , 0x00 } , mxf_read_sequence , sizeof ( MXFSequence ) , Sequence } ,
2014-11-30 20:16:27 +00:00
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x02 , 0x53 , 0x01 , 0x01 , 0x0D , 0x01 , 0x01 , 0x01 , 0x01 , 0x01 , 0x05 , 0x00 } , mxf_read_essence_group , sizeof ( MXFEssenceGroup ) , EssenceGroup } ,
2014-03-13 12:34:16 +00:00
{ { 0x06 , 0x0e , 0x2b , 0x34 , 0x02 , 0x53 , 0x01 , 0x01 , 0x0d , 0x01 , 0x01 , 0x01 , 0x01 , 0x01 , 0x11 , 0x00 } , mxf_read_source_clip , sizeof ( MXFStructuralComponent ) , SourceClip } ,
2015-03-14 01:58:38 +00:00
{ { 0x06 , 0x0e , 0x2b , 0x34 , 0x02 , 0x53 , 0x01 , 0x01 , 0x0d , 0x01 , 0x01 , 0x01 , 0x01 , 0x01 , 0x3f , 0x00 } , mxf_read_tagged_value , sizeof ( MXFTaggedValue ) , TaggedValue } ,
2014-03-13 12:34:16 +00:00
{ { 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 */
2014-08-12 17:02:41 +00:00
{ { 0x06 , 0x0e , 0x2b , 0x34 , 0x02 , 0x53 , 0x01 , 0x01 , 0x0d , 0x01 , 0x01 , 0x01 , 0x01 , 0x01 , 0x51 , 0x00 } , mxf_read_generic_descriptor , sizeof ( MXFDescriptor ) , Descriptor } , /* MPEG2VideoDescriptor */
2014-07-22 14:08:52 +00:00
{ { 0x06 , 0x0e , 0x2b , 0x34 , 0x02 , 0x53 , 0x01 , 0x01 , 0x0d , 0x01 , 0x01 , 0x01 , 0x01 , 0x01 , 0x5c , 0x00 } , mxf_read_generic_descriptor , sizeof ( MXFDescriptor ) , Descriptor } , /* VANC/VBI - SMPTE 436M */
2014-08-12 16:58:52 +00:00
{ { 0x06 , 0x0e , 0x2b , 0x34 , 0x02 , 0x53 , 0x01 , 0x01 , 0x0d , 0x01 , 0x01 , 0x01 , 0x01 , 0x01 , 0x5e , 0x00 } , mxf_read_generic_descriptor , sizeof ( MXFDescriptor ) , Descriptor } , /* MPEG2AudioDescriptor */
2014-03-13 12:34:16 +00:00
{ { 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 */
2014-03-19 20:09:16 +00:00
{ { 0x06 , 0x0e , 0x2b , 0x34 , 0x02 , 0x53 , 0x01 , 0x01 , 0x0d , 0x01 , 0x01 , 0x01 , 0x01 , 0x01 , 0x14 , 0x00 } , mxf_read_timecode_component , sizeof ( MXFTimecodeComponent ) , TimecodeComponent } ,
2014-10-25 00:31:24 +00:00
{ { 0x06 , 0x0e , 0x2b , 0x34 , 0x02 , 0x53 , 0x01 , 0x01 , 0x0d , 0x01 , 0x01 , 0x01 , 0x01 , 0x01 , 0x0c , 0x00 } , mxf_read_pulldown_component , sizeof ( MXFPulldownComponent ) , PulldownComponent } ,
2014-03-13 12:34:16 +00:00
{ { 0x06 , 0x0e , 0x2b , 0x34 , 0x02 , 0x53 , 0x01 , 0x01 , 0x0d , 0x01 , 0x04 , 0x01 , 0x02 , 0x02 , 0x00 , 0x00 } , mxf_read_cryptographic_context , sizeof ( MXFCryptoContext ) , CryptoContext } ,
{ { 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 02:12:14 +00:00
{ { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } , NULL , 0 , AnyType } ,
} ;
2014-11-30 20:16:27 +00:00
static int mxf_metadataset_init ( MXFMetadataSet * ctx , enum MXFMetadataSetType type )
{
switch ( type ) {
case MultipleDescriptor :
case Descriptor :
( ( MXFDescriptor * ) ctx ) - > pix_fmt = AV_PIX_FMT_NONE ;
( ( MXFDescriptor * ) ctx ) - > duration = AV_NOPTS_VALUE ;
break ;
default :
break ;
}
return 0 ;
}
2010-07-01 17:10:31 +00:00
static int mxf_read_local_tags ( MXFContext * mxf , KLVPacket * klv , MXFMetadataReadFunc * read_child , int ctx_size , enum MXFMetadataSetType type )
2008-08-07 02:12:14 +00:00
{
2011-02-20 10:04:12 +00:00
AVIOContext * pb = mxf - > fc - > pb ;
2008-08-07 02:12:14 +00:00
MXFMetadataSet * ctx = ctx_size ? av_mallocz ( ctx_size ) : mxf ;
2011-03-03 19:11:45 +00:00
uint64_t klv_end = avio_tell ( pb ) + klv - > length ;
2008-08-07 02:12:14 +00:00
if ( ! ctx )
2012-01-14 21:25:12 +00:00
return AVERROR ( ENOMEM ) ;
2014-11-30 20:16:27 +00:00
mxf_metadataset_init ( ctx , type ) ;
2014-08-07 20:12:41 +00:00
while ( avio_tell ( pb ) + 4 < klv_end & & ! avio_feof ( pb ) ) {
2012-01-14 21:25:12 +00:00
int ret ;
2011-02-21 15:43:01 +00:00
int tag = avio_rb16 ( pb ) ;
int size = avio_rb16 ( pb ) ; /* KLV specified by 0x53 */
2011-03-03 19:11:45 +00:00
uint64_t next = avio_tell ( pb ) + size ;
2008-08-07 02:12:14 +00:00
UID uid = { 0 } ;
2015-03-16 08:57:35 +00:00
av_log ( mxf - > fc , AV_LOG_TRACE , " local tag %#04x size %d \n " , tag , size ) ;
2008-08-07 02:12:14 +00:00
if ( ! size ) { /* ignore empty tag, needed for some files with empty UMID tag */
2009-01-08 02:57:21 +00:00
av_log ( mxf - > fc , AV_LOG_ERROR , " local tag %#04x with 0 size \n " , tag ) ;
2008-08-07 02:12:14 +00: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 ) ;
2015-03-16 08:57:35 +00:00
av_log ( mxf - > fc , AV_LOG_TRACE , " local tag %#04x \n " , local_tag ) ;
2008-08-07 02:12:14 +00:00
PRINT_KEY ( mxf - > fc , " uid " , uid ) ;
}
}
}
2014-12-15 00:33:13 +00:00
if ( ctx_size & & tag = = 0x3C0A ) {
2011-02-21 15:43:01 +00:00
avio_read ( pb , ctx - > uid , 16 ) ;
2014-12-15 00:33:13 +00:00
} else if ( ( ret = read_child ( ctx , pb , tag , size , uid , - 1 ) ) < 0 ) {
2015-01-28 01:59:03 +00:00
mxf_free_metadataset ( & ctx , ! ! ctx_size ) ;
2012-01-14 21:25:12 +00:00
return ret ;
2014-12-15 00:33:13 +00:00
}
2008-08-07 02:12:14 +00:00
2012-01-26 12:21:38 +00:00
/* Accept the 64k local set limit being exceeded (Avid). Don't accept
* it extending past the end of the KLV though ( zzuf5 . mxf ) . */
2011-12-21 09:49:27 +00:00
if ( avio_tell ( pb ) > klv_end ) {
2014-12-15 00:33:13 +00:00
if ( ctx_size ) {
ctx - > type = type ;
2015-01-28 01:59:03 +00:00
mxf_free_metadataset ( & ctx , ! ! ctx_size ) ;
2014-12-15 00:33:13 +00:00
}
2012-10-24 14:54:25 +00:00
2012-01-26 12:21:38 +00:00
av_log ( mxf - > fc , AV_LOG_ERROR ,
" local tag %#04x extends past end of local set @ %# " PRIx64 " \n " ,
2011-12-21 09:49:27 +00:00
tag , klv - > offset ) ;
return AVERROR_INVALIDDATA ;
} else if ( avio_tell ( pb ) < = next ) /* only seek forward, else this can loop for a long time */
2012-01-26 12:21:38 +00:00
avio_seek ( pb , next , SEEK_SET ) ;
2008-08-07 02:12:14 +00:00
}
if ( ctx_size ) ctx - > type = type ;
return ctx_size ? mxf_add_metadata_set ( mxf , ctx ) : 0 ;
}
2014-10-28 12:33:04 +00:00
/**
* Matches any partition pack key , in other words :
* - HeaderPartition
* - BodyPartition
* - FooterPartition
* @ return non - zero if the key is a partition pack key , zero otherwise
*/
static int mxf_is_partition_pack_key ( UID key )
{
//NOTE: this is a little lax since it doesn't constraint key[14]
return ! memcmp ( key , mxf_header_partition_pack_key , 13 ) & &
key [ 13 ] > = 2 & & key [ 13 ] < = 4 ;
}
/**
* Parses a metadata KLV
* @ return < 0 on error , 0 otherwise
*/
static int mxf_parse_klv ( MXFContext * mxf , KLVPacket klv , MXFMetadataReadFunc * read ,
int ctx_size , enum MXFMetadataSetType type )
{
AVFormatContext * s = mxf - > fc ;
int res ;
if ( klv . key [ 5 ] = = 0x53 ) {
res = mxf_read_local_tags ( mxf , & klv , read , ctx_size , type ) ;
} else {
uint64_t next = avio_tell ( s - > pb ) + klv . length ;
res = read ( mxf , s - > pb , 0 , klv . length , klv . key , klv . offset ) ;
/* only seek forward, else this can loop for a long time */
if ( avio_tell ( s - > pb ) > next ) {
av_log ( s , AV_LOG_ERROR , " read past end of KLV @ %# " PRIx64 " \n " ,
klv . offset ) ;
return AVERROR_INVALIDDATA ;
}
avio_seek ( s - > pb , next , SEEK_SET ) ;
}
if ( res < 0 ) {
av_log ( s , AV_LOG_ERROR , " error reading header metadata \n " ) ;
return res ;
}
return 0 ;
}
2011-03-14 16:00:21 +00:00
/**
2014-10-28 12:38:18 +00:00
* Seeks to the previous partition and parses it , if possible
2011-03-14 16:00:21 +00:00
* @ 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 ;
2014-10-28 12:38:18 +00:00
KLVPacket klv ;
int64_t current_partition_ofs ;
int ret ;
2011-03-14 16:00:21 +00:00
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 */
2014-10-28 12:38:18 +00:00
current_partition_ofs = mxf - > current_partition - > pack_ofs ; //includes run-in
2011-03-14 16:00:21 +00:00
avio_seek ( pb , mxf - > run_in + mxf - > current_partition - > previous_partition , SEEK_SET ) ;
mxf - > current_partition = NULL ;
2015-03-16 08:57:35 +00:00
av_log ( mxf - > fc , AV_LOG_TRACE , " seeking to previous partition \n " ) ;
2011-03-14 16:00:21 +00:00
2014-10-28 12:38:18 +00:00
/* Make sure this is actually a PartitionPack, and if so parse it.
* See deadlock2 . mxf
*/
if ( ( ret = klv_read_packet ( & klv , pb ) ) < 0 ) {
av_log ( mxf - > fc , AV_LOG_ERROR , " failed to read PartitionPack KLV \n " ) ;
return ret ;
}
if ( ! mxf_is_partition_pack_key ( klv . key ) ) {
av_log ( mxf - > fc , AV_LOG_ERROR , " PreviousPartition @ % " PRIx64 " isn't a PartitionPack \n " , klv . offset ) ;
return AVERROR_INVALIDDATA ;
}
/* We can't just check ofs >= current_partition_ofs because PreviousPartition
* can point to just before the current partition , causing klv_read_packet ( )
* to sync back up to it . See deadlock3 . mxf
*/
if ( klv . offset > = current_partition_ofs ) {
av_log ( mxf - > fc , AV_LOG_ERROR , " PreviousPartition for PartitionPack @ % "
PRIx64 " indirectly points to itself \n " , current_partition_ofs ) ;
return AVERROR_INVALIDDATA ;
}
if ( ( ret = mxf_parse_klv ( mxf , klv , mxf_read_partition_pack , 0 , 0 ) ) < 0 )
return ret ;
2011-03-14 16:00:21 +00:00
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 - > parsing_backward ) {
return mxf_seek_to_previous_partition ( mxf ) ;
2011-03-14 16:00:21 +00:00
} else {
2014-10-28 13:27:06 +00:00
if ( ! mxf - > footer_partition ) {
2015-04-20 01:19:29 +00:00
av_log ( mxf - > fc , AV_LOG_TRACE , " no FooterPartition \n " ) ;
2011-03-14 16:00:21 +00:00
return 0 ;
}
2011-03-14 16:00:21 +00:00
2015-04-20 01:19:29 +00:00
av_log ( mxf - > fc , AV_LOG_TRACE , " seeking to FooterPartition \n " ) ;
2011-03-14 16:00:21 +00:00
/* 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 ) {
2014-10-28 13:27:06 +00:00
av_log ( mxf - > fc , AV_LOG_INFO , " file is not seekable - not parsing FooterPartition \n " ) ;
2011-03-14 16:00:21 +00:00
return - 1 ;
}
2014-10-28 13:27:06 +00:00
/* seek to FooterPartition and parse backward */
if ( ( ret = avio_seek ( pb , mxf - > run_in + mxf - > footer_partition , SEEK_SET ) ) < 0 ) {
2013-10-18 10:44:56 +00:00
av_log ( mxf - > fc , AV_LOG_ERROR ,
2014-10-28 13:27:06 +00:00
" failed to seek to FooterPartition @ 0x% " PRIx64
2013-10-18 10:44:56 +00:00
" (% " PRId64 " ) - partial file? \n " ,
2014-10-28 13:27:06 +00:00
mxf - > run_in + mxf - > footer_partition , ret ) ;
2011-03-14 16:00:21 +00:00
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 ;
}
2011-12-08 10:18:21 +00:00
/**
* Figures out the proper offset and length of the essence container in each partition
*/
static void mxf_compute_essence_containers ( MXFContext * mxf )
{
int x ;
/* everything is already correct */
if ( mxf - > op = = OPAtom )
return ;
for ( x = 0 ; x < mxf - > partitions_count ; x + + ) {
MXFPartition * p = & mxf - > partitions [ x ] ;
if ( ! p - > body_sid )
continue ; /* BodySID == 0 -> no essence */
if ( x > = mxf - > partitions_count - 1 )
2014-10-28 13:27:06 +00:00
break ; /* FooterPartition - can't compute length (and we don't need to) */
2011-12-08 10:18:21 +00:00
/* essence container spans to the next partition */
p - > essence_length = mxf - > partitions [ x + 1 ] . this_partition - p - > essence_offset ;
if ( p - > essence_length < 0 ) {
/* next ThisPartition < essence_offset */
p - > essence_length = 0 ;
2012-01-26 12:21:42 +00:00
av_log ( mxf - > fc , AV_LOG_ERROR ,
" partition %i: bad ThisPartition = % " PRIX64 " \n " ,
2011-12-08 10:18:21 +00:00
x + 1 , mxf - > partitions [ x + 1 ] . this_partition ) ;
}
}
}
static int64_t round_to_kag ( int64_t position , int kag_size )
{
/* TODO: account for run-in? the spec isn't clear whether KAG should account for it */
/* NOTE: kag_size may be any integer between 1 - 2^10 */
int64_t ret = ( position / kag_size ) * kag_size ;
return ret = = position ? ret : ret + kag_size ;
}
2012-08-05 09:11:04 +00:00
static int is_pcm ( enum AVCodecID codec_id )
2012-01-24 10:36:39 +00:00
{
/* we only care about "normal" PCM codecs until we get samples */
2012-08-05 09:11:04 +00:00
return codec_id > = AV_CODEC_ID_PCM_S16LE & & codec_id < AV_CODEC_ID_PCM_S24DAUD ;
2012-01-24 10:36:39 +00:00
}
/**
2012-01-26 12:21:44 +00:00
* Deal with the case where for some audio atoms EditUnitByteCount is
* very small ( 2 , 4. . ) . In those cases we should read more than one
* sample per call to mxf_read_packet ( ) .
2012-01-24 10:36:39 +00:00
*/
static void mxf_handle_small_eubc ( AVFormatContext * s )
{
MXFContext * mxf = s - > priv_data ;
/* assuming non-OPAtom == frame wrapped
* no sane writer would wrap 2 byte PCM packets with 20 byte headers . . */
if ( mxf - > op ! = OPAtom )
return ;
/* expect PCM with exactly one index table segment and a small (< 32) EUBC */
2012-01-26 12:21:44 +00:00
if ( s - > nb_streams ! = 1 | |
s - > streams [ 0 ] - > codec - > codec_type ! = AVMEDIA_TYPE_AUDIO | |
! is_pcm ( s - > streams [ 0 ] - > codec - > codec_id ) | |
mxf - > nb_index_tables ! = 1 | |
mxf - > index_tables [ 0 ] . nb_segments ! = 1 | |
2012-01-24 10:36:39 +00:00
mxf - > index_tables [ 0 ] . segments [ 0 ] - > edit_unit_byte_count > = 32 )
return ;
/* arbitrarily default to 48 kHz PAL audio frame size */
2012-01-26 12:21:44 +00:00
/* TODO: We could compute this from the ratio between the audio
* and video edit rates for 48 kHz NTSC we could use the
* 1802 - 1802 - 1802 - 1802 - 1801 pattern . */
2012-01-24 10:36:39 +00:00
mxf - > edit_units_per_packet = 1920 ;
}
2015-01-15 03:26:11 +00:00
/**
* Deal with the case where OPAtom files does not have any IndexTableSegments .
*/
static int mxf_handle_missing_index_segment ( MXFContext * mxf )
{
AVFormatContext * s = mxf - > fc ;
AVStream * st = NULL ;
MXFIndexTableSegment * segment = NULL ;
MXFPartition * p = NULL ;
int essence_partition_count = 0 ;
int i , ret ;
if ( mxf - > op ! = OPAtom )
return 0 ;
/* TODO: support raw video without a index if they exist */
if ( s - > nb_streams ! = 1 | | s - > streams [ 0 ] - > codec - > codec_type ! = AVMEDIA_TYPE_AUDIO | | ! is_pcm ( s - > streams [ 0 ] - > codec - > codec_id ) )
return 0 ;
/* check if file already has a IndexTableSegment */
for ( i = 0 ; i < mxf - > metadata_sets_count ; i + + ) {
if ( mxf - > metadata_sets [ i ] - > type = = IndexTableSegment )
return 0 ;
}
/* find the essence partition */
for ( i = 0 ; i < mxf - > partitions_count ; i + + ) {
/* BodySID == 0 -> no essence */
if ( ! mxf - > partitions [ i ] . body_sid )
continue ;
p = & mxf - > partitions [ i ] ;
essence_partition_count + + ;
}
/* only handle files with a single essence partition */
if ( essence_partition_count ! = 1 )
return 0 ;
if ( ! ( segment = av_mallocz ( sizeof ( * segment ) ) ) )
return AVERROR ( ENOMEM ) ;
if ( ( ret = mxf_add_metadata_set ( mxf , segment ) ) ) {
2015-01-28 01:59:03 +00:00
mxf_free_metadataset ( ( MXFMetadataSet * * ) & segment , 1 ) ;
2015-01-15 03:26:11 +00:00
return ret ;
}
st = s - > streams [ 0 ] ;
segment - > type = IndexTableSegment ;
/* stream will be treated as small EditUnitByteCount */
segment - > edit_unit_byte_count = ( av_get_bits_per_sample ( st - > codec - > codec_id ) * st - > codec - > channels ) > > 3 ;
segment - > index_start_position = 0 ;
segment - > index_duration = s - > streams [ 0 ] - > duration ;
segment - > index_sid = p - > index_sid ;
segment - > body_sid = p - > body_sid ;
return 0 ;
}
2013-10-18 10:44:56 +00:00
static void mxf_read_random_index_pack ( AVFormatContext * s )
{
MXFContext * mxf = s - > priv_data ;
uint32_t length ;
2014-10-28 13:36:27 +00:00
int64_t file_size , max_rip_length , min_rip_length ;
2013-10-18 10:44:56 +00:00
KLVPacket klv ;
if ( ! s - > pb - > seekable )
return ;
file_size = avio_size ( s - > pb ) ;
2014-10-28 13:36:27 +00:00
/* S377m says to check the RIP length for "silly" values, without defining "silly".
* The limit below assumes a file with nothing but partition packs and a RIP .
* Before changing this , consider that a muxer may place each sample in its own partition .
*
* 105 is the size of the smallest possible PartitionPack
* 12 is the size of each RIP entry
* 28 is the size of the RIP header and footer , assuming an 8 - byte BER
*/
max_rip_length = ( ( file_size - mxf - > run_in ) / 105 ) * 12 + 28 ;
max_rip_length = FFMIN ( max_rip_length , INT_MAX ) ; //2 GiB and up is also silly
/* We're only interested in RIPs with at least two entries.. */
min_rip_length = 16 + 1 + 24 + 4 ;
/* See S377m section 11 */
2013-10-18 10:44:56 +00:00
avio_seek ( s - > pb , file_size - 4 , SEEK_SET ) ;
length = avio_rb32 ( s - > pb ) ;
2014-10-28 13:36:27 +00:00
if ( length < min_rip_length | | length > max_rip_length )
2013-10-18 10:44:56 +00:00
goto end ;
avio_seek ( s - > pb , file_size - length , SEEK_SET ) ;
if ( klv_read_packet ( & klv , s - > pb ) < 0 | |
! IS_KLV_KEY ( klv . key , mxf_random_index_pack_key ) | |
klv . length ! = length - 20 )
goto end ;
avio_skip ( s - > pb , klv . length - 12 ) ;
2014-10-28 13:27:06 +00:00
mxf - > footer_partition = avio_rb64 ( s - > pb ) ;
2013-10-18 10:44:56 +00:00
2014-10-28 13:36:27 +00:00
/* sanity check */
if ( mxf - > run_in + mxf - > footer_partition > = file_size ) {
av_log ( s , AV_LOG_WARNING , " bad FooterPartition in RIP - ignoring \n " ) ;
mxf - > footer_partition = 0 ;
}
2013-10-18 10:44:56 +00:00
end :
avio_seek ( s - > pb , mxf - > run_in , SEEK_SET ) ;
}
2012-01-12 12:20:36 +00:00
static int mxf_read_header ( AVFormatContext * s )
2008-08-07 02:12:14 +00:00
{
MXFContext * mxf = s - > priv_data ;
KLVPacket klv ;
2011-12-08 11:23:36 +00:00
int64_t essence_offset = 0 ;
2011-12-15 15:47:49 +00:00
int ret ;
2008-08-07 02:12:14 +00:00
2011-03-14 16:00:21 +00:00
mxf - > last_forward_tell = INT64_MAX ;
2012-01-24 10:36:39 +00:00
mxf - > edit_units_per_packet = 1 ;
2011-03-14 16:00:21 +00:00
2008-08-07 02:12:14 +00: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 " ) ;
2012-01-14 21:25:12 +00:00
return AVERROR_INVALIDDATA ;
2008-08-07 02:12:14 +00:00
}
2011-02-28 13:57:54 +00:00
avio_seek ( s - > pb , - 14 , SEEK_CUR ) ;
2008-08-07 02:12:14 +00:00
mxf - > fc = s ;
2011-03-14 16:00:21 +00:00
mxf - > run_in = avio_tell ( s - > pb ) ;
2013-10-18 10:44:56 +00:00
mxf_read_random_index_pack ( s ) ;
2014-08-07 20:12:41 +00:00
while ( ! avio_feof ( s - > pb ) ) {
2008-08-07 02:12:14 +00:00
const MXFMetadataReadTableEntry * metadata ;
2014-10-28 12:33:47 +00:00
2011-03-14 16:00:21 +00: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 02:12:14 +00:00
PRINT_KEY ( s , " read header " , klv . key ) ;
2015-03-16 08:57:35 +00:00
av_log ( s , AV_LOG_TRACE , " size % " PRIu64 " offset %# " PRIx64 " \n " , klv . length , klv . offset ) ;
2008-08-07 02:12:14 +00:00
if ( IS_KLV_KEY ( klv . key , mxf_encrypted_triplet_key ) | |
2011-03-14 16:00:21 +00:00
IS_KLV_KEY ( klv . key , mxf_essence_element_key ) | |
2011-12-10 11:11:11 +00:00
IS_KLV_KEY ( klv . key , mxf_avid_essence_element_key ) | |
2011-03-14 16:00:21 +00:00
IS_KLV_KEY ( klv . key , mxf_system_item_key ) ) {
2011-12-20 17:11:10 +00:00
if ( ! mxf - > current_partition ) {
av_log ( mxf - > fc , AV_LOG_ERROR , " found essence prior to first PartitionPack \n " ) ;
return AVERROR_INVALIDDATA ;
}
2011-12-08 10:18:21 +00:00
if ( ! mxf - > current_partition - > essence_offset ) {
/* for OP1a we compute essence_offset
* for OPAtom we point essence_offset after the KL ( usually op1a_essence_offset + 20 or 25 )
* TODO : for OP1a we could eliminate this entire if statement , always stopping parsing at op1a_essence_offset
* for OPAtom we still need the actual essence_offset though ( the KL ' s length can vary )
*/
int64_t op1a_essence_offset =
round_to_kag ( mxf - > current_partition - > this_partition +
mxf - > current_partition - > pack_length , mxf - > current_partition - > kag_size ) +
round_to_kag ( mxf - > current_partition - > header_byte_count , mxf - > current_partition - > kag_size ) +
round_to_kag ( mxf - > current_partition - > index_byte_count , mxf - > current_partition - > kag_size ) ;
if ( mxf - > op = = OPAtom ) {
/* point essence_offset to the actual data
* OPAtom has all the essence in one big KLV
*/
mxf - > current_partition - > essence_offset = avio_tell ( s - > pb ) ;
mxf - > current_partition - > essence_length = klv . length ;
} else {
/* NOTE: op1a_essence_offset may be less than to klv.offset (C0023S01.mxf) */
mxf - > current_partition - > essence_offset = op1a_essence_offset ;
}
}
2011-12-08 11:23:36 +00:00
if ( ! essence_offset )
essence_offset = klv . offset ;
2011-03-14 16:00:21 +00:00
/* seek to footer, previous partition or stop */
if ( mxf_parse_handle_essence ( mxf ) < = 0 )
break ;
2011-11-11 14:01:34 +00:00
continue ;
2014-10-28 12:33:04 +00:00
} else if ( mxf_is_partition_pack_key ( klv . key ) & & mxf - > current_partition ) {
2011-03-14 16:00:21 +00:00
/* next partition pack - keep going, seek to previous partition or stop */
if ( mxf_parse_handle_partition_or_eof ( mxf ) < = 0 )
break ;
2012-03-20 10:03:48 +00:00
else if ( mxf - > parsing_backward )
continue ;
/* we're still parsing forward. proceed to parsing this partition pack */
2011-11-11 14:01:34 +00:00
}
2008-08-07 02:12:14 +00:00
for ( metadata = mxf_metadata_read_table ; metadata - > read ; metadata + + ) {
if ( IS_KLV_KEY ( klv . key , metadata - > key ) ) {
2014-10-28 12:33:04 +00:00
if ( ( ret = mxf_parse_klv ( mxf , klv , metadata - > read , metadata - > ctx_size , metadata - > type ) ) < 0 )
2014-10-15 00:20:58 +00:00
goto fail ;
2008-08-07 02:12:14 +00:00
break ;
2014-08-12 14:55:22 +00:00
} else {
av_log ( s , AV_LOG_VERBOSE , " Dark key " PRIxUID " \n " ,
UID_ARG ( klv . key ) ) ;
2008-08-07 02:12:14 +00:00
}
}
if ( ! metadata - > read )
2011-03-15 08:14:38 +00:00
avio_skip ( s - > pb , klv . length ) ;
2008-08-07 02:12:14 +00:00
}
2011-03-14 16:00:21 +00:00
/* FIXME avoid seek */
2011-12-08 11:23:36 +00:00
if ( ! essence_offset ) {
2011-03-14 16:00:21 +00:00
av_log ( s , AV_LOG_ERROR , " no essence \n " ) ;
2014-12-15 00:33:13 +00:00
ret = AVERROR_INVALIDDATA ;
goto fail ;
2011-03-14 16:00:21 +00:00
}
2011-12-08 11:23:36 +00:00
avio_seek ( s - > pb , essence_offset , SEEK_SET ) ;
2011-12-08 10:18:21 +00:00
mxf_compute_essence_containers ( mxf ) ;
2011-12-16 08:50:58 +00:00
/* we need to do this before computing the index tables
* to be able to fill in zero IndexDurations with st - > duration */
if ( ( ret = mxf_parse_structural_metadata ( mxf ) ) < 0 )
2012-11-11 01:13:31 +00:00
goto fail ;
2011-12-16 08:50:58 +00:00
2015-01-15 03:26:11 +00:00
mxf_handle_missing_index_segment ( mxf ) ;
2011-12-15 15:47:49 +00:00
if ( ( ret = mxf_compute_index_tables ( mxf ) ) < 0 )
2012-11-11 01:13:31 +00:00
goto fail ;
2011-12-15 15:47:49 +00:00
if ( mxf - > nb_index_tables > 1 ) {
/* TODO: look up which IndexSID to use via EssenceContainerData */
av_log ( mxf - > fc , AV_LOG_INFO , " got %i index tables - only the first one (IndexSID %i) will be used \n " ,
mxf - > nb_index_tables , mxf - > index_tables [ 0 ] . index_sid ) ;
} else if ( mxf - > nb_index_tables = = 0 & & mxf - > op = = OPAtom ) {
av_log ( mxf - > fc , AV_LOG_ERROR , " cannot demux OPAtom without an index \n " ) ;
2012-11-11 01:13:31 +00:00
ret = AVERROR_INVALIDDATA ;
goto fail ;
2011-12-15 15:47:49 +00:00
}
2012-01-24 10:36:39 +00:00
mxf_handle_small_eubc ( s ) ;
2011-12-16 08:50:58 +00:00
return 0 ;
2012-11-11 01:13:31 +00:00
fail :
mxf_read_close ( s ) ;
return ret ;
2008-08-07 02:12:14 +00:00
}
2011-12-16 09:53:41 +00:00
/**
2012-03-02 10:16:10 +00:00
* Sets mxf - > current_edit_unit based on what offset we ' re currently at .
* @ return next_ofs if OK , < 0 on error
2011-12-16 09:53:41 +00:00
*/
2012-03-02 10:16:10 +00:00
static int64_t mxf_set_current_edit_unit ( MXFContext * mxf , int64_t current_offset )
2011-12-16 09:53:41 +00:00
{
2012-03-02 10:16:10 +00:00
int64_t last_ofs = - 1 , next_ofs = - 1 ;
2011-12-16 09:53:41 +00:00
MXFIndexTable * t = & mxf - > index_tables [ 0 ] ;
2012-01-26 12:21:32 +00:00
/* this is called from the OP1a demuxing logic, which means there
* may be no index tables */
2011-12-20 10:22:23 +00:00
if ( mxf - > nb_index_tables < = 0 )
2012-03-02 10:16:10 +00:00
return - 1 ;
2011-12-20 10:22:23 +00:00
2012-03-02 10:16:10 +00:00
/* find mxf->current_edit_unit so that the next edit unit starts ahead of current_offset */
2011-12-21 11:00:04 +00:00
while ( mxf - > current_edit_unit > = 0 ) {
2011-12-16 09:53:41 +00:00
if ( mxf_edit_unit_absolute_offset ( mxf , t , mxf - > current_edit_unit + 1 , NULL , & next_ofs , 0 ) < 0 )
2012-03-02 10:16:10 +00:00
return - 1 ;
2011-12-16 09:53:41 +00:00
2011-12-20 17:04:13 +00:00
if ( next_ofs < = last_ofs ) {
2012-01-26 12:21:36 +00:00
/* large next_ofs didn't change or current_edit_unit wrapped
* around this fixes the infinite loop on zzuf3 . mxf */
av_log ( mxf - > fc , AV_LOG_ERROR ,
" next_ofs didn't change. not deriving packet timestamps \n " ) ;
2012-03-02 10:16:10 +00:00
return - 1 ;
2011-12-20 17:04:13 +00:00
}
2012-03-02 10:16:10 +00:00
if ( next_ofs > current_offset )
2011-12-16 09:53:41 +00:00
break ;
2011-12-20 17:04:13 +00:00
last_ofs = next_ofs ;
2011-12-16 09:53:41 +00:00
mxf - > current_edit_unit + + ;
}
2012-03-02 10:16:10 +00:00
/* not checking mxf->current_edit_unit >= t->nb_ptses here since CBR files may lack IndexEntryArrays */
if ( mxf - > current_edit_unit < 0 )
return - 1 ;
2011-12-16 09:53:41 +00:00
2012-03-02 10:16:10 +00:00
return next_ofs ;
2011-12-16 09:53:41 +00:00
}
2012-09-13 19:15:48 +00:00
static int mxf_compute_sample_count ( MXFContext * mxf , int stream_index ,
uint64_t * sample_count )
2012-09-13 19:15:48 +00:00
{
int i , total = 0 , size = 0 ;
AVStream * st = mxf - > fc - > streams [ stream_index ] ;
MXFTrack * track = st - > priv_data ;
AVRational time_base = av_inv_q ( track - > edit_rate ) ;
AVRational sample_rate = av_inv_q ( st - > time_base ) ;
const MXFSamplesPerFrame * spf = NULL ;
if ( ( sample_rate . num / sample_rate . den ) = = 48000 )
spf = ff_mxf_get_samples_per_frame ( mxf - > fc , time_base ) ;
if ( ! spf ) {
2012-09-13 19:15:48 +00:00
int remainder = ( sample_rate . num * time_base . num ) %
( time_base . den * sample_rate . den ) ;
2012-09-13 19:15:48 +00:00
* sample_count = av_q2d ( av_mul_q ( ( AVRational ) { mxf - > current_edit_unit , 1 } ,
av_mul_q ( sample_rate , time_base ) ) ) ;
if ( remainder )
av_log ( mxf - > fc , AV_LOG_WARNING ,
2012-09-13 19:15:48 +00:00
" seeking detected on stream #%d with time base (%d/%d) and "
" sample rate (%d/%d), audio pts won't be accurate. \n " ,
stream_index , time_base . num , time_base . den ,
sample_rate . num , sample_rate . den ) ;
2012-09-13 19:15:48 +00:00
return 0 ;
}
while ( spf - > samples_per_frame [ size ] ) {
total + = spf - > samples_per_frame [ size ] ;
size + + ;
}
av_assert2 ( size ) ;
2012-11-17 01:20:50 +00:00
* sample_count = ( mxf - > current_edit_unit / size ) * ( uint64_t ) total ;
2012-09-13 19:15:48 +00:00
for ( i = 0 ; i < mxf - > current_edit_unit % size ; i + + ) {
* sample_count + = spf - > samples_per_frame [ i ] ;
}
return 0 ;
}
2012-09-13 19:15:48 +00:00
static int mxf_set_audio_pts ( MXFContext * mxf , AVCodecContext * codec ,
AVPacket * pkt )
2012-09-13 19:15:48 +00:00
{
MXFTrack * track = mxf - > fc - > streams [ pkt - > stream_index ] - > priv_data ;
2014-08-12 16:58:52 +00:00
int64_t bits_per_sample = codec - > bits_per_coded_sample ;
if ( ! bits_per_sample )
bits_per_sample = av_get_bits_per_sample ( codec - > codec_id ) ;
2012-09-13 19:15:48 +00:00
2012-09-13 19:15:48 +00:00
pkt - > pts = track - > sample_count ;
2012-09-13 19:15:48 +00:00
2013-09-27 16:54:58 +00:00
if ( codec - > channels < = 0
2014-03-06 21:39:18 +00:00
| | bits_per_sample < = 0
| | codec - > channels * ( int64_t ) bits_per_sample < 8 )
2012-12-12 10:35:31 +00:00
return AVERROR ( EINVAL ) ;
2014-03-06 21:39:18 +00:00
track - > sample_count + = pkt - > size / ( codec - > channels * ( int64_t ) bits_per_sample / 8 ) ;
2012-09-13 19:15:48 +00:00
return 0 ;
}
2011-12-16 08:19:01 +00:00
static int mxf_read_packet_old ( AVFormatContext * s , AVPacket * pkt )
{
KLVPacket klv ;
2012-03-02 10:16:10 +00:00
MXFContext * mxf = s - > priv_data ;
2014-01-08 00:51:48 +00:00
int ret ;
2011-12-16 08:19:01 +00:00
2014-03-06 22:53:36 +00:00
while ( ( ret = klv_read_packet ( & klv , s - > pb ) ) = = 0 ) {
2011-12-16 08:19:01 +00:00
PRINT_KEY ( s , " read packet " , klv . key ) ;
2015-03-16 08:57:35 +00:00
av_log ( s , AV_LOG_TRACE , " size % " PRIu64 " offset %# " PRIx64 " \n " , klv . length , klv . offset ) ;
2011-12-16 08:19:01 +00:00
if ( IS_KLV_KEY ( klv . key , mxf_encrypted_triplet_key ) ) {
2012-01-16 00:20:32 +00:00
ret = mxf_decrypt_triplet ( s , pkt , & klv ) ;
if ( ret < 0 ) {
2011-12-16 08:19:01 +00:00
av_log ( s , AV_LOG_ERROR , " invalid encoded triplet \n " ) ;
2014-01-08 00:51:48 +00:00
return ret ;
2011-12-16 08:19:01 +00:00
}
return 0 ;
}
if ( IS_KLV_KEY ( klv . key , mxf_essence_element_key ) | |
IS_KLV_KEY ( klv . key , mxf_avid_essence_element_key ) ) {
int index = mxf_get_stream_index ( s , & klv ) ;
2012-03-02 10:16:10 +00:00
int64_t next_ofs , next_klv ;
2012-03-07 09:03:16 +00:00
AVStream * st ;
MXFTrack * track ;
2012-09-13 19:15:48 +00:00
AVCodecContext * codec ;
2012-03-02 10:16:10 +00:00
2011-12-16 08:19:01 +00:00
if ( index < 0 ) {
2014-03-10 14:35:59 +00:00
av_log ( s , AV_LOG_ERROR ,
" error getting stream index % " PRIu32 " \n " ,
AV_RB32 ( klv . key + 12 ) ) ;
2011-12-16 08:19:01 +00:00
goto skip ;
}
2012-03-07 09:03:16 +00:00
st = s - > streams [ index ] ;
track = st - > priv_data ;
2011-12-16 08:19:01 +00:00
if ( s - > streams [ index ] - > discard = = AVDISCARD_ALL )
goto skip ;
2012-03-02 10:16:10 +00:00
next_klv = avio_tell ( s - > pb ) + klv . length ;
next_ofs = mxf_set_current_edit_unit ( mxf , klv . offset ) ;
if ( next_ofs > = 0 & & next_klv > next_ofs ) {
/* if this check is hit then it's possible OPAtom was treated as OP1a
* truncate the packet since it ' s probably very large ( > 2 GiB is common ) */
2013-02-25 22:54:28 +00:00
avpriv_request_sample ( s ,
" OPAtom misinterpreted as OP1a? "
" KLV for edit unit %i extending into "
" next edit unit " ,
2012-03-02 10:16:10 +00:00
mxf - > current_edit_unit ) ;
2012-03-02 10:16:10 +00:00
klv . length = next_ofs - avio_tell ( s - > pb ) ;
}
2011-12-16 08:19:01 +00:00
/* check for 8 channels AES3 element */
if ( klv . key [ 12 ] = = 0x06 & & klv . key [ 13 ] = = 0x01 & & klv . key [ 14 ] = = 0x10 ) {
2014-01-08 00:51:48 +00:00
ret = mxf_get_d10_aes3_packet ( s - > pb , s - > streams [ index ] ,
pkt , klv . length ) ;
if ( ret < 0 ) {
2011-12-16 08:19:01 +00:00
av_log ( s , AV_LOG_ERROR , " error reading D-10 aes3 frame \n " ) ;
2014-01-08 00:51:48 +00:00
return ret ;
2011-12-16 08:19:01 +00:00
}
} else {
2012-01-16 00:20:32 +00:00
ret = av_get_packet ( s - > pb , pkt , klv . length ) ;
2011-12-16 08:19:01 +00:00
if ( ret < 0 )
return ret ;
}
pkt - > stream_index = index ;
pkt - > pos = klv . offset ;
2011-12-16 09:53:41 +00:00
2014-10-18 13:26:26 +00:00
codec = st - > codec ;
2012-09-13 19:15:48 +00:00
2012-09-13 19:15:48 +00:00
if ( codec - > codec_type = = AVMEDIA_TYPE_VIDEO & & next_ofs > = 0 ) {
2012-03-02 10:16:10 +00:00
/* mxf->current_edit_unit good - see if we have an
* index table to derive timestamps from */
2012-03-02 10:16:10 +00:00
MXFIndexTable * t = & mxf - > index_tables [ 0 ] ;
if ( mxf - > nb_index_tables > = 1 & & mxf - > current_edit_unit < t - > nb_ptses ) {
pkt - > dts = mxf - > current_edit_unit + t - > first_dts ;
pkt - > pts = t - > ptses [ mxf - > current_edit_unit ] ;
2012-03-07 09:03:16 +00:00
} else if ( track - > intra_only ) {
/* intra-only -> PTS = EditUnit.
* let utils . c figure out DTS since it can be < PTS if low_delay = 0 ( Sony IMX30 ) */
pkt - > pts = mxf - > current_edit_unit ;
2012-03-02 10:16:10 +00:00
}
2012-09-13 19:15:48 +00:00
} else if ( codec - > codec_type = = AVMEDIA_TYPE_AUDIO ) {
2014-01-08 00:51:48 +00:00
ret = mxf_set_audio_pts ( mxf , codec , pkt ) ;
2012-09-13 19:15:48 +00:00
if ( ret < 0 )
return ret ;
2012-03-02 10:16:10 +00:00
}
/* seek for truncated packets */
avio_seek ( s - > pb , next_klv , SEEK_SET ) ;
2011-12-16 09:53:41 +00:00
2011-12-16 08:19:01 +00:00
return 0 ;
} else
skip :
avio_skip ( s - > pb , klv . length ) ;
}
2014-08-07 20:12:41 +00:00
return avio_feof ( s - > pb ) ? AVERROR_EOF : ret ;
2011-12-16 08:19:01 +00:00
}
static int mxf_read_packet ( AVFormatContext * s , AVPacket * pkt )
{
MXFContext * mxf = s - > priv_data ;
2011-12-16 09:53:41 +00:00
int ret , size ;
int64_t ret64 , pos , next_pos ;
2011-12-16 08:19:01 +00:00
AVStream * st ;
2011-12-16 09:53:41 +00:00
MXFIndexTable * t ;
2012-01-24 10:36:39 +00:00
int edit_units ;
2011-12-16 08:19:01 +00:00
2011-12-16 09:53:41 +00:00
if ( mxf - > op ! = OPAtom )
2011-12-16 08:19:01 +00:00
return mxf_read_packet_old ( s , pkt ) ;
2011-12-16 09:53:41 +00:00
/* OPAtom - clip wrapped demuxing */
2011-12-20 10:22:23 +00:00
/* NOTE: mxf_read_header() makes sure nb_index_tables > 0 for OPAtom */
2011-12-16 09:53:41 +00:00
st = s - > streams [ 0 ] ;
t = & mxf - > index_tables [ 0 ] ;
2011-12-16 08:19:01 +00:00
2011-12-16 09:53:41 +00:00
if ( mxf - > current_edit_unit > = st - > duration )
2011-12-16 08:19:01 +00:00
return AVERROR_EOF ;
2012-01-24 10:36:39 +00:00
edit_units = FFMIN ( mxf - > edit_units_per_packet , st - > duration - mxf - > current_edit_unit ) ;
2011-12-16 09:53:41 +00:00
if ( ( ret = mxf_edit_unit_absolute_offset ( mxf , t , mxf - > current_edit_unit , NULL , & pos , 1 ) ) < 0 )
return ret ;
2011-12-16 08:19:01 +00:00
2011-12-16 09:53:41 +00:00
/* compute size by finding the next edit unit or the end of the essence container
* not pretty , but it works */
2012-01-24 10:36:39 +00:00
if ( ( ret = mxf_edit_unit_absolute_offset ( mxf , t , mxf - > current_edit_unit + edit_units , NULL , & next_pos , 0 ) ) < 0 & &
2011-12-16 09:53:41 +00:00
( next_pos = mxf_essence_container_end ( mxf , t - > body_sid ) ) < = 0 ) {
av_log ( s , AV_LOG_ERROR , " unable to compute the size of the last packet \n " ) ;
return AVERROR_INVALIDDATA ;
}
2011-12-16 08:19:01 +00:00
2011-12-16 09:53:41 +00:00
if ( ( size = next_pos - pos ) < = 0 ) {
av_log ( s , AV_LOG_ERROR , " bad size: %i \n " , size ) ;
return AVERROR_INVALIDDATA ;
}
2011-12-16 08:19:01 +00:00
2011-12-16 09:53:41 +00:00
if ( ( ret64 = avio_seek ( s - > pb , pos , SEEK_SET ) ) < 0 )
return ret64 ;
2011-12-16 08:19:01 +00:00
2012-04-20 18:57:57 +00:00
if ( ( size = av_get_packet ( s - > pb , pkt , size ) ) < 0 )
return size ;
2011-12-16 08:19:01 +00:00
2012-09-13 19:15:48 +00:00
pkt - > stream_index = 0 ;
2011-12-16 09:53:41 +00:00
if ( st - > codec - > codec_type = = AVMEDIA_TYPE_VIDEO & & t - > ptses & &
mxf - > current_edit_unit > = 0 & & mxf - > current_edit_unit < t - > nb_ptses ) {
pkt - > dts = mxf - > current_edit_unit + t - > first_dts ;
pkt - > pts = t - > ptses [ mxf - > current_edit_unit ] ;
2012-09-13 19:15:48 +00:00
} else if ( st - > codec - > codec_type = = AVMEDIA_TYPE_AUDIO ) {
int ret = mxf_set_audio_pts ( mxf , st - > codec , pkt ) ;
if ( ret < 0 )
return ret ;
2011-12-16 08:19:01 +00:00
}
2012-01-24 10:36:39 +00:00
mxf - > current_edit_unit + = edit_units ;
2011-12-16 08:19:01 +00:00
return 0 ;
}
2008-08-07 02:12:14 +00:00
static int mxf_read_close ( AVFormatContext * s )
{
MXFContext * mxf = s - > priv_data ;
2011-12-20 08:59:29 +00:00
int i ;
2008-08-07 02:12:14 +00:00
av_freep ( & mxf - > packages_refs ) ;
2009-05-15 05:33:05 +00:00
for ( i = 0 ; i < s - > nb_streams ; i + + )
s - > streams [ i ] - > priv_data = NULL ;
2008-08-07 02:12:14 +00:00
for ( i = 0 ; i < mxf - > metadata_sets_count ; i + + ) {
2015-01-28 01:59:03 +00:00
mxf_free_metadataset ( mxf - > metadata_sets + i , 1 ) ;
2008-08-07 02:12:14 +00:00
}
2011-02-07 15:07:41 +00:00
av_freep ( & mxf - > partitions ) ;
2008-08-07 02:12:14 +00:00
av_freep ( & mxf - > metadata_sets ) ;
av_freep ( & mxf - > aesc ) ;
av_freep ( & mxf - > local_tags ) ;
2011-12-15 15:47:49 +00:00
2012-12-01 19:15:02 +00:00
if ( mxf - > index_tables ) {
for ( i = 0 ; i < mxf - > nb_index_tables ; i + + ) {
av_freep ( & mxf - > index_tables [ i ] . segments ) ;
av_freep ( & mxf - > index_tables [ i ] . ptses ) ;
av_freep ( & mxf - > index_tables [ i ] . fake_index ) ;
}
2011-12-16 08:42:52 +00:00
}
2011-12-15 15:47:49 +00:00
av_freep ( & mxf - > index_tables ) ;
2008-08-07 02:12:14 +00:00
return 0 ;
}
static int mxf_probe ( AVProbeData * p ) {
2012-12-25 00:54:20 +00:00
const uint8_t * bufp = p - > buf ;
const uint8_t * end = p - > buf + p - > buf_size ;
2008-08-07 02:12:14 +00:00
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 ) ;
2013-11-08 20:43:27 +00:00
for ( ; bufp < end ; ) {
if ( ! ( ( bufp [ 13 ] - 1 ) & 0xF2 ) ) {
if ( AV_RN32 ( bufp ) = = AV_RN32 ( mxf_header_partition_pack_key ) & &
AV_RN32 ( bufp + 4 ) = = AV_RN32 ( mxf_header_partition_pack_key + 4 ) & &
AV_RN32 ( bufp + 8 ) = = AV_RN32 ( mxf_header_partition_pack_key + 8 ) & &
AV_RN16 ( bufp + 12 ) = = AV_RN16 ( mxf_header_partition_pack_key + 12 ) )
return AVPROBE_SCORE_MAX ;
bufp + + ;
} else
bufp + = 10 ;
2008-08-07 02:12:14 +00:00
}
2013-11-08 20:43:27 +00:00
2008-08-07 02:12:14 +00:00
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 ;
2011-12-08 19:28:49 +00:00
MXFContext * mxf = s - > priv_data ;
int64_t seekpos ;
2012-09-13 19:15:48 +00:00
int i , ret ;
2011-12-16 09:53:41 +00:00
MXFIndexTable * t ;
2012-12-14 14:39:16 +00:00
MXFTrack * source_track = st - > priv_data ;
/* if audio then truncate sample_time to EditRate */
if ( st - > codec - > codec_type = = AVMEDIA_TYPE_AUDIO )
2012-09-13 19:15:48 +00:00
sample_time = av_rescale_q ( sample_time , st - > time_base ,
av_inv_q ( source_track - > edit_rate ) ) ;
2008-08-07 02:12:14 +00:00
2012-09-19 22:52:26 +00:00
if ( mxf - > nb_index_tables < = 0 ) {
2008-08-07 02:12:14 +00:00
if ( ! s - > bit_rate )
2012-01-14 21:25:12 +00:00
return AVERROR_INVALIDDATA ;
2008-08-07 02:12:14 +00:00
if ( sample_time < 0 )
sample_time = 0 ;
seconds = av_rescale ( sample_time , st - > time_base . num , st - > time_base . den ) ;
2011-09-14 17:26:48 +00:00
2014-01-07 20:26:14 +00:00
seekpos = avio_seek ( s - > pb , ( s - > bit_rate * seconds ) > > 3 , SEEK_SET ) ;
if ( seekpos < 0 )
return seekpos ;
2011-10-16 13:03:30 +00:00
ff_update_cur_dts ( s , st , sample_time ) ;
2013-04-10 23:09:40 +00:00
mxf - > current_edit_unit = sample_time ;
2011-12-08 19:28:49 +00:00
} else {
2011-12-16 09:53:41 +00:00
t = & mxf - > index_tables [ 0 ] ;
2011-12-08 19:28:49 +00:00
2011-12-16 09:53:41 +00:00
/* clamp above zero, else ff_index_search_timestamp() returns negative
* this also means we allow seeking before the start */
sample_time = FFMAX ( sample_time , 0 ) ;
2011-12-08 19:28:49 +00:00
2011-12-16 09:53:41 +00:00
if ( t - > fake_index ) {
/* behave as if we have a proper index */
if ( ( sample_time = ff_index_search_timestamp ( t - > fake_index , t - > nb_ptses , sample_time , flags ) ) < 0 )
return sample_time ;
} else {
/* no IndexEntryArray (one or more CBR segments)
* make sure we don ' t seek past the end */
2012-12-14 14:39:16 +00:00
sample_time = FFMIN ( sample_time , source_track - > original_duration - 1 ) ;
2011-12-08 19:28:49 +00:00
}
2014-01-15 16:52:19 +00:00
if ( ( ret = mxf_edit_unit_absolute_offset ( mxf , t , sample_time , & sample_time , & seekpos , 1 ) ) < 0 )
2011-12-16 09:53:41 +00:00
return ret ;
2011-12-08 19:28:49 +00:00
ff_update_cur_dts ( s , st , sample_time ) ;
2011-12-16 09:53:41 +00:00
mxf - > current_edit_unit = sample_time ;
2011-12-08 19:28:49 +00:00
avio_seek ( s - > pb , seekpos , SEEK_SET ) ;
}
2012-09-13 19:15:48 +00:00
// Update all tracks sample count
for ( i = 0 ; i < s - > nb_streams ; i + + ) {
AVStream * cur_st = s - > streams [ i ] ;
MXFTrack * cur_track = cur_st - > priv_data ;
uint64_t current_sample_count = 0 ;
if ( cur_st - > codec - > codec_type = = AVMEDIA_TYPE_AUDIO ) {
ret = mxf_compute_sample_count ( mxf , i , & current_sample_count ) ;
if ( ret < 0 )
return ret ;
cur_track - > sample_count = current_sample_count ;
}
}
2008-08-07 02:12:14 +00:00
return 0 ;
}
2011-01-25 22:03:28 +00:00
AVInputFormat ff_mxf_demuxer = {
2011-07-16 20:18:12 +00:00
. name = " mxf " ,
2012-07-24 01:23:48 +00:00
. long_name = NULL_IF_CONFIG_SMALL ( " MXF (Material eXchange Format) " ) ,
2011-07-16 20:18:12 +00:00
. 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 02:12:14 +00:00
} ;