HTML视频循环重新下载视频文件

Can*_*yer 7 html javascript google-chrome http amazon-s3

我有一个很大的HTML5视频。我也在使用Chrome。video元素具有loop属性,但是每次视频“循环播放”时,浏览器都会重新下载视频文件。我已经设定了Cache-Control "max-age=15768000, private"。但是,这不会阻止对相同文件的任何额外下载。我正在使用Amazon S3托管文件。s3服务器还使用Accepts Ranges标头进行响应,该标头导致使用206http响应代码请求文件的数百次部分下载。

这是我的视频标签:

<video autoplay="" loop="" class="asset current">
    <source src="https://mybucket.s3.us-east-2.amazonaws.com/myvideo.mp4">
</video>
Run Code Online (Sandbox Code Playgroud)

更新:

似乎最好的解决方案是阻止Accept Ranges标头与原始响应一起发送,而使用200 http响应代码。如何做到这一点,以便通过.htaccess文件完全缓存视频?

提前致谢。

Kai*_*ido 4

我不确定您面临的真正问题是什么。

Chrome 可能对缓存的内容有最大大小限制,如果是这种情况,那么不使用 Range-Requests 不会解决任何问题。

另一种可能的解释是缓存媒体并不是一个简单的任务。
如果没有看到您的文件,就很难确定您属于哪种情况,但您必须了解,要播放媒体,浏览器不需要获取整个文件。
例如,您可以很好地在 <audio> 元素中播放视频文件,因为不会使用视频流,浏览器很可能完全忽略它并仅下载音频流。不确定是否有,但他们可以。大多数媒体格式确实在文件中物理分离音频和视频流,并且它们的字节位置在元数据中标记。
他们当然可以缓存他们执行的范围请求,但我认为他们这样做的情况仍然相当罕见。

但禁用范围请求可能很诱人,您必须知道,如果您的服务器不允许范围请求,某些浏览器(Safari)将不会播放您的媒体。
所以即使如此,这可能也不是您想要的。


您可能想要尝试的第一件事是优化您的视频以供网络使用。提供 webm 文件而不是 mp4。对于相同的质量,这些通常会占用更少的空间,也许您可​​以避免最大大小的限制

如果生成的文件仍然太大,那么一个肮脏的解决方案是使用 MediaSource,以便将文件保存在内存中,并且您只需要获取它一次。

在以下示例中,文件将仅按 1MB 的块完全获取一次,并在获取时由 MediaSource 进行流式传输,然后仅将内存中的数据用于循环播放:

document.getElementById('streamVid').onclick = e => (async () => {

const url = 'https://upload.wikimedia.org/wikipedia/commons/transcoded/2/22/Volcano_Lava_Sample.webm/Volcano_Lava_Sample.webm.360p.webm';
// you must know the mimeType of your video before hand.
const type = 'video/webm; codecs="vp8, vorbis"';
if( !MediaSource.isTypeSupported( type ) ) {
  throw 'Unsupported';
}

const source = new MediaSource();
source.addEventListener('sourceopen', sourceOpen);
document.getElementById('out').src = URL.createObjectURL( source );

// async generator Range-Fetcher
async function* fetchRanges( url, chunk_size = 1024 * 1024 ) {
  let chunk = new ArrayBuffer(1);
  let cursor = 0;
  while( chunk.byteLength ) {
    const resp = await fetch( url, {
      method: "get",
        headers: { "Range": "bytes=" + cursor + "-" + ( cursor += chunk_size ) }
      }
    )
    chunk = resp.ok && await resp.arrayBuffer();
    cursor++; // add one byte for next iteration, Ranges are inclusive
    yield chunk;
  }
}
// set up our MediaSource
async function sourceOpen() {
  const buffer = source.addSourceBuffer( type );
  buffer.mode = "sequence";
  // waiting forward to appendAsync...
  const appendBuffer = ( chunk ) => {
    return new Promise( resolve => {
      buffer.addEventListener( 'update', resolve, { once: true } );
      buffer.appendBuffer( chunk );
    } );
  }
  // while our RangeFetcher is running
  for await ( const chunk of fetchRanges(url) ) {
    if( chunk ) { // append to our MediaSource
      await appendBuffer( chunk );
    }
    else { // when done
      source.endOfStream();
    }
  }
}
})().catch( console.error );
Run Code Online (Sandbox Code Playgroud)
<button id="streamVid">stream video</button>
<video id="out" controls muted autoplay loop></video>
Run Code Online (Sandbox Code Playgroud)