MSE (Media Source Extensions)를 사용하는 경우 최종적으로 처리해야 할 한 가지는 과도하게 가득 찬 버퍼입니다. 이 경우 QuotaExceededError
라는 것을 얻게 됩니다. 이 도움말에서는 이를 처리하는
몇 가지 방법을 다룰 것입니다
QuotaExceededError란 무엇인가요?
기본적으로 QuotaExceededError
는 SourceBuffer
객체에 너무 많은 데이터를 추가하려고 하면 발생합니다. 상위 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);
재생 해상도 낮추기
이는 최근 데이터를 삭제하고 다시 추가하는 것과 유사합니다. 아래 예는 해상도 낮추기만 보여주지만 사실 이 두 가지가 함께 실행될 수 있습니다.
이 기법을 사용할 때 유의해야 할 몇 가지 사항이 있습니다.
- 새 초기화 세그먼트를 추가해야 합니다. 표현을 변경할 때마다 이 작업을 수행해야 합니다. 새 초기화 세그먼트는 이어지는 미디어 세그먼트에 관한 것이어야 합니다.
- 추가된 미디어의 프레젠테이션 타임스탬프는 버퍼에 있는 데이터의 타임스탬프와 최대한 일치해야 하지만, 앞으로 건너뛰면 안 됩니다. 버퍼링된 데이터가 겹치면 브라우저에 따라 끊김 현상 또는 짧은 지연 현상이 발생할 수 있습니다. 추가하는 항목과 상관없이 플레이헤드를 겹치지 마세요. 오류가 발생합니다.
- 탐색 시 재생이 중단될 수 있습니다. 특정 위치를 찾아 그 위치에서 재생을 다시 시작하고 싶을 수 있습니다. 이렇게 하면 탐색이 완료될 때까지 재생이 중단됩니다.