ABR 스트림의 비트레이트 핑퐁 현상을 방지하는 방법

이 기사는 AI를 사용하여 영어에서 번역되었습니다. 원문 읽기

ABR 알고리즘을 혼란스럽게 만들지 않는 트랜스코딩 래더 설계 방법

실제 환경에서 HLS 재생을 관찰해 본 적이 있다면, 이런 현상을 본 적이 있을 것입니다: 스트림이 두 렌디션 사이를 계속 왔다 갔다 합니다. 올라갔다, 내려갔다, 올라갔다, 내려갔다. 시청자는 몇 초마다 화질이 끊임없이 변하는 것을 봅니다. 이는 처음부터 낮은 렌디션에 머무는 것보다 더 나쁜 경험입니다. 안정적인 720p 스트림은 의도적인 것으로 느껴지지만, 720p와 1080p 사이를 10초마다 오가는 스트림은 고장난 것처럼 느껴집니다.

근본적인 원인은 거의 항상 동일합니다: 인코딩 래더의 렌디션 간 비트레이트가 너무 가깝거나, 단계 간 화질 차이가 대역폭 증가를 정당화하지 못하는 경우입니다. 클라이언트 측 ABR 알고리즘이 결정을 내리지 못하는 이유는 "이 정도면 감당할 수 있다"와 "이건 감당할 수 없다"의 차이가 극히 미미하기 때문입니다.

이 문제를 올바르게 해결하는 방법에 대해 이야기해 봅시다.

비트 퍼 픽셀(BPP) 건전성 검사

무엇보다 먼저, 비트 퍼 픽셀(BPP)이 래더에 대해 무엇을 알려주는지 이해해야 합니다. 이는 주어진 해상도에 대해 특정 비트레이트가 적절한지 평가하는 가장 간단한 지표입니다.

공식은 간단합니다:

BPP = bitrate / (width × height × framerate)

예를 들어, 1920×1080 스트림을 4500 kbps, 30 fps로 전송하는 경우:

BPP = 4,500,000 / (1920 × 1080 × 30) = 0.072

왜 이것이 중요할까요? BPP는 각 단계의 압축 밀도를 알려주기 때문입니다. 래더에서 인접한 두 단계의 BPP 값이 매우 유사하면, 시청자는 의미 있는 화질 차이를 느끼지 못합니다. 하지만 ABR 알고리즘은 여전히 두 단계 사이를 전환하려 합니다. 이것이 핑퐁 현상의 원인입니다.

잘 설계된 래더는 해상도가 증가할수록 BPP 곡선이 하향해야 합니다. 이는 비디오 코덱의 실제 특성을 반영합니다: 높은 해상도에서는 480p와 동일한 체감 품질을 달성하기 위해 픽셀당 더 적은 비트가 필요합니다. BPP가 단계 전체에서 평탄하거나 일관성이 없다면, 무언가 잘못된 것입니다.

여기서 "0.70 법칙"이 실용적인 참고가 됩니다. 픽셀 수를 두 배로 늘릴 때(예를 들어 720p에서 1080p로), 낮은 해상도의 BPP에 대략 0.70배를 적용해야 한다는 개념입니다. 이것은 법칙이 아니라 경험 법칙이지만, 이상치를 빠르게 발견하는 방법을 제공합니다. 래더의 BPP 값을 그래프로 그렸을 때 하나의 단계가 이웃한 단계에 비해 눈에 띄게 높거나 낮다면, 그 단계가 문제를 일으킬 것입니다.

핵심: 깔끔하고 둥근 숫자의 비트레이트만 선택하지 마세요. 각 단계의 BPP를 계산하고 곡선이 합리적인지 확인하세요. 인접한 두 단계의 BPP가 15~20% 이내의 차이라면, 시청자는 구분하지 못하지만 ABR 휴리스틱은 두 단계 사이를 전환하는 데 시간을 낭비합니다.

비트레이트 간격: 1.5배 경험 법칙

보편적인 표준은 없지만, 일반적인 엔지니어링 가이드라인으로 인접한 비트레이트 단계 사이에 최소 1.5배의 비율을 유지하는 것이 권장됩니다. 일부 구현에서는 이를 2배까지 늘립니다.

왜 그럴까요? ABR 알고리즘은 대역폭 추정(BWE)을 사용하여 어떤 렌디션을 선택할지 결정하기 때문입니다. 추정에는 신뢰 구간이 있어 정확하지 않습니다. 두 렌디션이 2.5 Mbps와 3.0 Mbps에 있다면, 약간 불안정한 연결에서 BWE가 3.0 Mbps 위아래로 쉽게 진동하여 끊임없는 전환이 발생합니다. 대신 2.0 Mbps에서 4.0 Mbps로 점프한다면, 알고리즘이 전환을 트리거하려면 훨씬 더 큰 대역폭 변화가 필요합니다. 결과: 더 안정적인 재생.

구체적인 예를 들어보겠습니다. 깔끔한 4단계 래더가 있다고 가정합니다:

해상도 비트레이트 BPP (30fps) 이전 단계 대비 비율
480×270400 kbps0.103
960×5402000 kbps0.1295.0×
1280×7202800 kbps0.1011.4×
1920×10804500 kbps0.0721.6×

언뜻 보면 합리적으로 보입니다 — 4개의 해상도, 증가하는 비트레이트. 하지만 540p에서 720p로의 점프를 보세요: 2000 kbps에서 2800 kbps. 이는 겨우 1.4배 비율입니다. 2.5~3 Mbps 근처를 맴도는 연결(대부분의 모바일 연결이 이에 해당)에서는 BWE가 끊임없이 그 임계값을 넘나들 것입니다. 올라갔다, 내려갔다, 올라갔다, 내려갔다. 시청자는 몇 세그먼트마다 해상도가 전환되는 것을 봅니다.

또 다른 문제가 있습니다: BPP가 실제로 540p의 0.129에서 720p의 0.101로 떨어집니다. 즉, 시청자는 더 많은 픽셀을 얻지만 픽셀당 데이터는 적어집니다. 콘텐츠에 따라 720p 렌디션이 540p보다 의미 있게 더 좋아 보이지 않을 수 있습니다 — 해상도는 추가했지만 압축 여유를 잃은 것입니다. ABR 알고리즘은 의미 없는 전환을 하고 있는 셈입니다.

이 래더의 개선된 버전은 720p 비트레이트를 높이고 540p를 낮추는 것입니다:

해상도 비트레이트 BPP (30fps) 이전 단계 대비 비율
480×270400 kbps0.103
960×5401500 kbps0.0963.75×
1280×7203000 kbps0.1092.0×
1920×10805800 kbps0.0931.93×

이제 540p에서 720p로의 점프는 깔끔한 2배 비율입니다. 플레이어가 상위 전환을 고려하려면 BWE가 두 배가 되어야 합니다. 그리고 BPP는 실제로 0.096에서 0.109로 증가합니다. 즉, 720p 단계는 더 많은 픽셀 더 나은 압축 품질을 제공하여 시청자가 실제 개선을 느낍니다. 720p에서 1080p로의 점프도 1.93배로 마찬가지로 견고하며, BPP는 0.093으로 약간만 감소합니다. 이는 높은 해상도에서 기대되는 효율성 향상을 반영합니다.

레이트별 확인: 단일 렌디션 재생 테스트

팀들이 실행하는 것을 거의 보지 못하지만 매우 중요한 것이 있습니다: 각 렌디션을 개별적으로 재생하고 전체를 시청하는 것입니다.

당연한 것처럼 들리지만, 대부분의 사람들은 완전한 멀티 배리언트 스트림으로만 ABR을 테스트합니다. 단일 렌디션을 분리하여 처음부터 끝까지 재생하는 경우는 없습니다. 이렇게 하면 ABR 동작이 숨기고 있는 문제를 발견할 수 있습니다:

  • 자체 선언된 비트레이트에서도 버퍼링이 발생하는 렌디션 (플레이리스트에서 선언된 BANDWIDTH가 실제 피크 비트레이트에 비해 너무 낮기 때문)
  • 인코더가 특정 장면에서 어려움을 겪어 눈에 띄는 아티팩트가 발생하는 렌디션
  • 해상도/비트레이트 조합이 대상 장치의 디코더에 너무 부담이 되어 프레임 레이트가 떨어지거나 끊기는 렌디션

이를 테스트하기 위해 여러 방법으로 단일 렌디션 재생을 강제할 수 있습니다:

hls.js 데모 페이지 사용: 멀티 배리언트 스트림을 로드한 후, 품질 선택 드롭다운에서 각 레벨을 하나씩 수동으로 고정합니다. hlsjs.video-dev.org/demo/의 hls.js 데모는 모든 품질 레벨을 표시하고 ABR을 오버라이드할 수 있게 해줍니다. 대표적인 콘텐츠를 최소 몇 분간 재생하세요. "Buffer & Statistics" 탭에서 드롭된 프레임을 확인하세요.

Apple 플랫폼에서 AVPlayer 사용: AVPlayerItempreferredPeakBitRatepreferredMaximumResolution을 사용하여 재생을 단일 렌디션으로 제한합니다. 또는 더 간단하게: 하나의 배리언트만 포함하는 테스트 플레이리스트를 만드세요.

ffprobe 또는 mediainfo 사용: 재생하기 전에 각 렌디션의 실제 비트레이트 통계를 확인하세요. 마스터 플레이리스트의 BANDWIDTH 값은 평균이 아닌 피크를 반영해야 합니다. VBR 인코딩의 스파이크가 평균보다 40% 이상 높다면, 선언하는 BANDWIDTH에 이를 반영해야 합니다.

단일 렌디션이 자체 선언된 비트레이트에서 원활하게 재생되지 않으면, ABR 모드에서는 확실히 문제를 일으킬 것입니다. ABR 알고리즘은 충분한 대역폭이 있다고 생각하고 해당 렌디션을 선택하고, VBR 스파이크에 부딪혀 멈추고, 다시 내려가고, 복구되면 다시 해당 렌디션을 선택합니다 — 핑퐁입니다.

세그먼트 길이: ABR 전환 클록

사람들이 간과하는 또 다른 요소가 있습니다: 세그먼트 길이는 ABR 알고리즘이 결정을 내리는 빈도를 직접 제어합니다. 각 세그먼트 경계는 잠재적인 전환 지점입니다. 따라서 2초 세그먼트를 사용하면 플레이어는 분당 최대 30회까지 재평가하고 전환할 수 있습니다. 6초 세그먼트에서는 분당 10회로 줄어듭니다. 10초 세그먼트에서는 6회뿐입니다.

래더의 비트레이트 간격이 이미 좁은 경우 이는 매우 중요합니다. 짧은 세그먼트와 가까운 비트레이트 단계의 조합은 최악입니다 — 시청자가 볼 필요 없는 미세한 전환을 ABR 알고리즘에게 최대한 많은 기회를 주는 것입니다.

반대로, 긴 세그먼트는 진동에 대한 자연적인 완충 장치 역할을 합니다. 대역폭 추정이 변동하더라도, 플레이어는 방금 가져온 세그먼트의 길이 동안 현재 렌디션을 유지해야 합니다. 다음 결정 시점이 올 때까지 BWE가 안정될 수 있습니다.

HLS 사양은 특정 길이를 규정하지 않지만, Apple의 오서링 가이드라인은 6초 타깃을 권장합니다. 실제로는:

  • 2초 세그먼트는 빠른 시작과 신속한 적응이 중요한 저지연 라이브에 적합합니다. 그러나 지속적인 전환을 피하려면 간격이 넓은 래더가 필요합니다.
  • 6초 세그먼트는 VOD와 표준 라이브에 좋은 기본값입니다. 결정 사이에 ABR 알고리즘이 신뢰할 수 있는 대역폭 추정을 구축할 충분한 시간을 제공합니다.
  • 10초 세그먼트는 매우 안정적이지만 적응이 느립니다. 대역폭이 급격히 떨어지면, 플레이어는 시간 내에 완료할 수 없는 높은 비트레이트 세그먼트를 다운로드하는 데 갇히게 됩니다.

VBR 인코딩에도 미묘한 점이 있습니다: 세그먼트 내 비트레이트 변동은 세그먼트 길이에 따라 증가합니다. 장면 전환의 10초 세그먼트 — 정적 화면에서 액션 시퀀스로 — 는 내부적으로 막대한 비트레이트 변동을 가질 수 있습니다. 플레이리스트에서 선언된 BANDWIDTH가 전체 평균에는 맞지만 세그먼트별 피크에는 맞지 않으면, ABR 알고리즘은 예상치 못한 상황에 직면합니다. 짧은 세그먼트는 세그먼트별 비트레이트가 더 일관되는 경향이 있어 BWE 정확도가 향상됩니다.

결론: 진동이 보이고 래더 간격이 적절해 보인다면, 세그먼트 길이를 확인하세요. 4초에서 6초로 변경하는 것만으로 충분할 수 있습니다.

Network Link Conditioner로 실제 조건 시뮬레이션하기

안정적인 100 Mbps 광섬유 연결에서 ABR을 테스트하는 것은 의미가 없습니다. 실제 환경을 시뮬레이션해야 하며, macOS에서는 Apple의 Network Link Conditioner가 최적의 도구입니다.

Apple의 Additional Tools for Xcode 패키지에서 얻을 수 있습니다: Xcode에서 Xcode > Open Developer Tool > More Developer Tools로 이동하면 Apple 개발자 다운로드 페이지로 이동합니다. "Additional Tools for Xcode"를 검색하고, 사용 중인 Xcode 버전의 DMG를 다운로드하여 열고, Hardware 폴더에서 Network Link Conditioner.prefPane을 찾으세요. 더블 클릭하여 설치하면 시스템 설정(이전 macOS에서는 시스템 환경설정)에 패널로 나타납니다. 특정 처리량, 지연 시간, 패킷 손실률, DNS 지연을 가진 대역폭 프로필을 정의할 수 있습니다.

중요한 커스텀 프로필을 만드세요:

  • 보통 수준의 4G: 다운 8 Mbps / 업 2 Mbps, 80ms RTT, 1% 패킷 손실
  • 나쁜 WiFi: 다운 3 Mbps / 업 1 Mbps, 150ms RTT, 3% 패킷 손실
  • 전환 테스트: 15 Mbps로 시작, 재생 중 수동으로 2 Mbps로 전환

마지막 테스트가 결정적입니다. 래더가 잘 설계되었다면, 플레이어는 몇 초 내에 부드럽게 낮은 렌디션으로 이동하고 그 상태를 유지해야 합니다. 두 렌디션 사이에서 진동을 시작하면, 대역폭 경계에서 단계가 너무 가깝다는 뜻입니다.

iOS 기기에서는 개발자 설정을 통해 Network Link Conditioner를 사용할 수 있습니다 (기기를 Xcode에 연결한 후 설정 > 개발자에서 활성화).

이 테스트의 목표는 단순히 "버퍼링이 발생하는가?"가 아니라 "스트림이 하나의 렌디션에 안착하고 그 상태를 유지하는가?"입니다. 좋은 ABR 경험은 전환이 드물고 결정적인 것입니다. 시청자는 한 번 화질 변경을 보고, 그 후 안정됩니다.

Apple의 AVMetrics로 프로덕션 환경의 전환 모니터링하기

iOS 18부터 Apple은 AVFoundation에 AVMetrics API를 도입했습니다. 이것은 현장에서 ABR 동작을 모니터링하기 위한 혁신적인 도구입니다.

우리의 목적에 핵심적인 이벤트 유형은 배리언트 전환 이벤트입니다. AVPlayer가 HLS 배리언트 간 전환할 때마다, 어디에서 어디로 전환했는지와 미디어 렌디션 세부 정보를 알려주는 메트릭 이벤트를 받습니다. 플레이어가 리버퍼링할 때의 스톨 이벤트와, 세션 종료 시 전체 KPI를 포함하는 요약 이벤트도 받을 수 있습니다.

Swift 패턴은 다음과 같습니다:

let playerItem: AVPlayerItem = // your configured item

let switchMetrics = playerItem.metrics(
    forType: AVMetricPlayerItemVariantSwitchEvent.self
)
let stallMetrics = playerItem.metrics(
    forType: AVMetricPlayerItemStallEvent.self
)

for await (event, _) in switchMetrics.chronologicalMerge(with: stallMetrics) {
    switch event {
    case let switchEvent as AVMetricPlayerItemVariantSwitchEvent:
        // Log: from variant, to variant, timestamp
        await analytics.logSwitch(switchEvent)
    case let stallEvent as AVMetricPlayerItemStallEvent:
        // Log: stall duration, variant at time of stall
        await analytics.logStall(stallEvent)
    default:
        break
    }
}

분석 데이터에서 주목해야 할 사항:

  • 전환 빈도: 평균 세션에서 분당 3~4회 이상 전환이 있다면 래더에 문제가 있습니다. 건강한 스트림은 보통 시작 시 1~2회 전환하는 정도입니다.
  • 진동 패턴: 두 렌디션이 계속 번갈아 나타남 — 단계가 너무 가까운 전형적인 징후입니다.
  • 상위 전환과 관련된 스톨: 더 높은 렌디션으로 전환한 직후 스톨이 발생하면, 플레이리스트의 BANDWIDTH 선언이 너무 낮습니다.

WWDC 2025에서 Apple은 배리언트 전환 이벤트에 미디어 렌디션 정보를 포함하도록 AVMetrics를 확장하여, 전환 중 어떤 오디오/비디오/자막 트랙이 활성화되어 있었는지 더 쉽게 확인할 수 있게 되었습니다.

Apple 플랫폼이 아닌 경우, hls.js의 LEVEL_SWITCHEDFRAG_BUFFERED 이벤트에서 유사한 데이터를 수집할 수 있습니다. 동일한 원칙이 적용됩니다.

hls.js로 실험하기: ABR 동작 튜닝

hls.js 데모 페이지(hlsjs.video-dev.org/demo/)는 웹에서 ABR 전환 동작을 실험하기 위한 최고의 무료 도구입니다. HLS 스트림을 로드하고 "Real-time metrics"와 "Buffer & Statistics" 패널을 사용하여 무슨 일이 일어나는지 관찰하세요.

실험해 볼 주요 hls.js 설정 매개변수:

  • abrEwmaFastVoDabrEwmaSlowVoD: 대역폭 추정을 위한 EWMA(지수 가중 이동 평균)를 제어합니다. 낮은 값은 플레이어가 대역폭 변화에 더 빠르게 반응합니다(더 공격적인 전환). 높은 값은 더 보수적입니다(전환이 느리고 더 안정적). 전환이 너무 많다면 이 값을 높여보세요.
  • abrBandWidthFactor(기본값: 0.95)와 abrBandWidthUpFactor(기본값: 0.7): 안전 마진입니다. 플레이어는 비트레이트가 estimatedBandwidth × factor 이하인 렌디션을 선택합니다. 상위 전환 팩터는 의도적으로 낮게 설정됩니다 — 플레이어는 하위 전환보다 상위 전환에 더 보수적입니다. 래더 간격이 좁다면 진동을 줄이기 위해 abrBandWidthUpFactor를 0.6으로 낮추는 것을 고려하세요.
  • abrMaxWithRealBitrate(기본값: false): 활성화하면 ABR 컨트롤러가 플레이리스트에서 선언된 BANDWIDTH 대신 가져온 세그먼트의 실제 측정 비트레이트를 사용합니다. 선언된 비트레이트가 부정확한 경우 특히 유용합니다.

하지만 여기서 중요한 점이 있습니다: 안정적인 재생을 위해 이러한 매개변수를 크게 튜닝해야 한다면, 아마도 래더가 잘못된 것입니다. 이 매개변수들은 미세 조정용입니다. 인코딩 래더 자체가 기반입니다. 적절한 간격의 래더는 어떤 플레이어에서든 기본 ABR 설정으로 잘 작동합니다.

실용적 권장 사항

체크리스트로 요약하면:

  1. 래더의 각 단계에 대해 BPP를 계산하세요. 해상도가 증가할수록 BPP가 감소하는지 확인하세요. BPP가 인접 단계의 15% 이내인 단계는 제거하거나 조정하세요.
  2. 인접 단계 간 최소 1.5배 비트레이트 비율을 유지하세요. 가능하면 2배를 권장합니다. 특히 대역폭 변동이 가장 큰 영향을 미치는 래더의 하위 절반에서 중요합니다.
  3. 각 렌디션을 개별적으로 테스트하세요. 단일 배리언트 재생을 강제하고 대표적인 콘텐츠를 처음부터 끝까지 시청하세요. 단독으로 원활하게 재생되지 않으면, ABR에서도 원활하지 않습니다.
  4. Network Link Conditioner를 사용하여 대역폭 저하를 시뮬레이션하세요. 스트림이 렌디션에 빠르게 안착하고 유지되어야 합니다.
  5. 세그먼트 길이를 확인하세요. 2~4초에서 진동이 보이면, 6초를 시도하세요. 긴 세그먼트는 결정 사이에 BWE가 안정화될 시간을 더 줌으로써 전환 빈도를 자연스럽게 줄입니다.
  6. 플레이어를 계측하세요. Apple에서는 AVMetrics, 웹에서는 hls.js 이벤트를 사용하세요. 세션당 전환 빈도를 추적하세요. 시작 단계 이외에 세션 평균 전환 횟수가 몇 회 이상이면 조사하세요.
  7. 선언된 BANDWIDTH만 신뢰하지 마세요. hls.js에서 abrMaxWithRealBitrate를 사용하거나, ffprobe로 VBR 피크가 선언 값을 초과하지 않는지 확인하세요.
  8. 더 적은 단계가 더 좋은 경우가 많습니다. 적절한 간격의 5단계 래더가 절반의 단계가 너무 가까운 10단계 래더보다 우수합니다. 시청자에게 12개의 품질 레벨은 필요 없습니다. 의미 있게 다르고 안정적으로 재생되는 4~5개면 충분합니다.

ABR의 핵심은 보이지 않아야 한다는 것입니다. 시청자는 ABR이 작동하고 있다는 것을 인식해서는 안 됩니다. 만약 인식한다면, 무언가 잘못된 것입니다 — 그리고 열 번 중 아홉 번은 래더가 원인입니다.

참고 문헌:

Need Help With Your Streaming Project?

This article was written by experienced professionals available through iReplay.tv. Whether you need expertise in HLS, hls.js—our network of specialists can bring your project to life.

Hire a Professional →