ffmpeg: 확장이 아닌 Microsoft PCM을 사용하여 24비트 웨이브로 내보내기(Lavf58.76.100 사용)

ffmpeg: 확장이 아닌 Microsoft PCM을 사용하여 24비트 웨이브로 내보내기(Lavf58.76.100 사용)

FFMPEG를 사용하여 모드를 24비트 이상의 웨이브로 내보낼 때 FFMPEG는 일반 PCM 인코딩 대신 확장 가능한 인코딩을 사용하기로 결정하고 "Lavf58.76.100"을 사용합니다. 내보낸 WAV를 검사하기 위해 EXIFTool을 사용했는데 결과는 다음과 같습니다.

---- 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_FORMAT_EXTENSIBLE 태그가 있어야 합니다(답변을 참조하세요). 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_EXTENSIBLE~ 안에WAVEFORMATEX, 다음과 같이 명시되어 있습니다.

...

wFormatTag


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

...

그러한 진술을 사용하면 아마도 누구도 그것이 어쨌든 허용된다고 가정하지 않을 것입니다.

당신이 읽으면WAVEFORMATEX그리고WAVEFORMATEXTENSIBLE주의 깊게 살펴보면 후자가 존재하는 실제 이유(비트 심도 측면에서)는 전자가 확장 중 하나에 "실제" 샘플 크기를 저장하면서 8의 배수 컨테이너 크기를 저장할 수 있다는 점을 알 수 있습니다. 후자에 정의되어 있습니다. 예를 들어 일부 (불쾌한) 20비트 PCM 스트림의 경우 각각 24와 20입니다.

기록에 따르면, wavffmpeg의 muxer는 내가 볼 수 있는 한 방금 언급한 기발한 사례를 지원하지 않습니다(적어도 제대로 지원하지 않습니다). ( 0해당 스트림이 거부되지 않으면 두 필드 모두 값으로 기록될 것이라고 생각합니다.)

PCMWAVEFORMAT일부 24비트 오디오 형식으로 헤더를 작성하기 위해 ffmpeg가 정말로 필요한 경우 다음 패치를 사용하여 빌드하는 것을 고려할 수 있습니다.

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 파일을 얻을 수 있습니다.

관련 정보