Search code examples
javascripthtmlhtml5-videomedia-playervideo.js

How to make an html5 player play without a source


I am building a multimedia player that needs to control multiple other multimedia players on a page. In order to do that I want to have an area at the bottom of the page which contains a media playback controller (including a seekbar) that will control all other players on the page. For example, when a user hits the play button all the other players on the page starts playing.

I want to use a regular video/audio player, but instead of playing real content all I want is to have the controls, especially a seekbar which advances. The reason for not implementing playback controls on my own is because I want to use the power of video.js plugins (like event markers on the timeline).

I have managed to display a video.js player only with playback controls. In addition I have managed to set the duration. The problem is that the player doesn't play when I hit the play button nor calilng player.play().

This is because the player doesn't have a media source. video.js and the native player won't play without a media source.

Now, is there a way to force a player to play even without a source? Can I make it think it has one?

Thank you,


Solution

  • I have figured out a solution that works.

    Again the purpose is having working media controllers from video.js without loading any media content and the most important controller is the seek bar.

    I have been playing with video.js and was trying to make the seek bar advance without loading any media content and found out that calling player.currentTime() does actually updates the curretTime internal member but doesn't update the UI.

    Eventually I found out that in order to make video.js update the UI we need to trigger the timeupdate event.

    So I decided to implement a fake player that has control over all the other players and uses a video.js player as his UI (by showing only the media controls and hiding the video).

    The fake player need to use a precise timer as mentioned here.

    Conceptual example:

    import videojs from 'video.js';
    
    class MainMediaController {
        public static readonly INTERVAL = 250;
    
        protected _playerId: string;
        protected _duration: number;
        protected _mediaController: videojs.Player;
        protected _childPlayers: videojs.Player[];
        protected _currentTime: number;
    
        private _interval: number;
        private _intervalId: number;
    
        constructor(playerId: string, recordingDuration: number, childPlayers: videojs.Player[]) {
            this._playerId = playerId;          // id of the player at the bottom of the page which will be served as the main timeline
            this._duration = recordingDuration;
            this._interval = MainMediaController.INTERVAL;
            this._childPlayers = childPlayers;
            this._currentTime = 0;
    }
    
        public async init() {
            this._mediaController = videojs(this._playerId);
    
            // await for ready state
            await new Promise((resolve, reject) => {
                this._mediaController.ready(() => {
                    resolve();
                });
            });
    
            // set duration for a correct seek bar (longest.endTime - first.startTime)
            this._mediaController.duration(this._duration);
        }
    
        public play(){
            // update UI every 250ms
            this._intervalId = setInterval(this.intervalStep.bind(this), this._interval);
    
            for(let player of this._childPlayers){
                player.play();
            }
        }
    
        private intervalStep(){
            this._currentTime += 0.250;                          // 250ms
            this._mediaController.currentTime(this._currentTime);
            this._mediaController.trigger("timeupdate");         // trigger() is accessible don't worry
        }
    
        public pause(){...}
        public stop(){...}
        public seek(){...}
    }
    

    That solution let me use video.js plugins in my main timeline that has no video in it!!