ffmpeg: 拡張不可能な Microsoft PCM で 24 ビットの波形にエクスポート (Lavf58.76.100 を使用)

ffmpeg: 拡張不可能な Microsoft PCM で 24 ビットの波形にエクスポート (Lavf58.76.100 を使用)

FFMPEG を使用して mod を 24 ビット以上の wave にエクスポートすると、FFMPEG は通常の PCM エンコーディングではなく拡張エンコーディングを使用することを決定し、"Lavf58.76.100" を使用します (それが何であれ)。exiftool を使用してエクスポートされた wav を検査したところ、次のようになりました。

---- File ----
File Type                       : WAV
File Type Extension             : wav
MIME Type                       : audio/x-wav
---- RIFF ----
Encoding                        : Extensible
Num Channels                    : 2
Sample Rate                     : 48000
Avg Bytes Per Sec               : 288000
Bits Per Sample                 : 24
Software                        : Lavf58.76.100

問題は、多くのプログラムがこの拡張可能な wav 形式を理解しないことです。FFMPEG に代わりに通常の PCM を使用するように指示する方法はありますか? ベース ライブラリなどの他のプログラムは、通常の PCM エンコーディングを使用して 24 ビット wav にエクスポートできることに気付きました。

私が使用しているコマンドは次のとおりです:

ffmpeg -y -loglevel error -f libopenmpt -i c:\temp\sometrack.IT -map_metadata -1 -c:a pcm_s24le c:\temp\sometrack.wav

編集

この質問を書いている間、私は少しイライラしていて、知識が不足していました。今、すべてが完全に明らかになりました。16 ビットを超えるビット深度の wave ファイルには、WAVE_FORMAT_EXTENSIBLE タグが必要です (そして、それは理にかなっています。回答を参照してください)。私が mod ファイルを wave にレンダリングするために使用していた FFmpeg 以外のソフトウェアは、このルールを尊重していませんでした。明確にしてくれた Tom Yan に感謝します。

答え1

(私のコメントは全て正確ではないので、興味のある方は以下を参照してください。)

理論的には話し中、PCMWAVEFORMAT16 ビット以上の深度のオーディオに使用できます。ヘッダー構造には、このようなオーディオのサポートを妨げる制限はありません。

ただし、ffmpeg がそのような種類のオーディオに対してそのような形式で WAVE ヘッダーを書き込まない理由はいくつかあるようです。

まず、このフォーマットはWAVEFORMATEXそして、ドキュメントによると:

...

wBitsPerSample

... If wFormatTag is WAVE_FORMAT_PCM, then wBitsPerSample should be equal to
8 or 16. ...

...

上記の要件に加えて、ビット深度が 16 を超える PCM オーディオに対して定義されている値wFormatTag以外に値はありません。WAVE_FORMAT_EXTENSIBLE

で定義された「拡張機能」がWAVEFORMATEXTENSIBLE明確でないwFormatTag場合は省略できます。WAVE_FORMAT_EXTENSIBLEWAVEFORMATEX、次のように述べられています。

...

wFormatTag


... When this structure is included in a WAVEFORMATEXTENSIBLE structure,
this value must be WAVE_FORMAT_EXTENSIBLE. ...

...

このような声明では、おそらく誰もそれがとにかく許可されていると想定しないでしょう。

もしあなたが読むならWAVEFORMATEXそしてWAVEFORMATEXTENSIBLEよく見ると、後者が存在する本当の理由 (ビット深度の観点から) は、前者が 8 の倍数のコンテナ サイズを格納でき、"実際の" サンプル サイズが後者で定義されている拡張機能の 1 つに格納されるためであることがわかります。たとえば、(厄介な) 20 ビット PCM ストリームの場合はそれぞれ 24 と 20 です。

ただし、記録のために言っておくと、wav私が見る限り、ffmpeg の muxer は、先ほど述べた奇妙なケースを (少なくとも適切には) サポートしていません。 (0そのようなストリームが拒否されない場合は、両方のフィールドに の値が書き込まれると思います。)

PCMWAVEFORMATffmpegで 24 ビット オーディオの形式でヘッダーを書き込む必要がある場合は、次のパッチを使用してビルドすることを検討してください。

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 },
 };
 

次に、-extensible 0出力ファイルのパス/名前の前に追加することで、「通常の」24 ビット WAVE ファイルを取得できるはずです。

関連情報