[FFmpeg-devel] [PATCH v2 15/17] avformat/matroskaenc: Use av_fast_realloc_array for index entries

Andreas Rheinhardt andreas.rheinhardt at gmail.com
Wed Jan 1 15:46:56 EET 2020


Currently, the Matroska muxer reallocates its array of index entries
each time another entry is added. This is bad performance-wise,
especially on Windows where reallocations are slow. This is solved
by switching to av_fast_realloc_array() which ensures that actual
reallocations will happen only seldomly.

For an (admittedly extreme) example which consists of looping a video
consisting of a single keyframe of size 4KB 540000 times this improved
the time for writing a frame from 23524201 decicycles (516466 runs,
7822 skips) to 225240 decicycles (522122 runs, 2166 skips) on Windows.

(Writing CRC-32 elements was disabled for these tests.)

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt at gmail.com>
---
This patch will lead to a merge conflict with my recent Matroska muxer
patchset [1] (in particular, [2]), but it is trivially fixable. I will
update the other patchset as soon as one gets applied.

[1]: https://ffmpeg.org/pipermail/ffmpeg-devel/2020-January/255139.html
[2]: https://ffmpeg.org/pipermail/ffmpeg-devel/2020-January/255151.html

 libavformat/matroskaenc.c | 26 ++++++++++++++------------
 1 file changed, 14 insertions(+), 12 deletions(-)

diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c
index 469b604de6..2f5f8873db 100644
--- a/libavformat/matroskaenc.c
+++ b/libavformat/matroskaenc.c
@@ -88,7 +88,8 @@ typedef struct mkv_cuepoint {
 typedef struct mkv_cues {
     int64_t         segment_offset;
     mkv_cuepoint    *entries;
-    int             num_entries;
+    unsigned        num_entries;
+    unsigned        allocated_entries;
 } mkv_cues;
 
 typedef struct mkv_track {
@@ -171,7 +172,7 @@ typedef struct MatroskaMuxContext {
 
 /** per-cuepoint-track - 5 1-byte EBML IDs, 5 1-byte EBML sizes, 3 8-byte uint max
  * and one 1-byte uint for the track number (this assumes MAX_TRACKS to be <= 255) */
-#define MAX_CUETRACKPOS_SIZE 35
+#define MAX_CUETRACKPOS_SIZE 35LL
 
 /** per-cuepoint - 1 1-byte EBML ID, 1 1-byte EBML size, 8-byte uint max */
 #define MAX_CUEPOINT_CONTENT_SIZE(num_tracks) 10 + MAX_CUETRACKPOS_SIZE * num_tracks
@@ -535,15 +536,16 @@ static mkv_cues *mkv_start_cues(int64_t segment_offset)
 static int mkv_add_cuepoint(mkv_cues *cues, int stream, int tracknum, int64_t ts,
                             int64_t cluster_pos, int64_t relative_pos, int64_t duration)
 {
-    mkv_cuepoint *entries = cues->entries;
+    int ret;
 
     if (ts < 0)
         return 0;
 
-    entries = av_realloc_array(entries, cues->num_entries + 1, sizeof(mkv_cuepoint));
-    if (!entries)
-        return AVERROR(ENOMEM);
-    cues->entries = entries;
+    ret = av_fast_realloc_array(&cues->entries, &cues->allocated_entries,
+                                cues->num_entries + 1, UINT_MAX - 1,
+                                sizeof(*cues->entries));
+    if (ret < 0)
+        return ret;
 
     cues->entries[cues->num_entries].pts           = ts;
     cues->entries[cues->num_entries].stream_idx    = stream;
@@ -560,21 +562,21 @@ static int64_t mkv_write_cues(AVFormatContext *s, mkv_cues *cues, mkv_track *tra
     MatroskaMuxContext *mkv = s->priv_data;
     AVIOContext *dyn_cp, *pb = s->pb;
     int64_t currentpos;
-    int i, j, ret;
+    int ret;
 
     currentpos = avio_tell(pb);
     ret = start_ebml_master_crc32(pb, &dyn_cp, mkv, MATROSKA_ID_CUES);
     if (ret < 0)
         return ret;
 
-    for (i = 0; i < cues->num_entries; i++) {
+    for (unsigned i = 0; i < cues->num_entries; i++) {
         ebml_master cuepoint, track_positions;
         mkv_cuepoint *entry = &cues->entries[i];
         uint64_t pts = entry->pts;
-        int ctp_nb = 0;
+        unsigned ctp_nb = 0, j;
 
         // Calculate the number of entries, so we know the element size
-        for (j = 0; j < num_tracks; j++)
+        for (int j = 0; j < num_tracks; j++)
             tracks[j].has_cue = 0;
         for (j = 0; j < cues->num_entries - i && entry[j].pts == pts; j++) {
             int idx = entry[j].stream_idx;
@@ -591,7 +593,7 @@ static int64_t mkv_write_cues(AVFormatContext *s, mkv_cues *cues, mkv_track *tra
 
         // put all the entries from different tracks that have the exact same
         // timestamp into the same CuePoint
-        for (j = 0; j < num_tracks; j++)
+        for (int j = 0; j < num_tracks; j++)
             tracks[j].has_cue = 0;
         for (j = 0; j < cues->num_entries - i && entry[j].pts == pts; j++) {
             int idx = entry[j].stream_idx;
-- 
2.20.1



More information about the ffmpeg-devel mailing list