From 21cc4b3327e1b3df8cfa7320d2a0297d03686123 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Tomas=20H=C3=A4rdin?= Date: Thu, 8 Dec 2011 11:21:58 +0100 Subject: [PATCH] mxfdec: use av_dlog() for 'no corresponding source package found' This is not an error and expected behavior for OPAtom files. Signed-off-by: Janne Grunau --- libavformat/mxfdec.c | 175 +++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 143 insertions(+), 32 deletions(-) diff --git a/libavformat/mxfdec.c b/libavformat/mxfdec.c index e451fe1..b6445e1 100644 --- a/libavformat/mxfdec.c +++ b/libavformat/mxfdec.c @@ -69,6 +69,7 @@ typedef enum { OP3b, OP3c, OPAtom, + OPSonyOpt, /* FATE sample, violates the spec in places */ } MXFOP; typedef struct { @@ -79,6 +80,12 @@ typedef struct { int index_sid; int body_sid; int64_t this_partition; + int64_t essence_offset; ///< absolute offset of essence + int64_t essence_length; + int32_t kag_size; + int64_t header_byte_count; + int64_t index_byte_count; + int pack_length; } MXFPartition; typedef struct { @@ -148,6 +155,7 @@ typedef struct { int *slice; int *element_delta; int nb_delta_entries; + int8_t *temporal_offset_entries; int *flag_entries; uint64_t *stream_offset_entries; uint32_t **slice_offset_entries; @@ -200,7 +208,8 @@ enum MXFWrappingScheme { Clip, }; -typedef int MXFMetadataReadFunc(void *arg, AVIOContext *pb, int tag, int size, UID uid); +/* 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); typedef struct { const UID key; @@ -414,7 +423,7 @@ static int mxf_read_packet(AVFormatContext *s, AVPacket *pkt) return AVERROR_EOF; } -static int mxf_read_primer_pack(void *arg, AVIOContext *pb, int tag, int size, UID uid) +static int mxf_read_primer_pack(void *arg, AVIOContext *pb, int tag, int size, UID uid, int64_t klv_offset) { MXFContext *mxf = arg; int item_num = avio_rb32(pb); @@ -435,7 +444,7 @@ static int mxf_read_primer_pack(void *arg, AVIOContext *pb, int tag, int size, U return 0; } -static int mxf_read_partition_pack(void *arg, AVIOContext *pb, int tag, int size, UID uid) +static int mxf_read_partition_pack(void *arg, AVIOContext *pb, int tag, int size, UID uid, int64_t klv_offset) { MXFContext *mxf = arg; MXFPartition *partition; @@ -463,6 +472,7 @@ static int mxf_read_partition_pack(void *arg, AVIOContext *pb, int tag, int size memset(partition, 0, sizeof(*partition)); mxf->partitions_count++; + partition->pack_length = avio_tell(pb) - klv_offset + size; switch(uid[13]) { case 2: @@ -482,11 +492,13 @@ static int mxf_read_partition_pack(void *arg, AVIOContext *pb, int tag, int size /* 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; - avio_skip(pb, 8); + avio_skip(pb, 4); + partition->kag_size = avio_rb32(pb); partition->this_partition = avio_rb64(pb); partition->previous_partition = avio_rb64(pb); footer_partition = avio_rb64(pb); - avio_skip(pb, 16); + partition->header_byte_count = avio_rb64(pb); + partition->index_byte_count = avio_rb64(pb); partition->index_sid = avio_rb32(pb); avio_skip(pb, 8); partition->body_sid = avio_rb32(pb); @@ -518,8 +530,22 @@ static int mxf_read_partition_pack(void *arg, AVIOContext *pb, int tag, int size else if (op[12] == 3 && op[13] == 2) mxf->op = OP3b; else if (op[12] == 3 && op[13] == 3) mxf->op = OP3c; else if (op[12] == 0x10) mxf->op = OPAtom; - else - av_log(mxf->fc, AV_LOG_ERROR, "unknown operational pattern: %02xh %02xh\n", op[12], op[13]); + else if (op[12] == 64&& op[13] == 1) mxf->op = OPSonyOpt; + else { + 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); + } return 0; } @@ -536,7 +562,7 @@ static int mxf_add_metadata_set(MXFContext *mxf, void *metadata_set) return 0; } -static int mxf_read_cryptographic_context(void *arg, AVIOContext *pb, int tag, int size, UID uid) +static int mxf_read_cryptographic_context(void *arg, AVIOContext *pb, int tag, int size, UID uid, int64_t klv_offset) { MXFCryptoContext *cryptocontext = arg; if (size != 16) @@ -546,7 +572,7 @@ static int mxf_read_cryptographic_context(void *arg, AVIOContext *pb, int tag, i return 0; } -static int mxf_read_content_storage(void *arg, AVIOContext *pb, int tag, int size, UID uid) +static int mxf_read_content_storage(void *arg, AVIOContext *pb, int tag, int size, UID uid, int64_t klv_offset) { MXFContext *mxf = arg; switch (tag) { @@ -564,7 +590,7 @@ static int mxf_read_content_storage(void *arg, AVIOContext *pb, int tag, int siz return 0; } -static int mxf_read_source_clip(void *arg, AVIOContext *pb, int tag, int size, UID uid) +static int mxf_read_source_clip(void *arg, AVIOContext *pb, int tag, int size, UID uid, int64_t klv_offset) { MXFStructuralComponent *source_clip = arg; switch(tag) { @@ -586,7 +612,7 @@ static int mxf_read_source_clip(void *arg, AVIOContext *pb, int tag, int size, U return 0; } -static int mxf_read_material_package(void *arg, AVIOContext *pb, int tag, int size, UID uid) +static int mxf_read_material_package(void *arg, AVIOContext *pb, int tag, int size, UID uid, int64_t klv_offset) { MXFPackage *package = arg; switch(tag) { @@ -604,7 +630,7 @@ static int mxf_read_material_package(void *arg, AVIOContext *pb, int tag, int si return 0; } -static int mxf_read_track(void *arg, AVIOContext *pb, int tag, int size, UID uid) +static int mxf_read_track(void *arg, AVIOContext *pb, int tag, int size, UID uid, int64_t klv_offset) { MXFTrack *track = arg; switch(tag) { @@ -625,7 +651,7 @@ static int mxf_read_track(void *arg, AVIOContext *pb, int tag, int size, UID uid return 0; } -static int mxf_read_sequence(void *arg, AVIOContext *pb, int tag, int size, UID uid) +static int mxf_read_sequence(void *arg, AVIOContext *pb, int tag, int size, UID uid, int64_t klv_offset) { MXFSequence *sequence = arg; switch(tag) { @@ -649,7 +675,7 @@ static int mxf_read_sequence(void *arg, AVIOContext *pb, int tag, int size, UID return 0; } -static int mxf_read_source_package(void *arg, AVIOContext *pb, int tag, int size, UID uid) +static int mxf_read_source_package(void *arg, AVIOContext *pb, int tag, int size, UID uid, int64_t klv_offset) { MXFPackage *package = arg; switch(tag) { @@ -719,19 +745,22 @@ static int mxf_read_index_entry_array(AVIOContext *pb, MXFIndexTableSegment *seg length = avio_rb32(pb); - segment->flag_entries = av_mallocz(segment->nb_index_entries * - sizeof(*segment->flag_entries)); - segment->stream_offset_entries = av_mallocz(segment->nb_index_entries * - sizeof(*segment->stream_offset_entries)); - segment->slice_offset_entries = av_mallocz(segment->nb_index_entries * - sizeof(*segment->slice_offset_entries)); - - if (!segment->flag_entries || !segment->stream_offset_entries || - !segment->slice_offset_entries) + segment->temporal_offset_entries = av_mallocz(segment->nb_index_entries * + sizeof(*segment->temporal_offset_entries)); + segment->flag_entries = av_mallocz(segment->nb_index_entries * + sizeof(*segment->flag_entries)); + segment->stream_offset_entries = av_mallocz(segment->nb_index_entries * + sizeof(*segment->stream_offset_entries)); + segment->slice_offset_entries = av_mallocz(segment->nb_index_entries * + sizeof(*segment->slice_offset_entries)); + + if (!segment->flag_entries || !segment->stream_offset_entries || + !segment->slice_offset_entries || !segment->temporal_offset_entries) goto errmem; for (i = 0; i < segment->nb_index_entries; i++) { - avio_rb16(pb); /* TemporalOffset and KeyFrameOffset */ + segment->temporal_offset_entries[i] = avio_r8(pb); + avio_r8(pb); /* KeyFrameOffset */ segment->flag_entries[i] = avio_r8(pb); segment->stream_offset_entries[i] = avio_rb64(pb); if (segment->slice_count) { @@ -755,10 +784,11 @@ errmem: av_freep(&segment->flag_entries); av_freep(&segment->stream_offset_entries); av_freep(&segment->slice_offset_entries); + av_freep(&segment->temporal_offset_entries); return AVERROR(ENOMEM); } -static int mxf_read_index_table_segment(void *arg, AVIOContext *pb, int tag, int size, UID uid) +static int mxf_read_index_table_segment(void *arg, AVIOContext *pb, int tag, int size, UID uid, int64_t klv_offset) { MXFIndexTableSegment *segment = arg; switch(tag) { @@ -821,7 +851,7 @@ static void mxf_read_pixel_layout(AVIOContext *pb, MXFDescriptor *descriptor) ff_mxf_decode_pixel_layout(layout, &descriptor->pix_fmt); } -static int mxf_read_generic_descriptor(void *arg, AVIOContext *pb, int tag, int size, UID uid) +static int mxf_read_generic_descriptor(void *arg, AVIOContext *pb, int tag, int size, UID uid, int64_t klv_offset) { MXFDescriptor *descriptor = arg; switch(tag) { @@ -1153,7 +1183,7 @@ static int mxf_parse_structural_metadata(MXFContext *mxf) } } if (!source_package) { - av_log(mxf->fc, AV_LOG_ERROR, "material track %d: no corresponding source package found\n", material_track->track_id); + av_dlog(mxf->fc, "material track %d: no corresponding source package found\n", material_track->track_id); break; } for (k = 0; k < source_package->tracks_count; k++) { @@ -1353,7 +1383,7 @@ static int mxf_read_local_tags(MXFContext *mxf, KLVPacket *klv, MXFMetadataReadF } if (ctx_size && tag == 0x3C0A) avio_read(pb, ctx->uid, 16); - else if ((ret = read_child(ctx, pb, tag, size, uid)) < 0) + else if ((ret = read_child(ctx, pb, tag, size, uid, -1)) < 0) return ret; avio_seek(pb, next, SEEK_SET); @@ -1438,6 +1468,79 @@ static int mxf_parse_handle_partition_or_eof(MXFContext *mxf) return mxf->parsing_backward ? mxf_seek_to_previous_partition(mxf) : 1; } +/** + * Figure 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; + av_log(mxf->fc, AV_LOG_ERROR, "partition %i: bad ThisPartition = %lx\n", + 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; +} + +static inline void compute_partition_essence_offset(AVFormatContext *s, + MXFContext *mxf, + KLVPacket *klv) +{ + MXFPartition *cur_part = mxf->current_partition; + /* 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(cur_part->this_partition + cur_part->pack_length, + cur_part->kag_size) + + round_to_kag(cur_part->header_byte_count, cur_part->kag_size) + + round_to_kag(cur_part->index_byte_count, cur_part->kag_size); + + if (mxf->op == OPAtom) { + /* point essence_offset to the actual data + * OPAtom has all the essence in one big KLV + */ + cur_part->essence_offset = avio_tell(s->pb); + cur_part->essence_length = klv->length; + } else { + /* NOTE: op1a_essence_offset may be less than to klv.offset + * (C0023S01.mxf) */ + cur_part->essence_offset = op1a_essence_offset; + } +} + static int mxf_read_header(AVFormatContext *s, AVFormatParameters *ap) { MXFContext *mxf = s->priv_data; @@ -1469,9 +1572,13 @@ static int mxf_read_header(AVFormatContext *s, AVFormatParameters *ap) if (IS_KLV_KEY(klv.key, mxf_encrypted_triplet_key) || IS_KLV_KEY(klv.key, mxf_essence_element_key) || IS_KLV_KEY(klv.key, mxf_system_item_key)) { - if (IS_KLV_KEY(klv.key, mxf_system_item_key)) { - mxf->system_item = 1; - } + if (!mxf->current_partition->essence_offset) { + compute_partition_essence_offset(s, mxf, &klv); + } + + if (IS_KLV_KEY(klv.key, mxf_system_item_key)) { + mxf->system_item = 1; + } if (!mxf->essence_offset) mxf->essence_offset = klv.offset; @@ -1499,7 +1606,7 @@ static int mxf_read_header(AVFormatContext *s, AVFormatParameters *ap) res = mxf_read_local_tags(mxf, &klv, metadata->read, metadata->ctx_size, metadata->type); } else { uint64_t next = avio_tell(s->pb) + klv.length; - res = metadata->read(mxf, s->pb, 0, 0, klv.key); + res = metadata->read(mxf, s->pb, 0, klv.length, klv.key, klv.offset); avio_seek(s->pb, next, SEEK_SET); } if (res < 0) { @@ -1518,6 +1625,9 @@ static int mxf_read_header(AVFormatContext *s, AVFormatParameters *ap) return AVERROR_INVALIDDATA; } avio_seek(s->pb, mxf->essence_offset, SEEK_SET); + + mxf_compute_essence_containers(mxf); + return mxf_parse_structural_metadata(mxf); } @@ -1551,6 +1661,7 @@ static int mxf_read_close(AVFormatContext *s) av_freep(&seg->slice_offset_entries[j]); av_freep(&seg->slice); av_freep(&seg->element_delta); + av_freep(&seg->temporal_offset_entries); av_freep(&seg->flag_entries); av_freep(&seg->stream_offset_entries); av_freep(&seg->slice_offset_entries); -- 2.7.4