X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavformat%2Fmxfdec.c;h=10512efce3c68e113370a0a0fb4aa1ca5c9a26ac;hb=dfa77dead2c97ec84092066102b14a2524d4d88b;hp=98a71459b6dc1e32d0852ddc26f5e865637f822b;hpb=36c305f9db0ed9e0a4313f11683ea0de7efc496f;p=ffmpeg diff --git a/libavformat/mxfdec.c b/libavformat/mxfdec.c index 98a71459b6d..10512efce3c 100644 --- a/libavformat/mxfdec.c +++ b/libavformat/mxfdec.c @@ -148,17 +148,12 @@ typedef struct { int edit_unit_byte_count; int index_sid; int body_sid; - int slice_count; AVRational index_edit_rate; uint64_t index_start_position; uint64_t index_duration; - 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; int nb_index_entries; } MXFIndexTableSegment; @@ -210,12 +205,6 @@ typedef struct { int64_t last_forward_tell; int last_forward_partition; int current_edit_unit; - int current_stream; - int d10; - int broken_index; - int64_t first_dts; /* DTS = EditUnit + first_dts */ - int64_t *ptses; /* maps EditUnit -> PTS */ - int nb_ptses; int nb_index_tables; MXFIndexTable *index_tables; } MXFContext; @@ -477,19 +466,26 @@ static int mxf_read_partition_pack(void *arg, AVIOContext *pb, int tag, int size /* 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", + av_log(mxf->fc, AV_LOG_ERROR, "inconsistent FooterPartition value: %" PRIi64 " != %" PRIi64 "\n", mxf->footer_partition, footer_partition); } else { mxf->footer_partition = footer_partition; } } - av_dlog(mxf->fc, "PartitionPack: ThisPartition = 0x%lx, PreviousPartition = 0x%lx, " - "FooterPartition = 0x%lx, IndexSID = %i, BodySID = %i\n", + av_dlog(mxf->fc, "PartitionPack: ThisPartition = 0x%" PRIx64 ", PreviousPartition = 0x%" PRIx64 ", " + "FooterPartition = 0x%" PRIx64 ", IndexSID = %i, BodySID = %i\n", partition->this_partition, partition->previous_partition, footer_partition, partition->index_sid, partition->body_sid); + /* sanity check PreviousPartition if set */ + if (partition->previous_partition && + mxf->run_in + partition->previous_partition >= klv_offset) { + av_log(mxf->fc, AV_LOG_ERROR, "PreviousPartition points to this partition or forward\n"); + return AVERROR_INVALIDDATA; + } + 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; @@ -671,28 +667,9 @@ static int mxf_read_source_package(void *arg, AVIOContext *pb, int tag, int size return 0; } -static int mxf_read_delta_entry_array(AVIOContext *pb, MXFIndexTableSegment *segment) -{ - int i, length; - - segment->nb_delta_entries = avio_rb32(pb); - length = avio_rb32(pb); - - if (!(segment->slice = av_calloc(segment->nb_delta_entries, sizeof(*segment->slice))) || - !(segment->element_delta = av_calloc(segment->nb_delta_entries, sizeof(*segment->element_delta)))) - return AVERROR(ENOMEM); - - for (i = 0; i < segment->nb_delta_entries; i++) { - avio_r8(pb); /* PosTableIndex */ - segment->slice[i] = avio_r8(pb); - segment->element_delta[i] = avio_rb32(pb); - } - return 0; -} - static int mxf_read_index_entry_array(AVIOContext *pb, MXFIndexTableSegment *segment) { - int i, j, length; + int i, length; segment->nb_index_entries = avio_rb32(pb); length = avio_rb32(pb); @@ -702,24 +679,12 @@ static int mxf_read_index_entry_array(AVIOContext *pb, MXFIndexTableSegment *seg !(segment->stream_offset_entries = av_calloc(segment->nb_index_entries, sizeof(*segment->stream_offset_entries)))) return AVERROR(ENOMEM); - if (segment->slice_count && - !(segment->slice_offset_entries = av_calloc(segment->nb_index_entries, sizeof(*segment->slice_offset_entries)))) - return AVERROR(ENOMEM); - for (i = 0; i < segment->nb_index_entries; i++) { 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) { - if (!(segment->slice_offset_entries[i] = av_calloc(segment->slice_count, sizeof(**segment->slice_offset_entries)))) - return AVERROR(ENOMEM); - - for (j = 0; j < segment->slice_count; j++) - segment->slice_offset_entries[i][j] = avio_rb32(pb); - } - - avio_skip(pb, length - 11 - 4 * segment->slice_count); + avio_skip(pb, length - 11); } return 0; } @@ -740,13 +705,6 @@ static int mxf_read_index_table_segment(void *arg, AVIOContext *pb, int tag, int segment->body_sid = avio_rb32(pb); av_dlog(NULL, "BodySID %d\n", segment->body_sid); break; - case 0x3F08: - segment->slice_count = avio_r8(pb); - av_dlog(NULL, "SliceCount %d\n", segment->slice_count); - break; - case 0x3F09: - av_dlog(NULL, "DeltaEntryArray found\n"); - return mxf_read_delta_entry_array(pb, segment); case 0x3F0A: av_dlog(NULL, "IndexEntryArray found\n"); return mxf_read_index_entry_array(pb, segment); @@ -904,8 +862,6 @@ static const MXFCodecUL mxf_sound_essence_container_uls[] = { { { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, 0, CODEC_ID_NONE }, }; -static UID mxf_d10_ul = { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x03,0x01,0x02,0x01,0x01,0x01 }; - static int mxf_get_sorted_table_segments(MXFContext *mxf, int *nb_sorted_segments, MXFIndexTableSegment ***sorted_segments) { int i, j, nb_segments = 0; @@ -985,16 +941,16 @@ static int mxf_absolute_bodysid_offset(MXFContext *mxf, int body_sid, int64_t of offset -= p->essence_length; } - av_log(mxf->fc, AV_LOG_ERROR, "failed to find absolute offset of %lx in BodySID %i - partial file?\n", + av_log(mxf->fc, AV_LOG_ERROR, "failed to find absolute offset of %" PRIx64" in BodySID %i - partial file?\n", offset_in, body_sid); return AVERROR_INVALIDDATA; } /** - * Returns the length of the essence container with given BodySID, or zero if unknown + * Returns the end position of the essence container with given BodySID, or zero if unknown */ -static int64_t mxf_essence_container_length(MXFContext *mxf, int body_sid) +static int64_t mxf_essence_container_end(MXFContext *mxf, int body_sid) { int x; int64_t ret = 0; @@ -1008,7 +964,7 @@ static int64_t mxf_essence_container_length(MXFContext *mxf, int body_sid) if (!p->essence_length) return 0; - ret += p->essence_length; + ret = p->essence_offset + p->essence_length; } return ret; @@ -1063,132 +1019,6 @@ static int mxf_edit_unit_absolute_offset(MXFContext *mxf, MXFIndexTable *index_t return AVERROR_INVALIDDATA; } -static int mxf_parse_index(MXFContext *mxf, int track_id, AVStream *st, MXFIndexTableSegment **sorted_segments, int nb_sorted_segments) -{ - int64_t accumulated_offset = 0; - int j, k, l, ret; - int n_delta = track_id - 1; /* TrackID = 1-based stream index */ - - if (track_id < 1) { - av_log(mxf->fc, AV_LOG_ERROR, "TrackID not positive: %i\n", track_id); - return AVERROR_INVALIDDATA; - } - - for (j = 0; j < nb_sorted_segments; j++) { - int duration, sample_duration = 1, last_sample_size = 0; - int64_t segment_size; - MXFIndexTableSegment *tableseg = sorted_segments[j]; - int index_delta = 1, last_size_unknown = 0; - int64_t last_pos = 0; - - /* reset accumulated_offset on BodySID change */ - if (j > 0 && tableseg->body_sid != sorted_segments[j-1]->body_sid) - accumulated_offset = 0; - - if (tableseg->nb_index_entries == 2 * tableseg->index_duration + 1) { - /* Avid index - duplicate entries and total size as last entry */ - index_delta = 2; - } - - if (n_delta >= tableseg->nb_delta_entries && st->index != 0) - continue; - duration = tableseg->index_duration > 0 ? tableseg->index_duration : - st->duration - st->nb_index_entries; - segment_size = tableseg->edit_unit_byte_count * duration; - /* check small EditUnitByteCount for audio */ - if (tableseg->edit_unit_byte_count && tableseg->edit_unit_byte_count < 32 - && !tableseg->index_duration) { - /* duration might be prime relative to the new sample_duration, - * which means we need to handle the last frame differently */ - sample_duration = 8192; - last_sample_size = (duration % sample_duration) * tableseg->edit_unit_byte_count; - tableseg->edit_unit_byte_count *= sample_duration; - duration /= sample_duration; - if (last_sample_size) duration++; - } - - if (duration <= 0) { - av_log(mxf->fc, AV_LOG_WARNING, "0 duration in index for stream %i\n", st->index); - mxf->broken_index = 1; - return 0; - } - - for (k = l = 0; k < duration; k++, l += index_delta) { - int64_t pos; - int size, flags = 0; - - if (l < tableseg->nb_index_entries) { - pos = tableseg->stream_offset_entries[l]; - if (n_delta < tableseg->nb_delta_entries) { - if (n_delta < tableseg->nb_delta_entries - 1) { - size = - tableseg->slice_offset_entries[l][tableseg->slice[n_delta+1]-1] + - tableseg->element_delta[n_delta+1] - - tableseg->element_delta[n_delta]; - if (tableseg->slice[n_delta] > 0) - size -= tableseg->slice_offset_entries[l][tableseg->slice[n_delta]-1]; - } else if (l < tableseg->nb_index_entries - 1) { - size = tableseg->stream_offset_entries[l+1] - - tableseg->stream_offset_entries[l] - - tableseg->slice_offset_entries[l][tableseg->slice[tableseg->nb_delta_entries-1]-1] - - tableseg->element_delta[tableseg->nb_delta_entries-1]; - } else - size = 0; - if (tableseg->slice[n_delta] > 0) - pos += tableseg->slice_offset_entries[l][tableseg->slice[n_delta]-1]; - pos += tableseg->element_delta[n_delta]; - } else - size = 0; - flags = !(tableseg->flag_entries[l] & 0x30) ? AVINDEX_KEYFRAME : 0; - } else { - pos = (int64_t)k * tableseg->edit_unit_byte_count + accumulated_offset; - if (n_delta < tableseg->nb_delta_entries - 1) - size = tableseg->element_delta[n_delta+1] - tableseg->element_delta[n_delta]; - else { - /* use smaller size for last sample if we should */ - if (last_sample_size && k == duration - 1) - size = last_sample_size; - else - size = tableseg->edit_unit_byte_count; - if (tableseg->nb_delta_entries) - size -= tableseg->element_delta[tableseg->nb_delta_entries-1]; - } - if (n_delta < tableseg->nb_delta_entries) - pos += tableseg->element_delta[n_delta]; - flags = AVINDEX_KEYFRAME; - } - - if (last_size_unknown) - st->index_entries[st->nb_index_entries-1].size = pos - last_pos; - - last_size_unknown = size == 0; - last_pos = pos; - - if (mxf_absolute_bodysid_offset(mxf, tableseg->body_sid, pos, &pos) < 0) { - /* probably partial file - no point going further for this stream */ - break; - } - - av_dlog(mxf->fc, "Stream %d IndexEntry %d TrackID %d Offset %"PRIx64" Timestamp %"PRId64"\n", - st->index, st->nb_index_entries, track_id, pos, sample_duration * st->nb_index_entries); - - if ((ret = av_add_index_entry(st, pos, sample_duration * st->nb_index_entries, size, 0, flags)) < 0) - return ret; - } - - if (last_size_unknown) { - int64_t ecl = mxf_essence_container_length(mxf, tableseg->body_sid); - - if (ecl > 0) - st->index_entries[st->nb_index_entries-1].size = ecl - last_pos; - } - - accumulated_offset += segment_size; - } - - return 0; -} - static int mxf_compute_ptses_fake_index(MXFContext *mxf, MXFIndexTable *index_table) { int i, j, x; @@ -1198,8 +1028,10 @@ static int mxf_compute_ptses_fake_index(MXFContext *mxf, MXFIndexTable *index_ta for (i = 0; i < index_table->nb_segments; i++) { MXFIndexTableSegment *s = index_table->segments[i]; - if (!s->nb_index_entries) + if (!s->nb_index_entries) { + index_table->nb_ptses = 0; return 0; /* no TemporalOffsets */ + } index_table->nb_ptses += s->index_duration; } @@ -1249,14 +1081,25 @@ static int mxf_compute_ptses_fake_index(MXFContext *mxf, MXFIndexTable *index_ta for (i = x = 0; i < index_table->nb_segments; i++) { MXFIndexTableSegment *s = index_table->segments[i]; int index_delta = 1; + int n = s->nb_index_entries; - if (s->nb_index_entries == 2 * s->index_duration + 1) + if (s->nb_index_entries == 2 * s->index_duration + 1) { index_delta = 2; /* Avid index */ - for (j = 0; j < s->nb_index_entries; j += index_delta, x++) { + /* ignore the last entry - it's the size of the essence container */ + n--; + } + + for (j = 0; j < n; j += index_delta, x++) { int offset = s->temporal_offset_entries[j] / index_delta; int index = x + offset; + if (x >= index_table->nb_ptses) { + av_log(mxf->fc, AV_LOG_ERROR, "x >= nb_ptses - IndexEntryCount %i < IndexDuration %"PRId64"?\n", + s->nb_index_entries, s->index_duration); + break; + } + index_table->fake_index[x].timestamp = x; index_table->fake_index[x].flags = !(s->flag_entries[j] & 0x30) ? AVINDEX_KEYFRAME : 0; @@ -1371,8 +1214,7 @@ static int mxf_parse_structural_metadata(MXFContext *mxf) { MXFPackage *material_package = NULL; MXFPackage *temp_package = NULL; - int i, j, k, ret, nb_sorted_segments; - MXFIndexTableSegment **sorted_segments = NULL; + int i, j, k, ret; av_dlog(mxf->fc, "metadata sets count %d\n", mxf->metadata_sets_count); /* TODO: handle multiple material packages (OP3x) */ @@ -1385,12 +1227,6 @@ static int mxf_parse_structural_metadata(MXFContext *mxf) return -1; } - 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"); - mxf->broken_index = 1; - } - for (i = 0; i < material_package->tracks_count; i++) { MXFPackage *source_package = NULL; MXFTrack *material_track = NULL; @@ -1449,7 +1285,7 @@ static int mxf_parse_structural_metadata(MXFContext *mxf) break; } } - if (!source_track) + if (!source_track || !component) continue; if (!(source_track->sequence = mxf_resolve_strong_ref(mxf, &source_track->sequence_ref, Sequence))) { @@ -1521,10 +1357,6 @@ static int mxf_parse_structural_metadata(MXFContext *mxf) } } - /* HACK: revert to the old demuxing/seeking scode for D-10 for now */ - if (mxf_match_uid(essence_container_ul, mxf_d10_ul, 14)) - mxf->d10 = 1; - /* TODO: drop PictureEssenceCoding and SoundEssenceCompression, only check EssenceContainer */ codec_ul = mxf_get_codec_ul(ff_mxf_codec_uls, &descriptor->essence_codec_ul); st->codec->codec_id = codec_ul->id; @@ -1547,6 +1379,7 @@ static int mxf_parse_structural_metadata(MXFContext *mxf) st->codec->codec_id = container_ul->id; st->codec->channels = descriptor->channels; st->codec->bits_per_coded_sample = descriptor->bits_per_sample; + if (descriptor->sample_rate.den > 0) 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) { @@ -1567,15 +1400,10 @@ static int mxf_parse_structural_metadata(MXFContext *mxf) /* TODO: decode timestamps */ st->need_parsing = AVSTREAM_PARSE_TIMESTAMPS; } - - if (!mxf->broken_index && - (ret = mxf_parse_index(mxf, material_track->track_id, st, sorted_segments, nb_sorted_segments))) - goto fail_and_free; } ret = 0; fail_and_free: - av_free(sorted_segments); return ret; } @@ -1618,7 +1446,7 @@ static int mxf_read_local_tags(MXFContext *mxf, KLVPacket *klv, MXFMetadataReadF if (!ctx) return -1; - while (avio_tell(pb) + 4 < klv_end) { + while (avio_tell(pb) + 4 < klv_end && !url_feof(pb)) { int tag = avio_rb16(pb); int size = avio_rb16(pb); /* KLV specified by 0x53 */ uint64_t next = avio_tell(pb) + size; @@ -1645,6 +1473,13 @@ static int mxf_read_local_tags(MXFContext *mxf, KLVPacket *klv, MXFMetadataReadF else if (read_child(ctx, pb, tag, size, uid, -1) < 0) return -1; + /* accept the 64k local set limit being exceeded (Avid) + * don't accept it extending past the end of the KLV though (zzuf5.mxf) */ + if (avio_tell(pb) > klv_end) { + av_log(mxf->fc, AV_LOG_ERROR, "local tag %#04x extends past end of local set @ %#"PRIx64"\n", + tag, klv->offset); + return AVERROR_INVALIDDATA; + } else if (avio_tell(pb) <= next) /* only seek forward, else this can loop for a long time */ avio_seek(pb, next, SEEK_SET); } if (ctx_size) ctx->type = type; @@ -1681,11 +1516,6 @@ static int mxf_parse_handle_essence(MXFContext *mxf) AVIOContext *pb = mxf->fc->pb; int64_t ret; - if (!mxf->current_partition) { - av_log(mxf->fc, AV_LOG_ERROR, "found essence prior to PartitionPack\n"); - return AVERROR_INVALIDDATA; - } - if (mxf->parsing_backward) { return mxf_seek_to_previous_partition(mxf); } else { @@ -1753,7 +1583,7 @@ static void mxf_compute_essence_containers(MXFContext *mxf) 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", + av_log(mxf->fc, AV_LOG_ERROR, "partition %i: bad ThisPartition = %" PRIx64 "\n", x+1, mxf->partitions[x+1].this_partition); } } @@ -1801,6 +1631,12 @@ static int mxf_read_header(AVFormatContext *s, AVFormatParameters *ap) IS_KLV_KEY(klv.key, mxf_essence_element_key) || IS_KLV_KEY(klv.key, mxf_avid_essence_element_key) || 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"); + return AVERROR_INVALIDDATA; + } + 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) @@ -1847,6 +1683,14 @@ static int mxf_read_header(AVFormatContext *s, AVFormatParameters *ap) } else { uint64_t next = avio_tell(s->pb) + klv.length; res = metadata->read(mxf, s->pb, 0, klv.length, klv.key, klv.offset); + + /* only seek forward, else this can loop for a long time */ + if (avio_tell(s->pb) > next) { + av_log(s, AV_LOG_ERROR, "read past end of KLV @ %#"PRIx64"\n", + klv.offset); + return AVERROR_INVALIDDATA; + } + avio_seek(s->pb, next, SEEK_SET); } if (res < 0) { @@ -1888,6 +1732,44 @@ static int mxf_read_header(AVFormatContext *s, AVFormatParameters *ap) return 0; } +/** + * Computes DTS and PTS for the given video packet based on its offset. + */ +static void mxf_packet_timestamps(MXFContext *mxf, AVPacket *pkt) +{ + int64_t last_ofs = -1, next_ofs; + 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; + + /* find mxf->current_edit_unit so that the next edit unit starts ahead of pkt->pos */ + 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; + + 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; + } + + if (next_ofs > pkt->pos) + break; + + last_ofs = next_ofs; + mxf->current_edit_unit++; + } + + if (mxf->current_edit_unit < 0 || mxf->current_edit_unit >= t->nb_ptses) + return; + + pkt->dts = mxf->current_edit_unit + t->first_dts; + pkt->pts = t->ptses[mxf->current_edit_unit]; +} + static int mxf_read_packet_old(AVFormatContext *s, AVPacket *pkt) { KLVPacket klv; @@ -1927,6 +1809,10 @@ static int mxf_read_packet_old(AVFormatContext *s, AVPacket *pkt) } 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 */ + return 0; } else skip: @@ -1938,63 +1824,52 @@ static int mxf_read_packet_old(AVFormatContext *s, AVPacket *pkt) static int mxf_read_packet(AVFormatContext *s, AVPacket *pkt) { MXFContext *mxf = s->priv_data; - AVIndexEntry *e; - int ret; - int64_t ret64; - KLVPacket klv; + int ret, size; + int64_t ret64, pos, next_pos; AVStream *st; + MXFIndexTable *t; - /* TODO: better logic for this? - * only files that lack all index segments prior to the essence need this */ - if (!s->pb->seekable && mxf->op != OPAtom || mxf->d10 || mxf->broken_index) + if (mxf->op != OPAtom) return mxf_read_packet_old(s, pkt); - if (mxf->current_stream >= s->nb_streams) { - mxf->current_edit_unit++; - mxf->current_stream = 0; - } - - st = s->streams[mxf->current_stream]; + /* OPAtom - clip wrapped demuxing */ + /* NOTE: mxf_read_header() makes sure nb_index_tables > 0 for OPAtom */ + st = s->streams[0]; + t = &mxf->index_tables[0]; - if (mxf->current_edit_unit >= st->nb_index_entries) + if (mxf->current_edit_unit >= st->duration) return AVERROR_EOF; - e = &st->index_entries[mxf->current_edit_unit]; + if ((ret = mxf_edit_unit_absolute_offset(mxf, t, mxf->current_edit_unit, NULL, &pos, 1)) < 0) + return ret; - if ((ret64 = avio_seek(s->pb, e->pos, SEEK_SET)) < 0) - return ret64; + /* compute size by finding the next edit unit or the end of the essence container + * not pretty, but it works */ + if ((ret = mxf_edit_unit_absolute_offset(mxf, t, mxf->current_edit_unit + 1, NULL, &next_pos, 0)) < 0 && + (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; + } - if (mxf->op == OPAtom) { - /* OPAtom - no KL, just essence */ - if ((ret = av_get_packet(s->pb, pkt, e->size)) != e->size) - return ret < 0 ? ret : AVERROR_EOF; - } else { - /* read KL, read L bytes of essence */ - if ((ret = klv_read_packet(&klv, s->pb)) < 0) - return ret; + if ((size = next_pos - pos) <= 0) { + av_log(s, AV_LOG_ERROR, "bad size: %i\n", size); + return AVERROR_INVALIDDATA; + } - /* untested, but looks OK */ - if (IS_KLV_KEY(klv.key, mxf_encrypted_triplet_key)) { - int res = mxf_decrypt_triplet(s, pkt, &klv); - if (res < 0) { - av_log(s, AV_LOG_ERROR, "invalid encoded triplet\n"); - return -1; - } - return 0; - } + if ((ret64 = avio_seek(s->pb, pos, SEEK_SET)) < 0) + return ret64; - if ((ret = av_get_packet(s->pb, pkt, klv.length)) != klv.length) + if ((ret = av_get_packet(s->pb, pkt, size)) != size) return ret < 0 ? ret : AVERROR_EOF; - pkt->pos = e->pos; + 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]; } - if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO && mxf->ptses && mxf->current_edit_unit < mxf->nb_ptses) { - pkt->dts = mxf->current_edit_unit + mxf->first_dts; - pkt->pts = mxf->ptses[mxf->current_edit_unit]; - } - - pkt->stream_index = mxf->current_stream++; + pkt->stream_index = 0; + mxf->current_edit_unit++; return 0; } @@ -2003,7 +1878,7 @@ static int mxf_read_close(AVFormatContext *s) { MXFContext *mxf = s->priv_data; MXFIndexTableSegment *seg; - int i, j; + int i; av_freep(&mxf->packages_refs); @@ -2024,15 +1899,9 @@ static int mxf_read_close(AVFormatContext *s) break; case IndexTableSegment: seg = (MXFIndexTableSegment *)mxf->metadata_sets[i]; - if (seg->slice_count) - for (j = 0; j < seg->nb_index_entries; j++) - 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); break; default: break; @@ -2043,7 +1912,6 @@ static int mxf_read_close(AVFormatContext *s) av_freep(&mxf->metadata_sets); av_freep(&mxf->aesc); av_freep(&mxf->local_tags); - av_freep(&mxf->ptses); for (i = 0; i < mxf->nb_index_tables; i++) { av_freep(&mxf->index_tables[i].segments); @@ -2078,9 +1946,10 @@ static int mxf_read_seek(AVFormatContext *s, int stream_index, int64_t sample_ti int64_t seconds; MXFContext* mxf = s->priv_data; int64_t seekpos; - int index; + int ret; + MXFIndexTable *t; - if (mxf->d10) { + if (mxf->index_tables <= 0) { if (!s->bit_rate) return -1; if (sample_time < 0) @@ -2090,24 +1959,27 @@ static int mxf_read_seek(AVFormatContext *s, int stream_index, int64_t sample_ti return -1; ff_update_cur_dts(s, st, sample_time); } else { - if (st->nb_index_entries <= 0) - return -1; + t = &mxf->index_tables[0]; - index = av_index_search_timestamp(st, sample_time, flags); + /* 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); - av_dlog(s, "stream %d, timestamp %"PRId64", sample %d\n", st->index, sample_time, index); - - if (index < 0) { - if (sample_time < st->index_entries[0].timestamp) - index = 0; - else - return -1; + 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 */ + sample_time = FFMIN(sample_time, st->duration - 1); } - seekpos = st->index_entries[index].pos; - av_update_cur_dts(s, st, st->index_entries[index].timestamp); - mxf->current_edit_unit = st->index_entries[index].timestamp; - mxf->current_stream = 0; + if ((ret = mxf_edit_unit_absolute_offset(mxf, t, sample_time, &sample_time, &seekpos, 1)) << 0) + return ret; + + av_update_cur_dts(s, st, sample_time); + mxf->current_edit_unit = sample_time; avio_seek(s->pb, seekpos, SEEK_SET); } return 0;