7

I'm looking to change the video source of my VideoJS player dynamically. I tried one method of changing the source directly via the DOM and it did change it, but the player needs to reload. So looking at the official API here: http://docs.videojs.com/docs/api/player.html#Methodssrc

There's a method to change the source but when running the following code, it throws an error.

    var source = dropdown.options[dropdown.selectedIndex].value;

 var myVideo = videojs.getPlayers();
 console.log(myVideo);
 if (source == "Source2"){
  myVideo.src([
   {type: "application/x-mpegURL", src: "http://mycdn/playlist.m3u8"},
   {type: "rtmp/mp4", src: "rtmp://mycdn"}
  ]);
 }

Although the console does verify that myVideo is an object, calling the .src(source) function throws "TypeError: myVideo.src is not a function. (In 'myVideo.src', 'myVideo.src' is undefined)"

I've also found tutorials like this where the apparent more "official" way is to dispose of the player completely and reinitialize with new sources, but I can't seem to understand what he's doing. https://ineed.coffee/3201/how-to-dynamically-change-video-js-videos-and-captions-with-javascript/

Any help would be appreciated.


Solution: For testing purposes I just have a nice little drop down and added a click event to that, so it changes the channel to whatever the user wants.

var dropdown = document.getElementById('sel1');
var source = dropdown.options[dropdown.selectedIndex].value;

dropdown.addEventListener("click", function(){
source = dropdown.options[dropdown.selectedIndex].value;
console.log(source)

var myVideo = videojs('my-video');
console.log(myVideo);   
if (source == "Public Access"){
    myVideo.src([
        {type: "application/x-mpegURL", src: "http://mycdns/playlist.m3u8"},
        {type: "rtmp/mp4", src: "rtmp://mycdn"}
    ]);
}
else if (source == "Government"){
    myVideo.src([
        {type: "application/x-mpegURL", src: "http://mycdn/playlist.m3u8"},
        {type: "rtmp/mp4", src: "rtmp://mycdn"}
    ]);
}
else if (source == "Regional"){
    myVideo.src([
        {type: "application/x-mpegURL", src: "http://mycdn/playlist.m3u8"},
        {type: "rtmp/mp4", src: "rtmp://mysource"}
    ]);
}
});
Aaron Chamberlain
  • 653
  • 2
  • 10
  • 26
  • your solution worked for me as well, thanks! did not realize you could pass an array of objects into the `.src` method – subelsky Mar 06 '18 at 16:26

2 Answers2

1

getPlayers() returns an object containing all players, not a player.

You'd normally get a particular player with videojs('my_player_id').

misterben
  • 7,455
  • 2
  • 26
  • 47
  • Didn't realize this the distinction there so thanks. Making my variable the actual VideoJS Object then allows me to correctly use the .src() function. Interestingly, it resolves itself quite nicely and actually reloads the player. If I may confirm my suspicion however, when using this method it pre-determines which source from my array is suitable and plays that correct? I noticed that for me, in Chrome and Safari, it will change it to only the HLS url. Haven't tested it in a non-extensible browser yet, but I'm assuming it will take the RTMP feed? – Aaron Chamberlain Dec 29 '15 at 08:35
  • Also, if you're looking for an array of all players, `getAllPlayers()` returns one – e.g. if you want to dispose all players. (Although if you need to do that, you might be doing something wrong. :) ) – Rin Sep 18 '18 at 15:54
1

The way I do it is by using the suggested dispose method of the player object.

I have a function which creates a new player with an ID, which was different from the ID of the previous player (for some reason you can't instantiate a player with the same ID, even after it was disposed).

The full process is as follows:

  1. Create a parent element for your player.

        <div id="player-parent"></div>
    
  2. Create a function responsible for generating an initial player element on which you'll call the videojs constructor.

    function getPlayerInstance(curPlayerNumber, playerSource) {
        // curPlayerNumber is simply a counter number which must be different from any previous one passed to this function
        return $("<video id=\"video\ " + curPlayerNumber + "\" class=\"video-js vjs-default-skin\" controls data-setup='{\"plugins\" : { \"resolutionSelector\" : { \"default_res\" : \"360\" } } }'><source src=\"" + playerSource + "\" type=\"application/x-mpegURL\" data-res=\"360\"></video>");
    }
    
  3. Select your parent element

    $('#player-parent').append(getPlayerInstance(++playerCounter, someSourceHere));
    
    1. Instantiate your player, disposing any old players you might have.

This is pseudo code, for simplicity I assign the player to a global variable for easier access. You should do that differently.

    if (window.playerElement) {
        window.playerElement.dispose();
    }

    // the playerCounter variable is different for each function call
    videojs("video" + playerCounter).ready(function(){
        window.playerElement = this;
    });

Hope this was helpful, I wasted 3 days on this.

zerefel
  • 1,699
  • 2
  • 11
  • 13
  • 1
    If you end up here looking for help with using videojs with React and you're conditionally rendering several videos on the same page, this gist might be helpful: https://gist.github.com/rin/e4e7219f7a53e03538d5d4db04bedb0c (I realize this is not an answer to the OP's question and I apologize.) – Rin Sep 18 '18 at 15:56