Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
 help / color / mirror / Atom feed
From: Daniel Verkamp via ffmpeg-devel <ffmpeg-devel@ffmpeg.org>
To: ffmpeg-devel@ffmpeg.org
Cc: Daniel Verkamp <code@ffmpeg.org>
Subject: [FFmpeg-devel] [PR] avformat/wavenc: Keep fmt chunk first for -rf64 auto (PR #21556)
Date: Fri, 23 Jan 2026 09:42:45 -0000
Message-ID: <176916136646.25.701545660977719295@4457048688e7> (raw)

PR #21556 opened by Daniel Verkamp (drv)
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/21556
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/21556.patch

When the WAV muxer's `-rf64 auto` option is used, the output is intended
to be a normal WAV file if possible, only extended to RF64 format when
the file size grows too large. This was accomplished by reserving space
for the extra RF64-specific data using a standard JUNK chunk (ignored by
readers), then overwriting the reserved space later with a ds64 chunk if
needed.

In the original rf64 auto implementation, the JUNK chunk was placed
right after the RIFF/WAVE file header, before the fmt chunk; this is the
design suggested by the "Achieving compatibility between BWF and RF64"
section of the RF64 spec:

  RIFF 'WAVE' <JUNK chunk> <fmt-ck> ...

However, this approach means that the fmt chunk is no longer in its
conventional location at the beginning of the file, and some WAV-reading
tools are confused by this layout. For example, the `file` tool is not
able to show the format information for a file with the extra JUNK chunk
before fmt.

This change shuffles the order of the chunks for `-rf64 auto` mode so
that the reserved space follows fmt instead of preceding it:

  RIFF 'WAVE' <fmt-ck> <JUNK chunk> ...

With this small modification, tools expecting the fmt chunk to be the
first chunk in the file work with files produced by `-rf64 auto`.

This means the fmt chunk won't be in the location required by RF64, so
if the automatic RF64 conversion is triggered, the fmt chunk needs to be
relocated by rewriting it following the ds64 chunk during the conversion:

  RF64 'WAVE' <ds64 chunk> <fmt-ck> ...


>From 18ab86bee591be78f5e1a9771bb770e59c8efafc Mon Sep 17 00:00:00 2001
From: Daniel Verkamp <daniel@drv.nu>
Date: Fri, 23 Jan 2026 00:53:09 -0800
Subject: [PATCH] avformat/wavenc: Keep fmt chunk first for -rf64 auto

When the WAV muxer's `-rf64 auto` option is used, the output is intended
to be a normal WAV file if possible, only extended to RF64 format when
the file size grows too large. This was accomplished by reserving space
for the extra RF64-specific data using a standard JUNK chunk (ignored by
readers), then overwriting the reserved space later with a ds64 chunk if
needed.

In the original rf64 auto implementation, the JUNK chunk was placed
right after the RIFF/WAVE file header, before the fmt chunk; this is the
design suggested by the "Achieving compatibility between BWF and RF64"
section of the RF64 spec:

  RIFF 'WAVE' <JUNK chunk> <fmt-ck> ...

However, this approach means that the fmt chunk is no longer in its
conventional location at the beginning of the file, and some WAV-reading
tools are confused by this layout. For example, the `file` tool is not
able to show the format information for a file with the extra JUNK chunk
before fmt.

This change shuffles the order of the chunks for `-rf64 auto` mode so
that the reserved space follows fmt instead of preceding it:

  RIFF 'WAVE' <fmt-ck> <JUNK chunk> ...

With this small modification, tools expecting the fmt chunk to be the
first chunk in the file work with files produced by `-rf64 auto`.

This means the fmt chunk won't be in the location required by RF64, so
if the automatic RF64 conversion is triggered, the fmt chunk needs to be
relocated by rewriting it following the ds64 chunk during the conversion:

  RF64 'WAVE' <ds64 chunk> <fmt-ck> ...
---
 libavformat/wavenc.c | 24 ++++++++++++++++++++----
 1 file changed, 20 insertions(+), 4 deletions(-)

diff --git a/libavformat/wavenc.c b/libavformat/wavenc.c
index a515f4e2a2..01fffaafe5 100644
--- a/libavformat/wavenc.c
+++ b/libavformat/wavenc.c
@@ -315,9 +315,9 @@ static int wav_write_header(AVFormatContext *s)
 
     ffio_wfourcc(pb, "WAVE");
 
-    if (wav->rf64 != RF64_NEVER) {
-        /* write empty ds64 chunk or JUNK chunk to reserve space for ds64 */
-        ffio_wfourcc(pb, wav->rf64 == RF64_ALWAYS ? "ds64" : "JUNK");
+    if (wav->rf64 == RF64_ALWAYS) {
+        /* write empty ds64 chunk */
+        ffio_wfourcc(pb, "ds64");
         avio_wl32(pb, 28); /* chunk size */
         wav->ds64 = avio_tell(pb);
         ffio_fill(pb, 0, 28);
@@ -332,6 +332,16 @@ static int wav_write_header(AVFormatContext *s)
             return AVERROR(ENOSYS);
         }
         ff_end_tag(pb, fmt);
+
+        if (wav->rf64 == RF64_AUTO) {
+            /* reserve space for ds64 */
+            ffio_wfourcc(pb, "JUNK");
+            avio_wl32(pb, 28); /* chunk size */
+            ffio_fill(pb, 0, 28);
+
+            /* in RF64_AUTO mode, fmt + JUNK will be overwritten by ds64 + fmt */
+            wav->ds64 = fmt;
+        }
     }
 
     if (s->streams[0]->codecpar->codec_tag != 0x01 /* hence for all other than PCM */
@@ -411,6 +421,7 @@ static int wav_write_trailer(AVFormatContext *s)
     WAVMuxContext    *wav = s->priv_data;
     int64_t file_size, data_size;
     int64_t number_of_samples = 0;
+    int64_t pos;
     int rf64 = 0;
     int ret = 0;
 
@@ -459,7 +470,7 @@ static int wav_write_trailer(AVFormatContext *s)
             ffio_wfourcc(pb, "RF64");
             avio_wl32(pb, -1);
 
-            /* write ds64 chunk (overwrite JUNK if rf64 == RF64_AUTO) */
+            /* write ds64 chunk (overwrite fmt + JUNK if rf64 == RF64_AUTO) */
             avio_seek(pb, wav->ds64 - 8, SEEK_SET);
             ffio_wfourcc(pb, "ds64");
             avio_wl32(pb, 28);                  /* ds64 chunk size */
@@ -468,6 +479,11 @@ static int wav_write_trailer(AVFormatContext *s)
             avio_wl64(pb, number_of_samples);   /* fact chunk number of samples */
             avio_wl32(pb, 0);                   /* number of table entries for non-'data' chunks */
 
+            /* rewrite fmt in its RF64 position after ds64 */
+            pos = ff_start_tag(pb, "fmt ");
+            ret = ff_put_wav_header(s, pb, s->streams[0]->codecpar, 0);
+            ff_end_tag(pb, pos);
+
             /* write -1 in data chunk size */
             avio_seek(pb, wav->data - 4, SEEK_SET);
             avio_wl32(pb, -1);
-- 
2.52.0

_______________________________________________
ffmpeg-devel mailing list -- ffmpeg-devel@ffmpeg.org
To unsubscribe send an email to ffmpeg-devel-leave@ffmpeg.org

                 reply	other threads:[~2026-01-23  9:43 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=176916136646.25.701545660977719295@4457048688e7 \
    --to=ffmpeg-devel@ffmpeg.org \
    --cc=code@ffmpeg.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

This inbox may be cloned and mirrored by anyone:

	git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
		ffmpegdev@gitmailbox.com
	public-inbox-index ffmpegdev

Example config snippet for mirrors.


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git