AAC vs MP3 vs Opus 오디오 코덱 비교 | 음질·비트레이트·호환성 가이드

이 글의 핵심

비트레이트를 올려도 체감 음질이 그대로이거나 재압축 후 음질이 무너지는 현상은 코덱 내부 구조를 알면 설명됩니다. AAC 심리음향 모델, MP3 하이브리드 필터뱅크, Opus의 SILK+CELT 구조를 비교하고, VBR·ABR·CBR 선택과 무손실 마스터 기반 인코딩 사다리, MP3·AAC에서 Opus로 옮길 때의 주의점을 다룹니다.

들어가며

음성 통화, 음악 스트리밍, 게임, 팟캐스트까지 오디오 코덱은 필요한 대역폭과 체감 품질을 함께 결정합니다. MP3는 호환성 덕분에 여전히 널리 쓰이고, AAC는 Apple 생태계와 동영상 스트리밍에서 사실상 기본값이 되었으며, Opus는 낮은 지연과 음성 처리 능력으로 실시간 통신의 표준 자리를 차지했습니다.

이 글은 세 코덱의 설계 목적과 내부 구조(심리음향 모델, MDCT, Opus의 SILK+CELT 하이브리드)를 먼저 짚고, 비트레이트와 VBR/CBR에 따른 체감 품질 차이, 무손실 마스터와 라우드니스 같은 배포용 인코딩 원칙, FFmpeg 명령, 음악·음성·라이브별 선택 기준 순으로 정리합니다.


MP3·AAC·Opus 한눈에 비교

특성MP3AAC (LC)Opus
출시199319972012
압축 효율기준같은 비트레이트에서 MP3보다 효율적특히 저비트레이트에서 MP3보다 효율적
비트레이트 범위32-320 kbps대략 8-320 kbps (일반적 사용 범위)6-510 kbps
지연 (latency)높음중간낮음 (기본 26.5ms, 설정에 따라 5~66.5ms)
호환성최고높음중간
라이선스특허 만료특허 존재로열티 프리
대표 용도범용, 레거시스트리밍, 모바일VoIP, WebRTC

세 코덱의 역사와 설계 목표

MP3 (MPEG-1 Audio Layer III)

역사: 1993년 Fraunhofer IIS에서 개발, Napster를 통해 대중화 기술적 특징:

  • 심리음향 모델 + MDCT

  • 프레임 크기: 1152 샘플

  • Joint Stereo 지원 장점:

  • 거의 모든 기기에서 재생 가능

  • 사용자 인지도 최고

  • 편집 툴 지원 광범위 단점:

  • 동일 비트레이트에서 AAC/Opus 대비 효율 낮음

  • 5.1 서라운드 미지원

  • 고주파 손실 큼 FFmpeg 예제:

# VBR 고품질
ffmpeg -i input.wav -c:a libmp3lame -q:a 2 output.mp3
# CBR 192 kbps
ffmpeg -i input.wav -c:a libmp3lame -b:a 192k output.mp3
# 모노 (음성)
ffmpeg -i input.wav -ac 1 -c:a libmp3lame -b:a 64k output.mp3

AAC (Advanced Audio Coding)

역사: 1997년 MPEG-2 Part 7, 후에 MPEG-4 Part 3로 확장 프로파일:

  • AAC-LC: 가장 흔함, 범용

  • HE-AAC: 저비트레이트 최적화 (32-64 kbps)

  • HE-AACv2: 스테레오 효율 향상 장점:

  • 같은 비트레이트에서 MP3보다 효율적

  • 5.1 서라운드 지원

  • Apple 생태계 표준 단점:

  • 구형 기기 일부 미지원

  • 특허 라이선스 필요 (상용) FFmpeg 예제:

# AAC-LC 128 kbps
ffmpeg -i input.wav -c:a aac -b:a 128k output.m4a
# HE-AAC 64 kbps (저비트레이트)
ffmpeg -i input.wav -c:a libfdk_aac -profile:a aac_he -b:a 64k output.m4a
# VBR 모드 (libfdk_aac, 1~5 중 높을수록 고품질)
ffmpeg -i input.wav -c:a libfdk_aac -vbr 4 output.m4a

FFmpeg 내장 aac 인코더의 VBR(-q:a)은 실험적 기능이라, 내장 인코더를 쓸 때는 -b:a로 비트레이트를 지정하는 편이 안전합니다. libfdk_aac는 라이선스 문제로 대부분의 배포판 FFmpeg에 포함되지 않아 직접 빌드해야 합니다.

Opus

역사: 2012년 IETF RFC 6716, SILK + CELT 결합 기술적 특징:

  • SILK: 음성에 특화된 선형예측 기반 모드 (주로 저비트레이트)

  • CELT: 음악·광대역에 강한 MDCT 기반 모드 (중·고비트레이트)

  • 두 모드를 결합한 하이브리드 모드와, 입력에 따른 자동 전환 장점:

  • 음성에서 최고 효율

  • 저지연 (프레임 2.5ms, 알고리즘 지연 약 5ms까지 가능)

  • 로열티 프리

  • 6-510 kbps 광범위 지원 단점:

  • 레거시 하드웨어 미지원

  • 일부 DAW 미지원 FFmpeg 예제:

# 음성 (32 kbps)
ffmpeg -i input.wav -c:a libopus -b:a 32k -application voip output.opus
# 음악 (128 kbps)
ffmpeg -i input.wav -c:a libopus -b:a 128k -application audio output.opus
# VBR 모드
ffmpeg -i input.wav -c:a libopus -b:a 96k -vbr on output.opus
# WebM 컨테이너
ffmpeg -i input.wav -c:a libopus -b:a 128k output.webm

심리음향·MDCT·Opus 하이브리드 구조

인코더를 튜닝하거나 품질 문제를 분석할 때 실제로 등장하는 개념들입니다. 수식보다는 각 구성 요소가 제한된 비트를 어디에 쓰는지에 초점을 맞춥니다.

AAC의 심리음향 모델과 비트 배분

손실 오디오 코덱의 공통 목표는 같은 비트레이트에서 사람이 덜 민감한 성분부터 줄이는 것입니다. AAC는 MP3보다 필터뱅크와 부가 도구가 유연해서, 같은 심리음향 원리를 더 정교하게 적용할 수 있습니다.

청각은 주파수 축에서 일정 폭의 대역(임계 대역, critical band) 단위로 소리를 구분합니다. 강한 성분 근처의 약한 성분이 가려지는 현상을 동시 마스킹(simultaneous masking), 충격음(transient) 직전과 직후의 미세한 소리가 덜 들리는 현상을 시간 마스킹(temporal masking)이라고 합니다. 인코더는 입력 스펙트럼을 Bark 스케일 같은 청각 대역으로 나눈 뒤 대역마다 마스킹 임계(masking threshold)를 추정하고, 양자화 잡음이 그 임계 아래에 머물도록 비트를 배분합니다.

대역마다 신호 대 마스킹 비(SMR, signal-to-mask ratio)를 구하면 어느 대역에 비트가 더 필요한지 알 수 있습니다. 비트가 부족하면 마스킹이 강한 대역이나 스펙트럼이 평탄한 대역부터 거칠게 양자화되고, 비트가 넉넉하면 고주파와 미세한 디테일까지 살릴 여유가 생깁니다.

AAC에는 MP3에 없는 도구도 있습니다. TNS(temporal noise shaping)는 충격음 주변에서 양자화 잡음을 시간 방향으로 모아 프리에코(pre-echo, 충격음 직전에 번지는 잡음)를 줄입니다. PNS(perceptual noise substitution)는 음정이 거의 없는 잡음성 대역에서 세부 스펙트럼 대신 잡음 에너지 수준만 보내 비트를 아낍니다. M/S와 인텐시티 스테레오 같은 스테레오 도구는 중·저비트레이트에서 공간 정보를 효율적으로 압축합니다. 결과적으로 AAC는 어느 대역을 얼마나 거칠게 양자화할지를 MP3보다 세밀하게 제어할 수 있습니다.

AAC의 필터뱅크는 MDCT 하나로 이루어져 있습니다. 평소에는 긴 블록(1024 샘플)으로 주파수 해상도를 확보하고, 급격한 충격음이 감지되면 짧은 블록(128 샘플 × 8)으로 바꿔 시간 해상도를 높입니다. MP3의 롱/숏 블록 전환과 목적은 같지만, 필터뱅크 구조와 TNS 같은 도구에서 차이가 납니다.

MP3의 하이브리드 필터뱅크와 MDCT

MP3는 두 단계로 시간-주파수 해상도를 맞춥니다. 먼저 32채널 폴리페이즈 필터뱅크로 대역을 거칠게 나누고, 각 대역을 다시 MDCT로 잘게 분해합니다. 이 하이브리드 구조는 1990년대 초 계산 능력과 이전 규격(Layer I/II)과의 호환성 사이에서 타협한 결과로, 대역 사이의 에일리어싱 같은 부작용을 남겼습니다.

MDCT는 블록을 절반씩 겹쳐 변환하는 방식이라 블록 경계에서 생기는 불연속을 줄이면서 주파수 분해를 할 수 있습니다. MP3도 충격음 직전에는 롱 블록에서 숏 블록으로 전환해, 긴 변환이 만드는 프리에코를 완화합니다.

MP3 한 프레임은 1152 샘플이고, 576 샘플짜리 그래뉼(granule) 두 개로 나뉩니다. 블록 전환과 비트 배분은 이 그래뉼 단위로 이루어집니다. Joint Stereo는 좌우 채널의 상관이 클 때 합(mid)과 차(side) 성분으로 바꿔 비트를 절약합니다.

실제로는 LAME 같은 현대 인코더가 심리음향과 비트 배분을 잘 구현해 두었기 때문에, 사용자는 -V 계열 VBR이나 적절한 CBR을 고르는 것으로 품질을 정합니다. 내부 동작을 알고 있으면 왜 저비트레이트에서 고주파가 먼저 사라지는지, 왜 같은 kbps라도 곡마다 체감이 다른지를 설명할 수 있습니다.

Opus: SILK + CELT 하이브리드

Opus는 하나의 비트스트림 안에서 음성에 강한 모드와 음악·광대역에 강한 모드를 함께 다루도록 설계되었습니다. RFC 6716이 정의하는 것은 비트스트림과 디코더이고, 인코더는 SILK와 CELT를 상황에 맞게 골라 쓰거나 결합합니다.

SILK는 Skype가 개발한 음성 코덱에서 온 모드로, 선형예측(LPC)과 피치 추적으로 음성의 준주기적인 성질을 직접 모델링합니다. 저비트레이트에서도 말소리가 또렷하고, 말이 없는 구간에 거의 비트를 쓰지 않는 DTX(discontinuous transmission)와도 잘 맞아 VoIP와 게임 음성 채팅에 유리합니다.

CELT는 MDCT 기반으로 음악과 광대역 신호의 스펙트럼을 유지하는 모드입니다. 매우 짧은 프레임(최소 2.5ms)을 쓸 수 있어 지연을 낮게 유지하면서도 유연한 비트레이트를 지원합니다.

입력이 순수 음성이면 SILK가, 음악이나 혼합 신호면 CELT가 유리하며, 광대역 음성에는 저대역을 SILK로, 고대역을 CELT로 처리하는 하이브리드 모드가 쓰입니다. FFmpeg의 -application voip와 audio는 인코더가 음성 명료도와 음악 충실도 중 어디에 무게를 둘지 정하는 스위치로 이해하면 됩니다.

Opus는 내부적으로 48 kHz를 기준으로 동작하며, 프레임 길이를 2.5ms에서 60ms까지 조절해 알고리즘 지연을 바꿀 수 있습니다. 이런 특성 때문에 WebRTC에서 필수 지원 오디오 코덱으로 지정되어 있습니다.


비트레이트와 지각 품질의 관계

비트레이트와 체감 품질의 관계는 평균적인 청취자와 재생 환경을 가정한 이야기입니다. 실제로는 곡의 장르, 마스터링, 모노·스테레오 여부, 리샘플링에 따라 같은 kbps라도 체감이 달라집니다.

비트레이트를 올려도 체감이 안 나는 구간

손실 코덱의 비트레이트-왜곡 곡선에는 포화 구간이 있습니다. 저·중비트레이트에서는 몇십 kbps 차이가 크게 들리지만, 고비트레이트로 갈수록 ABX 블라인드 테스트 없이는 구분하기 어려운 영역이 넓어집니다. 스테레오 음악 스트리밍에서는 AAC-LC 128 kbps 전후, Opus 96~128 kbps 전후가 대역폭 대비 체감 품질이 좋은 지점으로 흔히 쓰입니다.

VBR·ABR·CBR의 의미

CBR은 피크 비트레이트를 고정해 전송 계획·저장 크기 예측이 쉽으며, VBR은 프레임마다 필요한 비트를 달리 써서 동일 평균 kbps에서 체감 품질을 높이는 경우가 많습니다. ABR은 둘의 절충입니다. 팟캐스트 RSS·레거시 플레이어처럼 가정이 보수적이면 CBR이 안전하며, 적응형 스트리밍(HLS/DASH)처럼 여러 렌더링을 따로 두는 경우에는 마스터를 무손실에 두고 사다리(ladder) 인코딩하는 편이 낫습니다.

음성과 음악의 비트 예산 차이

음성은 유효 대역이 좁고 준주기적인 패턴이 강해 SILK 같은 LPC 계열 모델이 매우 효율적입니다. 음악은 넓은 대역과 스테레오 공간감, 충격음이 동시에 있어 주파수와 시간 해상도를 모두 요구합니다. 그래서 모노 음성 32 kbps와 스테레오 팝 128 kbps는 인코딩 난이도 자체가 달라서, kbps 숫자만 놓고 비교하면 안 됩니다.


배포용 인코딩에서 반복되는 원칙

실서비스·방송·팟캐스트 현장에서 반복되는 패턴을 정리하면 다음과 같습니다.

무손실 마스터 한 번, 손실 인코딩은 채널별 한 번

편집과 믹스를 마친 마스터는 WAV나 FLAC 같은 무손실 포맷으로 보관하고, 배포 채널별로 한 번씩만 손실 인코딩합니다. 손실 포맷을 다시 손실 포맷으로 재압축하면 앞 단계 인코더가 버린 정보와 남긴 잡음 위에 새 양자화 잡음이 더해져, 프리에코나 금속성 아티팩트가 누적되기 쉽습니다.

비트레이트 사다리와 적응형 스트리밍

HLS와 DASH는 같은 타임라인에 여러 비트레이트 버전을 올려 두고 플레이어가 망 상태에 따라 고르게 합니다. 오디오도 64k(모바일), 96k, 128k, 256k처럼 단계를 나누고, 매니페스트에 코덱 프로파일(AAC-LC, 저비트레이트 단계라면 HE-AAC)을 명시합니다. 비디오와 오디오를 함께 묶을 때는 대상 플랫폼이 지원하는 오디오 코덱과 컨테이너(fMP4, TS) 조합을 먼저 정해야 합니다.

라우드니스와 헤드룸

리미터로 음압을 한계까지 끌어올린 마스터를 손실 압축하면, 디코딩 과정에서 샘플 값이 0 dBFS를 넘어 클리핑되거나 찌그러진 소리가 두드러질 수 있습니다. EBU R128 같은 라우드니스 기준에 맞춰 목표 음량을 정하고 트루 피크(true peak)를 -1 dBTP 정도로 여유 있게 두면, 플랫폼마다 음량이 들쑥날쑥한 문제와 함께 코덱이 만드는 클리핑도 줄일 수 있습니다.

ABX와 스펙트로그램으로 품질 검증하기

배포 전에는 원본과 인코딩 결과를 ABX 방식으로 비교하거나, 충격음이 많은 짧은 구간을 반복해서 들으며 문제를 찾습니다. 자동화 파이프라인에서는 FFmpeg로 디코딩한 뒤 스펙트로그램을 만들어 고주파가 잘려 나간 지점을 확인하거나, volumedetect·silencedetect 필터로 클리핑과 무음 구간을 검출하는 단계를 붙이기도 합니다.

FFmpeg에서 자주 쓰는 “안전한” 기본값 (요약)

목적권장 방향
최대 호환 배포MP3 CBR, 44.1 kHz, 모노/스테레오 명시
일반 음악 스트리밍AAC-LC, 128~192 kbps, .m4a/fMP4
실시간·음성Opus, -application voip, FEC/DTX는 시나리오에 맞게
웹 재생Ogg/WebM의 Opus 또는 MP4의 AAC + <source> 폴백

지연 시간 비교

실시간 통신에서는 음질만큼 지연이 중요합니다. 코덱의 알고리즘 지연은 프레임 크기와 인코더가 앞을 내다보는 구간(lookahead)으로 결정됩니다.

코덱프레임 크기지연 특성주 용도
MP31152 샘플큼 (인코더·디코더 지연이 수십~100ms 이상)파일 재생
AAC-LC1024 샘플중간 (수십 ms 이상)스트리밍
AAC-LD/ELD480/512 샘플작음방송 중계, FaceTime 등 통신
Opus2.5~60ms 선택기본 26.5ms, 최소 약 5ms실시간 통화

MP3와 AAC-LC는 지연이 커서 양방향 통화에는 맞지 않습니다. 실시간 음성이라면 Opus가 기본 선택이고, AAC 계열이 필요하다면 저지연 프로파일인 AAC-LD나 AAC-ELD를 씁니다.


용도별 코덱과 비트레이트 추천

시나리오추천 코덱비트레이트이유
음악 스트리밍AAC-LC128-256 kbps효율·품질 균형
팟캐스트MP364-96 kbps (모노)최대 호환
VoIP/화상회의Opus16-32 kbps저지연·음성 최적
게임 보이스챗Opus24-48 kbps저지연·대역폭 절약
인터넷 라디오AAC-LC/HE-AAC64-192 kbps넓은 재생 지원
USB/차량 오디오MP3192-320 kbps하드웨어 호환
웹 오디오Opus/AAC96-128 kbps브라우저 지원

스트리밍·화상회의·팟캐스트·게임 적용 사례

음악 스트리밍 플랫폼: AAC 사다리 + HLS

요구사항:

  • 다양한 품질 제공
  • 적응형 스트리밍
  • 대역폭 최적화

구현 전략

# 마스터 파일에서 다중 품질 생성
# 저품질 (모바일 데이터)
ffmpeg -i master.wav -c:a aac -b:a 96k low.m4a
# 중품질 (Wi-Fi)
ffmpeg -i master.wav -c:a aac -b:a 192k medium.m4a
# 고품질 (프리미엄)
ffmpeg -i master.wav -c:a aac -b:a 256k high.m4a
# 호환용 (레거시)
ffmpeg -i master.wav -c:a libmp3lame -b:a 192k compat.mp3

HLS 매니페스트

위에서 만든 .m4a 파일은 HLS용 세그먼트로 다시 패키징해야 합니다(예: ffmpeg -i low.m4a -c copy -f hls -hls_segment_type fmp4 low/playlist.m3u8). 마스터 플레이리스트의 각 항목은 개별 파일이 아니라 그 미디어 플레이리스트를 가리킵니다.

#EXTM3U
#EXT-X-STREAM-INF:BANDWIDTH=96000,CODECS="mp4a.40.2"
low/playlist.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=192000,CODECS="mp4a.40.2"
medium/playlist.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=256000,CODECS="mp4a.40.2"
high/playlist.m3u8

WebRTC 화상회의: Opus 저지연 설정

요구사항:

  • 초저지연 (<50ms)
  • 음성 명료도
  • 대역폭 적응

Opus 설정

WebRTC에서 Opus의 동작은 SDP의 fmtp 파라미터로 협상합니다. useinbandfec=1은 패킷 손실에 대비해 이전 프레임의 저품질 사본을 함께 보내는 인밴드 FEC를, usedtx=1은 말이 없는 구간에 전송을 거의 멈추는 DTX를 켭니다. SDP의 opus/48000/2는 규격상 항상 이렇게 표기하며, 실제 채널 수는 stereo 파라미터로 따로 정합니다. 송신 비트레이트는 RTCRtpSender.setParameters()의 maxBitrate로 제한할 수 있습니다.

m=audio 9 UDP/TLS/RTP/SAVPF 111
a=rtpmap:111 opus/48000/2
a=fmtp:111 minptime=10;useinbandfec=1;usedtx=1
a=maxptime:60

FFmpeg 테스트 인코딩

# 음성 최적화 (16 kbps)
ffmpeg -i voice.wav -c:a libopus -b:a 16k -application voip output.opus
# 음악 최적화 (128 kbps)
ffmpeg -i music.wav -c:a libopus -b:a 128k -application audio output.opus

팟캐스트 배포: 호환성 우선 MP3

요구사항:

  • 최대 호환성
  • 파일 크기 최소화
  • RSS 피드 지원

MP3 설정 (최대 호환)

# 모노, 64 kbps CBR
ffmpeg -i podcast.wav \
  -ac 1 \
  -c:a libmp3lame \
  -b:a 64k \
  -ar 44100 \
  -metadata title="에피소드 제목" \
  -metadata artist="팟캐스트 이름" \
  -metadata album="시즌 1" \
  -metadata date="2026" \
  output.mp3

Python 자동화

import subprocess
from pathlib import Path
def create_podcast_episode(input_file, metadata):
    """
    팟캐스트 에피소드 생성
    """
    output_file = Path(metadata['filename'])
    
    cmd = [
        'ffmpeg', '-y',
        '-i', input_file,
        '-ac', '1',
        '-c:a', 'libmp3lame',
        '-b:a', '64k',
        '-ar', '44100',
        '-metadata', f"title={metadata['title']}",
        '-metadata', f"artist={metadata['artist']}",
        '-metadata', f"album={metadata['album']}",
        '-metadata', f"date={metadata['date']}",
        str(output_file)
    ]
    
    subprocess.run(cmd, check=True)
    
    return output_file
# 사용
metadata = {
    'filename': 'episode_01.mp3',
    'title': '첫 번째 에피소드',
    'artist': '내 팟캐스트',
    'album': '시즌 1',
    'date': '2026'
}
create_podcast_episode('recording.wav', metadata)

게임 오디오: 플랫폼별 다중 코덱 빌드

요구사항:

  • PC: Opus (효율)
  • 모바일: AAC (호환)
  • 레거시: MP3 (폴백)

빌드 스크립트

import subprocess
from pathlib import Path
def build_game_audio(input_dir, output_dir):
    """
    게임 오디오 다중 포맷 생성
    """
    formats = [
        ('opus', 'libopus', '96k', '.opus'),
        ('aac', 'aac', '128k', '.m4a'),
        ('mp3', 'libmp3lame', '128k', '.mp3')
    ]
    
    for wav_file in Path(input_dir).glob('*.wav'):
        stem = wav_file.stem
        
        for name, codec, bitrate, ext in formats:
            output_file = Path(output_dir) / name / f"{stem}{ext}"
            output_file.parent.mkdir(parents=True, exist_ok=True)
            
            cmd = [
                'ffmpeg', '-y',
                '-i', str(wav_file),
                '-c:a', codec,
                '-b:a', bitrate,
                str(output_file)
            ]
            
            print(f"Creating {name}: {stem}{ext}")
            subprocess.run(cmd, check=True)
# 사용
build_game_audio('assets/audio', 'build/audio')

MP3·AAC에서 Opus로 옮길 때

MP3 → AAC

1단계: 호환성 확인

import subprocess
def check_aac_support():
    """
    FFmpeg AAC 인코더 확인
    """
    result = subprocess.run(
        ['ffmpeg', '-encoders'],
        capture_output=True,
        text=True
    )
    
    if 'aac' in result.stdout:
        print("AAC 인코더 사용 가능")
        return True
    return False

2단계: 비트레이트 조정

가능하면 무손실 원본에서 다시 인코딩해야 합니다. 원본이 없어 MP3를 AAC로 바꿀 수밖에 없다면, 재압축 손실을 고려해 원래 MP3보다 비트레이트를 크게 낮추지 않는 편이 좋습니다.

# MP3 → AAC (원본이 없을 때만)
ffmpeg -i input.mp3 -c:a aac -b:a 192k output.m4a

3단계: 메타데이터 이전

import subprocess
import json
def migrate_metadata(mp3_file, m4a_file):
    """
    MP3 ID3 → M4A 메타데이터
    """
    result = subprocess.run(
        ['ffprobe', '-v', 'quiet', '-print_format', 'json', '-show_format', mp3_file],
        capture_output=True,
        text=True
    )
    
    metadata = json.loads(result.stdout)['format']['tags']
    
    cmd = ['ffmpeg', '-y', '-i', mp3_file, '-c:a', 'aac', '-b:a', '128k']
    
    for key, value in metadata.items():
        cmd.extend(['-metadata', f'{key}={value}'])
    
    cmd.append(m4a_file)
    
    subprocess.run(cmd, check=True)
# 사용
migrate_metadata('song.mp3', 'song.m4a')

AAC/MP3 → Opus

1단계: 용도 확인

def select_opus_application(use_case):
    """
    Opus 애플리케이션 모드 선택
    """
    modes = {
        'voip': 'voip',      # 음성 통화
        'audio': 'audio',    # 음악
        'lowdelay': 'lowdelay'  # 저지연
    }
    
    return modes.get(use_case, 'audio')

2단계: 변환

# 음성 (32 kbps)
ffmpeg -i voice.mp3 -c:a libopus -b:a 32k -application voip output.opus
# 음악 (96 kbps)
ffmpeg -i music.aac -c:a libopus -b:a 96k -application audio output.opus

재생 실패와 음질 저하 해결

브라우저에서 Opus 파일이 재생되지 않을 때

증상: 일부 브라우저에서 Opus 파일이 재생되지 않음

<audio src="audio.opus" controls></audio>

원인: .opus 파일은 사실 Ogg 컨테이너입니다. Chrome과 Firefox는 문제없이 재생하지만, Safari는 버전과 플랫폼에 따라 Ogg 컨테이너 지원이 제한적이었습니다. 서버가 .opus를 application/octet-stream 같은 잘못된 MIME 타입으로 보내는 것도 흔한 원인입니다. 해결: audio/ogg 또는 audio/webm MIME 타입으로 서빙하고, AAC 버전을 폴백으로 함께 제공합니다.

# Ogg 컨테이너
ffmpeg -i input.wav -c:a libopus -b:a 128k output.ogg
# WebM 컨테이너
ffmpeg -i input.wav -c:a libopus -b:a 128k output.webm
<audio controls>
  <source src="audio.ogg" type="audio/ogg; codecs=opus">
  <source src="audio.m4a" type="audio/mp4">
</audio>

MP3를 AAC로 변환했더니 음질이 떨어질 때

증상: MP3 → AAC 변환 시 음질 저하

# 잘못된 예
ffmpeg -i input.mp3 -c:a aac -b:a 128k output.m4a
# 손실 → 손실 (품질 저하)

해결: 무손실 원본 유지

# 올바른 워크플로우
# 1. 원본 WAV/FLAC 보관
# 2. 필요한 포맷으로 한 번만 인코딩
ffmpeg -i master.wav -c:a aac -b:a 128k aac_version.m4a
ffmpeg -i master.wav -c:a libmp3lame -b:a 192k mp3_version.mp3

구형 기기에서 AAC/Opus가 재생되지 않을 때

증상: 구형 기기에서 AAC/Opus 재생 안 됨 해결: 다중 포맷 제공

<audio controls>
  <source src="audio.opus" type="audio/ogg; codecs=opus">
  <source src="audio.m4a" type="audio/mp4">
  <source src="audio.mp3" type="audio/mpeg">
  브라우저가 audio 태그를 지원하지 않습니다.
</audio>

VBR 인코딩 결과 크기를 미리 알 수 없을 때

증상: VBR 모드에서 파일 크기를 미리 알 수 없음 해결: ABR 또는 CBR 사용

# CBR (크기 예측 가능)
ffmpeg -i input.wav -c:a aac -b:a 128k output.m4a
# 파일 크기 계산
# 크기 = (비트레이트 * 시간) / 8
# 128 kbps * 300s / 8 = 4.8 MB

참고 자료


자주 묻는 질문 (FAQ)

Q. Opus로 인코딩한 파일이 브라우저에서 재생되지 않으면 무엇을 확인해야 하나요?

A. 대부분 코덱이 아니라 컨테이너와 MIME 타입 문제입니다. Opus 스트림은 Ogg나 WebM 컨테이너에 담아 올바른 MIME 타입으로 서빙해야 브라우저가 안정적으로 인식하므로, FFmpeg에서 -c:a libopus로 인코딩하면서 출력 확장자를 .ogg나 .webm으로 지정합니다. 구형 기기까지 지원해야 한다면 AAC 버전을 함께 준비해 두고 source 태그로 대체 경로를 두는 편이 안전합니다.


같이 보면 좋은 글