mirror of https://git.ffmpeg.org/ffmpeg.git
lavf/mxfdec: Speed up mxf_edit_unit_absolute_offset()
This involves computing the approximate location of the desired index table segment and linearly searching from there.
This commit is contained in:
parent
e3fa469a55
commit
649ac17efd
|
@ -262,6 +262,7 @@ typedef struct MXFIndexTableSegment {
|
||||||
int *flag_entries;
|
int *flag_entries;
|
||||||
uint64_t *stream_offset_entries;
|
uint64_t *stream_offset_entries;
|
||||||
int nb_index_entries;
|
int nb_index_entries;
|
||||||
|
int64_t offset;
|
||||||
} MXFIndexTableSegment;
|
} MXFIndexTableSegment;
|
||||||
|
|
||||||
typedef struct MXFPackage {
|
typedef struct MXFPackage {
|
||||||
|
@ -1899,18 +1900,44 @@ static int64_t mxf_essence_container_end(MXFContext *mxf, int body_sid)
|
||||||
/* EditUnit -> absolute offset */
|
/* EditUnit -> absolute offset */
|
||||||
static int mxf_edit_unit_absolute_offset(MXFContext *mxf, MXFIndexTable *index_table, int64_t edit_unit, AVRational edit_rate, int64_t *edit_unit_out, int64_t *offset_out, MXFPartition **partition_out, int nag)
|
static int mxf_edit_unit_absolute_offset(MXFContext *mxf, MXFIndexTable *index_table, int64_t edit_unit, AVRational edit_rate, int64_t *edit_unit_out, int64_t *offset_out, MXFPartition **partition_out, int nag)
|
||||||
{
|
{
|
||||||
int i;
|
int i = 0;
|
||||||
int64_t offset_temp = 0;
|
int64_t index_duration, index_end;
|
||||||
|
MXFIndexTableSegment *first_segment, *last_segment;
|
||||||
|
|
||||||
|
if (!index_table->nb_segments) {
|
||||||
|
av_log(mxf->fc, AV_LOG_ERROR, "no index table segments\n");
|
||||||
|
return AVERROR_INVALIDDATA;
|
||||||
|
}
|
||||||
|
|
||||||
edit_unit = av_rescale_q(edit_unit, index_table->segments[0]->index_edit_rate, edit_rate);
|
edit_unit = av_rescale_q(edit_unit, index_table->segments[0]->index_edit_rate, edit_rate);
|
||||||
|
|
||||||
for (i = 0; i < index_table->nb_segments; i++) {
|
first_segment = index_table->segments[0];
|
||||||
|
last_segment = index_table->segments[index_table->nb_segments - 1];
|
||||||
|
|
||||||
|
// clamp to actual range of index
|
||||||
|
index_end = av_sat_add64(last_segment->index_start_position, last_segment->index_duration);
|
||||||
|
edit_unit = FFMAX(FFMIN(edit_unit, index_end), first_segment->index_start_position);
|
||||||
|
|
||||||
|
// guess which table segment this edit unit is in
|
||||||
|
// saturation is fine since it's just a guess
|
||||||
|
// if the guess is wrong we revert to a linear search
|
||||||
|
index_duration = av_sat_sub64(index_end, first_segment->index_start_position);
|
||||||
|
|
||||||
|
// compute the guess, taking care not to cause overflow or division by zero
|
||||||
|
if (index_duration > 0 && edit_unit <= INT64_MAX / index_table->nb_segments) {
|
||||||
|
// a simple linear guesstimate
|
||||||
|
// this is accurate to within +-1 when partitions are generated at a constant rate like mxfenc does
|
||||||
|
int64_t i64 = index_table->nb_segments * edit_unit / index_duration;
|
||||||
|
// clamp and downcast to 32-bit
|
||||||
|
i = FFMAX(0, FFMIN(index_table->nb_segments - 1, i64));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; i >= 0 && i < index_table->nb_segments;) {
|
||||||
MXFIndexTableSegment *s = index_table->segments[i];
|
MXFIndexTableSegment *s = index_table->segments[i];
|
||||||
|
|
||||||
edit_unit = FFMAX(edit_unit, s->index_start_position); /* clamp if trying to seek before start */
|
if (s->index_start_position <= edit_unit && edit_unit < s->index_start_position + s->index_duration) {
|
||||||
|
|
||||||
if (edit_unit < s->index_start_position + s->index_duration) {
|
|
||||||
int64_t index = edit_unit - s->index_start_position;
|
int64_t index = edit_unit - s->index_start_position;
|
||||||
|
int64_t offset_temp = s->offset;
|
||||||
|
|
||||||
if (s->edit_unit_byte_count) {
|
if (s->edit_unit_byte_count) {
|
||||||
if (index > INT64_MAX / s->edit_unit_byte_count ||
|
if (index > INT64_MAX / s->edit_unit_byte_count ||
|
||||||
|
@ -1935,14 +1962,12 @@ static int mxf_edit_unit_absolute_offset(MXFContext *mxf, MXFIndexTable *index_t
|
||||||
*edit_unit_out = av_rescale_q(edit_unit, edit_rate, s->index_edit_rate);
|
*edit_unit_out = av_rescale_q(edit_unit, edit_rate, s->index_edit_rate);
|
||||||
|
|
||||||
return mxf_absolute_bodysid_offset(mxf, index_table->body_sid, offset_temp, offset_out, partition_out);
|
return mxf_absolute_bodysid_offset(mxf, index_table->body_sid, offset_temp, offset_out, partition_out);
|
||||||
|
} else if (edit_unit < s->index_start_position) {
|
||||||
|
// the segments are sorted by IndexStartPosition, so this is guaranteed to terminate
|
||||||
|
i--;
|
||||||
} else {
|
} else {
|
||||||
/* EditUnitByteCount == 0 for VBR indexes, which is fine since they use explicit StreamOffsets */
|
// edit_unit >= s->index_start_position + s->index_duration
|
||||||
if (s->edit_unit_byte_count && (s->index_duration > INT64_MAX / s->edit_unit_byte_count ||
|
i++;
|
||||||
s->edit_unit_byte_count * s->index_duration > INT64_MAX - offset_temp)
|
|
||||||
)
|
|
||||||
return AVERROR_INVALIDDATA;
|
|
||||||
|
|
||||||
offset_temp += s->edit_unit_byte_count * s->index_duration;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2127,6 +2152,7 @@ static int mxf_compute_index_tables(MXFContext *mxf)
|
||||||
for (int i = 0, j = 0; j < mxf->nb_index_tables; i += mxf->index_tables[j++].nb_segments) {
|
for (int i = 0, j = 0; j < mxf->nb_index_tables; i += mxf->index_tables[j++].nb_segments) {
|
||||||
MXFIndexTable *t = &mxf->index_tables[j];
|
MXFIndexTable *t = &mxf->index_tables[j];
|
||||||
MXFTrack *mxf_track = NULL;
|
MXFTrack *mxf_track = NULL;
|
||||||
|
int64_t offset_temp = 0;
|
||||||
|
|
||||||
t->segments = av_calloc(t->nb_segments, sizeof(*t->segments));
|
t->segments = av_calloc(t->nb_segments, sizeof(*t->segments));
|
||||||
if (!t->segments) {
|
if (!t->segments) {
|
||||||
|
@ -2155,8 +2181,10 @@ static int mxf_compute_index_tables(MXFContext *mxf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fix zero IndexDurations */
|
/* fix zero IndexDurations and compute segment offsets */
|
||||||
for (int k = 0; k < t->nb_segments; k++) {
|
for (int k = 0; k < t->nb_segments; k++) {
|
||||||
|
MXFIndexTableSegment *s = t->segments[k];
|
||||||
|
|
||||||
if (!t->segments[k]->index_edit_rate.num || !t->segments[k]->index_edit_rate.den) {
|
if (!t->segments[k]->index_edit_rate.num || !t->segments[k]->index_edit_rate.den) {
|
||||||
av_log(mxf->fc, AV_LOG_WARNING, "IndexSID %i segment %i has invalid IndexEditRate\n",
|
av_log(mxf->fc, AV_LOG_WARNING, "IndexSID %i segment %i has invalid IndexEditRate\n",
|
||||||
t->index_sid, k);
|
t->index_sid, k);
|
||||||
|
@ -2164,6 +2192,17 @@ static int mxf_compute_index_tables(MXFContext *mxf)
|
||||||
t->segments[k]->index_edit_rate = mxf_track->edit_rate;
|
t->segments[k]->index_edit_rate = mxf_track->edit_rate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s->offset = offset_temp;
|
||||||
|
|
||||||
|
/* EditUnitByteCount == 0 for VBR indexes, which is fine since they use explicit StreamOffsets */
|
||||||
|
if (s->edit_unit_byte_count && (s->index_duration > INT64_MAX / s->edit_unit_byte_count ||
|
||||||
|
s->edit_unit_byte_count * s->index_duration > INT64_MAX - offset_temp)) {
|
||||||
|
ret = AVERROR_INVALIDDATA;
|
||||||
|
goto finish_decoding_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset_temp += t->segments[k]->edit_unit_byte_count * t->segments[k]->index_duration;
|
||||||
|
|
||||||
if (t->segments[k]->index_duration)
|
if (t->segments[k]->index_duration)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue