Zettelkasten

목표 비트레이트로 인코딩하면 샘플링 레이트를 낮춰도 파일이 작아지지 않는다

·수정 1회

요약

  • 압축 코덱은 출력 크기를 지정받아 그 크기에 맞추므로, 입력 샘플링 레이트를 낮춰도 파일이 거의 그대로다. Opus 16 kbps에서 입력을 16 kHz → 8 kHz로 낮췄더니 크기는 6%만 줄었다.
  • 샘플링 레이트와 파일 크기가 비례하는 건 압축하지 않는 PCM에서만이다.
  • 대신 libopus는 입력 레이트를 코딩 대역의 천장으로 삼는다. 낮추면 아낀 건 없이 고역만 영구히 잃는다.

본문

두 값은 다른 단계에 있다

  • 샘플링 레이트: 입력 해상도. 1초에 파형을 몇 번 측정하는가. 담을 수 있는 최고 주파수를 정한다(나이퀴스트)
  • 비트레이트: 출력 예산. 1초 분량을 몇 비트로 적을 것인가

-b:a 16k는 "1초를 16,000비트로 요약하라"는 지시다. 원본을 48 kHz로 떴든 8 kHz로 떴든 인코더는 시킨 대로 16,000비트를 쓴다. 파일 크기를 정하는 건 지시값이지 입력이 아니다.

PCM에서만 비례한다

48,000회/초 × 16비트 = 768,000 bps
16,000회/초 × 16비트 = 256,000 bps

압축이 없으면 측정값을 그대로 적으므로 샘플링을 1/3로 줄이면 파일도 1/3이 된다. "샘플링 낮추면 용량 준다"는 이 경우에만 맞는 말인데, 목표 비트레이트를 받는 코덱에 그대로 적용하는 오해가 흔하다.

실측 (1:1 음성통화 녹음 8건, 44분)

설정 파일의 유효 비트레이트
Opus 16 kbps / 입력 16 kHz 8.9 kbps
Opus 16 kbps / 입력 8 kHz 8.4 kbps

6% 차이는 VBR이 담을 소리가 줄어 예산을 덜 쓴 잔돈이다. 절감이라 부를 수준이 아니다.

입력 레이트는 코딩 대역의 천장으로 작동한다

libopus src/opus_encoder.c:

/* Prevents Opus from wasting bits on frequencies that are above
   the Nyquist rate of the input signal */
if (st->Fs <= 8000 && st->bandwidth > OPUS_BANDWIDTH_NARROWBAND)
    st->bandwidth = OPUS_BANDWIDTH_NARROWBAND;

입력이 8 kHz면 비트레이트를 64 kbps로 올려도 narrowband(4 kHz)에 묶인다. 패킷 TOC 바이트를 직접 파싱해 확인한 결과다.

입력 비트레이트 실제 코딩된 대역
48 kHz 8 kbps narrowband 4 kHz
48 kHz 64 kbps fullband 20 kHz
8 kHz 64 kbps narrowband 4 kHz

즉 인코더의 대역 자동 선택은 좁히는 방향으로만 작동한다. 48 kHz로 넣어두면 예산이 적을 때 알아서 좁혀주지만, 8 kHz로 넣으면 넓힐 방법이 없다. 그래서 입력 레이트는 "코덱이 고를 수 있는 상한"을 정하는 값이지 크기 손잡이가 아니다.

음성 구간의 대역별 에너지를 원본과 비교했을 때, 8 kHz 입력 변형만 3.4 kHz 위가 원본의 13~22%, 6 kHz 위는 1%로 무너졌다. 위 코드가 강제한 결과다.

컨테이너 표기에 속지 말 것

Ogg Opus는 granule position을 48 kHz 단위로 고정하므로(RFC 7845 §4) ffprobe는 무엇을 넣든 sample_rate=48000을 보고한다. 입력 레이트 지정이 무시된 게 아니라 표기가 고정된 것이다. 지정값은 OpusHead의 Input Sample Rate 필드에 참고용 메타데이터로 남고(재생 레이트가 아니라고 RFC가 명시), 실제 효력은 위의 천장으로 나타난다.

부연

  • 대역 단계는 NB 4 kHz / MB 6 kHz / WB 8 kHz / SWB 12 kHz / FB 20 kHz의 5단계지만(RFC 6716 Table 1), libopus는 자동 선택에서 mediumband를 쓰지 않아 실제로 고르는 건 네 가지다
  • 자동 선택의 판단 기준은 지정 비트레이트 그 자체가 아니라 채널 수·프레임 길이·VBR 여부·패킷 손실률을 반영한 등가 비트레이트이며, 음성/음악 추정과 히스테리시스가 함께 걸린다
  • 이 동작은 RFC의 규범 조항이 아니라 참조 인코더의 기본값이고, OPUS_SET_BANDWIDTH로 명시하면 자동 선택이 멈춘다

결론

용량을 줄이려면 -b:a를 조절한다. -ar은 대역 상한 설정이다. 음성이라면 -ar 16000으로 wideband까지 허용해두고 -b:a로 품질과 크기를 정하는 게 맞다.

관련 노트

참고