diff mbox series

[FFmpeg-devel,v2,07/30] avformat/matroskaenc: Avoid allocations for SeekHead

Message ID 20200313220349.12974-1-andreas.rheinhardt@gmail.com
State Accepted
Headers show
Series Untitled series #536
Related show

Commit Message

Andreas Rheinhardt March 13, 2020, 10:03 p.m. UTC
Up until e7ddafd5, the Matroska muxer wrote two SeekHeads: One at the
beginning referencing the main level 1 elements (i.e. not the Clusters)
and one at the end, referencing the Clusters. This second SeekHead was
useless and has therefore been removed. Yet the SeekHead-related
functions and structures are still geared towards this usecase: They
are built around an allocated array of variable size that gets
reallocated every time an element is added to it although the maximum
number of Seek entries is a small compile-time constant, so that one should
rather include the array in the SeekHead structure itself; and said
structure should be contained in the MatroskaMuxContext instead of being
allocated separately.

The earlier code reserved space for a SeekHead with 10 entries, although
we currently write at most 6. Reducing said number implied that every
Matroska/Webm file will be 84 bytes smaller and required to adapt
several FATE tests; furthermore, the reserved amount overestimated the
amount needed for for the SeekHead's length field and how many bytes
need to be reserved to write a EBML Void element, bringing the total
reduction to 89 bytes.

This also fixes a potential segfault: If !mkv->is_live and if the
AVIOContext is initially unseekable when writing the header, the
SeekHead is already written when writing the header and this used to
free the SeekHead-related structures that have been allocated. But if
the AVIOContext happens to be seekable when writing the trailer, it will
be attempted to write the SeekHead again which will lead to segfaults
because the corresponding structures have already been freed.

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@gmail.com>
---
1. Changing seekability doesn't seem to happen in real life: Before
add68dcc (merged last April) the writing process for all level 1
elements was different depending upon whether the output was seekable
or not; if it switched between seekable and unseekable, the output would
be corrupt, yet no one reported this.
2. Only the commit message has been modified; the content of this patch
is unchanged since last time.
3. Changing seekability would still not go well. I'll work on it.

 libavformat/matroskaenc.c            | 119 ++++++++-------------------
 tests/fate/matroska.mak              |   2 +-
 tests/fate/wavpack.mak               |   4 +-
 tests/ref/fate/aac-autobsf-adtstoasc |   4 +-
 tests/ref/fate/binsub-mksenc         |   2 +-
 tests/ref/fate/rgb24-mkv             |   4 +-
 tests/ref/lavf-fate/av1.mkv          |   4 +-
 tests/ref/lavf/mka                   |   4 +-
 tests/ref/lavf/mkv                   |   4 +-
 tests/ref/lavf/mkv_attachment        |   4 +-
 tests/ref/seek/lavf-mkv              |  44 +++++-----
 11 files changed, 73 insertions(+), 122 deletions(-)

Comments

Andreas Rheinhardt March 18, 2020, 3:58 p.m. UTC | #1
Andreas Rheinhardt:
> Up until e7ddafd5, the Matroska muxer wrote two SeekHeads: One at the
> beginning referencing the main level 1 elements (i.e. not the Clusters)
> and one at the end, referencing the Clusters. This second SeekHead was
> useless and has therefore been removed. Yet the SeekHead-related
> functions and structures are still geared towards this usecase: They
> are built around an allocated array of variable size that gets
> reallocated every time an element is added to it although the maximum
> number of Seek entries is a small compile-time constant, so that one should
> rather include the array in the SeekHead structure itself; and said
> structure should be contained in the MatroskaMuxContext instead of being
> allocated separately.
> 
> The earlier code reserved space for a SeekHead with 10 entries, although
> we currently write at most 6. Reducing said number implied that every
> Matroska/Webm file will be 84 bytes smaller and required to adapt
> several FATE tests; furthermore, the reserved amount overestimated the
> amount needed for for the SeekHead's length field and how many bytes
> need to be reserved to write a EBML Void element, bringing the total
> reduction to 89 bytes.
> 
> This also fixes a potential segfault: If !mkv->is_live and if the
> AVIOContext is initially unseekable when writing the header, the
> SeekHead is already written when writing the header and this used to
> free the SeekHead-related structures that have been allocated. But if
> the AVIOContext happens to be seekable when writing the trailer, it will
> be attempted to write the SeekHead again which will lead to segfaults
> because the corresponding structures have already been freed.
> 
> Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@gmail.com>
> ---
> 1. Changing seekability doesn't seem to happen in real life: Before
> add68dcc (merged last April) the writing process for all level 1
> elements was different depending upon whether the output was seekable
> or not; if it switched between seekable and unseekable, the output would
> be corrupt, yet no one reported this.
> 2. Only the commit message has been modified; the content of this patch
> is unchanged since last time.
> 3. Changing seekability would still not go well. I'll work on it.
> 
>  libavformat/matroskaenc.c            | 119 ++++++++-------------------
>  tests/fate/matroska.mak              |   2 +-
>  tests/fate/wavpack.mak               |   4 +-
>  tests/ref/fate/aac-autobsf-adtstoasc |   4 +-
>  tests/ref/fate/binsub-mksenc         |   2 +-
>  tests/ref/fate/rgb24-mkv             |   4 +-
>  tests/ref/lavf-fate/av1.mkv          |   4 +-
>  tests/ref/lavf/mka                   |   4 +-
>  tests/ref/lavf/mkv                   |   4 +-
>  tests/ref/lavf/mkv_attachment        |   4 +-
>  tests/ref/seek/lavf-mkv              |  44 +++++-----
>  11 files changed, 73 insertions(+), 122 deletions(-)
> 
Ping. (The actual patch has been left out because of its length, but it
can be found at [1].)

- Andreas

[1]: https://ffmpeg.org/pipermail/ffmpeg-devel/2020-March/258390.html
diff mbox series

Patch

diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c
index 42f21eae8b..99ea3c6bf1 100644
--- a/libavformat/matroskaenc.c
+++ b/libavformat/matroskaenc.c
@@ -57,6 +57,10 @@ 
 #include "libavcodec/mpeg4audio.h"
 #include "libavcodec/internal.h"
 
+/* Level 1 elements we create a SeekHead entry for:
+ * Info, Tracks, Chapters, Attachments, Tags and Cues */
+#define MAX_SEEKHEAD_ENTRIES 6
+
 typedef struct ebml_master {
     int64_t         pos;                ///< absolute offset in the containing AVIOContext where the master's elements start
     int             sizebytes;          ///< how many bytes were reserved for the size
@@ -69,11 +73,9 @@  typedef struct mkv_seekhead_entry {
 
 typedef struct mkv_seekhead {
     int64_t                 filepos;
-    int64_t                 segment_offset;     ///< the file offset to the beginning of the segment
-    int                     reserved_size;      ///< -1 if appending to file
-    int                     max_entries;
-    mkv_seekhead_entry      *entries;
+    mkv_seekhead_entry      entries[MAX_SEEKHEAD_ENTRIES];
     int                     num_entries;
+    int                     reserved_size;
 } mkv_seekhead;
 
 typedef struct mkv_cuepoint {
@@ -136,7 +138,7 @@  typedef struct MatroskaMuxContext {
     int64_t         cluster_pts;
     int64_t         duration_offset;
     int64_t         duration;
-    mkv_seekhead    *seekhead;
+    mkv_seekhead    seekhead;
     mkv_cues        *cues;
     mkv_track       *tracks;
     mkv_attachments *attachments;
@@ -396,10 +398,6 @@  static void mkv_deinit(AVFormatContext *s)
     ffio_free_dyn_buf(&mkv->tracks_bc);
     ffio_free_dyn_buf(&mkv->tags_bc);
 
-    if (mkv->seekhead) {
-        av_freep(&mkv->seekhead->entries);
-        av_freep(&mkv->seekhead);
-    }
     if (mkv->cues) {
         av_freep(&mkv->cues->entries);
         av_freep(&mkv->cues);
@@ -412,61 +410,33 @@  static void mkv_deinit(AVFormatContext *s)
 }
 
 /**
- * Initialize a mkv_seekhead element to be ready to index level 1 Matroska
- * elements. If a maximum number of elements is specified, enough space
- * will be reserved at the current file location to write a seek head of
- * that size.
- *
- * @param segment_offset The absolute offset to the position in the file
- *                       where the segment begins.
- * @param numelements The maximum number of elements that will be indexed
- *                    by this seek head, 0 if unlimited.
+ * Initialize the SeekHead element to be ready to index level 1 Matroska
+ * elements. Enough space to write MAX_SEEKHEAD_ENTRIES SeekHead entries
+ * will be reserved at the current file location.
  */
-static mkv_seekhead *mkv_start_seekhead(AVIOContext *pb, int64_t segment_offset,
-                                        int numelements)
+static void mkv_start_seekhead(MatroskaMuxContext *mkv, AVIOContext *pb)
 {
-    mkv_seekhead *new_seekhead = av_mallocz(sizeof(mkv_seekhead));
-    if (!new_seekhead)
-        return NULL;
-
-    new_seekhead->segment_offset = segment_offset;
-
-    if (numelements > 0) {
-        new_seekhead->filepos = avio_tell(pb);
-        // 21 bytes max for a seek entry, 10 bytes max for the SeekHead ID
-        // and size, 6 bytes for a CRC32 element, and 3 bytes to guarantee
-        // that an EBML void element will fit afterwards
-        new_seekhead->reserved_size = numelements * MAX_SEEKENTRY_SIZE + 19;
-        new_seekhead->max_entries   = numelements;
-        put_ebml_void(pb, new_seekhead->reserved_size);
-    }
-    return new_seekhead;
+    mkv->seekhead.filepos = avio_tell(pb);
+    // 21 bytes max for a Seek entry, 6 bytes max for the SeekHead ID
+    // and size, 6 bytes for a CRC32 element, and 2 bytes to guarantee
+    // that an EBML void element will fit afterwards
+    mkv->seekhead.reserved_size = MAX_SEEKHEAD_ENTRIES * MAX_SEEKENTRY_SIZE + 14;
+    put_ebml_void(pb, mkv->seekhead.reserved_size);
 }
 
-static int mkv_add_seekhead_entry(mkv_seekhead *seekhead, uint32_t elementid, uint64_t filepos)
+static void mkv_add_seekhead_entry(MatroskaMuxContext *mkv, uint32_t elementid,
+                                   uint64_t filepos)
 {
-    mkv_seekhead_entry *entries = seekhead->entries;
+    mkv_seekhead *seekhead = &mkv->seekhead;
 
-    // don't store more elements than we reserved space for
-    if (seekhead->max_entries > 0 && seekhead->max_entries <= seekhead->num_entries)
-        return -1;
-
-    entries = av_realloc_array(entries, seekhead->num_entries + 1, sizeof(mkv_seekhead_entry));
-    if (!entries)
-        return AVERROR(ENOMEM);
-    seekhead->entries = entries;
+    av_assert1(seekhead->num_entries < MAX_SEEKHEAD_ENTRIES);
 
     seekhead->entries[seekhead->num_entries].elementid    = elementid;
-    seekhead->entries[seekhead->num_entries++].segmentpos = filepos - seekhead->segment_offset;
-
-    return 0;
+    seekhead->entries[seekhead->num_entries++].segmentpos = filepos - mkv->segment_offset;
 }
 
 /**
- * Write the seek head to the file and free it. If a maximum number of
- * elements was specified to mkv_start_seekhead(), the seek head will
- * be written at the location reserved for it. Otherwise, it is written
- * at the current location in the file.
+ * Write the SeekHead to the file at the location reserved for it.
  *
  * @return The file offset where the seekhead was written,
  * -1 if an error occurred.
@@ -474,19 +444,17 @@  static int mkv_add_seekhead_entry(mkv_seekhead *seekhead, uint32_t elementid, ui
 static int64_t mkv_write_seekhead(AVIOContext *pb, MatroskaMuxContext *mkv)
 {
     AVIOContext *dyn_cp;
-    mkv_seekhead *seekhead = mkv->seekhead;
+    mkv_seekhead *seekhead = &mkv->seekhead;
     ebml_master seekentry;
-    int64_t currentpos;
+    int64_t currentpos, remaining;
     int i;
 
     currentpos = avio_tell(pb);
 
-    if (seekhead->reserved_size > 0) {
         if (avio_seek(pb, seekhead->filepos, SEEK_SET) < 0) {
             currentpos = -1;
             goto fail;
         }
-    }
 
     if (start_ebml_master_crc32(pb, &dyn_cp, mkv, MATROSKA_ID_SEEKHEAD) < 0) {
         currentpos = -1;
@@ -507,16 +475,13 @@  static int64_t mkv_write_seekhead(AVIOContext *pb, MatroskaMuxContext *mkv)
     }
     end_ebml_master_crc32(pb, &dyn_cp, mkv);
 
-    if (seekhead->reserved_size > 0) {
-        uint64_t remaining = seekhead->filepos + seekhead->reserved_size - avio_tell(pb);
+    remaining = seekhead->filepos + seekhead->reserved_size - avio_tell(pb);
         put_ebml_void(pb, remaining);
         avio_seek(pb, currentpos, SEEK_SET);
 
         currentpos = seekhead->filepos;
-    }
+
 fail:
-    av_freep(&mkv->seekhead->entries);
-    av_freep(&mkv->seekhead);
 
     return currentpos;
 }
@@ -1429,9 +1394,7 @@  static int mkv_write_tracks(AVFormatContext *s)
     AVIOContext *pb = s->pb;
     int i, ret, default_stream_exists = 0;
 
-    ret = mkv_add_seekhead_entry(mkv->seekhead, MATROSKA_ID_TRACKS, avio_tell(pb));
-    if (ret < 0)
-        return ret;
+    mkv_add_seekhead_entry(mkv, MATROSKA_ID_TRACKS, avio_tell(pb));
 
     ret = start_ebml_master_crc32(pb, &mkv->tracks_bc, mkv, MATROSKA_ID_TRACKS);
     if (ret < 0)
@@ -1466,8 +1429,7 @@  static int mkv_write_chapters(AVFormatContext *s)
     if (!s->nb_chapters || mkv->wrote_chapters)
         return 0;
 
-    ret = mkv_add_seekhead_entry(mkv->seekhead, MATROSKA_ID_CHAPTERS, avio_tell(pb));
-    if (ret < 0) return ret;
+    mkv_add_seekhead_entry(mkv, MATROSKA_ID_CHAPTERS, avio_tell(pb));
 
     ret = start_ebml_master_crc32(pb, &dyn_cp, mkv, MATROSKA_ID_CHAPTERS);
     if (ret < 0) return ret;
@@ -1556,8 +1518,7 @@  static int mkv_write_tag_targets(AVFormatContext *s, uint32_t elementid,
     int ret;
 
     if (!mkv->tags_bc) {
-        ret = mkv_add_seekhead_entry(mkv->seekhead, MATROSKA_ID_TAGS, avio_tell(s->pb));
-        if (ret < 0) return ret;
+        mkv_add_seekhead_entry(mkv, MATROSKA_ID_TAGS, avio_tell(s->pb));
 
         ret = start_ebml_master_crc32(s->pb, &mkv->tags_bc, mkv, MATROSKA_ID_TAGS);
         if (ret < 0)
@@ -1727,8 +1688,7 @@  static int mkv_write_attachments(AVFormatContext *s)
 
     av_lfg_init(&c, av_get_random_seed());
 
-    ret = mkv_add_seekhead_entry(mkv->seekhead, MATROSKA_ID_ATTACHMENTS, avio_tell(pb));
-    if (ret < 0) return ret;
+    mkv_add_seekhead_entry(mkv, MATROSKA_ID_ATTACHMENTS, avio_tell(pb));
 
     ret = start_ebml_master_crc32(pb, &dyn_cp, mkv, MATROSKA_ID_ATTACHMENTS);
     if (ret < 0) return ret;
@@ -1877,16 +1837,10 @@  static int mkv_write_header(AVFormatContext *s)
     mkv->segment_offset = avio_tell(pb);
 
     // we write a seek head at the beginning to point to all other level
-    // one elements, which aren't more than 10 elements as we write only one
-    // of every other currently defined level 1 element
-    mkv->seekhead = mkv_start_seekhead(pb, mkv->segment_offset, 10);
-    if (!mkv->seekhead) {
-        return AVERROR(ENOMEM);
-    }
+    // one elements (except Clusters).
+    mkv_start_seekhead(mkv, pb);
 
-    ret = mkv_add_seekhead_entry(mkv->seekhead, MATROSKA_ID_INFO, avio_tell(pb));
-    if (ret < 0)
-        return ret;
+    mkv_add_seekhead_entry(mkv, MATROSKA_ID_INFO, avio_tell(pb));
 
     ret = start_ebml_master_crc32(pb, &mkv->info_bc, mkv, MATROSKA_ID_INFO);
     if (ret < 0)
@@ -2576,10 +2530,7 @@  static int mkv_write_trailer(AVFormatContext *s)
                 cuespos = mkv_write_cues(s, mkv->cues, mkv->tracks, s->nb_streams);
             }
 
-            ret = mkv_add_seekhead_entry(mkv->seekhead, MATROSKA_ID_CUES,
-                                         cuespos);
-            if (ret < 0)
-                return ret;
+            mkv_add_seekhead_entry(mkv, MATROSKA_ID_CUES, cuespos);
         }
 
         mkv_write_seekhead(pb, mkv);
diff --git a/tests/fate/matroska.mak b/tests/fate/matroska.mak
index 4aca4dc8eb..b9ed7322fd 100644
--- a/tests/fate/matroska.mak
+++ b/tests/fate/matroska.mak
@@ -12,7 +12,7 @@  fate-matroska-prores-header-insertion-bz2: CMD = framecrc -i $(TARGET_SAMPLES)/m
 FATE_MATROSKA-$(call DEMMUX, MATROSKA, MATROSKA) += fate-matroska-remux
 fate-matroska-remux: CMD = md5pipe -i $(TARGET_SAMPLES)/vp9-test-vectors/vp90-2-2pass-akiyo.webm -color_trc 4 -c:v copy -fflags +bitexact -strict -2 -f matroska
 fate-matroska-remux: CMP = oneline
-fate-matroska-remux: REF = e5457e5fa606d564a54914bd12f426c8
+fate-matroska-remux: REF = 49a60ef91cf7302ab7276f9373f8a429
 
 FATE_MATROSKA-$(call ALLYES, MATROSKA_DEMUXER VORBIS_PARSER) += fate-matroska-xiph-lacing
 fate-matroska-xiph-lacing: CMD = framecrc -i $(TARGET_SAMPLES)/mkv/xiph_lacing.mka -c:a copy
diff --git a/tests/fate/wavpack.mak b/tests/fate/wavpack.mak
index 286e17f2ae..a89cc1293d 100644
--- a/tests/fate/wavpack.mak
+++ b/tests/fate/wavpack.mak
@@ -91,12 +91,12 @@  fate-wavpack-matroskamode: CMD = md5 -i $(TARGET_SAMPLES)/wavpack/special/matros
 FATE_WAVPACK-$(call DEMMUX, WV, MATROSKA) += fate-wavpack-matroska_mux-mono
 fate-wavpack-matroska_mux-mono: CMD = md5pipe -i $(TARGET_SAMPLES)/wavpack/num_channels/mono_16bit_int.wv -c copy -fflags +bitexact -f matroska
 fate-wavpack-matroska_mux-mono: CMP = oneline
-fate-wavpack-matroska_mux-mono: REF = c5a2b46d8b31c9c2e7bfb436f9d56f02
+fate-wavpack-matroska_mux-mono: REF = 0a1a7c6d3b413925f8261c92d1d53363
 
 FATE_WAVPACK-$(call DEMMUX, WV, MATROSKA) += fate-wavpack-matroska_mux-61
 fate-wavpack-matroska_mux-61: CMD = md5pipe -i $(TARGET_SAMPLES)/wavpack/num_channels/eva_2.22_6.1_16bit-partial.wv -c copy -fflags +bitexact -f matroska
 fate-wavpack-matroska_mux-61: CMP = oneline
-fate-wavpack-matroska_mux-61: REF = 22fc2a591be22657d19cab89ad6eef55
+fate-wavpack-matroska_mux-61: REF = 1f012f7c237f46f2f63089ba84c589c5
 
 FATE_SAMPLES_AVCONV += $(FATE_WAVPACK-yes)
 fate-wavpack: $(FATE_WAVPACK-yes)
diff --git a/tests/ref/fate/aac-autobsf-adtstoasc b/tests/ref/fate/aac-autobsf-adtstoasc
index 9bf9dfe78f..45b68b62bd 100644
--- a/tests/ref/fate/aac-autobsf-adtstoasc
+++ b/tests/ref/fate/aac-autobsf-adtstoasc
@@ -1,5 +1,5 @@ 
-b09fc2f554712adbf84fe7899eb679d4 *tests/data/fate/aac-autobsf-adtstoasc.matroska
-6695 tests/data/fate/aac-autobsf-adtstoasc.matroska
+d10b73732b32f6b2f08885b40c41c77f *tests/data/fate/aac-autobsf-adtstoasc.matroska
+6606 tests/data/fate/aac-autobsf-adtstoasc.matroska
 #extradata 0:        2, 0x0030001c
 #tb 0: 1/1000
 #media_type 0: audio
diff --git a/tests/ref/fate/binsub-mksenc b/tests/ref/fate/binsub-mksenc
index 4b13ef217a..3266501de6 100644
--- a/tests/ref/fate/binsub-mksenc
+++ b/tests/ref/fate/binsub-mksenc
@@ -1 +1 @@ 
-a5811caa0caba3a3f9a449b91569745c
+03d376cc2e8622e7af540d4d9809dbf7
diff --git a/tests/ref/fate/rgb24-mkv b/tests/ref/fate/rgb24-mkv
index b9db53f592..43b4ee2e19 100644
--- a/tests/ref/fate/rgb24-mkv
+++ b/tests/ref/fate/rgb24-mkv
@@ -1,5 +1,5 @@ 
-ffe2c21083d56764aaae7945fd146326 *tests/data/fate/rgb24-mkv.matroska
-58305 tests/data/fate/rgb24-mkv.matroska
+92861b36a8220a3dae10d91cba614892 *tests/data/fate/rgb24-mkv.matroska
+58216 tests/data/fate/rgb24-mkv.matroska
 #tb 0: 1/10
 #media_type 0: video
 #codec_id 0: rawvideo
diff --git a/tests/ref/lavf-fate/av1.mkv b/tests/ref/lavf-fate/av1.mkv
index 242c63a541..bd8ae6eefa 100644
--- a/tests/ref/lavf-fate/av1.mkv
+++ b/tests/ref/lavf-fate/av1.mkv
@@ -1,3 +1,3 @@ 
-6604d339d44864be58b8580fe2fb52cc *tests/data/lavf-fate/lavf.av1.mkv
-55725 tests/data/lavf-fate/lavf.av1.mkv
+be4903a6a6710043383c8f38a535a8d3 *tests/data/lavf-fate/lavf.av1.mkv
+55636 tests/data/lavf-fate/lavf.av1.mkv
 tests/data/lavf-fate/lavf.av1.mkv CRC=0x7c27cc15
diff --git a/tests/ref/lavf/mka b/tests/ref/lavf/mka
index a244893cf2..e8239442e9 100644
--- a/tests/ref/lavf/mka
+++ b/tests/ref/lavf/mka
@@ -1,3 +1,3 @@ 
-a91bfdb08ff5a1e62b039748d16b07f7 *tests/data/lavf/lavf.mka
-43652 tests/data/lavf/lavf.mka
+58936d3ad4eb1372bd2e5845963fe17c *tests/data/lavf/lavf.mka
+43563 tests/data/lavf/lavf.mka
 tests/data/lavf/lavf.mka CRC=0x3a1da17e
diff --git a/tests/ref/lavf/mkv b/tests/ref/lavf/mkv
index 05999b79fb..4d73fbf39d 100644
--- a/tests/ref/lavf/mkv
+++ b/tests/ref/lavf/mkv
@@ -1,3 +1,3 @@ 
-3cddd26ed41f34925d3f34acabab174e *tests/data/lavf/lavf.mkv
-320555 tests/data/lavf/lavf.mkv
+6ec6d6a058a85bf616e0b981bb8e383f *tests/data/lavf/lavf.mkv
+320466 tests/data/lavf/lavf.mkv
 tests/data/lavf/lavf.mkv CRC=0xec6c3c68
diff --git a/tests/ref/lavf/mkv_attachment b/tests/ref/lavf/mkv_attachment
index 230dff369a..2e9711483f 100644
--- a/tests/ref/lavf/mkv_attachment
+++ b/tests/ref/lavf/mkv_attachment
@@ -1,3 +1,3 @@ 
-4a25c53150c09537cd4fcbff8f8f14ff *tests/data/lavf/lavf.mkv_attachment
-472706 tests/data/lavf/lavf.mkv_attachment
+41b4f132ada6e0faedf92e909526a899 *tests/data/lavf/lavf.mkv_attachment
+472617 tests/data/lavf/lavf.mkv_attachment
 tests/data/lavf/lavf.mkv_attachment CRC=0xec6c3c68
diff --git a/tests/ref/seek/lavf-mkv b/tests/ref/seek/lavf-mkv
index 6ed1f3a763..223e098829 100644
--- a/tests/ref/seek/lavf-mkv
+++ b/tests/ref/seek/lavf-mkv
@@ -1,48 +1,48 @@ 
-ret: 0         st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos:    803 size:   208
+ret: 0         st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos:    714 size:   208
 ret: 0         st:-1 flags:0  ts:-1.000000
-ret: 0         st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos:   1019 size: 27837
+ret: 0         st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos:    930 size: 27837
 ret: 0         st:-1 flags:1  ts: 1.894167
-ret: 0         st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292435 size: 27834
+ret: 0         st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292346 size: 27834
 ret: 0         st: 0 flags:0  ts: 0.788000
-ret: 0         st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292435 size: 27834
+ret: 0         st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292346 size: 27834
 ret: 0         st: 0 flags:1  ts:-0.317000
-ret: 0         st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos:   1019 size: 27837
+ret: 0         st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos:    930 size: 27837
 ret:-1         st: 1 flags:0  ts: 2.577000
 ret: 0         st: 1 flags:1  ts: 1.471000
-ret: 0         st: 1 flags:1 dts: 0.993000 pts: 0.993000 pos: 320276 size:   209
+ret: 0         st: 1 flags:1 dts: 0.993000 pts: 0.993000 pos: 320187 size:   209
 ret: 0         st:-1 flags:0  ts: 0.365002
-ret: 0         st: 0 flags:1 dts: 0.491000 pts: 0.491000 pos: 146987 size: 27925
+ret: 0         st: 0 flags:1 dts: 0.491000 pts: 0.491000 pos: 146898 size: 27925
 ret: 0         st:-1 flags:1  ts:-0.740831
-ret: 0         st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos:   1019 size: 27837
+ret: 0         st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos:    930 size: 27837
 ret:-1         st: 0 flags:0  ts: 2.153000
 ret: 0         st: 0 flags:1  ts: 1.048000
-ret: 0         st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292435 size: 27834
+ret: 0         st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292346 size: 27834
 ret: 0         st: 1 flags:0  ts:-0.058000
-ret: 0         st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos:    803 size:   208
+ret: 0         st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos:    714 size:   208
 ret: 0         st: 1 flags:1  ts: 2.836000
-ret: 0         st: 1 flags:1 dts: 0.993000 pts: 0.993000 pos: 320276 size:   209
+ret: 0         st: 1 flags:1 dts: 0.993000 pts: 0.993000 pos: 320187 size:   209
 ret:-1         st:-1 flags:0  ts: 1.730004
 ret: 0         st:-1 flags:1  ts: 0.624171
-ret: 0         st: 0 flags:1 dts: 0.491000 pts: 0.491000 pos: 146987 size: 27925
+ret: 0         st: 0 flags:1 dts: 0.491000 pts: 0.491000 pos: 146898 size: 27925
 ret: 0         st: 0 flags:0  ts:-0.482000
-ret: 0         st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos:   1019 size: 27837
+ret: 0         st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos:    930 size: 27837
 ret: 0         st: 0 flags:1  ts: 2.413000
-ret: 0         st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292435 size: 27834
+ret: 0         st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292346 size: 27834
 ret:-1         st: 1 flags:0  ts: 1.307000
 ret: 0         st: 1 flags:1  ts: 0.201000
-ret: 0         st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos:    803 size:   208
+ret: 0         st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos:    714 size:   208
 ret: 0         st:-1 flags:0  ts:-0.904994
-ret: 0         st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos:   1019 size: 27837
+ret: 0         st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos:    930 size: 27837
 ret: 0         st:-1 flags:1  ts: 1.989173
-ret: 0         st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292435 size: 27834
+ret: 0         st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292346 size: 27834
 ret: 0         st: 0 flags:0  ts: 0.883000
-ret: 0         st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292435 size: 27834
+ret: 0         st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292346 size: 27834
 ret: 0         st: 0 flags:1  ts:-0.222000
-ret: 0         st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos:   1019 size: 27837
+ret: 0         st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos:    930 size: 27837
 ret:-1         st: 1 flags:0  ts: 2.672000
 ret: 0         st: 1 flags:1  ts: 1.566000
-ret: 0         st: 1 flags:1 dts: 0.993000 pts: 0.993000 pos: 320276 size:   209
+ret: 0         st: 1 flags:1 dts: 0.993000 pts: 0.993000 pos: 320187 size:   209
 ret: 0         st:-1 flags:0  ts: 0.460008
-ret: 0         st: 0 flags:1 dts: 0.491000 pts: 0.491000 pos: 146987 size: 27925
+ret: 0         st: 0 flags:1 dts: 0.491000 pts: 0.491000 pos: 146898 size: 27925
 ret: 0         st:-1 flags:1  ts:-0.645825
-ret: 0         st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos:   1019 size: 27837
+ret: 0         st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos:    930 size: 27837