cambio de fuente en la etiqueta de video html5

138

Estoy tratando de construir un reproductor de video, que funcione en todas partes. Hasta ahora estaría con:

<video>
    <source src="video.mp4"></source>
    <source src="video.ogv"></source>
    <object data="flowplayer.swf" type="application/x-shockwave-flash">
        <param name="movie" value="flowplayer.swf" />
        <param name="flashvars" value='config={"clip":"video.mp4"}' />
    </object>
</video>

(como se ve en varios sitios, por ejemplo, video para todos ) hasta ahora, todo bien.

pero ahora también quiero algún tipo de lista de reproducción / menú junto con el reproductor de video, desde el cual puedo seleccionar otros videos. esos deben abrirse dentro de mi reproductor de inmediato. así que tendré que "cambiar dinámicamente la fuente del video" (como se ve en dev.opera.com/articles/everything-you-need-to-know-html5-video-audio/ - sección "Veamos otra película ") con javascript. Olvidémonos de la parte del flashplayer (y, por lo tanto, IE) por el momento, intentaré lidiar con eso más adelante.

entonces mi JS para cambiar las <source>etiquetas debería ser algo como:

<script>
function loadAnotherVideo() {
    var video = document.getElementsByTagName('video')[0];
    var sources = video.getElementsByTagName('source');
    sources[0].src = 'video2.mp4';
    sources[1].src = 'video2.ogv';
    video.load();
}
</script>

El problema es que esto no funciona en todos los navegadores. a saber, firefox = O hay una buena página, donde puedes observar el problema que estoy teniendo: http://www.w3.org/2010/05/video/mediaevents.html

Tan pronto como active el método load () (en Firefox, eso sí), el reproductor de video muere.

ahora he descubierto que cuando no uso varias <source>etiquetas, sino que solo un atributo src dentro de la <video>etiqueta, todo funciona en firefox.

así que mi plan es usar ese atributo src y determinar el archivo apropiado usando la función canPlayType () .

¿Lo estoy haciendo mal de alguna manera o estoy complicando las cosas?

sashn
fuente
Eso me suena bien. ¿Cómo es "complicado" simplificar el marcado?
Matt Ball
El problema es que me encuentro con muchos javascript y distinción de casos. si tal vez me perdí algo, como si hubiera una manera de hacerlo funcionar en Firefox con múltiples <source>etiquetas entonces supongo que sería más fácil
sashn
¿alguna vez te diste cuenta de la parte de flash en ie8?
Neeraj
@Neeraj la solución final involucró el complemento video.js que usa un reproductor flash como respaldo para IE8 y similares. Sin embargo, puede haber complementos superiores hoy. El uso del complemento tampoco ayudó con el problema de Firefox con respecto al método load (), que fue la motivación inicial de esta publicación. hoy, parece que ese problema se ha solucionado durante mucho tiempo.
sashn

Respuestas:

169

Odiaba todas estas respuestas porque eran demasiado cortas o dependían de otros marcos.

Aquí hay una "forma" de JS de vainilla de hacer esto, trabajando en Chrome, pruebe en otros navegadores:

http://jsfiddle.net/mattdlockyer/5eCEu/2/

HTML:

<video id="video" width="320" height="240"></video>

JS:

var video = document.getElementById('video');
var source = document.createElement('source');

source.setAttribute('src', 'http://www.tools4movies.com/trailers/1012/Kill%20Bill%20Vol.3.mp4');

video.appendChild(source);
video.play();

setTimeout(function() {  
    video.pause();

    source.setAttribute('src', 'http://www.tools4movies.com/trailers/1012/Despicable%20Me%202.mp4'); 

    video.load();
    video.play();
}, 3000);
mattdlockyer
fuente
11
Este fue el más limpio y más eficiente para mí.
Phil McCarty
No pude hacer que Chrome jugara con esto. SOLO si configuro el atributo src de video en la ruta webm
Adam Hey
2
El método de reproducción solo está permitido por un gesto del usuario en algunas políticas del navegador.
Anson
¡Aprecio mucho esto por otra razón! He estado intentando configurar una página de video que no muestra CUALQUIER video hasta que el visitante selecciona uno. Podría configurar una etiqueta de video con una etiqueta de origen vacía, pero siempre generaría una falla en una consola de depuración de JavaScript. Ahora sé que puedo esperar para agregar una 'fuente' hasta que el usuario seleccione una. Hasta ahora, no entendía que necesitaba usar CreateElement () para crear una fuente, ¡y luego usar appendChild () para agregarlo al elemento de video! Para la selección posterior, puedo verificar primero para ver si el elemento fuente existe, así que no repito ese paso.
Randy
Esta solución funciona muy bien si alguien se enfrenta al problema con el tipo de contenido de la respuesta de carga útil, incluso si el tipo de contenido especificado es correcto pero aún se comporta de manera extraña.
meDeepakJain
63

Modernizr funcionó como un encanto para mí.

Lo que hice es que no lo usé <source>. De alguna manera esto arruinó las cosas, ya que el video solo funcionó la primera vez que se llamó a load (). En cambio, utilicé el atributo de origen dentro de la etiqueta de video -> <video src="blabla.webm" />y utilicé Modernizr para determinar qué formato admitía el navegador.

<script>
var v = new Array();

v[0] = [
        "videos/video1.webmvp8.webm",
        "videos/video1.theora.ogv",
        "videos/video1.mp4video.mp4"
        ];
v[1] = [
        "videos/video2.webmvp8.webm",
        "videos/video2.theora.ogv",
        "videos/video2.mp4video.mp4"
        ];
v[2] = [
        "videos/video3.webmvp8.webm",
        "videos/video3.theora.ogv",
        "videos/video3.mp4video.mp4"
        ];

function changeVid(n){
    var video = document.getElementById('video');

    if(Modernizr.video && Modernizr.video.webm) {
        video.setAttribute("src", v[n][0]);
    } else if(Modernizr.video && Modernizr.video.ogg) {
        video.setAttribute("src", v[n][1]);
    } else if(Modernizr.video && Modernizr.video.h264) {
        video.setAttribute("src", v[n][2]);
    }

    video.load();
}
</script>

Espero que esto te ayude :)

Si no desea usar Modernizr , siempre puede usar CanPlayType () .

Marius Engen Haugen
fuente
¿No quiere decir v [n] [1] para el segundo si (Modernizr.video && Modernizr.video.ogg) es cierto?
bergie3000
1
Después de probar otros métodos, probé este enfoque Modernizr y funcionó bien. Chrome (por alguna razón) no cargaría un mp4 en mi caso, pero cargaría un webm. Gracias @MariusEngenHaugen
Adam Hey
Me alegra poder estar de servicio @AdamHey
Marius Engen Haugen
32

Tu plan original me suena bien. Probablemente encontrará más peculiaridades del navegador relacionadas con la gestión dinámica de los <source>elementos, como se indica aquí en la nota de especificaciones de W3:

La modificación dinámica de un elemento fuente y su atributo cuando el elemento ya está insertado en un elemento de video o audio no tendrá ningún efecto. Para cambiar lo que se está reproduciendo, simplemente use el atributo src en el elemento multimedia directamente, posiblemente haciendo uso del método canPlayType () para elegir entre los recursos disponibles. Generalmente, manipular elementos fuente manualmente después de que el documento ha sido analizado es un enfoque innecesariamente [sic] complicado.

http://dev.w3.org/html5/spec/Overview.html#the-source-element

greg.kindel
fuente
19

Resolví esto con este método simple

function changeSource(url) {
   var video = document.getElementById('video');
   video.src = url;
   video.play();
}
Joaquin Iurchuk
fuente
10

En lugar de hacer que el mismo reproductor de video cargue nuevos archivos, ¿por qué no borrar todo el <video>elemento y recrearlo? La mayoría de los navegadores lo cargarán automáticamente si los src son correctos.

Ejemplo (usando Prototype ):

var vid = new Element('video', { 'autoplay': 'autoplay', 'controls': 'controls' });
var src = new Element('source', { 'src': 'video.ogg', 'type': 'video/ogg' });

vid.update(src);
src.insert({ before: new Element('source', { 'src': 'video.mp4', 'type': 'video/mp4' }) });

$('container_div').update(vid);
Stephen Walcher
fuente
66
Eso ralentiza significativamente el navegador en general, ya que incluso después de eliminar la etiqueta de video, el navegador aún carga los videos eliminados hasta el final.
Moe Sweet
Algunos navegadores (móviles) no le permiten reproducir medios mediante programación sin interacción del usuario, y dado que ya ha tenido una interacción en el elemento, reemplazarlo por uno nuevo perderá esa capacidad.
Max Waterman
6

Simplemente ponga un div y actualice el contenido ...

<script>
function setvideo(src) {
    document.getElementById('div_video').innerHTML = '<video autoplay controls id="video_ctrl" style="height: 100px; width: 100px;"><source src="'+src+'" type="video/mp4"></video>';
    document.getElementById('video_ctrl').play();
}
</script>
<button onClick="setvideo('video1.mp4');">Video1</button>
<div id="div_video"> </div>
Jose Antonio Galeano
fuente
6

De acuerdo a la especificación

La modificación dinámica de un elemento fuente y su atributo cuando el elemento ya está insertado en un elemento de video o audio no tendrá ningún efecto. Para cambiar lo que se está reproduciendo, simplemente use el atributo src en el elemento multimedia directamente, posiblemente haciendo uso del método canPlayType () para elegir entre los recursos disponibles. En general, la manipulación manual de los elementos de origen después de analizar el documento es un enfoque innecesariamente complicado.

Entonces, lo que estás tratando de hacer aparentemente no debe funcionar.

Yaur
fuente
@ greg.kindel Me di cuenta después de que publiqué ... pero la razón por la que no me di cuenta en primer lugar es que su texto de introducción es confuso. ¿De qué plan original estamos hablando? ¿El plan original original que no funcionará o el plan original actualizado que sigue la guía que ambos publicamos?
Yaur
justo, debería haber citado. Me refería a su plan de "simplemente usar ese atributo src y determinar el archivo apropiado usando la función canPlayType ()" que funciona.
greg.kindel
4

Yaur: Aunque lo que ha copiado y pegado es un buen consejo, esto no significa que sea imposible cambiar el elemento fuente de un elemento de video HTML5 de manera elegante, incluso en IE9 (o IE8 para el caso). (Esta solución NO involucra reemplazar todo el elemento de video, ya que es una mala práctica de codificación).

Aquí se puede encontrar una solución completa para cambiar / cambiar videos en etiquetas de video HTML5 a través de JavaScript y se prueba en todos los navegadores HTML5 (Firefox, Chrome, Safari, IE9, etc.).

Si esto ayuda, o si tiene problemas, hágamelo saber.

mkralla11
fuente
¡Brillante! Esta es la manera de hacerlo. Ni siquiera necesitas jQuery; en el código vinculado, sustituya: mp4Vid.setAttribute ('src', "/pathTo/newVideo.mp4");
Velojet
3

Vengo con esto para cambiar la fuente de video dinámicamente. El evento "canplay" en algún momento no se activa en Firefox, así que he agregado "metadatos cargados" También detengo el video anterior si hay uno ...

var loadVideo = function(movieUrl) {
    console.log('loadVideo()');
    $videoLoading.show();
    var isReady = function (event) {
            console.log('video.isReady(event)', event.type);
            video.removeEventListener('canplay', isReady);
            video.removeEventListener('loadedmetadata', isReady);
            $videoLoading.hide();
            video.currentTime = 0;
            video.play();
        },
        whenPaused = function() {
            console.log('video.whenPaused()');
            video.removeEventListener('pause', whenPaused);
            video.addEventListener('canplay', isReady, false);
            video.addEventListener('loadedmetadata', isReady, false); // Sometimes Firefox don't trigger "canplay" event...
            video.src = movieUrl; // Change actual source
        };

    if (video.src && !video.paused) {
        video.addEventListener('pause', whenPaused, false);
        video.pause();
    }
    else whenPaused();
};
molokoloco
fuente
La solución, definitivamente funcionó para mí, Firefox no está manejando propiedad ni canplaytampoco canplaythroughy lodedmetadatadebe agregarse (y eliminarse más tarde) a los controladores de video :-(
Lord of Freaks
3

Esta es mi solución:

<video id="playVideo" width="680" height="400" controls="controls">
    <source id="sourceVideo" src="{{video.videoHigh}}" type="video/mp4">
</video>
    <br />
<button class="btn btn-warning" id="{{video.videoHigh}}" onclick="changeSource(this)">HD</button>
<button class="btn btn-warning" id="{{video.videoLow}}" onclick="changeSource(this)">Regular</button>

<script type="text/javascript">
    var getVideo = document.getElementById("playVideo");
    var getSource = document.getElementById("sourceVideo");
    function changeSource(vid) {
        var geturl = vid.id;
        getSource .setAttribute("src", geturl);
        getVideo .load()
        getVideo .play();
        getVideo .volume = 0.5;
    }
</script>
Vlogs de TI
fuente
2

Usar las <source />etiquetas me resultó difícil en Chrome 14.0.835.202 específicamente, aunque funcionó bien para mí en Firefox. (Esta podría ser mi falta de conocimiento, pero pensé que una solución alternativa podría ser útil de todos modos). Así que terminé usando una <video />etiqueta y configurando el atributo src directamente en la etiqueta de video. La canPlayVideo('<mime type>')función se usó para determinar si el navegador específico podía reproducir el video de entrada o no. Lo siguiente funciona en Firefox y Chrome.

Incidentalmente, tanto FireFox como Chrome reproducen el formato "ogg", aunque Chrome recomienda "webm". Puse el cheque para el soporte del navegador de "ogg" primero solo porque otras publicaciones han mencionado que FireFox prefiere primero la fuente ogg (es decir <source src="..." type="video/ogg"/>). Pero no he probado (y dudo mucho) si el orden en el código hace alguna diferencia o no al configurar el "src" en la etiqueta de video.

HTML

<body onload="setupVideo();">
    <video id="media" controls="true" preload="auto" src="">
    </video>
</body>

JavaScript

function setupVideo() {
       // You will probably get your video name differently
       var videoName = "http://video-js.zencoder.com/oceans-clip.mp4";

       // Get all of the uri's we support
       var indexOfExtension = videoName.lastIndexOf(".");
       //window.alert("found index of extension " + indexOfExtension);
       var extension = videoName.substr(indexOfExtension, videoName.length - indexOfExtension);
       //window.alert("extension is " + extension);
       var ogguri = encodeURI(videoName.replace(extension, ".ogv"));
       var webmuri = encodeURI(videoName.replace(extension, ".webm"));
       var mp4uri = encodeURI(videoName.replace(extension, ".mp4"));
       //window.alert(" URI is " + webmuri);


       // Get the video element
       var v = document.getElementById("media");
       window.alert(" media is " + v);

       // Test for support
       if (v.canPlayType("video/ogg")) {
            v.setAttribute("src", ogguri);
           //window.alert("can play ogg");
       }
       else if (v.canPlayType("video/webm")) {
           v.setAttribute("src", webmuri);
           //window.alert("can play webm");
       }
       else if (v.canPlayType("video/mp4")) {
           v.setAttribute("src", mp4uri);
           //window.alert("can play mp4");
       }
       else {
           window.alert("Can't play anything");
       }

      v.load();
      v.play();
  }
ItsAllABadJoke
fuente
2

He estado investigando esto durante bastante tiempo y estoy tratando de hacer lo mismo, así que espero que esto ayude a alguien más. He estado usando crossbrowsertesting.com y literalmente probé esto en casi todos los navegadores conocidos por el hombre. La solución que tengo actualmente funciona en Opera, Chrome, Firefox 3.5+, IE8 +, iPhone 3GS, iPhone 4, iPhone 4s, iPhone 5, iPhone 5s, iPad 1+, Android 2.3+, Windows Phone 8.

Fuentes que cambian dinámicamente

Cambiar dinámicamente el video es muy difícil, y si desea una copia de seguridad de Flash, tendrá que eliminar el video del DOM / página y volver a agregarlo para que Flash se actualice porque Flash no reconocerá las actualizaciones dinámicas de Flash vars. Si usted va a utilizar JavaScript para cambiar de forma dinámica, me gustaría eliminar por completo todos los <source>elementos y sólo tiene que utilizar canPlayTypepara establecer el srcen JavaScript y breako returndespués de que el primer tipo de vídeo compatible y no se olvide de actualizar dinámicamente el mp4 de destello var. Además, algunos navegadores no registrarán que ha cambiado la fuente a menos que llame video.load(). Creo que el problema .load()que estabas experimentando se puede solucionar llamando primerovideo.pause(). Eliminar y agregar elementos de video puede ralentizar el navegador porque continúa almacenando el video eliminado, pero hay una solución alternativa .

Soporte de navegador cruzado

En cuanto a la porción real entre navegadores, también llegué a Video For Everybody . Ya probé el complemento MediaelementJS Wordpress, que resultó causar muchos más problemas de los que resolvió. Sospecho que los problemas se debieron al complemento de Wordpress y no a la biblioteca en realidad. Estoy tratando de encontrar algo que funcione sin JavaScript, si es posible. Hasta ahora, lo que se me ocurrió es este HTML simple:

<video width="300" height="150" controls="controls" poster="http://sandbox.thewikies.com/vfe-generator/images/big-buck-bunny_poster.jpg" class="responsive">
<source src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.ogv" type="video/ogg" />
<source src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4" type="video/mp4" />
<source src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.webm" type="video/webm" />
<source src="http://alex-watson.net/wp-content/uploads/2014/07/big_buck_bunny.iphone.mp4" type="video/mp4" />
<source src="http://alex-watson.net/wp-content/uploads/2014/07/big_buck_bunny.iphone3g.mp4" type="video/mp4" />
<object type="application/x-shockwave-flash" data="http://releases.flowplayer.org/swf/flowplayer-3.2.1.swf" width="561" height="297">
    <param name="movie" value="http://releases.flowplayer.org/swf/flowplayer-3.2.1.swf" />
    <param name="allowFullScreen" value="true" />
    <param name="wmode" value="transparent" />
    <param name="flashVars" value="config={'playlist':['http://sandbox.thewikies.com/vfe-generator/images/big-buck-bunny_poster.jpg',{'url':'http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4','autoPlay':false}]}" />
    <img alt="No Video" src="http://sandbox.thewikies.com/vfe-generator/images/big-buck-bunny_poster.jpg" width="561" height="297" title="No video playback capabilities, please download the video below" />
</object>
<strong>Download video:</strong>  <a href="video.mp4">MP4 format</a> | <a href="video.ogv">Ogg format</a> | <a href="video.webm">WebM format</a>
</video>

Notas importantes :

  • Terminé poniendo el ogg como el primero <source>porque Mac OS Firefox deja de intentar reproducir el video si encuentra un MP4 como el primero <source>.
  • Los tipos MIME correctos son importantes. Los archivos .ogv deben ser video/ogg, no video/ogv
  • Si tiene video HD, el mejor transcodificador que he encontrado para archivos OGG de calidad HD es Firefogg
  • El .iphone.mp4archivo es para iPhone 4+ que solo reproducirá videos que sean MPEG-4 con H.264 Baseline 3 Video y audio AAC. El mejor transcodificador que encontré para ese formato es Handbrake, usar el preajuste de iPhone y iPod Touch funcionará en iPhone 4+, pero para que el iPhone 3GS funcione, debe usar el preajuste de iPod que tiene una resolución mucho más baja que agregué video.iphone3g.mp4.
  • En el futuro podremos usar un mediaatributo en los <source>elementos para dirigir dispositivos móviles con consultas de medios, pero en este momento los dispositivos Apple y Android más antiguos no lo admiten lo suficientemente bien.

Editar :

  • Todavía estoy usando Video For Everybody, pero ahora he hecho la transición al uso de FlowPlayer, para controlar el respaldo de Flash, que tiene una increíble API de JavaScript que se puede usar para controlarlo.
Alex W
fuente
Esta parece ser la respuesta a la pregunta "¿Cómo juego el video cross browser?" y no esta pregunta que es "¿Cómo configuro una lista de reproducción para mi video?".
Quentin
@Quentin Fue, para empezar, porque así es como encontré esta pregunta a través de Google y OP dijo que está tratando de construir un reproductor de video que funcione en todas partes. Actualicé la respuesta para abordar su pregunta dinámica también.
Alex W
2

Tengo una aplicación web similar y no estoy enfrentando ese tipo de problema en absoluto. Lo que hago es algo como esto:

var sources = new Array();

sources[0] = /path/to/file.mp4
sources[1] = /path/to/another/file.ogg
etc..

entonces, cuando quiero cambiar las fuentes, tengo una función que hace algo como esto:

this.loadTrack = function(track){
var mediaSource = document.getElementsByTagName('source')[0];
mediaSource.src = sources[track];

    var player = document.getElementsByTagName('video')[0];
    player.load();

}

Hago esto para que el usuario pueda abrirse camino a través de una lista de reproducción, pero puede verificar el UserAgent y luego cargar el archivo apropiado de esa manera. Intenté usar varias etiquetas de origen como sugirieron todos en Internet, pero me pareció mucho más limpio y mucho más confiable manipular el atributo src de una sola etiqueta de origen. El código anterior se escribió desde la memoria, por lo que es posible que haya pasado por alto algunos de los detalles, pero la idea general es cambiar dinámicamente el atributo src de la etiqueta fuente usando JavaScript, cuando sea apropiado.

aamiri
fuente
1

Intenta mover la fuente OGG a la parte superior. He notado que Firefox a veces se confunde y detiene al jugador cuando el que quiere jugar, OGG, no es el primero.

Vale la pena intentarlo.

Ian Devlin
fuente
1

Otra forma de hacerlo en Jquery.

HTML

<video id="videoclip" controls="controls" poster="" title="Video title">
    <source id="mp4video" src="video/bigbunny.mp4" type="video/mp4"  />
</video>

<div class="list-item">
     <ul>
         <li class="item" data-video = "video/bigbunny.mp4"><a href="javascript:void(0)">Big Bunny.</a></li>
     </ul>
</div>

Jquery

$(".list-item").find(".item").on("click", function() {
        let videoData = $(this).data("video");
        let videoSource = $("#videoclip").find("#mp4video");
        videoSource.attr("src", videoData);
        let autoplayVideo = $("#videoclip").get(0);
        autoplayVideo.load();
        autoplayVideo.play();
    });
青木 Japón
fuente
0

Usando JavaScript y jQuery:

<script src="js/jquery.js"></script>
...
<video id="vid" width="1280" height="720" src="v/myvideo01.mp4" controls autoplay></video>
...
function chVid(vid) {
    $("#vid").attr("src",vid);
}
...
<div onclick="chVid('v/myvideo02.mp4')">See my video #2!</div>
pbies
fuente