버퍼링 할당량 초과

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);

재생 해상도 낮추기

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

이 기법을 사용할 때는 다음 사항에 유의해야 합니다.

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