Chrome: для воспроизведения видео, которое загружается через fetch/XHR

Я пытаюсь добиться, чтобы Chrome загружал видеофайл в виде данных (через Fetch API, XHR и т. Д.) И воспроизводил его, используя <video> пока он все еще загружается, не отправляя два отдельных запроса на один и тот же URL и не дожидаясь полной загрузки файла.

Это легко получить ReadableStream из Fetch API (response.body), но я не могу найти способ кормить его в video элемент. Я понял, мне нужно blob URL для этого, который может быть создан с помощью MediaSource объект. Тем не менее SourceBuffer#appendStream метод, который звучит как то, что нужно, не реализован в Chrome, поэтому я не могу подключить поток напрямую к MediaSource объект.

Я, вероятно, могу прочитать поток в кусках, создать Uint8Array из них, и использовать SourceBuffer#appendBuffer, но это означает, что воспроизведение не начнется немедленно, если только размер чанка не очень мал. Кроме того, создается ощущение, что вы вручную делаете что-то, что все эти API должны иметь в наличии из коробки. Если нет других решений, и я иду по этому пути, каких предостережений я должен ожидать?

Существуют ли другие способы создания URL-адреса BLOB-объекта для ReadableStream? Или есть способ сделать fetch а также <video> подать заявку? Есть так много новых API, что я мог легко что-то пропустить.

2 ответа

После часов экспериментов нашел наполовину рабочее решение:

      const video = document.getElementById('audio');

const mediaSource = new MediaSource();

video.src = window.URL.createObjectURL(mediaSource);

mediaSource.addEventListener('sourceopen', async () => {

  const sourceBuffer = mediaSource.addSourceBuffer('audio/webm; codecs="opus"');

  const response = await fetch(audioSRC);

  const body = response.body

  const reader = body.getReader()

  let streamNotDone = true;

  while (streamNotDone) {

    const {value, done} = await reader.read();
    
    if (done) {streamNotDone = false; break;}
    
    await new Promise((resolve, reject) => {
      sourceBuffer.appendBuffer(value)

      sourceBuffer.onupdateend = (() => {
        resolve(true);
      })
    }) 

  }
});

Он работает с https://developer.mozilla.org/en-US/docs/Web/API/MediaSource.

Кроме того, я тестировал это только с форматом webm / opus, но я считаю, что он должен работать с другими форматами, если вы его укажете .

Попробуй это:

(async function(){
  const res = await fetch('http://xxxx.mp4')
  const blob = await res.blob()
  const src = window.URL.createObjectURL(blob)
  const el = document.getElementById('video')
  el.src = src
  el.play()
})()

Другие вопросы по тегам