VideoJS-Dynamically Change Sources

Aaron Chamberlain picture Aaron Chamberlain · Dec 23, 2015 · Viewed 16.8k times · Source

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.

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"}
    ]);
}
});

Answer

zerefel picture zerefel · Dec 24, 2015

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.