diff options
Diffstat (limited to 'libavformat/mxfdec.c')
-rw-r--r-- | libavformat/mxfdec.c | 145 |
1 files changed, 133 insertions, 12 deletions
diff --git a/libavformat/mxfdec.c b/libavformat/mxfdec.c index d0a8a3a..5967df0 100644 --- a/libavformat/mxfdec.c +++ b/libavformat/mxfdec.c @@ -2,20 +2,20 @@ * MXF demuxer. * Copyright (c) 2006 SmartJog S.A., Baptiste Coudurier <baptiste dot coudurier at smartjog dot com> * - * This file is part of Libav. + * This file is part of FFmpeg. * - * Libav is free software; you can redistribute it and/or + * 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. * - * Libav is distributed in the hope that it will be useful, + * 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 Libav; if not, write to the Free Software + * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ @@ -51,6 +51,34 @@ #include "avformat.h" #include "mxf.h" +typedef enum { + Header, + BodyPartition, + Footer +} MXFPartitionType; + +typedef enum { + OP1a, + OP1b, + OP1c, + OP2a, + OP2b, + OP2c, + OP3a, + OP3b, + OP3c, + OPAtom, +} MXFOP; + +typedef struct { + int closed; + int complete; + MXFPartitionType type; + uint64_t previous_partition; + int index_sid; + int body_sid; +} MXFPartition; + typedef struct { UID uid; enum MXFMetadataSetType type; @@ -126,6 +154,9 @@ typedef struct { } MXFMetadataSet; typedef struct { + MXFPartition *partitions; + unsigned partitions_count; + MXFOP op; UID *packages_refs; int packages_count; MXFMetadataSet **metadata_sets; @@ -134,6 +165,7 @@ typedef struct { struct AVAES *aesc; uint8_t *local_tags; int local_tags_count; + uint64_t footer_partition; } MXFContext; enum MXFWrappingScheme { @@ -180,7 +212,7 @@ static int64_t klv_decode_ber_length(AVIOContext *pb) static int mxf_read_sync(AVIOContext *pb, const uint8_t *key, unsigned size) { int i, b; - for (i = 0; i < size && !pb->eof_reached; i++) { + for (i = 0; i < size && !url_feof(pb); i++) { b = avio_r8(pb); if (b == key[0]) i = 0; @@ -311,7 +343,7 @@ static int mxf_read_packet(AVFormatContext *s, AVPacket *pkt) { KLVPacket klv; - while (!s->pb->eof_reached) { + while (!url_feof(s->pb)) { if (klv_read_packet(&klv, s->pb) < 0) return -1; PRINT_KEY(s, "read packet", klv.key); @@ -373,6 +405,80 @@ 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, ByteIOContext *pb, int tag, int size, UID uid) +{ + MXFContext *mxf = arg; + MXFPartition *partition; + UID op; + uint64_t footer_partition; + + if (mxf->partitions_count+1 >= UINT_MAX / sizeof(*mxf->partitions)) + return AVERROR(ENOMEM); + + mxf->partitions = av_realloc(mxf->partitions, (mxf->partitions_count + 1) * sizeof(*mxf->partitions)); + if (!mxf->partitions) + return AVERROR(ENOMEM); + + partition = &mxf->partitions[mxf->partitions_count++]; + + 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; + avio_skip(pb, 16); + partition->previous_partition = avio_rb64(pb); + footer_partition = avio_rb64(pb); + avio_skip(pb, 16); + partition->index_sid = avio_rb32(pb); + avio_skip(pb, 8); + partition->body_sid = avio_rb32(pb); + avio_read(pb, op, sizeof(UID)); + + /* some files don'thave FooterPartition set in every partition */ + if (footer_partition) { + if (mxf->footer_partition && mxf->footer_partition != footer_partition) { + av_log(mxf->fc, AV_LOG_ERROR, "inconsistent FooterPartition value: %li != %li\n", + mxf->footer_partition, footer_partition); + } else { + mxf->footer_partition = footer_partition; + } + } + + av_dlog(mxf->fc, "PartitionPack: PreviousPartition = 0x%lx, " + "FooterPartition = 0x%lx, IndexSID = %i, BodySID = %i\n", + partition->previous_partition, footer_partition, + partition->index_sid, partition->body_sid); + + if (op[12] == 1 && op[13] == 1) mxf->op = OP1a; + else if (op[12] == 1 && op[13] == 2) mxf->op = OP1b; + else if (op[12] == 1 && op[13] == 3) mxf->op = OP1c; + else if (op[12] == 2 && op[13] == 1) mxf->op = OP2a; + else if (op[12] == 2 && op[13] == 2) mxf->op = OP2b; + else if (op[12] == 2 && op[13] == 3) mxf->op = OP2c; + else if (op[12] == 3 && op[13] == 1) mxf->op = OP3a; + else if (op[12] == 3 && op[13] == 2) mxf->op = OP3b; + else if (op[12] == 3 && op[13] == 3) mxf->op = OP3c; + else if (op[12] == 0x10) mxf->op = OPAtom; + else + av_log(mxf->fc, AV_LOG_ERROR, "unknown operational pattern: %02xh %02xh\n", op[12], op[13]); + + return 0; +} + static int mxf_add_metadata_set(MXFContext *mxf, void *metadata_set) { if (mxf->metadata_sets_count+1 >= UINT_MAX / sizeof(*mxf->metadata_sets)) @@ -829,12 +935,12 @@ static int mxf_parse_structural_metadata(MXFContext *mxf) st->codec->sample_rate = descriptor->sample_rate.num / descriptor->sample_rate.den; /* TODO: implement CODEC_ID_RAWAUDIO */ if (st->codec->codec_id == CODEC_ID_PCM_S16LE) { - if (descriptor->bits_per_sample == 24) + if (descriptor->bits_per_sample > 16 && descriptor->bits_per_sample <= 24) st->codec->codec_id = CODEC_ID_PCM_S24LE; else if (descriptor->bits_per_sample == 32) st->codec->codec_id = CODEC_ID_PCM_S32LE; } else if (st->codec->codec_id == CODEC_ID_PCM_S16BE) { - if (descriptor->bits_per_sample == 24) + if (descriptor->bits_per_sample > 16 && descriptor->bits_per_sample <= 24) st->codec->codec_id = CODEC_ID_PCM_S24BE; else if (descriptor->bits_per_sample == 32) st->codec->codec_id = CODEC_ID_PCM_S32BE; @@ -852,6 +958,16 @@ static int mxf_parse_structural_metadata(MXFContext *mxf) 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 }, + { { 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 }, { { 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 }, @@ -923,7 +1039,7 @@ static int mxf_read_header(AVFormatContext *s, AVFormatParameters *ap) } avio_seek(s->pb, -14, SEEK_CUR); mxf->fc = s; - while (!s->pb->eof_reached) { + while (!url_feof(s->pb)) { const MXFMetadataReadTableEntry *metadata; if (klv_read_packet(&klv, s->pb) < 0) @@ -942,8 +1058,11 @@ static int mxf_read_header(AVFormatContext *s, AVFormatParameters *ap) int res; if (klv.key[5] == 0x53) { res = mxf_read_local_tags(mxf, &klv, metadata->read, metadata->ctx_size, metadata->type); - } else - res = metadata->read(mxf, s->pb, 0, 0, NULL); + } else { + uint64_t next = avio_tell(s->pb) + klv.length; + res = metadata->read(mxf, s->pb, 0, 0, klv.key); + avio_seek(s->pb, next, SEEK_SET); + } if (res < 0) { av_log(s, AV_LOG_ERROR, "error reading header metadata\n"); return -1; @@ -984,6 +1103,7 @@ static int mxf_read_close(AVFormatContext *s) } av_freep(&mxf->metadata_sets[i]); } + av_freep(&mxf->partitions); av_freep(&mxf->metadata_sets); av_freep(&mxf->aesc); av_freep(&mxf->local_tags); @@ -1018,7 +1138,8 @@ static int mxf_read_seek(AVFormatContext *s, int stream_index, int64_t sample_ti if (sample_time < 0) sample_time = 0; seconds = av_rescale(sample_time, st->time_base.num, st->time_base.den); - avio_seek(s->pb, (s->bit_rate * seconds) >> 3, SEEK_SET); + if (avio_seek(s->pb, (s->bit_rate * seconds) >> 3, SEEK_SET) < 0) + return -1; av_update_cur_dts(s, st, sample_time); return 0; } |