Search code examples
javascriptnode.jssocket.iovideo-streamingmedia-source

MediaSource API: Video not playing


I am making a module for Magic Mirror which runs on a RPi. The module is supposed to allow the user select a video file on their mobile, start reading the file and send the stream back to html video tag on the magic mirror. This is more like mirroring/casting a video from mobile device to magic mirror (rpi). The framework is based on Nodejs.

Currently I am trying to read a local file and send the stream to the client.

I am using the following code for the server:

module.exports = NodeHelper.create({
    socketNotificationReceived: function(notification, payload) {
        var self = this;
        switch(notification) {
            case "INITIATEDEVICES":
                var readStream = fs.createReadStream("./modules/MMM-MP4Player/video.mp4");
                readStream.addListener('data', function(data){
                    self.sendSocketNotification('Video_File',data);
                });
                break;
        }
    }
});

The following code is for the client:

Module.register("MMM-MP4Player",{
    start: function(){
        window.URL = window.URL || window.webkitURL;
        window.MediaSource = window.MediaSource || window.WebKitMediaSource;
        if(!!! window.MediaSource){
            console.log('MediaSource API is not available!');
        }
    },
    getDom: function() {
        var self = this;
        wrapper = document.createElement("div");
        videoElement = document.createElement("video");
        videoElement.width = 1280;
        videoElement.height = 720;
        videoElement.controls = true;
        videoElement.autoplay = true;
        videoElement.id = self.identifier+"_player";
        wrapper.appendChild(videoElement);
        
        setTimeout(function(){ 
            self.mediaSource = new MediaSource();
            self.queue = [];
            videoElement.src = window.URL.createObjectURL(self.mediaSource);
            self.mediaSource.addEventListener('sourceopen', function(e){
                self.sourceBuffer = self.mediaSource.addSourceBuffer('video/mp4; codecs="avc1.42E01E,mp4a.40.2"'); // video/webm; codecs="vorbis,vp9"
                videoElement.play();
                self.sourceBuffer.addEventListener('update', function() {
                    if (self.queue.length > 0 && !self.sourceBuffer.updating) {
                        self.sourceBuffer.appendBuffer(self.queue.shift());
                    }
                });
            }, false);

            self.sendSocketNotification("INITIATEDEVICES");
        }, 2000);
        return wrapper;
    },

    socketNotificationReceived: function(notification, payload){
        var self = this;
        switch(notification){
            case "Error": // Universal error handler
                break;
            case "Video_File":
                if (self.sourceBuffer.updating || self.queue.length > 0) {
                    self.queue.push(new Uint8Array(payload.data));
                } else {
                    self.sourceBuffer.appendBuffer(new Uint8Array(payload.data));
                }
                break;
        }
    }   
});

The video chunks are being sent perfectly from the server and received by the client too. Its just that the video player remains empty. All suggestions are welcome.

Thanks.


Solution

  • Alright. So after no help from stackoverflow, I kept on experimenting and finally corrected the problem. Posting it here just to help someone else.

    I made some minor adjustment to the code and changed the file to a dash-compliant file. Need to now focus on how to convert a video buffer to dash-compliant on the fly. Anyways here is the code.

    Module.register("MMM-MP4Player",{
        getDom: function() {
            var self = this;
            wrapper = document.createElement("div");
            videoElement = document.createElement("video");
            videoElement.width = 300;
            videoElement.height = 200;
            videoElement.controls = true;
            videoElement.autoplay = true;
            videoElement.id = self.identifier+"_player";
            wrapper.appendChild(videoElement);
    
            window.URL = window.URL || window.webkitURL;
            window.MediaSource = window.MediaSource || window.WebKitMediaSource;
            self.mimeCodec = 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"';
            self.queue = [];
            if(window.MediaSource && window.MediaSource.isTypeSupported(self.mimeCodec)){
                setTimeout(function(){ 
                    self.mediaSource = new MediaSource();
                    videoElement.src = window.URL.createObjectURL(self.mediaSource);
                    videoElement.play();
                    self.mediaSource.addEventListener('sourceopen', function(e){
                        self.sourceBuffer = self.mediaSource.addSourceBuffer(self.mimeCodec);
                        self.sourceBuffer.addEventListener('updateend', function() {
                            if (self.queue.length > 0 && !self.sourceBuffer.updating) {
                                self.sourceBuffer.appendBuffer(self.queue.shift());
                            }
                        }, false);                  
                    }, false);
                    self.sendSocketNotification("INITIATEDEVICES");
                }, 2000);
            }
            return wrapper;
        },
    
        socketNotificationReceived: function(notification, payload){
            var self = this;
            switch(notification){
                case "Video_File":
                    if (self.sourceBuffer.updating || self.queue.length > 0) {
                        self.queue.push(new Uint8Array(payload));
                    } else {
                        self.sourceBuffer.appendBuffer(new Uint8Array(payload));
                    }
                    break;
            }
        }
    });
    

    Any help on the video buffer conversion in Nodejs is welcome.