.png)
Я заметил, что когда я использую FFMPEG для экспорта мода в волну в 24 бита или выше, 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? Я заметил, что другие программы, такие как библиотека bass, могут экспортировать в 24-битный wav, используя обычное кодирование PCM.
Вот команда, которую я использую:
ffmpeg -y -loglevel error -f libopenmpt -i c:\temp\sometrack.IT -map_metadata -1 -c:a pcm_s24le c:\temp\sometrack.wav
Редактировать
Пока я писал этот вопрос, я был немного расстроен и мне не хватало знаний. Теперь все предельно ясно: файлы wave с битовой глубиной выше 16 бит должны иметь тег WAVE_FORMAT_EXTENSIBLE (и это имеет смысл, см. ответ). Программное обеспечение, которое я использовал для рендеринга файлов mod в wave, кроме FFmpeg, не соблюдало это правило. Спасибо, Том Ян, за разъяснения.
решение1
(Не все мои комментарии были точными/правильными, поэтому, если вам интересно, обратитесь к следующей информации.)
ТеоретическиГоворящий,PCMWAVEFORMAT
может использоваться для аудио с глубиной цвета более 16 бит. Структура заголовка не накладывает никаких ограничений, которые мешали бы поддерживать такое аудио.
Однако, по-видимому, есть несколько причин, по которым ffmpeg не записывает заголовок WAVE в таком формате для такого типа аудио.
Во-первых, формат был замененWAVEFORMATEX
, и, согласно документации:
...
wBitsPerSample
... If wFormatTag is WAVE_FORMAT_PCM, then wBitsPerSample should be equal to
8 or 16. ...
...
В дополнение к вышеуказанному требованию, не существует wFormatTag
другого значения, кроме WAVE_FORMAT_EXTENSIBLE
того, которое определено для звука PCM с битовой глубиной выше 16.
Будут ли «расширения», определенные вWAVEFORMATEXTENSIBLE
может быть опущен, когда wFormatTag
это WAVE_FORMAT_EXTENSIBLE
не совсем понятно.WAVEFORMATEX
, утверждается, что:
...
wFormatTag
... When this structure is included in a WAVEFORMATEXTENSIBLE structure,
this value must be WAVE_FORMAT_EXTENSIBLE. ...
...
При таком заявлении, вероятно, никто не будет/не должен предполагать, что это вообще разрешено.
Если вы читаетеWAVEFORMATEX
иWAVEFORMATEXTENSIBLE
внимательно, вы заметите, что настоящая причина существования последнего (с точки зрения битовой глубины) заключается в том, что он позволяет первому хранить размер контейнера, кратный 8, при этом «реальный» размер выборки хранится в одном из расширений, определенных во втором. Например, 24 и 20 соответственно для некоторого (отвратительного) 20-битного потока PCM.
Однако для справки: wav
насколько я могу судить, мультиплексор ffmpeg НЕ поддерживает (по крайней мере, не должным образом) только что упомянутый странный случай. (Я думаю, что оба поля будут записаны со значением 0
, если такой поток не будет отклонен.)
Если вам действительно нужно, чтобы ffmpeg записал заголовок в формате PCMWAVEFORMAT
для 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-файлом.