[FFmpeg-trac] #8578(avformat:new): FFmpeg 4.2 breaks Matroska streaming

FFmpeg trac at avcodec.org
Mon Mar 23 00:00:08 EET 2020


#8578: FFmpeg 4.2 breaks Matroska streaming
-------------------------------------+-------------------------------------
             Reporter:  Sesse        |                    Owner:
                 Type:  defect       |                   Status:  new
             Priority:  normal       |                Component:  avformat
              Version:  git-master   |               Resolution:
             Keywords:  mkv          |               Blocked By:
  regression                         |
             Blocking:               |  Reproduced by developer:  0
Analyzed by developer:  0            |
-------------------------------------+-------------------------------------

Comment (by mkver):

 1. The "variable" returned by avformat_write_header() that you store and
 send to the client is the header written by avformat_write_header() and
 not the return value of avformat_write_header(), isn't it? (Yes, a stupid
 question, but I just want to be sure.)
 2. The AVIOContext's is flagged as non-seekable (i.e. pb->seekable &
 AVIO_SEEKABLE_NORMAL is wrong), I presume?
 3. Before the patchset that the cited commit belongs to was applied there
 were two interwoven codepaths for writing clusters (and other level 1
 elements). Both assembled the clusters in memory via a dynamic buffer (an
 AVIOContext that you can open with avio_open_dyn_buf()) (let's call it
 dyn) before outputting via the real AVIOContext (called pb in the
 following).
 a) The codepath for seekable output: Write the Cluster element ID via pb;
 also write Matroska's "unknown-length" length via pb (using the maximal
 length of 8 bytes for the length field). If a CRC-32 element is going to
 be written, reserve six bytes for it by writing an EBML-Void element in
 dyn. Then write content of the cluster as usual into dyn. When the cluster
 is to be finished, output the CRC-32 (if it is to be written) via pb and
 then write the whole content of dyn (containing the Cluster's content)
 with the exception of the bytes reserved for the CRC-32 (if any) via pb.
 Then seek back (in pb) to length field to update it (i.e. overwrite it
 with the real length that is now known) and seek back to the end of the
 Cluster again to write the next Cluster (or the Cues if this was the last
 one and Cues should be written at the end).
 b) The codepath for unseekable output: Write the Cluster element ID into
 dyn; also write an "unknown-length" length field into dyn. Then write the
 Cluster into dyn (without writing CRC-32 elements, because that was just
 not supported by the implementation). When closing the Cluster, the length
 field was updated (requiring seeks but that is possible because we are
 seeking with dyn, not pb) and the whole Cluster has been output (i.e. sent
 to pb) in one avio_write().
 4. Given that both codepaths relied on dynamic buffers they could be
 merged into one: Write Cluster element ID to pb; open dyn and reserve
 space for the CRC-32 in dyn (if it is to be written). Write Cluster
 content into dyn. When the Cluster is to be finished, write the correct
 length field for the Cluster (said size is now known!).* Then write the
 CRC-32 to pb (if ...) and then write the actual Cluster content (excluding
 the stuff at the beginning reserved for the CRC-32). This is what the
 patchset to which the cited patch belongs does. This patch is the very one
 that stopped the Cluster to be output in one go for nonseekable output; so
 your fuzzy result makes sense.
 5. As it happens, I already have a patch that should fix this. It modifies
 the process as follows: Open dyn and reserve space for CRC-32 (if ...).
 Write Cluster content into dyn. When the Cluster is to be finished, write
 the Cluster element ID, the length field, the CRC-32 (if ...) and the
 Cluster content (excluding the part reserved for the CRC-32 element (if
 ...)). You can find it
 [https://patchwork.ffmpeg.org/project/ffmpeg/patch/20200101005837.11356-16-andreas.rheinhardt@gmail.com/
 here]; yet it is part of a longer patchset and you will also have to apply
 [https://patchwork.ffmpeg.org/project/ffmpeg/patch/20200313220349.12974-1-andreas.rheinhardt@gmail.com/
 this patch],
 [https://patchwork.ffmpeg.org/project/ffmpeg/patch/20200101005837.11356-10-andreas.rheinhardt@gmail.com/
 this patch],
 [https://patchwork.ffmpeg.org/project/ffmpeg/patch/20200101005837.11356-11-andreas.rheinhardt@gmail.com/
 this patch],
 [https://patchwork.ffmpeg.org/project/ffmpeg/patch/20200101005837.11356-12-andreas.rheinhardt@gmail.com/
 this patch],
 [https://patchwork.ffmpeg.org/project/ffmpeg/patch/20200101005837.11356-13-andreas.rheinhardt@gmail.com/
 this patch],
 [https://patchwork.ffmpeg.org/project/ffmpeg/patch/20200101005837.11356-14-andreas.rheinhardt@gmail.com/
 this patch],
 [https://patchwork.ffmpeg.org/project/ffmpeg/patch/20200313231536.16949-1-andreas.rheinhardt@gmail.com/
 this patch] and finally
 [https://patchwork.ffmpeg.org/project/ffmpeg/patch/20200101005837.11356-16-andreas.rheinhardt@gmail.com/
 this patch]. Can you test whether this indeed fixes your problem?

 *: We save a few bytes here: Matroska (or actually EBML, the thing
 Matroska is built on) uses variable-length length-fields where smaller
 lengths take less bytes to encode and given that the length to write is
 known at this point the smallest possible length field is chosen.

--
Ticket URL: <https://trac.ffmpeg.org/ticket/8578#comment:4>
FFmpeg <https://ffmpeg.org>
FFmpeg issue tracker


More information about the FFmpeg-trac mailing list