ffmpeg: Exportar a onda de 24 bits con Microsoft PCM, no extensible (con Lavf58.76.100)

ffmpeg: Exportar a onda de 24 bits con Microsoft PCM, no extensible (con Lavf58.76.100)

Noto que, cuando uso FFMPEG para exportar un mod a una onda de 24 bits o superior, FFMPEG decide usar codificación extensible en lugar de codificación PCM normal y usa "Lavf58.76.100", sea lo que sea. Utilicé exiftool para inspeccionar el wav exportado y este es el resultado:

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

El problema es que muchos programas no entienden este formato wav extensible. ¿Hay alguna forma de decirle a FFMPEG que utilice PCM normal en su lugar? Noto que otros programas, como la biblioteca de bajos, pueden exportar a un wav de 24 bits utilizando la codificación PCM normal.

Este es el comando que estoy usando:

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

Editar

Mientras escribía esta pregunta, estaba un poco frustrado y carecía de conocimientos. Ahora todo está perfectamente claro; Los archivos wave con una profundidad de bits superior a 16 bits deben tener la etiqueta WAVE_FORMAT_EXTENSIBLE (y tiene sentido, consulte la respuesta). El software que estaba usando para renderizar archivos mod en formato wave, aparte de FFmpeg, no cumplía con esta regla. Gracias, Tom Yan por aclararlo.

Respuesta1

(No todos mis comentarios fueron precisos/correctos, así que consulte lo siguiente si está interesado).

Teóricamentediscurso,PCMWAVEFORMATse puede utilizar para audio con una profundidad de bits superior a 16. La estructura del encabezado no plantea ninguna limitación que le impida soportar dicho audio.

Sin embargo, aparentemente existen algunas razones por las que ffmpeg no escribe un encabezado WAVE en ese formato para ese tipo de audio.

Por un lado, el formato ha sido reemplazado porWAVEFORMATEX, y, según la documentación:

...

wBitsPerSample

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

...

Además del requisito anterior, no existe ningún wFormatTagvalor distinto WAVE_FORMAT_EXTENSIBLEal definido para audio PCM con una profundidad de bits superior a 16.

Si las "extensiones" definidas enWAVEFORMATEXTENSIBLEse puede omitir cuando no wFormatTagestá WAVE_FORMAT_EXTENSIBLEdel todo claro. EnWAVEFORMATEX, se afirma que:

...

wFormatTag


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

...

Con tal afirmación, probablemente nadie debería asumir que está permitido de todos modos.

Si tu leesWAVEFORMATEXyWAVEFORMATEXTENSIBLECon cuidado, notará que la verdadera razón por la que existe este último (en términos de profundidad de bits) es que le permite al primero almacenar un tamaño de contenedor múltiplo de 8 con el tamaño de muestra "real" almacenado en una de las extensiones. definido en este último. Por ejemplo, 24 y 20 respectivamente para alguna (desagradable) transmisión PCM de 20 bits.

Sin embargo, para que conste, el wavmuxer de ffmpeg NO admite (al menos no correctamente) el caso peculiar que acabo de mencionar, hasta donde puedo ver. ( 0Creo que ambos campos se escribirían con el valor de si dicha secuencia no se rechaza).

En caso de que realmente necesite ffmpeg para escribir el encabezado en el formato de PCMWAVEFORMATaudio de 24 bits, puede considerar compilarlo con el siguiente parche:

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

Luego, al agregar -extensible 0antes de la ruta/nombre del archivo de salida, debería poder obtener lo que llamó un archivo WAVE "normal" de 24 bits.

información relacionada