[FFmpeg-devel] [PATCH] avformat/utils: Change compute_chapters_end() from O(n²) to O(n log n)
Michael Niedermayer
michael at niedermayer.cc
Sat Nov 21 19:24:29 EET 2020
Fixes: Timeout (49sec -> 9sec)
Fixes: 27427/clusterfuzz-testcase-minimized-ffmpeg_dem_FFMETADATA_fuzzer-5140589838073856
Found-by: continuous fuzzing process https://github.com/google/oss-fuzz/tree/master/projects/ffmpeg
Signed-off-by: Michael Niedermayer <michael at niedermayer.cc>
---
libavformat/utils.c | 43 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 43 insertions(+)
diff --git a/libavformat/utils.c b/libavformat/utils.c
index 503e583ad0..9fac3fc2aa 100644
--- a/libavformat/utils.c
+++ b/libavformat/utils.c
@@ -3191,15 +3191,58 @@ enum AVCodecID av_codec_get_id(const AVCodecTag *const *tags, unsigned int tag)
return AV_CODEC_ID_NONE;
}
+static int chapter_start_cmp(const void *p1, const void *p2)
+{
+ AVChapter *ch1 = *(AVChapter**)p1;
+ AVChapter *ch2 = *(AVChapter**)p2;
+ int delta = av_compare_ts(ch1->start, ch1->time_base, ch2->start, ch2->time_base);
+ if (delta)
+ return delta;
+ return (ch1 > ch2) - (ch1 < ch2);
+}
+
static void compute_chapters_end(AVFormatContext *s)
{
unsigned int i, j;
int64_t max_time = 0;
+ int computations = 0;
if (s->duration > 0 && s->start_time < INT64_MAX - s->duration)
max_time = s->duration +
((s->start_time == AV_NOPTS_VALUE) ? 0 : s->start_time);
+ for (i = 0; i < s->nb_chapters; i++)
+ if (s->chapters[i]->end == AV_NOPTS_VALUE)
+ computations ++;
+
+ if (computations > 5) {
+ AVChapter **timetable = av_malloc(s->nb_chapters * sizeof(*timetable));
+ if (timetable) {
+ for (i = 0; i < s->nb_chapters; i++)
+ timetable[i] = s->chapters[i];
+ qsort(timetable, s->nb_chapters, sizeof(*timetable), chapter_start_cmp);
+
+ for (i = 0; i < s->nb_chapters; i++)
+ if (timetable[i]->end == AV_NOPTS_VALUE) {
+ AVChapter *ch = timetable[i];
+ int64_t end = max_time ? av_rescale_q(max_time, AV_TIME_BASE_Q,
+ ch->time_base)
+ : INT64_MAX;
+
+ if (i + 1 < s->nb_chapters) {
+ AVChapter *ch1 = timetable[i + 1];
+ int64_t next_start = av_rescale_q(ch1->start, ch1->time_base,
+ ch->time_base);
+ if (next_start > ch->start && next_start < end)
+ end = next_start;
+ }
+ ch->end = (end == INT64_MAX || end < ch->start) ? ch->start : end;
+ }
+ av_free(timetable);
+ return;
+ }
+ }
+
for (i = 0; i < s->nb_chapters; i++)
if (s->chapters[i]->end == AV_NOPTS_VALUE) {
AVChapter *ch = s->chapters[i];
--
2.17.1
More information about the ffmpeg-devel
mailing list