버퍼링 할당량 초과

조 메들리
조 메들리

MSE (Media Source Extensions)를 사용하는 경우 최종적으로 처리해야 할 한 가지는 과도하게 가득 찬 버퍼입니다. 이 경우 QuotaExceededError라는 것을 얻게 됩니다. 이 도움말에서는 이를 처리하는 몇 가지 방법을 다룰 것입니다

QuotaExceededError란 무엇인가요?

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

할당량 콘솔 오류입니다.

이와 관련해 몇 가지 주의할 사항이 있습니다. 먼저 QuotaExceededError라는 이름이 메시지의 어디에도 표시되지 않습니다. 이를 확인하려면 오류를 포착하고 시계 또는 범위 창에서 검사할 수 있는 위치에 중단점을 설정합니다. 아래에 나와 있습니다.

할당량 확인 기간

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

다른 브라우저에서의 동작

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

다행히 Chrome, Edge, Firefox와 함께 이 오류가 발생합니다. 다른 브라우저를 사용하는 경우 자체적으로 테스트를 해야 합니다. 실제 미디어 플레이어용으로 빌드하는 것은 아닐지라도 François Beaufort의 소스 버퍼 제한 테스트를 사용하면 최소한 동작을 관찰할 수 있습니다.

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

정확한 숫자는 브라우저에 따라 다릅니다. 현재 추가된 데이터의 양을 쿼리할 수 없기 때문에 직접 추가하는 양을 추적해야 합니다. 볼 만한 자료는 이 글을 작성하는 당시 제가 수집할 수 있는 최선의 데이터입니다. Chrome의 경우 이 숫자는 상한값이므로 시스템이 메모리 압력에 도달하면 이 숫자가 작아질 수 있습니다.

Chrome Chromecast* Firefox Safari 에지
동영상 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);

재생 해상도 낮추기

이는 최근 데이터를 삭제하고 다시 추가하는 것과 유사합니다. 아래 예는 해상도 낮추기만 보여주지만 사실 이 두 가지가 함께 실행될 수 있습니다.

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

  • 새 초기화 세그먼트를 추가해야 합니다. 표현을 변경할 때마다 이 작업을 수행해야 합니다. 새 초기화 세그먼트는 이어지는 미디어 세그먼트에 관한 것이어야 합니다.
  • 추가된 미디어의 프레젠테이션 타임스탬프는 버퍼에 있는 데이터의 타임스탬프와 최대한 일치해야 하지만, 앞으로 건너뛰면 안 됩니다. 버퍼링된 데이터가 겹치면 브라우저에 따라 끊김 현상 또는 짧은 지연 현상이 발생할 수 있습니다. 추가하는 항목과 상관없이 플레이헤드를 겹치지 마세요. 오류가 발생합니다.
  • 탐색 시 재생이 중단될 수 있습니다. 특정 위치를 찾아 그 위치에서 재생을 다시 시작하고 싶을 수 있습니다. 이렇게 하면 탐색이 완료될 때까지 재생이 중단됩니다.