diff options
Diffstat (limited to 'libavformat/mxfdec.c')
-rw-r--r-- | libavformat/mxfdec.c | 386 |
1 files changed, 262 insertions, 124 deletions
diff --git a/libavformat/mxfdec.c b/libavformat/mxfdec.c index dd10240..5cf9709 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 */ @@ -48,6 +48,7 @@ #include "libavutil/aes.h" #include "libavutil/mathematics.h" #include "libavcodec/bytestream.h" +#include "libavutil/timecode.h" #include "avformat.h" #include "internal.h" #include "mxf.h" @@ -69,7 +70,7 @@ typedef enum { OP3b, OP3c, OPAtom, - OPSonyOpt, /* FATE sample, violates the spec in places */ + OPSONYOpt, /* FATE sample, violates the spec in places */ } MXFOP; typedef struct { @@ -116,11 +117,21 @@ typedef struct { typedef struct { UID uid; enum MXFMetadataSetType type; + int drop_frame; + int start_frame; + struct AVRational rate; + AVTimecode tc; +} MXFTimecodeComponent; + +typedef struct { + UID uid; + enum MXFMetadataSetType type; MXFSequence *sequence; /* mandatory, and only one */ UID sequence_ref; int track_id; uint8_t track_number[4]; AVRational edit_rate; + int intra_only; } MXFTrack; typedef struct { @@ -131,9 +142,13 @@ typedef struct { AVRational sample_rate; AVRational aspect_ratio; int width; - int height; + int height; /* Field height, not frame height */ + int frame_layout; /* See MXFFrameLayout enum */ int channels; int bits_per_sample; + unsigned int component_depth; + unsigned int horiz_subsampling; + unsigned int vert_subsampling; UID *sub_descriptors_refs; int sub_descriptors_count; int linked_track_id; @@ -257,7 +272,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; @@ -504,19 +519,21 @@ static int mxf_read_partition_pack(void *arg, AVIOContext *pb, int tag, int size 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] == 64&& op[13] == 1) mxf->op = OPSonyOpt; + else if (op[12] == 64&& op[13] == 1) mxf->op = OPSONYOpt; else if (op[12] == 0x10) { /* SMPTE 390m: "There shall be exactly one essence container" - * 2011_DCPTEST_24FPS.V.mxf violates this and is frame wrapped, - * which is why we assume OP1a. */ + * 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 */ if (nb_essence_containers != 1) { + MXFOP op = nb_essence_containers ? OP1a : OPAtom; + /* only nag once */ if (!mxf->op) - av_log(mxf->fc, AV_LOG_WARNING, - "\"OPAtom\" with %u ECs - assuming OP1a\n", - nb_essence_containers); + av_log(mxf->fc, AV_LOG_WARNING, "\"OPAtom\" with %u ECs - assuming %s\n", + nb_essence_containers, op == OP1a ? "OP1a" : "OPAtom"); - mxf->op = OP1a; + mxf->op = op; } else mxf->op = OPAtom; } else { @@ -527,7 +544,7 @@ static int mxf_read_partition_pack(void *arg, AVIOContext *pb, int tag, int size 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) + if (mxf->op == OPSONYOpt) partition->kag_size = 512; else partition->kag_size = 1; @@ -620,6 +637,23 @@ static int mxf_read_material_package(void *arg, AVIOContext *pb, int tag, int si return 0; } +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; +} + static int mxf_read_track(void *arg, AVIOContext *pb, int tag, int size, UID uid, int64_t klv_offset) { MXFTrack *track = arg; @@ -631,8 +665,8 @@ static int mxf_read_track(void *arg, AVIOContext *pb, int tag, int size, UID uid avio_read(pb, track->track_number, 4); break; case 0x4B01: - track->edit_rate.den = avio_rb32(pb); track->edit_rate.num = avio_rb32(pb); + track->edit_rate.den = avio_rb32(pb); break; case 0x4803: avio_read(pb, track->sequence_ref, 16); @@ -696,29 +730,12 @@ static int mxf_read_index_entry_array(AVIOContext *pb, MXFIndexTableSegment *seg int i, length; segment->nb_index_entries = avio_rb32(pb); - if (!segment->nb_index_entries) - return 0; - else if (segment->nb_index_entries < 0 || - segment->nb_index_entries > - (INT_MAX >> av_log2(sizeof(*segment->stream_offset_entries)))) - return AVERROR(ENOMEM); - length = avio_rb32(pb); - 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)); - - if (!segment->flag_entries || !segment->stream_offset_entries || - !segment->temporal_offset_entries) { - av_freep(&segment->flag_entries); - av_freep(&segment->stream_offset_entries); - av_freep(&segment->temporal_offset_entries); + 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))) || + !(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++) { segment->temporal_offset_entries[i] = avio_r8(pb); @@ -789,6 +806,7 @@ static void mxf_read_pixel_layout(AVIOContext *pb, MXFDescriptor *descriptor) static int mxf_read_generic_descriptor(void *arg, AVIOContext *pb, int tag, int size, UID uid, int64_t klv_offset) { MXFDescriptor *descriptor = arg; + descriptor->pix_fmt = PIX_FMT_NONE; switch(tag) { case 0x3F01: descriptor->sub_descriptors_count = avio_rb32(pb); @@ -815,10 +833,22 @@ static int mxf_read_generic_descriptor(void *arg, AVIOContext *pb, int tag, int case 0x3202: descriptor->height = avio_rb32(pb); break; + case 0x320C: + descriptor->frame_layout = avio_r8(pb); + break; case 0x320E: descriptor->aspect_ratio.num = avio_rb32(pb); descriptor->aspect_ratio.den = avio_rb32(pb); break; + 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; case 0x3D03: descriptor->sample_rate.num = avio_rb32(pb); descriptor->sample_rate.den = avio_rb32(pb); @@ -892,8 +922,22 @@ static const MXFCodecUL mxf_picture_essence_container_uls[] = { // video essence container uls { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x02,0x0D,0x01,0x03,0x01,0x02,0x04,0x60,0x01 }, 14, CODEC_ID_MPEG2VIDEO }, /* MPEG-ES Frame wrapped */ { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x03,0x01,0x02,0x02,0x41,0x01 }, 14, CODEC_ID_DVVIDEO }, /* DV 625 25mbps */ + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x03,0x01,0x02,0x05,0x00,0x00 }, 14, CODEC_ID_RAWVIDEO }, /* Uncompressed Picture */ { { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, 0, CODEC_ID_NONE }, }; + +/* EC ULs for intra-only formats */ +static const MXFCodecUL mxf_intra_only_essence_container_uls[] = { + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x03,0x01,0x02,0x01,0x00,0x00 }, 14, 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, CODEC_ID_NONE }, +}; + +/* intra-only PictureEssenceCoding ULs, where no corresponding EC UL exists */ +static const MXFCodecUL mxf_intra_only_picture_essence_coding_uls[] = { + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x02,0x01,0x32,0x00,0x00 }, 14, CODEC_ID_H264 }, /* H.264/MPEG-4 AVC Intra Profiles */ + { { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, 0, CODEC_ID_NONE }, +}; + static const MXFCodecUL mxf_sound_essence_container_uls[] = { // sound essence container uls { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x03,0x01,0x02,0x06,0x01,0x00 }, 14, CODEC_ID_PCM_S16LE }, /* BWF Frame wrapped */ @@ -914,9 +958,8 @@ static int mxf_get_sorted_table_segments(MXFContext *mxf, int *nb_sorted_segment if (mxf->metadata_sets[i]->type == IndexTableSegment) nb_segments++; - *sorted_segments = av_mallocz(nb_segments * sizeof(**sorted_segments)); - unsorted_segments = av_mallocz(nb_segments * sizeof(*unsorted_segments)); - if (!sorted_segments || !unsorted_segments) { + if (!(unsorted_segments = av_calloc(nb_segments, sizeof(*unsorted_segments))) || + !(*sorted_segments = av_calloc(nb_segments, sizeof(**sorted_segments)))) { av_freep(sorted_segments); av_free(unsorted_segments); return AVERROR(ENOMEM); @@ -931,19 +974,23 @@ static int mxf_get_sorted_table_segments(MXFContext *mxf, int *nb_sorted_segment /* 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; + uint64_t best_index_duration = 0; for (j = 0; j < nb_segments; j++) { MXFIndexTableSegment *s = unsorted_segments[j]; /* Require larger BosySID, IndexSID or IndexStartPosition then the previous entry. This removes duplicates. * We want the smallest values for the keys than what we currently have, unless this is the first such entry this time around. + * If we come across an entry with the same IndexStartPosition but larger IndexDuration, then we'll prefer it over the one we currently have. */ if ((i == 0 || s->body_sid > last_body_sid || s->index_sid > last_index_sid || s->index_start_position > last_index_start) && - (best == -1 || s->body_sid < best_body_sid || s->index_sid < best_index_sid || s->index_start_position < best_index_start)) { + (best == -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))) { best = j; best_body_sid = s->body_sid; best_index_sid = s->index_sid; best_index_start = s->index_start_position; + best_index_duration = s->index_duration; } } @@ -1034,7 +1081,7 @@ static int mxf_edit_unit_absolute_offset(MXFContext *mxf, MXFIndexTable *index_t if (s->nb_index_entries == 2 * s->index_duration + 1) index *= 2; /* Avid index */ - if (index < 0 || index > s->nb_index_entries) { + if (index < 0 || index >= s->nb_index_entries) { 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; @@ -1084,14 +1131,8 @@ static int mxf_compute_ptses_fake_index(MXFContext *mxf, MXFIndexTable *index_ta if (index_table->nb_ptses <= 0) return 0; - if (index_table->nb_ptses > INT_MAX >> av_log2(sizeof(AVIndexEntry)) + 1) - return AVERROR(ENOMEM); - - index_table->ptses = av_mallocz(index_table->nb_ptses * - sizeof(int64_t)); - index_table->fake_index = av_mallocz(index_table->nb_ptses * - sizeof(AVIndexEntry)); - if (!index_table->ptses || !index_table->fake_index) { + 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); return AVERROR(ENOMEM); } @@ -1196,9 +1237,7 @@ static int mxf_compute_index_tables(MXFContext *mxf) } } - if (mxf->nb_index_tables > INT_MAX >> av_log2(sizeof(MXFIndexTable)) + 1 || - !(mxf->index_tables = av_mallocz(mxf->nb_index_tables * - sizeof(MXFIndexTable)))) { + if (!(mxf->index_tables = av_calloc(mxf->nb_index_tables, sizeof(MXFIndexTable)))) { av_log(mxf->fc, AV_LOG_ERROR, "failed to allocate index tables\n"); ret = AVERROR(ENOMEM); goto finish_decoding_index; @@ -1217,12 +1256,8 @@ static int mxf_compute_index_tables(MXFContext *mxf) for (i = j = 0; j < mxf->nb_index_tables; i += mxf->index_tables[j++].nb_segments) { MXFIndexTable *t = &mxf->index_tables[j]; - if (t->nb_segments > - (INT_MAX >> av_log2(sizeof(MXFIndexTableSegment *))) || - !(t->segments = av_mallocz(t->nb_segments * - sizeof(MXFIndexTableSegment*)))) { - av_log(mxf->fc, AV_LOG_ERROR, "failed to allocate IndexTableSegment" - " pointer array\n"); + if (!(t->segments = av_calloc(t->nb_segments, sizeof(MXFIndexTableSegment*)))) { + av_log(mxf->fc, AV_LOG_ERROR, "failed to allocate IndexTableSegment pointer array\n"); ret = AVERROR(ENOMEM); goto finish_decoding_index; } @@ -1266,6 +1301,22 @@ finish_decoding_index: return ret; } +static int mxf_is_intra_only(MXFDescriptor *descriptor) +{ + return mxf_get_codec_ul(mxf_intra_only_essence_container_uls, + &descriptor->essence_container_ul)->id != CODEC_ID_NONE || + mxf_get_codec_ul(mxf_intra_only_picture_essence_coding_uls, + &descriptor->essence_codec_ul)->id != CODEC_ID_NONE; +} + +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; +} + static int mxf_parse_structural_metadata(MXFContext *mxf) { MXFPackage *material_package = NULL; @@ -1290,24 +1341,48 @@ static int mxf_parse_structural_metadata(MXFContext *mxf) MXFTrack *temp_track = NULL; MXFDescriptor *descriptor = NULL; MXFStructuralComponent *component = NULL; + MXFTimecodeComponent *mxf_tc = NULL; UID *essence_container_ul = NULL; const MXFCodecUL *codec_ul = NULL; const MXFCodecUL *container_ul = NULL; + const MXFCodecUL *pix_fmt_ul = NULL; AVStream *st; + AVTimecode tc; + int flags; if (!(material_track = mxf_resolve_strong_ref(mxf, &material_package->tracks_refs[i], Track))) { av_log(mxf->fc, AV_LOG_ERROR, "could not resolve material track strong ref\n"); continue; } + if ((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; + if (av_timecode_init(&tc, mxf_tc->rate, flags, mxf_tc->start_frame, mxf->fc) == 0) { + mxf_add_timecode_metadata(&mxf->fc->metadata, "timecode", &tc); + } + } + 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"); continue; } + 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; + if (av_timecode_init(&tc, mxf_tc->rate, flags, mxf_tc->start_frame, mxf->fc) == 0) { + mxf_add_timecode_metadata(&mxf->fc->metadata, "timecode", &tc); + break; + } + } + /* TODO: handle multiple source clips */ for (j = 0; j < material_track->sequence->structural_components_count; j++) { - /* TODO: handle timecode component */ component = mxf_resolve_strong_ref(mxf, &material_track->sequence->structural_components_refs[j], SourceClip); if (!component) continue; @@ -1369,7 +1444,7 @@ static int mxf_parse_structural_metadata(MXFContext *mxf) if (st->duration == -1) st->duration = AV_NOPTS_VALUE; st->start_time = component->start_position; - avpriv_set_pts_info(st, 64, material_track->edit_rate.num, material_track->edit_rate.den); + avpriv_set_pts_info(st, 64, material_track->edit_rate.den, material_track->edit_rate.num); PRINT_KEY(mxf->fc, "data definition ul", source_track->sequence->data_definition_ul); codec_ul = mxf_get_codec_ul(ff_mxf_data_definition_uls, &source_track->sequence->data_definition_ul); @@ -1421,13 +1496,49 @@ static int mxf_parse_structural_metadata(MXFContext *mxf) st->codec->extradata_size = descriptor->extradata_size; } if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) { + source_track->intra_only = mxf_is_intra_only(descriptor); container_ul = mxf_get_codec_ul(mxf_picture_essence_container_uls, essence_container_ul); if (st->codec->codec_id == CODEC_ID_NONE) st->codec->codec_id = container_ul->id; st->codec->width = descriptor->width; - st->codec->height = descriptor->height; - if (st->codec->codec_id == CODEC_ID_RAWVIDEO) + 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: + 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: + break; + case SeparateFields: + st->codec->height *= 2; /* Turn field height into frame height. */ + break; + default: + av_log(mxf->fc, AV_LOG_INFO, "Unknown frame layout type: %d\n", descriptor->frame_layout); + } + if (st->codec->codec_id == CODEC_ID_RAWVIDEO) { st->codec->pix_fmt = descriptor->pix_fmt; + if (st->codec->pix_fmt == PIX_FMT_NONE) { + pix_fmt_ul = mxf_get_codec_ul(ff_mxf_pixel_format_uls, &descriptor->essence_codec_ul); + st->codec->pix_fmt = pix_fmt_ul->id; + if (st->codec->pix_fmt == PIX_FMT_NONE) { + /* 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) { + st->codec->pix_fmt = PIX_FMT_UYVY422; + } + } + } + } st->need_parsing = AVSTREAM_PARSE_HEADERS; } else if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) { container_ul = mxf_get_codec_ul(mxf_sound_essence_container_uls, essence_container_ul); @@ -1491,6 +1602,7 @@ static const MXFMetadataReadTableEntry mxf_metadata_read_table[] = { { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x47,0x00 }, mxf_read_generic_descriptor, sizeof(MXFDescriptor), Descriptor }, /* AES3 */ { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x3A,0x00 }, mxf_read_track, sizeof(MXFTrack), Track }, /* Static Track */ { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x3B,0x00 }, mxf_read_track, sizeof(MXFTrack), Track }, /* Generic Track */ + { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x14,0x00 }, mxf_read_timecode_component, sizeof(MXFTimecodeComponent), TimecodeComponent }, { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x04,0x01,0x02,0x02,0x00,0x00 }, mxf_read_cryptographic_context, sizeof(MXFCryptoContext), CryptoContext }, { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x10,0x01,0x00 }, mxf_read_index_table_segment, sizeof(MXFIndexTableSegment), IndexTableSegment }, { { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, NULL, 0, AnyType }, @@ -1504,7 +1616,7 @@ static int mxf_read_local_tags(MXFContext *mxf, KLVPacket *klv, MXFMetadataReadF if (!ctx) return AVERROR(ENOMEM); - while (avio_tell(pb) + 4 < klv_end && !pb->eof_reached) { + while (avio_tell(pb) + 4 < klv_end && !url_feof(pb)) { int ret; int tag = avio_rb16(pb); int size = avio_rb16(pb); /* KLV specified by 0x53 */ @@ -1618,8 +1730,7 @@ static int mxf_parse_handle_partition_or_eof(MXFContext *mxf) } /** - * Figure out the proper offset and length of the essence container - * in each partition + * Figures out the proper offset and length of the essence container in each partition */ static void mxf_compute_essence_containers(MXFContext *mxf) { @@ -1659,38 +1770,6 @@ static int64_t round_to_kag(int64_t position, int 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 is_pcm(enum CodecID codec_id) { /* we only care about "normal" PCM codecs until we get samples */ @@ -1745,7 +1824,7 @@ static int mxf_read_header(AVFormatContext *s) mxf->fc = s; mxf->run_in = avio_tell(s->pb); - while (!s->pb->eof_reached) { + while (!url_feof(s->pb)) { const MXFMetadataReadTableEntry *metadata; if (klv_read_packet(&klv, s->pb) < 0) { @@ -1764,13 +1843,32 @@ static int mxf_read_header(AVFormatContext *s) IS_KLV_KEY(klv.key, mxf_system_item_key)) { if (!mxf->current_partition) { - av_log(mxf->fc, AV_LOG_ERROR, - "found essence prior to first PartitionPack\n"); + av_log(mxf->fc, AV_LOG_ERROR, "found essence prior to first PartitionPack\n"); return AVERROR_INVALIDDATA; } if (!mxf->current_partition->essence_offset) { - compute_partition_essence_offset(s, mxf, &klv); + /* 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; + } } if (!essence_offset) @@ -1785,6 +1883,9 @@ static int mxf_read_header(AVFormatContext *s) /* next partition pack - keep going, seek to previous partition or stop */ if(mxf_parse_handle_partition_or_eof(mxf) <= 0) break; + else if (mxf->parsing_backward) + continue; + /* we're still parsing forward. proceed to parsing this partition pack */ } for (metadata = mxf_metadata_read_table; metadata->read; metadata++) { @@ -1847,87 +1948,125 @@ static int mxf_read_header(AVFormatContext *s) } /** - * Computes DTS and PTS for the given video packet based on its offset. + * Sets mxf->current_edit_unit based on what offset we're currently at. + * @return next_ofs if OK, <0 on error */ -static void mxf_packet_timestamps(MXFContext *mxf, AVPacket *pkt) +static int64_t mxf_set_current_edit_unit(MXFContext *mxf, int64_t current_offset) { - int64_t last_ofs = -1, next_ofs; + int64_t last_ofs = -1, next_ofs = -1; MXFIndexTable *t = &mxf->index_tables[0]; /* this is called from the OP1a demuxing logic, which means there * may be no index tables */ if (mxf->nb_index_tables <= 0) - return; + return -1; - /* find mxf->current_edit_unit so that the next edit unit starts ahead of pkt->pos */ + /* find mxf->current_edit_unit so that the next edit unit starts ahead of current_offset */ while (mxf->current_edit_unit >= 0) { if (mxf_edit_unit_absolute_offset(mxf, t, mxf->current_edit_unit + 1, NULL, &next_ofs, 0) < 0) - break; + return -1; if (next_ofs <= last_ofs) { /* 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"); - return; + return - 1; } - if (next_ofs > pkt->pos) + if (next_ofs > current_offset) break; last_ofs = next_ofs; mxf->current_edit_unit++; } - if (mxf->current_edit_unit < 0 || mxf->current_edit_unit >= t->nb_ptses) - return; + /* not checking mxf->current_edit_unit >= t->nb_ptses here since CBR files may lack IndexEntryArrays */ + if (mxf->current_edit_unit < 0) + return -1; - pkt->dts = mxf->current_edit_unit + t->first_dts; - pkt->pts = t->ptses[mxf->current_edit_unit]; + return next_ofs; } static int mxf_read_packet_old(AVFormatContext *s, AVPacket *pkt) { KLVPacket klv; + MXFContext *mxf = s->priv_data; - while (!s->pb->eof_reached) { + while (!url_feof(s->pb)) { + int ret; if (klv_read_packet(&klv, s->pb) < 0) return -1; 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)) { - int res = mxf_decrypt_triplet(s, pkt, &klv); - if (res < 0) { + ret = mxf_decrypt_triplet(s, pkt, &klv); + if (ret < 0) { av_log(s, AV_LOG_ERROR, "invalid encoded triplet\n"); - return -1; + return AVERROR_INVALIDDATA; } 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); + int64_t next_ofs, next_klv; + AVStream *st; + MXFTrack *track; + if (index < 0) { av_log(s, AV_LOG_ERROR, "error getting stream index %d\n", AV_RB32(klv.key+12)); goto skip; } + + st = s->streams[index]; + track = st->priv_data; + if (s->streams[index]->discard == AVDISCARD_ALL) goto skip; + + 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) */ + av_log_ask_for_sample(s, + "KLV for edit unit %i extends into next edit unit - OPAtom misinterpreted as OP1a?\n", + mxf->current_edit_unit); + klv.length = next_ofs - avio_tell(s->pb); + } + /* check for 8 channels AES3 element */ if (klv.key[12] == 0x06 && klv.key[13] == 0x01 && klv.key[14] == 0x10) { if (mxf_get_d10_aes3_packet(s->pb, s->streams[index], pkt, klv.length) < 0) { av_log(s, AV_LOG_ERROR, "error reading D-10 aes3 frame\n"); - return -1; + return AVERROR_INVALIDDATA; } } else { - int ret = av_get_packet(s->pb, pkt, klv.length); + ret = av_get_packet(s->pb, pkt, klv.length); if (ret < 0) return ret; } pkt->stream_index = index; pkt->pos = klv.offset; - if (s->streams[index]->codec->codec_type == AVMEDIA_TYPE_VIDEO) - mxf_packet_timestamps(s->priv_data, pkt); /* offset -> EditUnit -> DTS/PTS */ + if (s->streams[index]->codec->codec_type == AVMEDIA_TYPE_VIDEO && next_ofs >= 0) { + /* 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]; + } 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; + } + } + + /* seek for truncated packets */ + avio_seek(s->pb, next_klv, SEEK_SET); return 0; } else @@ -1978,8 +2117,8 @@ static int mxf_read_packet(AVFormatContext *s, AVPacket *pkt) if ((ret64 = avio_seek(s->pb, pos, SEEK_SET)) < 0) return ret64; - if ((ret = av_get_packet(s->pb, pkt, size)) != size) - return ret < 0 ? ret : AVERROR_EOF; + if ((size = av_get_packet(s->pb, pkt, size)) < 0) + return size; if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO && t->ptses && mxf->current_edit_unit >= 0 && mxf->current_edit_unit < t->nb_ptses) { @@ -1993,7 +2132,6 @@ static int mxf_read_packet(AVFormatContext *s, AVPacket *pkt) return 0; } - static int mxf_read_close(AVFormatContext *s) { MXFContext *mxf = s->priv_data; |