X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;ds=sidebyside;f=libavformat%2Fmxfdec.c;h=e0a4b5bd11e6a9683506d363f4881c3160ea336f;hb=f50741147ccac999a8a3e8a15244cbe525537622;hp=4f30877f6d659e3ba3064d682bc112c709b08339;hpb=9492bb58eeea474158f9c523fd77395629117b57;p=ffmpeg diff --git a/libavformat/mxfdec.c b/libavformat/mxfdec.c index 4f30877f6d6..e0a4b5bd11e 100644 --- a/libavformat/mxfdec.c +++ b/libavformat/mxfdec.c @@ -91,6 +91,7 @@ typedef struct MXFPartition { int64_t index_byte_count; int pack_length; int64_t pack_ofs; ///< absolute offset of pack in file, including run-in + int64_t body_offset; } MXFPartition; typedef struct MXFCryptoContext { @@ -612,7 +613,7 @@ static int mxf_read_partition_pack(void *arg, AVIOContext *pb, int tag, int size 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_offset = avio_rb64(pb); partition->body_sid = avio_rb32(pb); if (avio_read(pb, op, sizeof(UID)) != sizeof(UID)) { av_log(mxf->fc, AV_LOG_ERROR, "Failed reading UID\n"); @@ -1309,9 +1310,15 @@ static int mxf_get_sorted_table_segments(MXFContext *mxf, int *nb_sorted_segment * 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 || - (s->index_start_position == best_index_start && s->index_duration > best_index_duration))) { + if ((i == 0 || + s->body_sid > last_body_sid || + s->body_sid == last_body_sid && s->index_sid > last_index_sid || + 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->body_sid == best_body_sid && s->index_sid < best_index_sid || + s->body_sid == best_body_sid && s->index_sid == best_index_sid && s->index_start_position < best_index_start || + s->body_sid == best_body_sid && s->index_sid == best_index_sid && 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; @@ -1341,7 +1348,10 @@ static int mxf_get_sorted_table_segments(MXFContext *mxf, int *nb_sorted_segment 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 */ + MXFPartition *last_p = NULL; + + if (offset < 0) + return AVERROR(EINVAL); for (x = 0; x < mxf->partitions_count; x++) { MXFPartition *p = &mxf->partitions[x]; @@ -1349,17 +1359,20 @@ static int mxf_absolute_bodysid_offset(MXFContext *mxf, int body_sid, int64_t of if (p->body_sid != body_sid) continue; - if (offset < p->essence_length || !p->essence_length) { - *offset_out = p->essence_offset + offset; - return 0; - } + if (p->body_offset > offset) + break; + + last_p = p; + } - offset -= p->essence_length; + if (last_p && (!last_p->essence_length || last_p->essence_length > (offset - last_p->body_offset))) { + *offset_out = last_p->essence_offset + (offset - last_p->body_offset); + return 0; } av_log(mxf->fc, AV_LOG_ERROR, "failed to find absolute offset of %"PRIX64" in BodySID %i - partial file?\n", - offset_in, body_sid); + offset, body_sid); return AVERROR_INVALIDDATA; } @@ -1558,14 +1571,6 @@ static int mxf_compute_index_tables(MXFContext *mxf) { int i, j, k, ret, nb_sorted_segments; MXFIndexTableSegment **sorted_segments = NULL; - AVStream *st = NULL; - - for (i = 0; i < mxf->fc->nb_streams; i++) { - if (mxf->fc->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_DATA) - continue; - st = mxf->fc->streams[i]; - break; - } if ((ret = mxf_get_sorted_table_segments(mxf, &nb_sorted_segments, &sorted_segments)) || nb_sorted_segments <= 0) { @@ -1604,6 +1609,7 @@ 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]; + MXFTrack *mxf_track = NULL; t->segments = av_mallocz_array(t->nb_segments, sizeof(*t->segments)); @@ -1626,6 +1632,14 @@ static int mxf_compute_index_tables(MXFContext *mxf) if ((ret = mxf_compute_ptses_fake_index(mxf, t)) < 0) goto finish_decoding_index; + for (k = 0; k < mxf->fc->nb_streams; k++) { + MXFTrack *track = mxf->fc->streams[k]->priv_data; + if (track && track->index_sid == t->index_sid) { + mxf_track = track; + break; + } + } + /* fix zero IndexDurations */ for (k = 0; k < t->nb_segments; k++) { if (t->segments[k]->index_duration) @@ -1635,7 +1649,7 @@ static int mxf_compute_index_tables(MXFContext *mxf) 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 (!st) { + if (!mxf_track) { av_log(mxf->fc, AV_LOG_WARNING, "no streams?\n"); break; } @@ -1643,7 +1657,7 @@ static int mxf_compute_index_tables(MXFContext *mxf) /* 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 = st->duration; + t->segments[k]->index_duration = mxf_track->original_duration; break; } } @@ -3041,6 +3055,42 @@ fail: return ret; } +static MXFIndexTable *mxf_find_index_table(MXFContext *mxf, int index_sid) +{ + int i; + for (i = 0; i < mxf->nb_index_tables; i++) + if (mxf->index_tables[i].index_sid == index_sid) + return &mxf->index_tables[i]; + return NULL; +} + +/* Get the edit unit of the next packet from current_offset in a track. The returned edit unit can be original_duration as well! */ +static int mxf_get_next_track_edit_unit(MXFContext *mxf, MXFTrack *track, int64_t current_offset, int64_t *edit_unit_out) +{ + int64_t a, b, m, offset; + MXFIndexTable *t = mxf_find_index_table(mxf, track->index_sid); + + if (!t || track->original_duration <= 0) + return -1; + + a = -1; + b = track->original_duration; + + while (b - a > 1) { + m = (a + b) >> 1; + if (mxf_edit_unit_absolute_offset(mxf, t, m, NULL, &offset, 0) < 0) + return -1; + if (offset < current_offset) + a = m; + else + b = m; + } + + *edit_unit_out = b; + + return 0; +} + /** * Sets mxf->current_edit_unit based on what offset we're currently at. * @return next_ofs if OK, <0 on error @@ -3401,6 +3451,20 @@ static int mxf_read_seek(AVFormatContext *s, int stream_index, int64_t sample_ti mxf->current_edit_unit = sample_time; } else { t = &mxf->index_tables[0]; + if (t->index_sid != source_track->index_sid) { + /* If the first index table does not belong to the stream, then find a stream which does belong to the index table */ + for (i = 0; i < s->nb_streams; i++) { + MXFTrack *new_source_track = s->streams[i]->priv_data; + if (new_source_track && new_source_track->index_sid == t->index_sid) { + sample_time = av_rescale_q(sample_time, new_source_track->edit_rate, source_track->edit_rate); + source_track = new_source_track; + st = s->streams[i]; + break; + } + } + if (i == s->nb_streams) + return AVERROR_INVALIDDATA; + } /* clamp above zero, else ff_index_search_timestamp() returns negative * this also means we allow seeking before the start */ @@ -3440,13 +3504,19 @@ static int mxf_read_seek(AVFormatContext *s, int stream_index, int64_t sample_ti 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->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { - ret = mxf_compute_sample_count(mxf, i, ¤t_sample_count); - if (ret < 0) - return ret; - - cur_track->sample_count = current_sample_count; + int64_t track_edit_unit; + if (st != cur_st && mxf_get_next_track_edit_unit(mxf, cur_track, seekpos, &track_edit_unit) >= 0) { + cur_track->sample_count = av_rescale_q(track_edit_unit, + av_inv_q(cur_track->edit_rate), + cur_st->time_base); + } else { + uint64_t current_sample_count = 0; + ret = mxf_compute_sample_count(mxf, i, ¤t_sample_count); + if (ret < 0) + return ret; + cur_track->sample_count = current_sample_count; + } } } return 0;