libavformat/mxfdec.c
d09ea6ba
 /*
  * MXF demuxer.
406792e7
  * Copyright (c) 2006 SmartJog S.A., Baptiste Coudurier <baptiste dot coudurier at smartjog dot com>
d09ea6ba
  *
  * 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 336M KLV Data Encoding Protocol Using Key-Length-Value
  * SMPTE 377M MXF File Format Specifications
  * SMPTE 378M Operational Pattern 1a
  * SMPTE 379M MXF Generic Container
  * SMPTE 381M Mapping MPEG Streams into the MXF Generic Container
  * SMPTE 382M Mapping AES3 and Broadcast Wave Audio into the MXF Generic Container
  * SMPTE 383M 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 377M D.1
  */
 
8f8bc923
 #include <stdint.h>
 
d09ea6ba
 #include "libavutil/aes.h"
83cab07a
 #include "libavutil/avassert.h"
0ebcdf5c
 #include "libavutil/mathematics.h"
251bf875
 #include "libavcodec/bytestream.h"
a26e83da
 #include "libavutil/intreadwrite.h"
ad029c24
 #include "libavutil/timecode.h"
251bf875
 #include "avformat.h"
a2faa951
 #include "internal.h"
c69968b4
 #include "mxf.h"
d09ea6ba
 
9289eada
 typedef enum {
     Header,
     BodyPartition,
     Footer
 } MXFPartitionType;
 
 typedef enum {
1de5154d
     OP1a = 1,
9289eada
     OP1b,
     OP1c,
     OP2a,
     OP2b,
     OP2c,
     OP3a,
     OP3b,
     OP3c,
     OPAtom,
fd34dbea
     OPSONYOpt,  /* FATE sample, violates the spec in places */
9289eada
 } MXFOP;
 
 typedef struct {
     int closed;
     int complete;
     MXFPartitionType type;
     uint64_t previous_partition;
     int index_sid;
     int body_sid;
e5f9c892
     int64_t this_partition;
21cc4b33
     int64_t essence_offset;         ///< absolute offset of essence
33624623
     int64_t essence_length;
fd34dbea
     int32_t kag_size;
     int64_t header_byte_count;
     int64_t index_byte_count;
     int pack_length;
9289eada
 } MXFPartition;
 
d09ea6ba
 typedef struct {
     UID uid;
     enum MXFMetadataSetType type;
     UID source_container_ul;
 } MXFCryptoContext;
 
 typedef struct {
     UID uid;
     enum MXFMetadataSetType type;
     UID source_package_uid;
     UID data_definition_ul;
     int64_t duration;
     int64_t start_position;
     int source_track_id;
 } MXFStructuralComponent;
 
 typedef struct {
     UID uid;
     enum MXFMetadataSetType type;
     UID data_definition_ul;
     UID *structural_components_refs;
     int structural_components_count;
     int64_t duration;
 } MXFSequence;
 
 typedef struct {
     UID uid;
     enum MXFMetadataSetType type;
ad029c24
     int drop_frame;
     int start_frame;
     struct AVRational rate;
     AVTimecode tc;
 } MXFTimecodeComponent;
 
 typedef struct {
     UID uid;
     enum MXFMetadataSetType type;
d09ea6ba
     MXFSequence *sequence; /* mandatory, and only one */
     UID sequence_ref;
     int track_id;
     uint8_t track_number[4];
     AVRational edit_rate;
f6daa9f4
     int intra_only;
83cab07a
     uint64_t sample_count;
928727f9
     int64_t original_duration;  ///< duration before multiplying st->duration by SampleRate/EditRate
d09ea6ba
 } MXFTrack;
 
 typedef struct {
     UID uid;
     enum MXFMetadataSetType type;
     UID essence_container_ul;
     UID essence_codec_ul;
     AVRational sample_rate;
     AVRational aspect_ratio;
     int width;
84b9b4aa
     int height; /* Field height, not frame height */
     int frame_layout; /* See MXFFrameLayout enum */
c7166248
 #define MXF_TFF 1
 #define MXF_BFF 2
     int field_dominance;
d09ea6ba
     int channels;
     int bits_per_sample;
34210e8d
     unsigned int component_depth;
     unsigned int horiz_subsampling;
     unsigned int vert_subsampling;
d09ea6ba
     UID *sub_descriptors_refs;
     int sub_descriptors_count;
     int linked_track_id;
     uint8_t *extradata;
     int extradata_size;
716d413c
     enum AVPixelFormat pix_fmt;
d09ea6ba
 } MXFDescriptor;
 
 typedef struct {
     UID uid;
     enum MXFMetadataSetType type;
7ddb0607
     int edit_unit_byte_count;
     int index_sid;
     int body_sid;
     AVRational index_edit_rate;
     uint64_t index_start_position;
     uint64_t index_duration;
7560c264
     int8_t *temporal_offset_entries;
7ddb0607
     int *flag_entries;
     uint64_t *stream_offset_entries;
     int nb_index_entries;
861b4f01
 } MXFIndexTableSegment;
 
 typedef struct {
     UID uid;
     enum MXFMetadataSetType type;
d09ea6ba
     UID package_uid;
     UID *tracks_refs;
     int tracks_count;
     MXFDescriptor *descriptor; /* only one */
     UID descriptor_ref;
 } MXFPackage;
 
 typedef struct {
     UID uid;
     enum MXFMetadataSetType type;
 } MXFMetadataSet;
 
8ce41721
 /* decoded index table */
 typedef struct {
     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 */
2212e040
     AVIndexEntry *fake_index;   /* used for calling ff_index_search_timestamp() */
8ce41721
 } MXFIndexTable;
 
d09ea6ba
 typedef struct {
9289eada
     MXFPartition *partitions;
     unsigned partitions_count;
     MXFOP op;
d09ea6ba
     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;
f5ed83c3
     uint64_t last_partition;
d377deaa
     uint64_t footer_partition;
7ddb0607
     KLVPacket current_klv_data;
     int current_klv_index;
dcd30b83
     int run_in;
     MXFPartition *current_partition;
     int parsing_backward;
     int64_t last_forward_tell;
289bc144
     int last_forward_partition;
ddcf3e05
     int current_edit_unit;
8ce41721
     int nb_index_tables;
     MXFIndexTable *index_tables;
d8531a1c
     int edit_units_per_packet;      ///< how many edit units to read at a time (PCM, OPAtom)
d09ea6ba
 } MXFContext;
 
 enum MXFWrappingScheme {
     Frame,
     Clip,
 };
 
fd34dbea
 /* 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);
39bb30f6
 
d09ea6ba
 typedef struct {
     const UID key;
39bb30f6
     MXFMetadataReadFunc *read;
d09ea6ba
     int ctx_size;
     enum MXFMetadataSetType type;
 } MXFMetadataReadTableEntry;
 
d7da4d47
 static int mxf_read_close(AVFormatContext *s);
 
d09ea6ba
 /* 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 };
0bcada9f
 static const uint8_t mxf_avid_essence_element_key[]        = { 0x06,0x0e,0x2b,0x34,0x01,0x02,0x01,0x01,0x0e,0x04,0x03,0x01 };
fd1cea65
 static const uint8_t mxf_system_item_key[]                 = { 0x06,0x0E,0x2B,0x34,0x02,0x05,0x01,0x01,0x0D,0x01,0x03,0x01,0x04 };
d09ea6ba
 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 };
f5ed83c3
 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 };
d09ea6ba
 static const uint8_t mxf_sony_mpeg4_extradata[]            = { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x01,0x0e,0x06,0x06,0x02,0x02,0x01,0x00,0x00 };
 
 #define IS_KLV_KEY(x, y) (!memcmp(x, y, sizeof(y)))
 
471fe57e
 static int64_t klv_decode_ber_length(AVIOContext *pb)
d09ea6ba
 {
e63a3628
     uint64_t size = avio_r8(pb);
d09ea6ba
     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)
bcd5d979
             return AVERROR_INVALIDDATA;
d09ea6ba
         size = 0;
         while (bytes_num--)
e63a3628
             size = size << 8 | avio_r8(pb);
d09ea6ba
     }
     return size;
 }
 
471fe57e
 static int mxf_read_sync(AVIOContext *pb, const uint8_t *key, unsigned size)
d09ea6ba
 {
     int i, b;
     for (i = 0; i < size && !url_feof(pb); i++) {
e63a3628
         b = avio_r8(pb);
d09ea6ba
         if (b == key[0])
             i = 0;
         else if (b != key[i])
             i = -1;
     }
     return i == size;
 }
 
471fe57e
 static int klv_read_packet(KLVPacket *klv, AVIOContext *pb)
d09ea6ba
 {
     if (!mxf_read_sync(pb, mxf_klv_key, 4))
bcd5d979
         return AVERROR_INVALIDDATA;
384c9c2f
     klv->offset = avio_tell(pb) - 4;
d09ea6ba
     memcpy(klv->key, mxf_klv_key, 4);
e63a3628
     avio_read(pb, klv->key + 4, 12);
d09ea6ba
     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 */
471fe57e
 static int mxf_get_d10_aes3_packet(AVIOContext *pb, AVStream *st, AVPacket *pkt, int64_t length)
d09ea6ba
 {
     const uint8_t *buf_ptr, *end_ptr;
     uint8_t *data_ptr;
     int i;
 
     if (length > 61444) /* worst case PAL 1920 samples 8 channels */
bcd5d979
         return AVERROR_INVALIDDATA;
0c46e958
     length = av_get_packet(pb, pkt, length);
     if (length < 0)
         return length;
d09ea6ba
     data_ptr = pkt->data;
c7a38887
     end_ptr = pkt->data + length;
     buf_ptr = pkt->data + 4; /* skip SMPTE 331M header */
aa0cb16c
     for (; end_ptr - buf_ptr >= st->codec->channels * 4; ) {
d09ea6ba
         for (i = 0; i < st->codec->channels; i++) {
             uint32_t sample = bytestream_get_le32(&buf_ptr);
dd1c8f3e
             if (st->codec->bits_per_coded_sample == 24)
d09ea6ba
                 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
     }
0c46e958
     av_shrink_packet(pkt, data_ptr - pkt->data);
d09ea6ba
     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;
471fe57e
     AVIOContext *pb = s->pb;
384c9c2f
     int64_t end = avio_tell(pb) + klv->length;
735e601b
     int64_t size;
d09ea6ba
     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) {
e002e329
         mxf->aesc = av_aes_alloc();
d09ea6ba
         if (!mxf->aesc)
bcd5d979
             return AVERROR(ENOMEM);
d09ea6ba
         av_aes_init(mxf->aesc, s->key, 128, 1);
     }
     // crypto context
45a8a02a
     avio_skip(pb, klv_decode_ber_length(pb));
d09ea6ba
     // plaintext offset
     klv_decode_ber_length(pb);
e63a3628
     plaintext_size = avio_rb64(pb);
d09ea6ba
     // source klv key
     klv_decode_ber_length(pb);
e63a3628
     avio_read(pb, klv->key, 16);
d09ea6ba
     if (!IS_KLV_KEY(klv, mxf_essence_element_key))
bcd5d979
         return AVERROR_INVALIDDATA;
d09ea6ba
     index = mxf_get_stream_index(s, klv);
     if (index < 0)
bcd5d979
         return AVERROR_INVALIDDATA;
d09ea6ba
     // source size
     klv_decode_ber_length(pb);
e63a3628
     orig_size = avio_rb64(pb);
d09ea6ba
     if (orig_size < plaintext_size)
bcd5d979
         return AVERROR_INVALIDDATA;
d09ea6ba
     // enc. code
     size = klv_decode_ber_length(pb);
     if (size < 32 || size - 32 < orig_size)
bcd5d979
         return AVERROR_INVALIDDATA;
e63a3628
     avio_read(pb, ivec, 16);
     avio_read(pb, tmpbuf, 16);
d09ea6ba
     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;
0c46e958
     size = av_get_packet(pb, pkt, size);
     if (size < 0)
         return size;
     else if (size < plaintext_size)
         return AVERROR_INVALIDDATA;
d09ea6ba
     size -= plaintext_size;
     if (mxf->aesc)
         av_aes_crypt(mxf->aesc, &pkt->data[plaintext_size],
                      &pkt->data[plaintext_size], size >> 4, ivec, 1);
0c46e958
     av_shrink_packet(pkt, orig_size);
d09ea6ba
     pkt->stream_index = index;
45a8a02a
     avio_skip(pb, end - avio_tell(pb));
d09ea6ba
     return 0;
 }
 
fd34dbea
 static int mxf_read_primer_pack(void *arg, AVIOContext *pb, int tag, int size, UID uid, int64_t klv_offset)
d09ea6ba
 {
39bb30f6
     MXFContext *mxf = arg;
e63a3628
     int item_num = avio_rb32(pb);
     int item_len = avio_rb32(pb);
d09ea6ba
 
     if (item_len != 18) {
1ecdf891
         avpriv_request_sample(pb, "Primer pack item length %d", item_len);
bcd5d979
         return AVERROR_PATCHWELCOME;
d09ea6ba
     }
daa29058
     if (item_num > 65536) {
         av_log(mxf->fc, AV_LOG_ERROR, "item_num %d is too large\n", item_num);
bcd5d979
         return AVERROR_INVALIDDATA;
daa29058
     }
     mxf->local_tags = av_calloc(item_num, item_len);
d09ea6ba
     if (!mxf->local_tags)
bcd5d979
         return AVERROR(ENOMEM);
daa29058
     mxf->local_tags_count = item_num;
e63a3628
     avio_read(pb, mxf->local_tags, item_num*item_len);
d09ea6ba
     return 0;
 }
 
fd34dbea
 static int mxf_read_partition_pack(void *arg, AVIOContext *pb, int tag, int size, UID uid, int64_t klv_offset)
9289eada
 {
     MXFContext *mxf = arg;
5ca39a0b
     MXFPartition *partition, *tmp_part;
9289eada
     UID op;
d377deaa
     uint64_t footer_partition;
1de5154d
     uint32_t nb_essence_containers;
9289eada
 
c5714097
     tmp_part = av_realloc_array(mxf->partitions, mxf->partitions_count + 1, sizeof(*mxf->partitions));
5ca39a0b
     if (!tmp_part)
         return AVERROR(ENOMEM);
     mxf->partitions = tmp_part;
9289eada
 
289bc144
     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++;
fd34dbea
     partition->pack_length = avio_tell(pb) - klv_offset + size;
9289eada
 
     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;
fd34dbea
     avio_skip(pb, 4);
     partition->kag_size = avio_rb32(pb);
e5f9c892
     partition->this_partition = avio_rb64(pb);
9289eada
     partition->previous_partition = avio_rb64(pb);
d377deaa
     footer_partition = avio_rb64(pb);
fd34dbea
     partition->header_byte_count = avio_rb64(pb);
     partition->index_byte_count = avio_rb64(pb);
9289eada
     partition->index_sid = avio_rb32(pb);
     avio_skip(pb, 8);
     partition->body_sid = avio_rb32(pb);
4162ceea
     if (avio_read(pb, op, sizeof(UID)) != sizeof(UID)) {
         av_log(mxf->fc, AV_LOG_ERROR, "Failed reading UID\n");
         return AVERROR_INVALIDDATA;
     }
1de5154d
     nb_essence_containers = avio_rb32(pb);
9289eada
 
d377deaa
     /* some files don'thave FooterPartition set in every partition */
     if (footer_partition) {
         if (mxf->footer_partition && mxf->footer_partition != footer_partition) {
4fbd3e89
             av_log(mxf->fc, AV_LOG_ERROR,
                    "inconsistent FooterPartition value: %"PRIu64" != %"PRIu64"\n",
d377deaa
                    mxf->footer_partition, footer_partition);
         } else {
             mxf->footer_partition = footer_partition;
         }
     }
 
4fbd3e89
     av_dlog(mxf->fc,
             "PartitionPack: ThisPartition = 0x%"PRIX64
             ", PreviousPartition = 0x%"PRIX64", "
             "FooterPartition = 0x%"PRIX64", IndexSID = %i, BodySID = %i\n",
e5f9c892
             partition->this_partition,
d377deaa
             partition->previous_partition, footer_partition,
9289eada
             partition->index_sid, partition->body_sid);
 
46d65fb8
     /* sanity check PreviousPartition if set */
     if (partition->previous_partition &&
         mxf->run_in + partition->previous_partition >= klv_offset) {
df2a8508
         av_log(mxf->fc, AV_LOG_ERROR,
                "PreviousPartition points to this partition or forward\n");
46d65fb8
         return AVERROR_INVALIDDATA;
     }
 
9289eada
     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;
fd34dbea
     else if (op[12] == 64&& op[13] == 1) mxf->op = OPSONYOpt;
1de5154d
     else if (op[12] == 0x10) {
         /* SMPTE 390m: "There shall be exactly one essence container"
8c7721e7
          * 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 */
1de5154d
         if (nb_essence_containers != 1) {
8c7721e7
             MXFOP op = nb_essence_containers ? OP1a : OPAtom;
 
1de5154d
             /* only nag once */
             if (!mxf->op)
8c7721e7
                 av_log(mxf->fc, AV_LOG_WARNING, "\"OPAtom\" with %u ECs - assuming %s\n",
                        nb_essence_containers, op == OP1a ? "OP1a" : "OPAtom");
1de5154d
 
8c7721e7
             mxf->op = op;
1de5154d
         } else
             mxf->op = OPAtom;
     } else {
fd34dbea
         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)) {
         av_log(mxf->fc, AV_LOG_WARNING, "invalid KAGSize %i - guessing ", partition->kag_size);
 
         if (mxf->op == OPSONYOpt)
             partition->kag_size = 512;
         else
             partition->kag_size = 1;
 
         av_log(mxf->fc, AV_LOG_WARNING, "%i\n", partition->kag_size);
     }
9289eada
 
     return 0;
 }
 
d09ea6ba
 static int mxf_add_metadata_set(MXFContext *mxf, void *metadata_set)
 {
5ca39a0b
     MXFMetadataSet **tmp;
c5714097
 
     tmp = av_realloc_array(mxf->metadata_sets, mxf->metadata_sets_count + 1, sizeof(*mxf->metadata_sets));
5ca39a0b
     if (!tmp)
         return AVERROR(ENOMEM);
     mxf->metadata_sets = tmp;
d09ea6ba
     mxf->metadata_sets[mxf->metadata_sets_count] = metadata_set;
     mxf->metadata_sets_count++;
     return 0;
 }
 
fd34dbea
 static int mxf_read_cryptographic_context(void *arg, AVIOContext *pb, int tag, int size, UID uid, int64_t klv_offset)
d09ea6ba
 {
39bb30f6
     MXFCryptoContext *cryptocontext = arg;
d09ea6ba
     if (size != 16)
bcd5d979
         return AVERROR_INVALIDDATA;
d09ea6ba
     if (IS_KLV_KEY(uid, mxf_crypto_source_container_ul))
e63a3628
         avio_read(pb, cryptocontext->source_container_ul, 16);
d09ea6ba
     return 0;
 }
 
fd34dbea
 static int mxf_read_content_storage(void *arg, AVIOContext *pb, int tag, int size, UID uid, int64_t klv_offset)
d09ea6ba
 {
39bb30f6
     MXFContext *mxf = arg;
d09ea6ba
     switch (tag) {
     case 0x1901:
e63a3628
         mxf->packages_count = avio_rb32(pb);
daa29058
         mxf->packages_refs = av_calloc(mxf->packages_count, sizeof(UID));
d09ea6ba
         if (!mxf->packages_refs)
bcd5d979
             return AVERROR(ENOMEM);
45a8a02a
         avio_skip(pb, 4); /* useless size of objects, always 16 according to specs */
e63a3628
         avio_read(pb, (uint8_t *)mxf->packages_refs, mxf->packages_count * sizeof(UID));
d09ea6ba
         break;
     }
     return 0;
 }
 
fd34dbea
 static int mxf_read_source_clip(void *arg, AVIOContext *pb, int tag, int size, UID uid, int64_t klv_offset)
d09ea6ba
 {
39bb30f6
     MXFStructuralComponent *source_clip = arg;
d09ea6ba
     switch(tag) {
     case 0x0202:
e63a3628
         source_clip->duration = avio_rb64(pb);
d09ea6ba
         break;
     case 0x1201:
e63a3628
         source_clip->start_position = avio_rb64(pb);
d09ea6ba
         break;
     case 0x1101:
         /* UMID, only get last 16 bytes */
45a8a02a
         avio_skip(pb, 16);
e63a3628
         avio_read(pb, source_clip->source_package_uid, 16);
d09ea6ba
         break;
     case 0x1102:
e63a3628
         source_clip->source_track_id = avio_rb32(pb);
d09ea6ba
         break;
     }
     return 0;
 }
 
fd34dbea
 static int mxf_read_material_package(void *arg, AVIOContext *pb, int tag, int size, UID uid, int64_t klv_offset)
d09ea6ba
 {
39bb30f6
     MXFPackage *package = arg;
d09ea6ba
     switch(tag) {
     case 0x4403:
e63a3628
         package->tracks_count = avio_rb32(pb);
daa29058
         package->tracks_refs = av_calloc(package->tracks_count, sizeof(UID));
d09ea6ba
         if (!package->tracks_refs)
bcd5d979
             return AVERROR(ENOMEM);
45a8a02a
         avio_skip(pb, 4); /* useless size of objects, always 16 according to specs */
e63a3628
         avio_read(pb, (uint8_t *)package->tracks_refs, package->tracks_count * sizeof(UID));
d09ea6ba
         break;
     }
     return 0;
 }
 
ad029c24
 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;
 }
 
fd34dbea
 static int mxf_read_track(void *arg, AVIOContext *pb, int tag, int size, UID uid, int64_t klv_offset)
d09ea6ba
 {
39bb30f6
     MXFTrack *track = arg;
d09ea6ba
     switch(tag) {
     case 0x4801:
e63a3628
         track->track_id = avio_rb32(pb);
d09ea6ba
         break;
     case 0x4804:
e63a3628
         avio_read(pb, track->track_number, 4);
d09ea6ba
         break;
     case 0x4B01:
e63a3628
         track->edit_rate.num = avio_rb32(pb);
3592bd50
         track->edit_rate.den = avio_rb32(pb);
d09ea6ba
         break;
     case 0x4803:
e63a3628
         avio_read(pb, track->sequence_ref, 16);
d09ea6ba
         break;
     }
     return 0;
 }
 
fd34dbea
 static int mxf_read_sequence(void *arg, AVIOContext *pb, int tag, int size, UID uid, int64_t klv_offset)
d09ea6ba
 {
39bb30f6
     MXFSequence *sequence = arg;
d09ea6ba
     switch(tag) {
     case 0x0202:
e63a3628
         sequence->duration = avio_rb64(pb);
d09ea6ba
         break;
     case 0x0201:
e63a3628
         avio_read(pb, sequence->data_definition_ul, 16);
d09ea6ba
         break;
     case 0x1001:
e63a3628
         sequence->structural_components_count = avio_rb32(pb);
daa29058
         sequence->structural_components_refs = av_calloc(sequence->structural_components_count, sizeof(UID));
d09ea6ba
         if (!sequence->structural_components_refs)
bcd5d979
             return AVERROR(ENOMEM);
45a8a02a
         avio_skip(pb, 4); /* useless size of objects, always 16 according to specs */
e63a3628
         avio_read(pb, (uint8_t *)sequence->structural_components_refs, sequence->structural_components_count * sizeof(UID));
d09ea6ba
         break;
     }
     return 0;
 }
 
fd34dbea
 static int mxf_read_source_package(void *arg, AVIOContext *pb, int tag, int size, UID uid, int64_t klv_offset)
d09ea6ba
 {
39bb30f6
     MXFPackage *package = arg;
d09ea6ba
     switch(tag) {
     case 0x4403:
e63a3628
         package->tracks_count = avio_rb32(pb);
daa29058
         package->tracks_refs = av_calloc(package->tracks_count, sizeof(UID));
d09ea6ba
         if (!package->tracks_refs)
bcd5d979
             return AVERROR(ENOMEM);
45a8a02a
         avio_skip(pb, 4); /* useless size of objects, always 16 according to specs */
e63a3628
         avio_read(pb, (uint8_t *)package->tracks_refs, package->tracks_count * sizeof(UID));
d09ea6ba
         break;
     case 0x4401:
         /* UMID, only get last 16 bytes */
45a8a02a
         avio_skip(pb, 16);
e63a3628
         avio_read(pb, package->package_uid, 16);
d09ea6ba
         break;
     case 0x4701:
e63a3628
         avio_read(pb, package->descriptor_ref, 16);
d09ea6ba
         break;
     }
     return 0;
 }
 
7ddb0607
 static int mxf_read_index_entry_array(AVIOContext *pb, MXFIndexTableSegment *segment)
 {
54cbbdd2
     int i, length;
7ddb0607
 
     segment->nb_index_entries = avio_rb32(pb);
682b6db7
 
7ddb0607
     length = avio_rb32(pb);
 
7560c264
     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))) ||
7ddb0607
         !(segment->stream_offset_entries = av_calloc(segment->nb_index_entries, sizeof(*segment->stream_offset_entries))))
         return AVERROR(ENOMEM);
 
     for (i = 0; i < segment->nb_index_entries; i++) {
7560c264
         segment->temporal_offset_entries[i] = avio_r8(pb);
         avio_r8(pb);                                        /* KeyFrameOffset */
7ddb0607
         segment->flag_entries[i] = avio_r8(pb);
         segment->stream_offset_entries[i] = avio_rb64(pb);
0e764cf5
         avio_skip(pb, length - 11);
7ddb0607
     }
     return 0;
 }
 
fd34dbea
 static int mxf_read_index_table_segment(void *arg, AVIOContext *pb, int tag, int size, UID uid, int64_t klv_offset)
861b4f01
 {
7ddb0607
     MXFIndexTableSegment *segment = arg;
861b4f01
     switch(tag) {
7ddb0607
     case 0x3F05:
         segment->edit_unit_byte_count = avio_rb32(pb);
         av_dlog(NULL, "EditUnitByteCount %d\n", segment->edit_unit_byte_count);
         break;
     case 0x3F06:
         segment->index_sid = avio_rb32(pb);
         av_dlog(NULL, "IndexSID %d\n", segment->index_sid);
         break;
     case 0x3F07:
         segment->body_sid = avio_rb32(pb);
         av_dlog(NULL, "BodySID %d\n", segment->body_sid);
         break;
     case 0x3F0A:
         av_dlog(NULL, "IndexEntryArray found\n");
         return mxf_read_index_entry_array(pb, segment);
     case 0x3F0B:
         segment->index_edit_rate.num = avio_rb32(pb);
         segment->index_edit_rate.den = avio_rb32(pb);
         av_dlog(NULL, "IndexEditRate %d/%d\n", segment->index_edit_rate.num,
                 segment->index_edit_rate.den);
         break;
     case 0x3F0C:
         segment->index_start_position = avio_rb64(pb);
         av_dlog(NULL, "IndexStartPosition %"PRId64"\n", segment->index_start_position);
         break;
     case 0x3F0D:
         segment->index_duration = avio_rb64(pb);
         av_dlog(NULL, "IndexDuration %"PRId64"\n", segment->index_duration);
         break;
861b4f01
     }
     return 0;
 }
 
471fe57e
 static void mxf_read_pixel_layout(AVIOContext *pb, MXFDescriptor *descriptor)
d09ea6ba
 {
11fdc4d4
     int code, value, ofs = 0;
187630b2
     char layout[16] = {0}; /* not for printing, may end up not terminated on purpose */
d09ea6ba
 
     do {
e63a3628
         code = avio_r8(pb);
         value = avio_r8(pb);
9ef5a9de
         av_dlog(NULL, "pixel layout: code %#x\n", code);
11fdc4d4
 
187630b2
         if (ofs <= 14) {
11fdc4d4
             layout[ofs++] = code;
             layout[ofs++] = value;
1d22d269
         } else
             break;  /* don't read byte by byte on sneaky files filled with lots of non-zeroes */
d09ea6ba
     } while (code != 0); /* SMPTE 377M E.2.46 */
11fdc4d4
 
     ff_mxf_decode_pixel_layout(layout, &descriptor->pix_fmt);
d09ea6ba
 }
 
fd34dbea
 static int mxf_read_generic_descriptor(void *arg, AVIOContext *pb, int tag, int size, UID uid, int64_t klv_offset)
d09ea6ba
 {
39bb30f6
     MXFDescriptor *descriptor = arg;
716d413c
     descriptor->pix_fmt = AV_PIX_FMT_NONE;
d09ea6ba
     switch(tag) {
     case 0x3F01:
e63a3628
         descriptor->sub_descriptors_count = avio_rb32(pb);
daa29058
         descriptor->sub_descriptors_refs = av_calloc(descriptor->sub_descriptors_count, sizeof(UID));
d09ea6ba
         if (!descriptor->sub_descriptors_refs)
bcd5d979
             return AVERROR(ENOMEM);
45a8a02a
         avio_skip(pb, 4); /* useless size of objects, always 16 according to specs */
e63a3628
         avio_read(pb, (uint8_t *)descriptor->sub_descriptors_refs, descriptor->sub_descriptors_count * sizeof(UID));
d09ea6ba
         break;
     case 0x3004:
e63a3628
         avio_read(pb, descriptor->essence_container_ul, 16);
d09ea6ba
         break;
     case 0x3006:
e63a3628
         descriptor->linked_track_id = avio_rb32(pb);
d09ea6ba
         break;
     case 0x3201: /* PictureEssenceCoding */
e63a3628
         avio_read(pb, descriptor->essence_codec_ul, 16);
d09ea6ba
         break;
     case 0x3203:
e63a3628
         descriptor->width = avio_rb32(pb);
d09ea6ba
         break;
     case 0x3202:
e63a3628
         descriptor->height = avio_rb32(pb);
d09ea6ba
         break;
84b9b4aa
     case 0x320C:
         descriptor->frame_layout = avio_r8(pb);
         break;
d09ea6ba
     case 0x320E:
e63a3628
         descriptor->aspect_ratio.num = avio_rb32(pb);
         descriptor->aspect_ratio.den = avio_rb32(pb);
d09ea6ba
         break;
69e93792
     case 0x3212:
         descriptor->field_dominance = avio_r8(pb);
         break;
34210e8d
     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;
d09ea6ba
     case 0x3D03:
e63a3628
         descriptor->sample_rate.num = avio_rb32(pb);
         descriptor->sample_rate.den = avio_rb32(pb);
d09ea6ba
         break;
     case 0x3D06: /* SoundEssenceCompression */
e63a3628
         avio_read(pb, descriptor->essence_codec_ul, 16);
d09ea6ba
         break;
     case 0x3D07:
e63a3628
         descriptor->channels = avio_rb32(pb);
d09ea6ba
         break;
     case 0x3D01:
e63a3628
         descriptor->bits_per_sample = avio_rb32(pb);
d09ea6ba
         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)) {
b6557080
             if (descriptor->extradata)
                 av_log(NULL, AV_LOG_WARNING, "Duplicate sony_mpeg4_extradata\n");
             av_free(descriptor->extradata);
             descriptor->extradata_size = 0;
7d05bbb6
             descriptor->extradata = av_malloc(size);
d09ea6ba
             if (!descriptor->extradata)
bcd5d979
                 return AVERROR(ENOMEM);
d09ea6ba
             descriptor->extradata_size = size;
e63a3628
             avio_read(pb, descriptor->extradata, size);
d09ea6ba
         }
         break;
     }
     return 0;
 }
 
 /*
  * Match an uid independently of the version byte and up to len common bytes
  * Returns: boolean
  */
 static int mxf_match_uid(const UID key, const UID uid, int len)
 {
     int i;
     for (i = 0; i < len; i++) {
         if (i != 7 && key[i] != uid[i])
             return 0;
     }
     return 1;
 }
 
 static const MXFCodecUL *mxf_get_codec_ul(const MXFCodecUL *uls, UID *uid)
 {
5ac4d768
     while (uls->uid[0]) {
d09ea6ba
         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;
 }
 
5207f959
 static const MXFCodecUL mxf_picture_essence_container_uls[] = {
4ee873e3
     // video essence container uls
36ef5369
     { { 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 */
     { { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },  0,      AV_CODEC_ID_NONE },
5207f959
 };
f6daa9f4
 
 /* EC ULs for intra-only formats */
 static const MXFCodecUL mxf_intra_only_essence_container_uls[] = {
36ef5369
     { { 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 */
     { { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },  0,       AV_CODEC_ID_NONE },
f6daa9f4
 };
 
 /* intra-only PictureEssenceCoding ULs, where no corresponding EC UL exists */
 static const MXFCodecUL mxf_intra_only_picture_essence_coding_uls[] = {
36ef5369
     { { 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 */
c461265a
     { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x07,0x04,0x01,0x02,0x02,0x03,0x01,0x01,0x00 }, 14,   AV_CODEC_ID_JPEG2000 }, /* JPEG2000 Codestream */
36ef5369
     { { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },  0,       AV_CODEC_ID_NONE },
f6daa9f4
 };
 
5207f959
 static const MXFCodecUL mxf_sound_essence_container_uls[] = {
4ee873e3
     // sound essence container uls
36ef5369
     { { 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 */
     { { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },  0,      AV_CODEC_ID_NONE },
4ee873e3
 };
 
7ddb0607
 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++;
 
bd141f5e
     if (!nb_segments)
         return AVERROR_INVALIDDATA;
 
7ddb0607
     if (!(unsorted_segments = av_calloc(nb_segments, sizeof(*unsorted_segments))) ||
         !(*sorted_segments  = av_calloc(nb_segments, sizeof(**sorted_segments)))) {
682b6db7
         av_freep(sorted_segments);
7ddb0607
         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;
a61fada3
         uint64_t best_index_duration = 0;
7ddb0607
 
         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.
a61fada3
              * If we come across an entry with the same IndexStartPosition but larger IndexDuration, then we'll prefer it over the one we currently have.
7ddb0607
              */
             if ((i == 0     || s->body_sid > last_body_sid || s->index_sid > last_index_sid || s->index_start_position > last_index_start) &&
a61fada3
                 (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))) {
7ddb0607
                 best             = j;
                 best_body_sid    = s->body_sid;
                 best_index_sid   = s->index_sid;
                 best_index_start = s->index_start_position;
a61fada3
                 best_index_duration = s->index_duration;
7ddb0607
             }
         }
 
         /* 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;
 }
 
5e67e3ea
 /**
  * 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;
     }
 
4fbd3e89
     av_log(mxf->fc, AV_LOG_ERROR,
            "failed to find absolute offset of %"PRIX64" in BodySID %i - partial file?\n",
5e67e3ea
            offset_in, body_sid);
 
     return AVERROR_INVALIDDATA;
 }
 
1e14bfc1
 /**
2eba8da6
  * 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;
 }
 
36c305f9
 /* 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;
b720915b
     int64_t offset_temp = 0;
36c305f9
 
     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 */
 
3b370abf
                 if (index < 0 || index >= s->nb_index_entries) {
36c305f9
                     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;
 }
 
2212e040
 static int mxf_compute_ptses_fake_index(MXFContext *mxf, MXFIndexTable *index_table)
7d531e83
 {
2212e040
     int i, j, x;
7d531e83
     int8_t max_temporal_offset = -128;
 
     /* first compute how many entries we have */
2212e040
     for (i = 0; i < index_table->nb_segments; i++) {
         MXFIndexTableSegment *s = index_table->segments[i];
7d531e83
 
0cd21dda
         if (!s->nb_index_entries) {
             index_table->nb_ptses = 0;
7d531e83
             return 0;                               /* no TemporalOffsets */
0cd21dda
         }
7d531e83
 
2212e040
         index_table->nb_ptses += s->index_duration;
7d531e83
     }
 
     /* paranoid check */
2212e040
     if (index_table->nb_ptses <= 0)
7d531e83
         return 0;
 
2212e040
     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);
7d531e83
         return AVERROR(ENOMEM);
2212e040
     }
7d531e83
 
     /* we may have a few bad TemporalOffsets
      * make sure the corresponding PTSes don't have the bogus value 0 */
2212e040
     for (x = 0; x < index_table->nb_ptses; x++)
         index_table->ptses[x] = AV_NOPTS_VALUE;
7d531e83
 
     /**
      * 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.
      */
2212e040
     for (i = x = 0; i < index_table->nb_segments; i++) {
         MXFIndexTableSegment *s = index_table->segments[i];
7d531e83
         int index_delta = 1;
085249a3
         int n = s->nb_index_entries;
7d531e83
 
085249a3
         if (s->nb_index_entries == 2 * s->index_duration + 1) {
7d531e83
             index_delta = 2;    /* Avid index */
085249a3
             /* ignore the last entry - it's the size of the essence container */
             n--;
         }
 
         for (j = 0; j < n; j += index_delta, x++) {
7d531e83
             int offset = s->temporal_offset_entries[j] / index_delta;
             int index  = x + offset;
 
6e9081f4
             if (x >= index_table->nb_ptses) {
a3923482
                 av_log(mxf->fc, AV_LOG_ERROR,
                        "x >= nb_ptses - IndexEntryCount %i < IndexDuration %"PRId64"?\n",
6e9081f4
                        s->nb_index_entries, s->index_duration);
                 break;
             }
 
2212e040
             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) {
7d531e83
                 av_log(mxf->fc, AV_LOG_ERROR,
                        "index entry %i + TemporalOffset %i = %i, which is out of bounds\n",
                        x, offset, index);
                 continue;
             }
 
2212e040
             index_table->ptses[index] = x;
7d531e83
             max_temporal_offset = FFMAX(max_temporal_offset, offset);
         }
     }
 
2212e040
     index_table->first_dts = -max_temporal_offset;
7d531e83
 
     return 0;
 }
 
8ce41721
 /**
  * Sorts and collects index table segments into index tables.
  * Also computes PTSes if possible.
  */
 static int mxf_compute_index_tables(MXFContext *mxf)
 {
b56adc78
     int i, j, k, ret, nb_sorted_segments;
8ce41721
     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;
         }
     }
 
1a4e4ad0
     mxf->index_tables = av_mallocz_array(mxf->nb_index_tables,
                                          sizeof(*mxf->index_tables));
     if (!mxf->index_tables) {
8ce41721
         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];
 
1a4e4ad0
         t->segments = av_mallocz_array(t->nb_segments,
                                        sizeof(*t->segments));
 
         if (!t->segments) {
f028d4d1
             av_log(mxf->fc, AV_LOG_ERROR, "failed to allocate IndexTableSegment"
                    " pointer array\n");
8ce41721
             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;
2212e040
 
         if ((ret = mxf_compute_ptses_fake_index(mxf, t)) < 0)
             goto finish_decoding_index;
b56adc78
 
         /* 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;
         }
8ce41721
     }
 
     ret = 0;
 finish_decoding_index:
     av_free(sorted_segments);
     return ret;
 }
 
f6daa9f4
 static int mxf_is_intra_only(MXFDescriptor *descriptor)
 {
     return mxf_get_codec_ul(mxf_intra_only_essence_container_uls,
7a72695c
                             &descriptor->essence_container_ul)->id != AV_CODEC_ID_NONE ||
f6daa9f4
            mxf_get_codec_ul(mxf_intra_only_picture_essence_coding_uls,
7a72695c
                             &descriptor->essence_codec_ul)->id     != AV_CODEC_ID_NONE;
f6daa9f4
 }
 
ad029c24
 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;
 }
 
d09ea6ba
 static int mxf_parse_structural_metadata(MXFContext *mxf)
 {
     MXFPackage *material_package = NULL;
     MXFPackage *temp_package = NULL;
f9872655
     int i, j, k, ret;
d09ea6ba
 
9ef5a9de
     av_dlog(mxf->fc, "metadata sets count %d\n", mxf->metadata_sets_count);
d09ea6ba
     /* 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");
bcd5d979
         return AVERROR_INVALIDDATA;
d09ea6ba
     }
 
     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;
ad029c24
         MXFTimecodeComponent *mxf_tc = NULL;
d09ea6ba
         UID *essence_container_ul = NULL;
         const MXFCodecUL *codec_ul = NULL;
         const MXFCodecUL *container_ul = NULL;
34210e8d
         const MXFCodecUL *pix_fmt_ul = NULL;
d09ea6ba
         AVStream *st;
ad029c24
         AVTimecode tc;
         int flags;
d09ea6ba
 
         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;
         }
 
ad029c24
         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;
33f39c02
             if (av_timecode_init(&tc, mxf_tc->rate, flags, mxf_tc->start_frame, mxf->fc) == 0) {
ad029c24
                 mxf_add_timecode_metadata(&mxf->fc->metadata, "timecode", &tc);
             }
         }
 
d09ea6ba
         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");
1e699993
             continue;
d09ea6ba
         }
 
ad029c24
         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;
33f39c02
             if (av_timecode_init(&tc, mxf_tc->rate, flags, mxf_tc->start_frame, mxf->fc) == 0) {
ad029c24
                 mxf_add_timecode_metadata(&mxf->fc->metadata, "timecode", &tc);
                 break;
             }
         }
 
d09ea6ba
         /* TODO: handle multiple source clips */
         for (j = 0; j < material_track->sequence->structural_components_count; j++) {
             component = mxf_resolve_strong_ref(mxf, &material_track->sequence->structural_components_refs[j], SourceClip);
             if (!component)
                 continue;
 
             for (k = 0; k < mxf->packages_count; k++) {
                 temp_package = mxf_resolve_strong_ref(mxf, &mxf->packages_refs[k], SourcePackage);
                 if (!temp_package)
                     continue;
                 if (!memcmp(temp_package->package_uid, component->source_package_uid, 16)) {
                     source_package = temp_package;
                     break;
                 }
             }
             if (!source_package) {
623128d7
                 av_dlog(mxf->fc, "material track %d: no corresponding source package found\n", material_track->track_id);
d09ea6ba
                 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");
4a4c4278
                     ret = AVERROR_INVALIDDATA;
8a2cb2ab
                     goto fail_and_free;
d09ea6ba
                 }
                 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;
             }
         }
5e5e69d0
         if (!source_track || !component)
d09ea6ba
             continue;
 
e1914b5a
         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");
f028d4d1
             ret = AVERROR_INVALIDDATA;
8a2cb2ab
             goto fail_and_free;
e1914b5a
         }
 
         /* 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;
         }
 
84ad31ff
         st = avformat_new_stream(mxf->fc, NULL);
d09ea6ba
         if (!st) {
             av_log(mxf->fc, AV_LOG_ERROR, "could not allocate stream\n");
8a2cb2ab
             ret = AVERROR(ENOMEM);
             goto fail_and_free;
d09ea6ba
         }
84ad31ff
         st->id = source_track->track_id;
d09ea6ba
         st->priv_data = source_track;
928727f9
         source_track->original_duration = st->duration = component->duration;
d09ea6ba
         if (st->duration == -1)
             st->duration = AV_NOPTS_VALUE;
         st->start_time = component->start_position;
7d56f2ff
         if (material_track->edit_rate.num <= 0 ||
             material_track->edit_rate.den <= 0) {
83cab07a
             av_log(mxf->fc, AV_LOG_WARNING,
7d56f2ff
                    "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);
83cab07a
             material_track->edit_rate = (AVRational){25, 1};
         }
3592bd50
         avpriv_set_pts_info(st, 64, material_track->edit_rate.den, material_track->edit_rate.num);
d09ea6ba
 
928727f9
         /* ensure SourceTrack EditRate == MaterialTrack EditRate since only the former is accessible via st->priv_data */
         source_track->edit_rate = material_track->edit_rate;
 
d09ea6ba
         PRINT_KEY(mxf->fc, "data definition   ul", source_track->sequence->data_definition_ul);
5ac4d768
         codec_ul = mxf_get_codec_ul(ff_mxf_data_definition_uls, &source_track->sequence->data_definition_ul);
         st->codec->codec_type = codec_ul->id;
d09ea6ba
 
         source_package->descriptor = mxf_resolve_strong_ref(mxf, &source_package->descriptor_ref, AnyType);
         if (source_package->descriptor) {
             if (source_package->descriptor->type == MultipleDescriptor) {
                 for (j = 0; j < source_package->descriptor->sub_descriptors_count; j++) {
                     MXFDescriptor *sub_descriptor = mxf_resolve_strong_ref(mxf, &source_package->descriptor->sub_descriptors_refs[j], Descriptor);
 
                     if (!sub_descriptor) {
                         av_log(mxf->fc, AV_LOG_ERROR, "could not resolve sub descriptor strong ref\n");
                         continue;
                     }
                     if (sub_descriptor->linked_track_id == source_track->track_id) {
                         descriptor = sub_descriptor;
                         break;
                     }
                 }
             } else if (source_package->descriptor->type == Descriptor)
                 descriptor = source_package->descriptor;
         }
         if (!descriptor) {
             av_log(mxf->fc, AV_LOG_INFO, "source track %d: stream %d, no descriptor found\n", source_track->track_id, st->index);
             continue;
         }
         PRINT_KEY(mxf->fc, "essence codec     ul", descriptor->essence_codec_ul);
         PRINT_KEY(mxf->fc, "essence container ul", descriptor->essence_container_ul);
         essence_container_ul = &descriptor->essence_container_ul;
         /* HACK: replacing the original key with mxf_encrypted_essence_container
          * is not allowed according to s429-6, try to find correct information anyway */
         if (IS_KLV_KEY(essence_container_ul, mxf_encrypted_essence_container)) {
             av_log(mxf->fc, AV_LOG_INFO, "broken encrypted mxf file\n");
             for (k = 0; k < mxf->metadata_sets_count; k++) {
                 MXFMetadataSet *metadata = mxf->metadata_sets[k];
                 if (metadata->type == CryptoContext) {
                     essence_container_ul = &((MXFCryptoContext *)metadata)->source_container_ul;
                     break;
                 }
             }
         }
ddcf3e05
 
d09ea6ba
         /* TODO: drop PictureEssenceCoding and SoundEssenceCompression, only check EssenceContainer */
c69968b4
         codec_ul = mxf_get_codec_ul(ff_mxf_codec_uls, &descriptor->essence_codec_ul);
84e7d368
         st->codec->codec_id = (enum AVCodecID)codec_ul->id;
182e342f
         av_log(mxf->fc, AV_LOG_VERBOSE, "%s: Universal Label: ",
                avcodec_get_name(st->codec->codec_id));
d7145760
         for (k = 0; k < 16; k++) {
182e342f
             av_log(mxf->fc, AV_LOG_VERBOSE, "%.2x",
                    descriptor->essence_codec_ul[k]);
d7145760
             if (!(k+1 & 19) || k == 5)
                 av_log(mxf->fc, AV_LOG_VERBOSE, ".");
         }
182e342f
         av_log(mxf->fc, AV_LOG_VERBOSE, "\n");
ecf442a5
 
72415b2a
         if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
f6daa9f4
             source_track->intra_only = mxf_is_intra_only(descriptor);
5207f959
             container_ul = mxf_get_codec_ul(mxf_picture_essence_container_uls, essence_container_ul);
36ef5369
             if (st->codec->codec_id == AV_CODEC_ID_NONE)
d09ea6ba
                 st->codec->codec_id = container_ul->id;
             st->codec->width = descriptor->width;
84b9b4aa
             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:
def01739
                     st->codec->field_order = AV_FIELD_PROGRESSIVE;
84b9b4aa
                     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:
f452d6c3
                     break;
                 case SeparateFields:
c7166248
                     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);
                         break;
                     }
634d6705
                     /* Turn field height into frame height. */
                     st->codec->height *= 2;
cbda76c7
                     break;
84b9b4aa
                 default:
                     av_log(mxf->fc, AV_LOG_INFO, "Unknown frame layout type: %d\n", descriptor->frame_layout);
             }
36ef5369
             if (st->codec->codec_id == AV_CODEC_ID_RAWVIDEO) {
11fdc4d4
                 st->codec->pix_fmt = descriptor->pix_fmt;
716d413c
                 if (st->codec->pix_fmt == AV_PIX_FMT_NONE) {
fda891e1
                     pix_fmt_ul = mxf_get_codec_ul(ff_mxf_pixel_format_uls,
                                                   &descriptor->essence_codec_ul);
84e7d368
                     st->codec->pix_fmt = (enum AVPixelFormat)pix_fmt_ul->id;
716d413c
                     if (st->codec->pix_fmt == AV_PIX_FMT_NONE) {
34210e8d
                         /* 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) {
716d413c
                             st->codec->pix_fmt = AV_PIX_FMT_UYVY422;
34210e8d
                         }
                     }
                 }
             }
d09ea6ba
             st->need_parsing = AVSTREAM_PARSE_HEADERS;
72415b2a
         } else if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
5207f959
             container_ul = mxf_get_codec_ul(mxf_sound_essence_container_uls, essence_container_ul);
13f0cd68
             /* Only overwrite existing codec ID if it is unset or A-law, which is the default according to SMPTE RP 224. */
84e7d368
             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;
d09ea6ba
             st->codec->channels = descriptor->channels;
dd1c8f3e
             st->codec->bits_per_coded_sample = descriptor->bits_per_sample;
d6b81ff9
 
83cab07a
             if (descriptor->sample_rate.den > 0) {
d6b81ff9
                 st->codec->sample_rate = descriptor->sample_rate.num / descriptor->sample_rate.den;
93370d12
                 avpriv_set_pts_info(st, 64, descriptor->sample_rate.den, descriptor->sample_rate.num);
83cab07a
             } else {
93370d12
                 av_log(mxf->fc, AV_LOG_WARNING, "invalid sample rate (%d/%d) "
ad0560fe
                        "found for stream #%d, time base forced to 1/48000\n",
93370d12
                        descriptor->sample_rate.num, descriptor->sample_rate.den,
                        st->index);
83cab07a
                 avpriv_set_pts_info(st, 64, 1, 48000);
             }
d6b81ff9
 
928727f9
             /* if duration is set, rescale it from EditRate to SampleRate */
             if (st->duration != AV_NOPTS_VALUE)
                 st->duration = av_rescale_q(st->duration, av_inv_q(material_track->edit_rate), st->time_base);
 
36ef5369
             /* TODO: implement AV_CODEC_ID_RAWAUDIO */
             if (st->codec->codec_id == AV_CODEC_ID_PCM_S16LE) {
3e48dcea
                 if (descriptor->bits_per_sample > 16 && descriptor->bits_per_sample <= 24)
36ef5369
                     st->codec->codec_id = AV_CODEC_ID_PCM_S24LE;
d09ea6ba
                 else if (descriptor->bits_per_sample == 32)
36ef5369
                     st->codec->codec_id = AV_CODEC_ID_PCM_S32LE;
             } else if (st->codec->codec_id == AV_CODEC_ID_PCM_S16BE) {
3e48dcea
                 if (descriptor->bits_per_sample > 16 && descriptor->bits_per_sample <= 24)
36ef5369
                     st->codec->codec_id = AV_CODEC_ID_PCM_S24BE;
d09ea6ba
                 else if (descriptor->bits_per_sample == 32)
36ef5369
                     st->codec->codec_id = AV_CODEC_ID_PCM_S32BE;
             } else if (st->codec->codec_id == AV_CODEC_ID_MP2) {
d09ea6ba
                 st->need_parsing = AVSTREAM_PARSE_FULL;
             }
         }
c5142a95
         if (descriptor->extradata) {
a807c682
             if (!ff_alloc_extradata(st->codec, descriptor->extradata_size)) {
c5142a95
                 memcpy(st->codec->extradata, descriptor->extradata, descriptor->extradata_size);
42bd0cd2
             }
ecf442a5
         } else if (st->codec->codec_id == AV_CODEC_ID_H264) {
             ret = ff_generate_avci_extradata(st);
             if (ret < 0)
                 return ret;
c5142a95
         }
72415b2a
         if (st->codec->codec_type != AVMEDIA_TYPE_DATA && (*essence_container_ul)[15] > 0x01) {
ddcf3e05
             /* TODO: decode timestamps */
             st->need_parsing = AVSTREAM_PARSE_TIMESTAMPS;
d09ea6ba
         }
     }
8a2cb2ab
 
2212e040
     ret = 0;
8a2cb2ab
 fail_and_free:
     return ret;
d09ea6ba
 }
 
25b143aa
 static int mxf_read_utf16_string(AVIOContext *pb, int size, char** str)
 {
     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);
 
     if ((ret = avio_get_str16be(pb, size, *str, buf_size)) < 0) {
         av_freep(str);
         return ret;
     }
 
     return ret;
 }
 
 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;
 }
 
 static int mxf_timestamp_to_str(uint64_t timestamp, char **str)
 {
578d9cf7
     struct tm time = {0};
25b143aa
     time.tm_year = (timestamp >> 48) - 1900;
c8b36444
     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);
25b143aa
 
423089e9
     /* ensure month/day are valid */
     time.tm_mon  = FFMAX(time.tm_mon, 0);
     time.tm_mday = FFMAX(time.tm_mday, 1);
 
25b143aa
     *str = av_mallocz(32);
     if (!*str)
         return AVERROR(ENOMEM);
8da2a3ab
     strftime(*str, 32, "%Y-%m-%d %H:%M:%S", &time);
25b143aa
 
     return 0;
 }
 
 #define SET_STR_METADATA(pb, name, str) do { \
     if ((ret = mxf_read_utf16_string(pb, size, &str)) < 0) \
         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;
 }
 
d09ea6ba
 static const MXFMetadataReadTableEntry mxf_metadata_read_table[] = {
     { { 0x06,0x0E,0x2B,0x34,0x02,0x05,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x05,0x01,0x00 }, mxf_read_primer_pack },
9289eada
     { { 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 },
25b143aa
     { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0D,0x01,0x01,0x01,0x01,0x01,0x30,0x00 }, mxf_read_identification_metadata },
d09ea6ba
     { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x18,0x00 }, mxf_read_content_storage, 0, AnyType },
     { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x37,0x00 }, mxf_read_source_package, sizeof(MXFPackage), SourcePackage },
     { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x36,0x00 }, mxf_read_material_package, sizeof(MXFPackage), MaterialPackage },
     { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x0F,0x00 }, mxf_read_sequence, sizeof(MXFSequence), Sequence },
     { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x11,0x00 }, mxf_read_source_clip, sizeof(MXFStructuralComponent), SourceClip },
     { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x44,0x00 }, mxf_read_generic_descriptor, sizeof(MXFDescriptor), MultipleDescriptor },
     { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x42,0x00 }, mxf_read_generic_descriptor, sizeof(MXFDescriptor), Descriptor }, /* Generic Sound */
     { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x28,0x00 }, mxf_read_generic_descriptor, sizeof(MXFDescriptor), Descriptor }, /* CDCI */
     { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x29,0x00 }, mxf_read_generic_descriptor, sizeof(MXFDescriptor), Descriptor }, /* RGBA */
     { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x51,0x00 }, mxf_read_generic_descriptor, sizeof(MXFDescriptor), Descriptor }, /* MPEG 2 Video */
     { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x48,0x00 }, mxf_read_generic_descriptor, sizeof(MXFDescriptor), Descriptor }, /* Wave */
     { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x47,0x00 }, mxf_read_generic_descriptor, sizeof(MXFDescriptor), Descriptor }, /* AES3 */
     { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x3A,0x00 }, mxf_read_track, sizeof(MXFTrack), Track }, /* Static Track */
     { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x3B,0x00 }, mxf_read_track, sizeof(MXFTrack), Track }, /* Generic Track */
ad029c24
     { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x14,0x00 }, mxf_read_timecode_component, sizeof(MXFTimecodeComponent), TimecodeComponent },
d09ea6ba
     { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x04,0x01,0x02,0x02,0x00,0x00 }, mxf_read_cryptographic_context, sizeof(MXFCryptoContext), CryptoContext },
861b4f01
     { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x10,0x01,0x00 }, mxf_read_index_table_segment, sizeof(MXFIndexTableSegment), IndexTableSegment },
d09ea6ba
     { { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, NULL, 0, AnyType },
 };
 
39bb30f6
 static int mxf_read_local_tags(MXFContext *mxf, KLVPacket *klv, MXFMetadataReadFunc *read_child, int ctx_size, enum MXFMetadataSetType type)
d09ea6ba
 {
471fe57e
     AVIOContext *pb = mxf->fc->pb;
d09ea6ba
     MXFMetadataSet *ctx = ctx_size ? av_mallocz(ctx_size) : mxf;
384c9c2f
     uint64_t klv_end = avio_tell(pb) + klv->length;
d09ea6ba
 
     if (!ctx)
bcd5d979
         return AVERROR(ENOMEM);
2116e4ba
     while (avio_tell(pb) + 4 < klv_end && !url_feof(pb)) {
bcd5d979
         int ret;
e63a3628
         int tag = avio_rb16(pb);
         int size = avio_rb16(pb); /* KLV specified by 0x53 */
384c9c2f
         uint64_t next = avio_tell(pb) + size;
d09ea6ba
         UID uid = {0};
 
9ef5a9de
         av_dlog(mxf->fc, "local tag %#04x size %d\n", tag, size);
d09ea6ba
         if (!size) { /* ignore empty tag, needed for some files with empty UMID tag */
8a47ad5e
             av_log(mxf->fc, AV_LOG_ERROR, "local tag %#04x with 0 size\n", tag);
d09ea6ba
             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);
9ef5a9de
                     av_dlog(mxf->fc, "local tag %#04x\n", local_tag);
d09ea6ba
                     PRINT_KEY(mxf->fc, "uid", uid);
                 }
             }
         }
         if (ctx_size && tag == 0x3C0A)
e63a3628
             avio_read(pb, ctx->uid, 16);
4a4c4278
         else if ((ret = read_child(ctx, pb, tag, size, uid, -1)) < 0)
bcd5d979
             return ret;
d09ea6ba
 
11800c8c
         /* Accept the 64k local set limit being exceeded (Avid). Don't accept
          * it extending past the end of the KLV though (zzuf5.mxf). */
e7839602
         if (avio_tell(pb) > klv_end) {
fbb39f44
             if (ctx_size)
                 av_free(ctx);
 
11800c8c
             av_log(mxf->fc, AV_LOG_ERROR,
                    "local tag %#04x extends past end of local set @ %#"PRIx64"\n",
e7839602
                    tag, klv->offset);
             return AVERROR_INVALIDDATA;
         } else if (avio_tell(pb) <= next)   /* only seek forward, else this can loop for a long time */
11800c8c
             avio_seek(pb, next, SEEK_SET);
d09ea6ba
     }
     if (ctx_size) ctx->type = type;
     return ctx_size ? mxf_add_metadata_set(mxf, ctx) : 0;
 }
 
dcd30b83
 /**
  * Seeks to the previous partition, if possible
  * @return <= 0 if we should stop parsing, > 0 if we should keep going
  */
 static int mxf_seek_to_previous_partition(MXFContext *mxf)
 {
     AVIOContext *pb = mxf->fc->pb;
 
     if (!mxf->current_partition ||
         mxf->run_in + mxf->current_partition->previous_partition <= mxf->last_forward_tell)
         return 0;   /* we've parsed all partitions */
 
     /* seek to previous partition */
     avio_seek(pb, mxf->run_in + mxf->current_partition->previous_partition, SEEK_SET);
     mxf->current_partition = NULL;
 
     av_dlog(mxf->fc, "seeking to previous partition\n");
 
     return 1;
 }
 
 /**
  * Called when essence is encountered
  * @return <= 0 if we should stop parsing, > 0 if we should keep going
  */
 static int mxf_parse_handle_essence(MXFContext *mxf)
 {
     AVIOContext *pb = mxf->fc->pb;
     int64_t ret;
 
     if (mxf->parsing_backward) {
         return mxf_seek_to_previous_partition(mxf);
f5ed83c3
     } else if (mxf->footer_partition || mxf->last_partition){
         uint64_t offset;
 
         offset = mxf->footer_partition ? mxf->footer_partition : mxf->last_partition;
dcd30b83
 
f5ed83c3
         av_dlog(mxf->fc, "seeking to last partition\n");
dcd30b83
 
         /* 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) {
f5ed83c3
             av_log(mxf->fc, AV_LOG_INFO, "file is not seekable - not parsing last partition\n");
dcd30b83
             return -1;
         }
 
f5ed83c3
         /* seek to last partition and parse backward */
         if ((ret = avio_seek(pb, mxf->run_in + offset, SEEK_SET)) < 0) {
             av_log(mxf->fc, AV_LOG_ERROR, "failed to seek to last partition @ 0x%"PRIx64" (%"PRId64") - partial file?\n",
                    mxf->run_in + offset, ret);
dcd30b83
             return ret;
         }
 
         mxf->current_partition = NULL;
         mxf->parsing_backward = 1;
f5ed83c3
     } else {
         av_dlog(mxf->fc, "can't find last partition\n");
         return 0;
dcd30b83
     }
 
     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;
 }
 
33624623
 /**
  * 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)
             break;          /* last partition - can't compute length (and we don't need to) */
 
         /* 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;
4fbd3e89
             av_log(mxf->fc, AV_LOG_ERROR,
                    "partition %i: bad ThisPartition = %"PRIX64"\n",
33624623
                    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;
 }
 
36ef5369
 static int is_pcm(enum AVCodecID codec_id)
d8531a1c
 {
     /* we only care about "normal" PCM codecs until we get samples */
36ef5369
     return codec_id >= AV_CODEC_ID_PCM_S16LE && codec_id < AV_CODEC_ID_PCM_S24DAUD;
d8531a1c
 }
 
 /**
c65642d3
  * 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().
d8531a1c
  */
 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 */
c65642d3
     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                  ||
d8531a1c
         mxf->index_tables[0].segments[0]->edit_unit_byte_count >= 32)
         return;
 
     /* arbitrarily default to 48 kHz PAL audio frame size */
c65642d3
     /* 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. */
d8531a1c
     mxf->edit_units_per_packet = 1920;
 }
 
f5ed83c3
 static void mxf_read_random_index_pack(AVFormatContext *s)
 {
     MXFContext *mxf = s->priv_data;
     uint32_t length;
     int64_t file_size;
     KLVPacket klv;
 
     if (!s->pb->seekable)
         return;
 
     file_size = avio_size(s->pb);
     avio_seek(s->pb, file_size - 4, SEEK_SET);
     length = avio_rb32(s->pb);
     if (length <= 32 || length >= FFMIN(file_size, INT_MAX))
         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);
     mxf->last_partition = avio_rb64(s->pb);
 
 end:
     avio_seek(s->pb, mxf->run_in, SEEK_SET);
 }
 
6e9651d1
 static int mxf_read_header(AVFormatContext *s)
d09ea6ba
 {
     MXFContext *mxf = s->priv_data;
     KLVPacket klv;
5e67e3ea
     int64_t essence_offset = 0;
1c010fd0
     int64_t last_pos = -1;
     uint64_t last_pos_index = 1;
8ce41721
     int ret;
d09ea6ba
 
dcd30b83
     mxf->last_forward_tell = INT64_MAX;
d8531a1c
     mxf->edit_units_per_packet = 1;
dcd30b83
 
d09ea6ba
     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");
bcd5d979
         return AVERROR_INVALIDDATA;
d09ea6ba
     }
f59d8ff8
     avio_seek(s->pb, -14, SEEK_CUR);
d09ea6ba
     mxf->fc = s;
dcd30b83
     mxf->run_in = avio_tell(s->pb);
 
f5ed83c3
     mxf_read_random_index_pack(s);
 
d09ea6ba
     while (!url_feof(s->pb)) {
         const MXFMetadataReadTableEntry *metadata;
1c010fd0
         if (avio_tell(s->pb) == last_pos) {
             av_log(mxf->fc, AV_LOG_ERROR, "MXF structure loop detected\n");
             return AVERROR_INVALIDDATA;
         }
         if ((1ULL<<61) % last_pos_index++ == 0)
             last_pos = avio_tell(s->pb);
dcd30b83
         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;
         }
 
d09ea6ba
         PRINT_KEY(s, "read header", klv.key);
b0a4e5f9
         av_dlog(s, "size %"PRIu64" offset %#"PRIx64"\n", klv.length, klv.offset);
d09ea6ba
         if (IS_KLV_KEY(klv.key, mxf_encrypted_triplet_key) ||
dcd30b83
             IS_KLV_KEY(klv.key, mxf_essence_element_key) ||
0bcada9f
             IS_KLV_KEY(klv.key, mxf_avid_essence_element_key) ||
dcd30b83
             IS_KLV_KEY(klv.key, mxf_system_item_key)) {
184f4790
 
             if (!mxf->current_partition) {
                 av_log(mxf->fc, AV_LOG_ERROR, "found essence prior to first PartitionPack\n");
                 return AVERROR_INVALIDDATA;
             }
 
33624623
             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;
                 }
             }
 
5e67e3ea
             if (!essence_offset)
                 essence_offset = klv.offset;
dcd30b83
 
             /* seek to footer, previous partition or stop */
             if (mxf_parse_handle_essence(mxf) <= 0)
                 break;
fd1cea65
             continue;
dcd30b83
         } else if (!memcmp(klv.key, mxf_header_partition_pack_key, 13) &&
                    klv.key[13] >= 2 && klv.key[13] <= 4 && mxf->current_partition) {
             /* next partition pack - keep going, seek to previous partition or stop */
             if(mxf_parse_handle_partition_or_eof(mxf) <= 0)
                 break;
393b81f0
             else if (mxf->parsing_backward)
                 continue;
             /* we're still parsing forward. proceed to parsing this partition pack */
fd1cea65
         }
d09ea6ba
 
         for (metadata = mxf_metadata_read_table; metadata->read; metadata++) {
             if (IS_KLV_KEY(klv.key, metadata->key)) {
39bb30f6
                 int res;
                 if (klv.key[5] == 0x53) {
                     res = mxf_read_local_tags(mxf, &klv, metadata->read, metadata->ctx_size, metadata->type);
47886e36
                 } else {
                     uint64_t next = avio_tell(s->pb) + klv.length;
fd34dbea
                     res = metadata->read(mxf, s->pb, 0, klv.length, klv.key, klv.offset);
e7839602
 
                     /* 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;
                     }
 
47886e36
                     avio_seek(s->pb, next, SEEK_SET);
                 }
39bb30f6
                 if (res < 0) {
d09ea6ba
                     av_log(s, AV_LOG_ERROR, "error reading header metadata\n");
bcd5d979
                     return res;
d09ea6ba
                 }
                 break;
             }
         }
         if (!metadata->read)
45a8a02a
             avio_skip(s->pb, klv.length);
d09ea6ba
     }
dcd30b83
     /* FIXME avoid seek */
5e67e3ea
     if (!essence_offset)  {
dcd30b83
         av_log(s, AV_LOG_ERROR, "no essence\n");
         return AVERROR_INVALIDDATA;
     }
5e67e3ea
     avio_seek(s->pb, essence_offset, SEEK_SET);
33624623
 
     mxf_compute_essence_containers(mxf);
 
b56adc78
     /* 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)
d7da4d47
         goto fail;
b56adc78
 
8ce41721
     if ((ret = mxf_compute_index_tables(mxf)) < 0)
d7da4d47
         goto fail;
8ce41721
 
     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");
d7da4d47
         ret = AVERROR_INVALIDDATA;
         goto fail;
8ce41721
     }
 
d8531a1c
     mxf_handle_small_eubc(s);
 
b56adc78
     return 0;
d7da4d47
 fail:
     mxf_read_close(s);
 
     return ret;
d09ea6ba
 }
 
2eba8da6
 /**
bf2290a8
  * Sets mxf->current_edit_unit based on what offset we're currently at.
  * @return next_ofs if OK, <0 on error
2eba8da6
  */
bf2290a8
 static int64_t mxf_set_current_edit_unit(MXFContext *mxf, int64_t current_offset)
2eba8da6
 {
bf2290a8
     int64_t last_ofs = -1, next_ofs = -1;
2eba8da6
     MXFIndexTable *t = &mxf->index_tables[0];
 
29fc8f50
     /* this is called from the OP1a demuxing logic, which means there
      * may be no index tables */
1888bd1b
     if (mxf->nb_index_tables <= 0)
bf2290a8
         return -1;
1888bd1b
 
bf2290a8
     /* find mxf->current_edit_unit so that the next edit unit starts ahead of current_offset */
cc1dda85
     while (mxf->current_edit_unit >= 0) {
2eba8da6
         if (mxf_edit_unit_absolute_offset(mxf, t, mxf->current_edit_unit + 1, NULL, &next_ofs, 0) < 0)
bf2290a8
             return -1;
2eba8da6
 
4ae7d451
         if (next_ofs <= last_ofs) {
e352c96c
             /* 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");
1fadf53e
             return -1;
4ae7d451
         }
 
bf2290a8
         if (next_ofs > current_offset)
2eba8da6
             break;
 
4ae7d451
         last_ofs = next_ofs;
2eba8da6
         mxf->current_edit_unit++;
     }
 
bf2290a8
     /* not checking mxf->current_edit_unit >= t->nb_ptses here since CBR files may lack IndexEntryArrays */
     if (mxf->current_edit_unit < 0)
         return -1;
2eba8da6
 
bf2290a8
     return next_ofs;
2eba8da6
 }
 
83cab07a
 static int mxf_compute_sample_count(MXFContext *mxf, int stream_index, uint64_t *sample_count)
 {
     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) {
         int remainder = (sample_rate.num * time_base.num) % (time_base.den * sample_rate.den);
         *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,
                    "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);
         return 0;
     }
 
     while (spf->samples_per_frame[size]) {
         total += spf->samples_per_frame[size];
         size++;
     }
 
     av_assert2(size);
 
caedd51e
     *sample_count = (mxf->current_edit_unit / size) * (uint64_t)total;
83cab07a
     for (i = 0; i < mxf->current_edit_unit % size; i++) {
         *sample_count += spf->samples_per_frame[i];
     }
 
     return 0;
 }
 
 static int mxf_set_audio_pts(MXFContext *mxf, AVCodecContext *codec, AVPacket *pkt)
 {
     MXFTrack *track = mxf->fc->streams[pkt->stream_index]->priv_data;
     pkt->pts = track->sample_count;
9790a03e
     if (   codec->channels <= 0
         || av_get_bits_per_sample(codec->codec_id) <= 0
         || codec->channels * (int64_t)av_get_bits_per_sample(codec->codec_id) < 8)
75b3911e
         return AVERROR(EINVAL);
e5e422bc
     track->sample_count += pkt->size / (codec->channels * (int64_t)av_get_bits_per_sample(codec->codec_id) / 8);
83cab07a
     return 0;
 }
 
31029e30
 static int mxf_read_packet_old(AVFormatContext *s, AVPacket *pkt)
 {
     KLVPacket klv;
bf2290a8
     MXFContext *mxf = s->priv_data;
31029e30
 
3967f680
     while (klv_read_packet(&klv, s->pb) == 0) {
4a4c4278
         int ret;
31029e30
         PRINT_KEY(s, "read packet", klv.key);
         av_dlog(s, "size %"PRIu64" offset %#"PRIx64"\n", klv.length, klv.offset);
         if (IS_KLV_KEY(klv.key, mxf_encrypted_triplet_key)) {
4a4c4278
             ret = mxf_decrypt_triplet(s, pkt, &klv);
             if (ret < 0) {
31029e30
                 av_log(s, AV_LOG_ERROR, "invalid encoded triplet\n");
4a4c4278
                 return AVERROR_INVALIDDATA;
31029e30
             }
             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);
bf2290a8
             int64_t next_ofs, next_klv;
eb74e9ea
             AVStream *st;
             MXFTrack *track;
83cab07a
             AVCodecContext *codec;
bf2290a8
 
31029e30
             if (index < 0) {
                 av_log(s, AV_LOG_ERROR, "error getting stream index %d\n", AV_RB32(klv.key+12));
                 goto skip;
             }
eb74e9ea
 
             st = s->streams[index];
             track = st->priv_data;
 
31029e30
             if (s->streams[index]->discard == AVDISCARD_ALL)
                 goto skip;
bf2290a8
 
             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) */
1ecdf891
                 avpriv_request_sample(s,
                                       "OPAtom misinterpreted as OP1a?"
                                       "KLV for edit unit %i extending into "
                                       "next edit unit",
1fadf53e
                                       mxf->current_edit_unit);
bf2290a8
                 klv.length = next_ofs - avio_tell(s->pb);
             }
 
31029e30
             /* check for 8 channels AES3 element */
             if (klv.key[12] == 0x06 && klv.key[13] == 0x01 && klv.key[14] == 0x10) {
                 if (mxf_get_d10_aes3_packet(s->pb, s->streams[index], pkt, klv.length) < 0) {
                     av_log(s, AV_LOG_ERROR, "error reading D-10 aes3 frame\n");
4a4c4278
                     return AVERROR_INVALIDDATA;
31029e30
                 }
             } else {
4a4c4278
                 ret = av_get_packet(s->pb, pkt, klv.length);
31029e30
                 if (ret < 0)
                     return ret;
             }
             pkt->stream_index = index;
             pkt->pos = klv.offset;
2eba8da6
 
83cab07a
             codec = s->streams[index]->codec;
             if (codec->codec_type == AVMEDIA_TYPE_VIDEO && next_ofs >= 0) {
bf2290a8
                 /* mxf->current_edit_unit good - see if we have an index table to derive timestamps from */
                 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];
eb74e9ea
                 } 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;
bf2290a8
                 }
83cab07a
             } else if (codec->codec_type == AVMEDIA_TYPE_AUDIO) {
                 int ret = mxf_set_audio_pts(mxf, codec, pkt);
                 if (ret < 0)
                     return ret;
bf2290a8
             }
 
             /* seek for truncated packets */
             avio_seek(s->pb, next_klv, SEEK_SET);
2eba8da6
 
31029e30
             return 0;
         } else
         skip:
             avio_skip(s->pb, klv.length);
     }
3967f680
     return url_feof(s->pb) ? AVERROR_EOF : -1;
31029e30
 }
 
 static int mxf_read_packet(AVFormatContext *s, AVPacket *pkt)
 {
     MXFContext *mxf = s->priv_data;
2eba8da6
     int ret, size;
     int64_t ret64, pos, next_pos;
31029e30
     AVStream *st;
2eba8da6
     MXFIndexTable *t;
d8531a1c
     int edit_units;
31029e30
 
2eba8da6
     if (mxf->op != OPAtom)
31029e30
         return mxf_read_packet_old(s, pkt);
 
2eba8da6
     /* OPAtom - clip wrapped demuxing */
1888bd1b
     /* NOTE: mxf_read_header() makes sure nb_index_tables > 0 for OPAtom */
2eba8da6
     st = s->streams[0];
     t = &mxf->index_tables[0];
31029e30
 
2eba8da6
     if (mxf->current_edit_unit >= st->duration)
31029e30
         return AVERROR_EOF;
 
d8531a1c
     edit_units = FFMIN(mxf->edit_units_per_packet, st->duration - mxf->current_edit_unit);
 
2eba8da6
     if ((ret = mxf_edit_unit_absolute_offset(mxf, t, mxf->current_edit_unit, NULL, &pos, 1)) < 0)
         return ret;
31029e30
 
2eba8da6
     /* compute size by finding the next edit unit or the end of the essence container
      * not pretty, but it works */
d8531a1c
     if ((ret = mxf_edit_unit_absolute_offset(mxf, t, mxf->current_edit_unit + edit_units, NULL, &next_pos, 0)) < 0 &&
2eba8da6
         (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;
     }
31029e30
 
2eba8da6
     if ((size = next_pos - pos) <= 0) {
         av_log(s, AV_LOG_ERROR, "bad size: %i\n", size);
         return AVERROR_INVALIDDATA;
     }
31029e30
 
2eba8da6
     if ((ret64 = avio_seek(s->pb, pos, SEEK_SET)) < 0)
         return ret64;
31029e30
 
dd5e1fc2
     if ((size = av_get_packet(s->pb, pkt, size)) < 0)
         return size;
31029e30
 
83cab07a
     pkt->stream_index = 0;
 
2eba8da6
     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];
83cab07a
     } else if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
         int ret = mxf_set_audio_pts(mxf, st->codec, pkt);
         if (ret < 0)
             return ret;
31029e30
     }
 
d8531a1c
     mxf->current_edit_unit += edit_units;
31029e30
 
     return 0;
 }
 
d09ea6ba
 static int mxf_read_close(AVFormatContext *s)
 {
     MXFContext *mxf = s->priv_data;
7ddb0607
     MXFIndexTableSegment *seg;
54cbbdd2
     int i;
d09ea6ba
 
     av_freep(&mxf->packages_refs);
8be080ae
 
     for (i = 0; i < s->nb_streams; i++)
         s->streams[i]->priv_data = NULL;
 
d09ea6ba
     for (i = 0; i < mxf->metadata_sets_count; i++) {
         switch (mxf->metadata_sets[i]->type) {
9f92e590
         case Descriptor:
             av_freep(&((MXFDescriptor *)mxf->metadata_sets[i])->extradata);
             break;
d09ea6ba
         case MultipleDescriptor:
             av_freep(&((MXFDescriptor *)mxf->metadata_sets[i])->sub_descriptors_refs);
             break;
         case Sequence:
             av_freep(&((MXFSequence *)mxf->metadata_sets[i])->structural_components_refs);
             break;
         case SourcePackage:
         case MaterialPackage:
             av_freep(&((MXFPackage *)mxf->metadata_sets[i])->tracks_refs);
             break;
7ddb0607
         case IndexTableSegment:
             seg = (MXFIndexTableSegment *)mxf->metadata_sets[i];
7560c264
             av_freep(&seg->temporal_offset_entries);
7ddb0607
             av_freep(&seg->flag_entries);
             av_freep(&seg->stream_offset_entries);
             break;
d09ea6ba
         default:
             break;
         }
         av_freep(&mxf->metadata_sets[i]);
     }
9289eada
     av_freep(&mxf->partitions);
d09ea6ba
     av_freep(&mxf->metadata_sets);
     av_freep(&mxf->aesc);
     av_freep(&mxf->local_tags);
8ce41721
 
873049e6
     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);
         }
2212e040
     }
8ce41721
     av_freep(&mxf->index_tables);
 
d09ea6ba
     return 0;
 }
 
 static int mxf_probe(AVProbeData *p) {
59693ed9
     const uint8_t *bufp = p->buf;
     const uint8_t *end = p->buf + p->buf_size;
d09ea6ba
 
     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);
a26e83da
 
     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;
d09ea6ba
     }
a26e83da
 
d09ea6ba
     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;
ddcf3e05
     MXFContext* mxf = s->priv_data;
     int64_t seekpos;
83cab07a
     int i, ret;
2eba8da6
     MXFIndexTable *t;
928727f9
     MXFTrack *source_track = st->priv_data;
 
     /* if audio then truncate sample_time to EditRate */
     if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO)
         sample_time = av_rescale_q(sample_time, st->time_base, av_inv_q(source_track->edit_rate));
d09ea6ba
 
db0087dc
     if (mxf->nb_index_tables <= 0) {
d09ea6ba
     if (!s->bit_rate)
bcd5d979
         return AVERROR_INVALIDDATA;
d09ea6ba
     if (sample_time < 0)
         sample_time = 0;
     seconds = av_rescale(sample_time, st->time_base.num, st->time_base.den);
3359246d
 
42f91322
     seekpos = avio_seek(s->pb, (s->bit_rate * seconds) >> 3, SEEK_SET);
     if (seekpos < 0)
         return seekpos;
 
a2faa951
     ff_update_cur_dts(s, st, sample_time);
f1e606c7
     mxf->current_edit_unit = sample_time;
ddcf3e05
     } else {
2eba8da6
         t = &mxf->index_tables[0];
ddcf3e05
 
2eba8da6
         /* 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);
ddcf3e05
 
2eba8da6
         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 */
928727f9
             sample_time = FFMIN(sample_time, source_track->original_duration - 1);
ddcf3e05
         }
 
fd334b9b
         if ((ret = mxf_edit_unit_absolute_offset(mxf, t, sample_time, &sample_time, &seekpos, 1)) < 0)
2eba8da6
             return ret;
 
f028d4d1
         ff_update_cur_dts(s, st, sample_time);
2eba8da6
         mxf->current_edit_unit = sample_time;
ddcf3e05
         avio_seek(s->pb, seekpos, SEEK_SET);
     }
83cab07a
 
     // 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;
         }
     }
d09ea6ba
     return 0;
 }
 
66355be3
 AVInputFormat ff_mxf_demuxer = {
dfc2c4d9
     .name           = "mxf",
0177b7d2
     .long_name      = NULL_IF_CONFIG_SMALL("MXF (Material eXchange Format)"),
dfc2c4d9
     .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,
d09ea6ba
 };