El bucle de video HTML vuelve a descargar el archivo de video

8

Tengo un video HTML5 que es bastante grande. También estoy usando Chrome. El elemento de video tiene el loopatributo, pero cada vez que el video se "repite", el navegador vuelve a descargar el archivo de video. Me he puesto Cache-Control "max-age=15768000, private". Sin embargo, esto no evita descargas adicionales del archivo idéntico. Estoy usando Amazon S3 para alojar el archivo. Además, el servidor s3 responde con el Accepts Rangesencabezado, lo que hace que se soliciten varios cientos de descargas parciales del archivo con el 206código de respuesta http.

Aquí está mi etiqueta de video:

<video autoplay="" loop="" class="asset current">
    <source src="https://mybucket.s3.us-east-2.amazonaws.com/myvideo.mp4">
</video>

ACTUALIZAR:

Parece que la mejor solución es evitar que el Accept Rangesencabezado se envíe con la respuesta original y, en su lugar, usar un código de respuesta 200 http. ¿Cómo se puede lograr esto para que el video se almacene completamente en caché a través de un .htaccessarchivo?

Gracias por adelantado.

Cañón Moyer
fuente
1
¿Qué tan grande es el video y con qué frecuencia se repetirá? Otra forma de manejar esto es con un trabajador de servicio.
Brad
@Brad Son 900mb y se repiten infinitamente.
Cannon Moyer
¿Has comprobado el tamaño de caché en el navegador?
David Bradshaw el
¿Cómo sabías que el navegador vuelve a descargar el archivo? ¿Tiene el mismo problema cuando reproduce el archivo desde una fuente local (a diferencia de amazon s3). ¿Está reproduciendo el archivo en una sola página o existe en DOM?
Kalimah
1
¿Intentaste volver a codificar tu video? ¿Sucede lo mismo con una versión webm de tu video?
Kaiido

Respuestas:

1

No estoy seguro de cuál es el verdadero problema que enfrenta.

Podría ser que Chrome tenga un límite de tamaño máximo de lo que almacenarían en caché, y si fuera el caso, no usar Range-Requests no resolvería nada.

Otra posible explicación es que el almacenamiento en caché de medios no es realmente una tarea simple.
Sin ver su archivo, es difícil saber con certeza en qué caso se encuentra, pero debe comprender que para reproducir un medio, el navegador no necesita recuperar todo el archivo.
Por ejemplo, puede reproducir un archivo de video en un elemento <audio>, ya que la transmisión de video no se utilizará, un navegador podría omitirlo completamente y descargar solo la transmisión de audio. No estoy seguro si alguno lo hace, pero podrían. La mayoría de los formatos de medios separan físicamente las transmisiones de audio y video en el archivo y sus posiciones de bytes están marcadas en los metadatos.
Ciertamente podrían almacenar en caché las solicitudes de rango que realizan, pero creo que todavía es bastante raro que lo hagan.

Pero aunque sea tentador deshabilitar Range-Requests, debe saber que algunos navegadores (Safari) no reproducirán sus medios si su servidor no permite Range-Requests.
Entonces, incluso entonces, probablemente no sea lo que quieres.


Lo primero que puede intentar es optimizar su video para uso web. En lugar de mp4, sirva un archivo webm. Por lo general, ocuparán menos espacio para la misma calidad y quizás evite la limitación de tamaño máximo .

Si el archivo resultante sigue siendo demasiado grande, entonces una solución sucia sería usar un MediaSource para que el archivo se mantenga en la memoria y solo deba buscarlo una vez.

En el siguiente ejemplo, el archivo se recuperará por completo solo una vez, en fragmentos de 1 MB, transmitido por MediaSource mientras se recupera y luego solo se utilizarán los datos en la memoria para las reproducciones en bucle:

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 );
<button id="streamVid">stream video</button>
<video id="out" controls muted autoplay loop></video>

Kaiido
fuente
0

Google Chrome tiene un límite para el tamaño de la captura de archivos. En este caso, mi respuesta anterior no funcionaría. Debe usar algo como el compresor de archivos; este recurso puede comprimir el archivo lo suficiente como para que la caché de archivos sea elegible. El navegador web puede tener un nuevo tamaño de caché establecido manualmente, sin embargo, esto no es factible si el usuario final no ha designado su caché para estar de acuerdo con el espacio requerido para guardar el video largo.

JTS
fuente