[FFmpeg-devel] [PATCH] avformat/wavenc: allow WAVEFORMATEXTENSIBLE to be suppressed

Tom Yan tom.ty89 at gmail.com
Mon Dec 27 10:01:33 EET 2021


While WAVEFORMATEX sort of mandates WAVEFORMATEXTENSIBLE to be
used for audio with sample size other than 8 or 16,
PCMWAVEFORMAT does not practically have any limitation in
supporting higher sample size that is a multiple of 8 (or sample
rate higher than 48000).

In terms of sample size, the only real reason that the extension
exists is that it allows both an actual sample size and a
multiple-of-8 container size to be stored. However, such facility
is of no use when the actual sample size is a multiple of 8, let
alone that muxer never made use of it (since it never actually
supported sample size like 20 anyway; at least not in the way it
is supposed to.)

Although WAVEFORMATEXTENSIBLE has been around for more than two
decades, apparently programs and libraries that do not support
the format still exist.

Therefore, adding an option that allows the WAVEFORMATEXTENSIBLE
"extensions" to be suppressed and the format tag field to be set
to WAVE_FORMAT_PCM (0x0001) for audio with sample size higher than
16 (or sample rate higher than 48000).

Signed-off-by: Tom Yan <tom.ty89 at gmail.com>
---
 libavformat/riff.h    | 5 +++++
 libavformat/riffenc.c | 4 ++--
 libavformat/wavenc.c  | 5 ++++-
 3 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/libavformat/riff.h b/libavformat/riff.h
index 85d6786663..5794857f53 100644
--- a/libavformat/riff.h
+++ b/libavformat/riff.h
@@ -57,6 +57,11 @@ void ff_put_bmp_header(AVIOContext *pb, AVCodecParameters *par, int for_asf, int
  */
 #define FF_PUT_WAV_HEADER_SKIP_CHANNELMASK      0x00000002
 
+/**
+ * Tell ff_put_wav_header() not to write WAVEFORMATEXTENSIBLE extensions if possible.
+ */
+#define FF_PUT_WAV_HEADER_FORCE_PCMWAVEFORMAT      0x00000004
+
 /**
  * Write WAVEFORMAT header structure.
  *
diff --git a/libavformat/riffenc.c b/libavformat/riffenc.c
index ffccfa3d48..4dc8ca6e0f 100644
--- a/libavformat/riffenc.c
+++ b/libavformat/riffenc.c
@@ -80,9 +80,9 @@ int ff_put_wav_header(AVFormatContext *s, AVIOContext *pb,
     waveformatextensible = (par->channels > 2 && par->channel_layout) ||
                            par->channels == 1 && par->channel_layout && par->channel_layout != AV_CH_LAYOUT_MONO ||
                            par->channels == 2 && par->channel_layout && par->channel_layout != AV_CH_LAYOUT_STEREO ||
-                           par->sample_rate > 48000 ||
                            par->codec_id == AV_CODEC_ID_EAC3 ||
-                           av_get_bits_per_sample(par->codec_id) > 16;
+                           ((par->sample_rate > 48000 || av_get_bits_per_sample(par->codec_id) > 16) &&
+                            !(flags & FF_PUT_WAV_HEADER_FORCE_PCMWAVEFORMAT));
 
     if (waveformatextensible)
         avio_wl16(pb, 0xfffe);
diff --git a/libavformat/wavenc.c b/libavformat/wavenc.c
index 2317700be1..bd41d6eeb3 100644
--- a/libavformat/wavenc.c
+++ b/libavformat/wavenc.c
@@ -83,6 +83,7 @@ typedef struct WAVMuxContext {
     int peak_block_pos;
     int peak_ppv;
     int peak_bps;
+    int extensible;
 } WAVMuxContext;
 
 #if CONFIG_WAV_MUXER
@@ -324,9 +325,10 @@ static int wav_write_header(AVFormatContext *s)
     }
 
     if (wav->write_peak != PEAK_ONLY) {
+        int flags = !wav->extensible ? FF_PUT_WAV_HEADER_FORCE_PCMWAVEFORMAT : 0;
         /* format header */
         fmt = ff_start_tag(pb, "fmt ");
-        if (ff_put_wav_header(s, pb, s->streams[0]->codecpar, 0) < 0) {
+        if (ff_put_wav_header(s, pb, s->streams[0]->codecpar, flags) < 0) {
             av_log(s, AV_LOG_ERROR, "Codec %s not supported in WAVE format\n",
                    avcodec_get_name(s->streams[0]->codecpar->codec_id));
             return AVERROR(ENOSYS);
@@ -494,6 +496,7 @@ static const AVOption options[] = {
     { "peak_block_size", "Number of audio samples used to generate each peak frame.",   OFFSET(peak_block_size), AV_OPT_TYPE_INT, { .i64 = 256 }, 0, 65536, ENC },
     { "peak_format",     "The format of the peak envelope data (1: uint8, 2: uint16).", OFFSET(peak_format), AV_OPT_TYPE_INT,     { .i64 = PEAK_FORMAT_UINT16 }, PEAK_FORMAT_UINT8, PEAK_FORMAT_UINT16, ENC },
     { "peak_ppv",        "Number of peak points per peak value (1 or 2).",              OFFSET(peak_ppv), AV_OPT_TYPE_INT, { .i64 = 2 }, 1, 2, ENC },
+    { "extensible",      "Write WAVEFORMATEXTENSIBLE extensions.",                      OFFSET(extensible), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, ENC },
     { NULL },
 };
 
-- 
2.34.1



More information about the ffmpeg-devel mailing list