changement de source sur la balise vidéo html5

139

J'essaye de construire un lecteur vidéo, qui fonctionne partout. jusqu'à présent, j'irais avec:

<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>

(comme vu sur plusieurs sites, par exemple la vidéo pour tout le monde ) jusqu'à présent, tout va bien.

mais maintenant je veux aussi une sorte de liste de lecture / menu avec le lecteur vidéo, à partir duquel je peux sélectionner d'autres vidéos. ceux-ci devraient être ouverts immédiatement dans mon lecteur. donc je devrai "changer dynamiquement la source de la vidéo" (comme vu sur dev.opera.com/articles/everything-you-need-to-know-html5-video-audio/ - section "Regardons un autre film ") avec javascript. oublions pour le moment la partie flashplayer (et donc IE), j'essaierai de m'en occuper plus tard.

donc mon JS pour changer les <source>balises devrait être quelque chose comme:

<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>

Le problème est que cela ne fonctionne pas dans tous les navigateurs. à savoir, firefox = O il y a une belle page, où vous pouvez observer le problème que j'ai: http://www.w3.org/2010/05/video/mediaevents.html

dès que je déclenche la méthode load () (dans Firefox, remarquez), le lecteur vidéo meurt.

maintenant, j'ai découvert que lorsque je n'utilise pas plusieurs <source>balises, mais qu'un seul attribut src dans la <video>balise, tout fonctionne dans Firefox.

donc mon plan est d'utiliser simplement cet attribut src et de déterminer le fichier approprié en utilisant la fonction canPlayType () .

est-ce que je fais mal ou complique les choses?

sashn
la source
Cela me semble très bien. En quoi est-il «compliqué» de simplifier le balisage?
Matt Ball
le problème est que je me vois rencontrer beaucoup de javascript et la distinction des cas. si peut-être j'ai manqué quelque chose, comme s'il y avait un moyen de le faire fonctionner dans Firefox AVEC plusieurs <source>balises. alors je suppose que ce serait plus facile
sashn
avez-vous déjà découvert la partie flash sur ie8?
Neeraj
@Neeraj la solution finale impliquait le plugin video.js qui utilise un lecteur flash comme solution de secours pour IE8 et autres. il pourrait cependant y avoir des plugins supérieurs aujourd'hui. l'utilisation du plugin n'a pas non plus aidé avec le problème de Firefox concernant la méthode load (), qui était la motivation initiale de ce message. aujourd'hui, ce problème est résolu depuis longtemps, semble-t-il.
sashn

Réponses:

169

J'ai détesté toutes ces réponses parce qu'elles étaient trop courtes ou reposaient sur d'autres cadres.

Voici "une" façon vanilla JS de faire cela, fonctionnant dans Chrome, veuillez tester dans d'autres navigateurs:

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
la source
11
C'était le plus propre et le plus efficace pour moi.
Phil McCarty
Je n'ai pas pu convaincre Chrome de jouer avec ça. UNIQUEMENT si je mets l'attribut video src sur le chemin webm
Adam Hey
2
La méthode de lecture n'est autorisée que par un geste de l'utilisateur dans certaines stratégies de navigateur.
Anson
J'apprécie tellement cela pour une autre raison! J'ai essayé de créer une page vidéo qui n'affiche AUCUNE vidéo jusqu'à ce que le visiteur en sélectionne une. Je pourrais configurer une balise vidéo avec une balise source vide, mais cela générerait toujours un échec sur une console de débogage javascript. Maintenant, je sais que je peux attendre d'ajouter une «source» jusqu'à ce que l'utilisateur en sélectionne une. Jusqu'à présent, je ne comprenais pas que je devais utiliser CreateElement () pour créer une source, puis utiliser appendChild () pour l'ajouter à l'élément vidéo! Pour la sélection ultérieure, je peux vérifier d'abord si l'élément source existe afin de ne pas répéter cette étape.
Randy
Cette solution fonctionne très bien si quelqu'un est confronté au problème de type de contenu de la réponse de la charge utile, même si le type de contenu spécifié est correct mais se comporte toujours de manière étrange.
meDeepakJain
63

Modernizr a fonctionné comme un charme pour moi.

Ce que j'ai fait, c'est que je ne l'ai pas utilisé <source>. D'une manière ou d'une autre, cela a foiré les choses, car la vidéo ne fonctionnait que la première fois que load () était appelée. Au lieu de cela, j'ai utilisé l'attribut source à l'intérieur de la balise vidéo -> <video src="blabla.webm" />et utilisé Modernizr pour déterminer le format pris en charge par le navigateur.

<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>

J'espère que cela vous aidera :)

Si vous ne souhaitez pas utiliser Modernizr , vous pouvez toujours utiliser CanPlayType () .

Marius Engen Haugen
la source
Ne voulez-vous pas dire v [n] [1] pour le second si (Modernizr.video && Modernizr.video.ogg) est vrai?
bergie3000
1
Après avoir essayé d'autres méthodes, j'ai essayé cette approche Modernizr et cela a bien fonctionné. Chrome (pour une raison quelconque) ne chargerait pas un mp4 dans mon cas, mais chargerait un webm. Merci @MariusEngenHaugen
Adam Hey
Heureux de pouvoir être utile @AdamHey
Marius Engen Haugen
32

Votre plan original me convient. Vous trouverez probablement plus de bizarreries de navigateur traitant de la gestion dynamique des <source>éléments, comme indiqué ici par la note de spécification W3:

La modification dynamique d'un élément source et de son attribut lorsque l'élément est déjà inséré dans un élément vidéo ou audio n'aura aucun effet. Pour changer ce qui est en cours de lecture, utilisez simplement l'attribut src directement sur l'élément média, en utilisant éventuellement la méthode canPlayType () pour choisir parmi les ressources disponibles. Généralement, manipuler manuellement les éléments sources après que le document a été analysé est une approche inutilement [sic] compliquée.

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

greg.kindel
la source
19

J'ai résolu cela avec cette méthode simple

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

Au lieu d'avoir le même lecteur vidéo pour charger de nouveaux fichiers, pourquoi ne pas effacer tout l' <video>élément et le recréer. La plupart des navigateurs le chargeront automatiquement si les src sont corrects.

Exemple (avec 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
la source
6
Cela ralentit considérablement le navigateur dans son ensemble, car même après la suppression de la balise vidéo, le navigateur charge toujours les vidéos supprimées jusqu'à la fin.
Moe Sweet
Certains navigateurs (mobiles) ne vous permettent pas de lire des médias par programme sans interaction de l'utilisateur, et comme vous avez déjà eu une interaction sur l'élément, le remplacer par un nouveau perdra cette capacité.
Max Waterman
6

Il suffit de mettre un div et de mettre à jour le contenu ...

<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>
José Antonio Galeano
la source
6

Selon les spécifications

La modification dynamique d'un élément source et de son attribut lorsque l'élément est déjà inséré dans un élément vidéo ou audio n'aura aucun effet. Pour changer ce qui est en cours de lecture, utilisez simplement l'attribut src directement sur l'élément média, en utilisant éventuellement la méthode canPlayType () pour choisir parmi les ressources disponibles. Généralement, la manipulation manuelle des éléments source après l'analyse du document est une approche inutilement compliquée.

Donc, ce que vous essayez de faire n'est apparemment pas censé fonctionner.

Yaur
la source
@ greg.kindel J'ai remarqué après avoir posté ... mais la raison pour laquelle je n'ai pas remarqué en premier lieu est que votre texte d'introduction est déroutant. De quel plan original parlons-nous? Le plan original original qui ne fonctionnera pas ou le plan original mis à jour qui suit les conseils que nous avons tous les deux publiés?
Yaur
assez juste, j'aurais dû citer. Je voulais dire que son plan était "d'utiliser simplement cet attribut src et de déterminer le fichier approprié en utilisant la fonction canPlayType ()" qui fonctionne.
greg.kindel
4

Yaur: Bien que ce que vous avez copié et collé soit un bon conseil, cela ne signifie pas qu'il est impossible de changer l'élément source d'un élément vidéo HTML5 avec élégance, même dans IE9 (ou IE8 d'ailleurs). (Cette solution n'implique PAS remplacer tout l'élément vidéo, car il s'agit d'une mauvaise pratique de codage).

Une solution complète pour changer / changer de vidéo dans les balises vidéo HTML5 via javascript peut être trouvée ici et est testée dans tous les navigateurs HTML5 (Firefox, Chrome, Safari, IE9, etc.).

Si cela vous aide ou si vous rencontrez des problèmes, faites-le moi savoir.

mkralla11
la source
Brillant! C'est la manière de procéder. Vous n'avez même pas besoin de jQuery; dans le code lié, remplacez: mp4Vid.setAttribute ('src', "/pathTo/newVideo.mp4");
Velojet
3

Je viens avec cela pour changer la source vidéo de manière dynamique. L'événement "canplay" ne se déclenche parfois pas dans Firefox, j'ai donc ajouté "sharedmetadata". Aussi je mets en pause la vidéo précédente s'il y en a une ...

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
la source
Le correctif a vraiment fonctionné pour moi, Firefox ne gère pas la propriété canplayni canplaythroughet lodedmetadatadoit être ajouté (et supprimé plus tard) aux gestionnaires vidéo :-(
Lord of freaks
3

Voici ma solution:

<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 informatiques
la source
2

L'utilisation des <source />balises s'est avérée difficile pour moi dans Chrome 14.0.835.202 en particulier, même si cela a bien fonctionné pour moi dans FireFox. (Cela pourrait être mon manque de connaissances, mais je pensais qu'une solution alternative pourrait être utile de toute façon.) Donc, j'ai fini par utiliser simplement une <video />balise et définir l'attribut src directement sur la balise vidéo elle-même. La canPlayVideo('<mime type>')fonction a été utilisée pour déterminer si le navigateur spécifique pouvait ou non lire la vidéo d'entrée. Ce qui suit fonctionne dans FireFox et Chrome.

Incidemment, FireFox et Chrome utilisent le format "ogg", bien que Chrome recommande "webm". J'ai mis la vérification du support du navigateur de "ogg" en premier uniquement parce que d'autres messages ont mentionné que FireFox préfère la source ogg en premier (c'est-à-dire <source src="..." type="video/ogg"/>). Mais, je n'ai pas testé (et je doute fortement) que l'ordre dans le code fasse une différence lors de la définition du "src" sur la balise vidéo.

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();
  }
ItsAllABadBlague
la source
2

Je fais des recherches sur ce sujet depuis un bon moment et j'essaie de faire la même chose, alors j'espère que cela aidera quelqu'un d'autre. J'utilise crossbrowsertesting.com et je le teste littéralement dans presque tous les navigateurs connus de l'homme. La solution dont je dispose actuellement fonctionne sous Opera, Chrome, Firefox 3.5+, IE8 +, iPhone 3GS, iPhone 4, iPhone 4s, iPhone 5, iPhone 5s, iPad 1+, Android 2.3+, Windows Phone 8.

Sources à changement dynamique

La modification dynamique de la vidéo est très difficile, et si vous voulez une solution de secours Flash, vous devrez supprimer la vidéo du DOM / page et la rajouter pour que Flash se mette à jour car Flash ne reconnaîtra pas les mises à jour dynamiques des variables Flash. Si vous allez utiliser JavaScript pour le modifier dynamiquement, je supprimerais complètement tous les <source>éléments et je l'utiliserais simplement canPlayTypepour définir le srcdans JavaScript et / breakou returnaprès le premier type de vidéo pris en charge et n'oubliez pas de mettre à jour dynamiquement le flash var mp4. De plus, certains navigateurs n'enregistrent pas que vous avez changé la source à moins que vous n'appeliez video.load(). Je pense que le problème que .load()vous rencontrez peut être résolu en appelant d'abordvideo.pause(). La suppression et l'ajout d'éléments vidéo peuvent ralentir le navigateur car il continue de mettre en mémoire tampon la vidéo supprimée, mais il existe une solution de contournement .

Prise en charge de plusieurs navigateurs

En ce qui concerne la partie réelle de plusieurs navigateurs, je suis également arrivé à Video For Everybody . J'ai déjà essayé le plugin MediaelementJS Wordpress, qui s'est avéré causer beaucoup plus de problèmes qu'il n'en a résolu. Je soupçonne que les problèmes étaient dus au plug-in Wordpress et non à la bibliothèque. J'essaie de trouver quelque chose qui fonctionne sans JavaScript, si possible. Jusqu'à présent, ce que j'ai trouvé est ce 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>

Remarques importantes :

  • Fini par mettre l'ogg comme le premier <source>parce que Mac OS Firefox arrête d'essayer de lire la vidéo s'il rencontre un MP4 comme premier <source>.
  • Les types MIME corrects sont importants .ogv fichiers doivent être video/ogg, non video/ogv
  • Si vous avez une vidéo HD, le meilleur transcodeur que j'ai trouvé pour les fichiers OGG de qualité HD est Firefogg
  • Le .iphone.mp4fichier est destiné à l'iPhone 4+, qui ne lira que les vidéos MPEG-4 avec vidéo H.264 Baseline 3 et audio AAC. Le meilleur transcodeur que j'ai trouvé pour ce format est Handbrake, l'utilisation du préréglage iPhone et iPod Touch fonctionnera sur iPhone 4+, mais pour que l'iPhone 3GS fonctionne, vous devez utiliser le préréglage iPod qui a une résolution beaucoup plus basse que j'ai ajoutée video.iphone3g.mp4.
  • À l'avenir, nous pourrons utiliser un mediaattribut sur les <source>éléments pour cibler les appareils mobiles avec des requêtes multimédias, mais pour le moment, les anciens appareils Apple et Android ne le prennent pas suffisamment en charge.

Modifier :

  • J'utilise toujours Video For Everybody mais je suis maintenant passé à l'utilisation de FlowPlayer, pour contrôler la solution de secours Flash, qui dispose d'une API JavaScript géniale qui peut être utilisée pour le contrôler.
Alex W
la source
Cela semble être la réponse à la question "Comment puis-je lire une vidéo dans un navigateur croisé?" et pas cette question qui est "Comment créer une playlist pour ma vidéo?".
Quentin
@Quentin C'était, pour commencer, parce que c'est ainsi que j'ai trouvé cette question via Google et OP a dit qu'il essayait de créer un lecteur vidéo qui fonctionne partout. J'ai également mis à jour la réponse pour répondre à sa question dynamique.
Alex W
2

J'ai une application Web similaire et je ne suis pas du tout confronté à ce genre de problème. Ce que je fais est quelque chose comme ceci:

var sources = new Array();

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

puis quand je veux changer les sources, j'ai une fonction qui fait quelque chose comme ceci:

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

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

}

Je fais cela pour que l'utilisateur puisse se frayer un chemin dans une liste de lecture, mais vous pouvez vérifier userAgent puis charger le fichier approprié de cette façon. J'ai essayé d'utiliser plusieurs balises source comme tout le monde le suggérait sur Internet, mais j'ai trouvé beaucoup plus propre et beaucoup plus fiable de manipuler l'attribut src d'une seule balise source. Le code ci-dessus a été écrit à partir de la mémoire, donc j'ai peut-être passé sous silence certains détails, mais l'idée générale est de changer dynamiquement l'attribut src de la balise source en utilisant javascript, le cas échéant.

aamiri
la source
1

Essayez de déplacer la source OGG vers le haut. J'ai remarqué que Firefox se confond parfois et arrête le joueur lorsque celui à qui il veut jouer, OGG, n'est pas le premier.

Ça vaut le coup d'essayer.

Ian Devlin
la source
1

Une autre façon de le faire dans 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();
    });
青木 Japon
la source
0

Utilisation de JavaScript et 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>
petits
la source