버퍼링 할당량 초과

Joe Medley
Joe Medley

Media Source Extensions (MSE)를 사용하는 경우 결국 처리해야 하는 한 가지 문제가 오버플로 버퍼입니다. 이 경우 QuotaExceededError가 발생합니다. 이 도움말에서는 이 문제를 해결하는 몇 가지 방법을 설명합니다.

QuotaExceededError란 무엇인가요?

기본적으로 QuotaExceededErrorSourceBuffer 객체에 너무 많은 데이터를 추가하려고 하면 발생합니다. 상위 MediaSource 요소에 SourceBuffer 객체를 더 추가해도 이 오류가 발생할 수 있습니다. 이러한 내용은 이 도움말에서 다루지 않습니다. SourceBuffer에 데이터가 너무 많은 경우 SourceBuffer.appendBuffer()를 호출하면 Chrome 콘솔 창에 다음 메시지가 트리거됩니다.

할당량 콘솔 오류

이와 관련해 몇 가지 유의해야 할 사항이 있습니다. 먼저 QuotaExceededError 이름이 메시지 어디에도 표시되지 않습니다. 이를 확인하려면 오류를 포착할 수 있는 위치에 브레이크포인트를 설정하고 보기 또는 범위 창에서 이를 검사합니다. 아래에서 확인해 보세요.

할당량 보기 창

둘째, SourceBuffer가 처리할 수 있는 데이터의 양을 확인할 확실한 방법이 없습니다.

다른 브라우저의 동작

이 문서를 작성하는 시점에는 Safari가 많은 빌드에서 QuotaExceededError을 발생시키지 않습니다. 대신 2단계 알고리즘을 사용하여 프레임을 삭제하고 appendBuffer()를 처리할 공간이 충분하면 중지합니다. 먼저 현재 시간으로부터 0~30초 사이의 프레임을 30초 단위로 해제합니다. 그런 다음 재생 시간에서 currentTime 후 30초까지 30초 단위로 프레임을 해제합니다. 자세한 내용은 2014년 Webkit 변경사항을 참고하세요.

다행히 Chrome과 함께 Edge와 Firefox에서도 이 오류가 발생합니다. 다른 브라우저를 사용 중이라면 직접 테스트해야 합니다. 실제 미디어 플레이어를 위해 빌드하지는 않겠지만, 프랑소와 보포르의 소스 버퍼 한도 테스트를 사용하면 적어도 동작을 관찰할 수 있습니다.

데이터를 얼마나 추가할 수 있나요?

정확한 숫자는 브라우저마다 다릅니다. 현재 추가된 데이터의 양을 쿼리할 수 없으므로 추가하는 양을 직접 추적해야 합니다. 주목해야 할 사항은 다음과 같습니다. 이메일을 작성하는 시점에 수집할 수 있는 최선의 데이터입니다. Chrome의 경우 이 숫자는 상한선이므로 시스템에 메모리 부족 문제가 발생하면 더 작을 수 있습니다.

Chrome Chromecast* Firefox Safari Edge
동영상 150MB 30MB 100MB 290MB 알 수 없음
오디오 12MB 2MB 15MB 14MB 알 수 없음
  • 또는 메모리가 제한된 기타 Chrome 기기

그러면 어떻게 해야 하나요?

지원되는 데이터의 양은 매우 다양하며 SourceBuffer에서 데이터의 양을 찾을 수 없으므로 QuotaExceededError를 처리하여 간접적으로 가져와야 합니다. 이제 몇 가지 방법을 살펴보겠습니다.

QuotaExceededError를 처리하는 방법에는 여러 가지가 있습니다. 실제로는 하나 이상의 접근 방식을 조합하는 것이 가장 좋습니다. HTMLMediaElement.currentTime을 초과하여 가져오고 추가하려는 양에 따라 작업을 기반으로 하고 QuotaExceededError에 따라 크기를 조정하는 방식을 취해야 합니다. 또한 mpd 파일(MPEG-DASH) 또는 m3u8 파일(HLS)과 같은 매니페스트를 사용하면 버퍼에 추가하는 데이터를 추적하는 데 도움이 됩니다.

이제 QuotaExceededError를 처리하는 몇 가지 접근 방식을 살펴보겠습니다.

  • 불필요한 데이터를 삭제하고 다시 추가합니다.
  • 더 작은 프래그먼트를 추가합니다.
  • 재생 해상도를 낮춥니다.

이 두 가지를 함께 사용할 수도 있지만 하나씩 설명하겠습니다.

불필요한 데이터 삭제 및 다시 추가

사실 이 메서드는 '가장 빨리 사용될 가능성이 낮은 데이터를 삭제한 다음 곧 사용될 가능성이 높은 데이터의 추가를 다시 시도'해야 합니다. 제목이 너무 깁니다. 무슨 말인지 기억해 두셔야 해요.

최근 데이터를 삭제하는 것은 SourceBuffer.remove()를 호출하는 것만큼 간단하지 않습니다. SourceBuffer에서 데이터를 삭제하려면 업데이트 플래그가 false여야 합니다. 지원되지 않는 경우 데이터를 삭제하기 전에 SourceBuffer.abort()를 호출합니다.

SourceBuffer.remove()를 호출할 때 유의해야 할 사항이 몇 가지 있습니다.

  • 이 경우 재생에 부정적인 영향을 미칠 수 있습니다. 예를 들어 동영상을 곧 다시 재생하거나 반복하려면 동영상의 시작 부분을 삭제하지 않는 것이 좋습니다. 마찬가지로 나 또는 사용자가 데이터를 삭제한 동영상 부분으로 탐색하는 경우 탐색을 충족하기 위해 해당 데이터를 다시 추가해야 합니다.
  • 가능한 한 보수적으로 삭제합니다. currentTime 또는 그 이전의 키프레임에서 시작되는 현재 재생 중인 프레임 그룹을 삭제하면 재생 지연이 발생할 수 있으므로 주의하세요. 이러한 정보를 매니페스트에서 사용할 수 없는 경우 웹 앱에 의해 바이트스트림에서 파싱되어야 할 수도 있습니다. 미디어 매니페스트 또는 미디어의 키프레임 간격에 대한 앱 지식을 사용하면 현재 재생 중인 미디어를 삭제하지 않도록 앱에서 삭제 범위를 선택하는 데 도움이 될 수 있습니다. 삭제하는 항목이 무엇이든 현재 재생 중인 사진 그룹이나 그 이후의 처음 몇 개는 삭제하지 마세요. 일반적으로 미디어가 더 이상 필요하지 않다고 확신하지 않는 한 현재 시간 이후부터는 삭제하지 않습니다. 재생 헤드 근처에서 삭제하면 중단될 수 있습니다.
  • Safari 9 및 Safari 10이 SourceBuffer.abort()를 올바르게 구현하지 않습니다. 오히려 오류를 발생시켜 재생을 중단시킵니다. 다행히 여기여기에 공개 버그 추적기가 있습니다. 그때까지는 어떻게든 이 문제를 해결해야 합니다. Shaka Player는 이러한 버전의 Safari에서 빈 abort() 함수를 스텁하여 이를 실행합니다.

더 작은 프래그먼트 추가

아래에 절차를 보여드렸습니다. 이 방법은 모든 경우에 작동하지 않을 수 있지만, 더 작은 청크의 크기를 필요에 맞게 조정할 수 있다는 이점이 있습니다. 또한 네트워크로 돌아가지 않아도 되므로 일부 사용자에게는 추가 데이터 비용이 발생할 수 있습니다.

const pieces = new Uint8Array([data]);
(function appendFragments(pieces) {
    if (sourceBuffer.updating) {
    return;
    }
    pieces.forEach(piece => {
    try {
        sourceBuffer.appendBuffer(piece);
    }
    catch e {
        if (e.name !== 'QuotaExceededError') {
        throw e;
        }

        // Reduction schedule: 80%, 60%, 40%, 20%, 16%, 12%, 8%, 4%, fail.
        const reduction = pieces[0].byteLength * 0.8;
        if (reduction / data.byteLength < 0.04) {
        throw new Error('MediaSource threw QuotaExceededError too many times');
        }
        const newPieces = [
        pieces[0].slice(0, reduction),
        pieces[0].slice(reduction, pieces[0].byteLength)
        ];
        pieces.splice(0, 1, newPieces[0], newPieces[1]);
        appendBuffer(pieces);  
    }
    });
})(pieces);

재생 해상도 낮추기

이는 최근 데이터를 삭제하고 다시 추가하는 것과 유사합니다. 사실 두 작업은 함께 실행할 수 있지만 아래 예에서는 해상도만 낮추는 방법을 보여줍니다.

이 기법을 사용할 때 유의해야 할 몇 가지 사항이 있습니다.

  • 새 초기화 세그먼트를 추가해야 합니다. 표현을 변경할 때마다 이 작업을 실행해야 합니다. 새 초기화 세그먼트는 다음 미디어 세그먼트를 위한 것이어야 합니다.
  • 추가된 미디어의 프레젠테이션 타임스탬프는 버퍼에 있는 데이터의 타임스탬프와 최대한 일치해야 하지만 점프할 수는 없습니다. 버퍼링된 데이터를 겹치면 브라우저에 따라 끊김이나 잠시 중단이 발생할 수 있습니다. 추가하는 항목과 관계없이 재생 헤드를 겹치지 마세요. 그러면 오류가 발생합니다.
  • 탐색 시 재생이 중단될 수 있습니다. 특정 위치로 이동하여 거기서 재생을 재개하고 싶을 수 있습니다. 이렇게 하면 탐색이 완료될 때까지 재생 중단이 발생한다는 점에 유의하세요.