ffmpeg: Exportieren in 24-Bit-Wave mit Microsoft PCM, nicht erweiterbar (mit Lavf58.76.100)

ffmpeg: Exportieren in 24-Bit-Wave mit Microsoft PCM, nicht erweiterbar (mit Lavf58.76.100)

Mir fällt auf, dass FFMPEG, wenn ich einen Mod in eine Wave mit 24 Bit oder mehr exportiere, sich für die Verwendung von Extensible Encoding anstelle von normalem PCM-Encoding entscheidet und „Lavf58.76.100“ verwendet, was auch immer das sein mag. Ich habe exiftool verwendet, um die exportierte WAV-Datei zu überprüfen, und das ist das Ergebnis:

---- 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

Das Problem ist, dass viele Programme dieses erweiterbare WAV-Format nicht verstehen. Gibt es eine Möglichkeit, FFMPEG anzuweisen, stattdessen normales PCM zu verwenden? Mir ist aufgefallen, dass andere Programme wie die Bass-Bibliothek mit normaler PCM-Kodierung in ein 24-Bit-WAV-Format exportieren können.

Dies ist der Befehl, den ich verwende:

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

Bearbeiten

Während ich diese Frage schrieb, war ich etwas frustriert und es fehlte mir an Wissen. Jetzt ist alles vollkommen klar: Wave-Dateien mit einer Bittiefe von mehr als 16 Bit sollten das Tag WAVE_FORMAT_EXTENSIBLE haben (und das macht Sinn, siehe Antwort). Die Software, die ich zum Rendern von Mod-Dateien in Wave verwendete, abgesehen von FFmpeg, hielt sich nicht an diese Regel. Vielen Dank, Tom Yan, für die Klarstellung.

Antwort1

(Nicht alle meine Kommentare waren genau/richtig, lesen Sie also bei Interesse das Folgende.)

TheoretischApropos,PCMWAVEFORMATkann für Audio mit einer Bittiefe von mehr als 16 verwendet werden. Die Header-Struktur weist keine Einschränkung auf, die die Unterstützung solchen Audios verhindert.

Es gibt jedoch anscheinend einige Gründe, warum ffmpeg für diese Art von Audio keinen WAVE-Header in diesem Format schreibt.

Zum einen wurde das Format abgelöst durchWAVEFORMATEX, und laut Dokumentation:

...

wBitsPerSample

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

...

Zusätzlich zu der oben genannten Anforderung gibt es keinen wFormatTaganderen Wert als WAVE_FORMAT_EXTENSIBLEden, der für PCM-Audio mit einer Bittiefe von über 16 definiert ist.

Ob die inWAVEFORMATEXTENSIBLEkann weggelassen werden, wenn wFormatTages WAVE_FORMAT_EXTENSIBLEnicht ganz klar ist. InWAVEFORMATEX, es wird angegeben, daß:

...

wFormatTag


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

...

Bei so einer Aussage würde/sollte wohl sowieso niemand davon ausgehen, dass es erlaubt ist.

Wenn Sie lesenWAVEFORMATEXUndWAVEFORMATEXTENSIBLEWenn Sie genau hinschauen, werden Sie feststellen, dass der wahre Grund für die Existenz des letzteren (in Bezug auf die Bittiefe) darin besteht, dass es dem ersteren ermöglicht, eine Containergröße von einem Vielfachen von 8 zu speichern, wobei die „echte“ Beispielgröße in einer der im letzteren definierten Erweiterungen gespeichert wird. Beispielsweise 24 bzw. 20 für einen (bösen) 20-Bit-PCM-Stream.

Der Vollständigkeit halber sei erwähnt, dass der wavMuxer von ffmpeg den soeben erwähnten Sonderfall meines Wissens NICHT (zumindest nicht richtig) unterstützt. ( 0Ich glaube, beide Felder würden mit dem Wert von geschrieben, wenn ein solcher Stream nicht abgelehnt wird.)

Falls Sie unbedingt ffmpeg benötigen, um den Header im Format PCMWAVEFORMATfür 24-Bit-Audio zu schreiben, können Sie den folgenden Patch verwenden, um ihn zu erstellen:

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

Wenn Sie dann vor dem Pfad/Namen der Ausgabedatei hinzufügen -extensible 0, sollten Sie eine sogenannte „normale“ 24-Bit-WAVE-Datei erhalten.

verwandte Informationen