Electron實現跨平臺全能視頻播放器

最近在看英文字幕的電影,聽力水平通常,有些字幕對話想多回放幾遍。這個是一個比較小衆的需求,發現目前的播放器都不支持。因而就想本身實現個有字幕回放功能的播放器。跨平臺的開源播放器,好比VLC、MPV,開發的門檻都挺高的。若是能用Electron作播放器的話,添加一些個性的功能,應該會比較簡單,寫一些html、js就能夠。使用Electron製做播放器碰到的最大問題是,H5 video標籤只支持部分的視頻格式。通過一段時間的研究,這個問題已經解決。目前基於Electron的跨平臺全能播放器已經實現,並加上了我最想要的字幕對話回放功能。html

使用ffmpeg支持全部視頻格式

在Electron應用裏,H5 video標籤支持視頻的本地路徑。 H5 video標籤只支持部分的視頻格式(mp四、webm和ogg)。須要使用ffmpeg支持其餘格式的視頻文件(mkv、rmvb、flv...)。這裏可使用ffmpeg的nodejs封裝庫 fluentffmpeg。 先使用ffmpeg檢查視頻文件是否能夠直接用H5 video標籤直接播放。前端

var videoSupport = function (videoPath) {
    let p = new Promise(function (resolve, reject) {
        let command = ffmpeg()
            .input(videoPath)
            .ffprobe(function (err, data) {
                if (err) {
                    reject(err);
                    return;
                }
                var streams = data.streams;
                var checkResult = {
                    videoCodecSupport: false,
                    audioCodecSupport: false,
                    duration: data.format.duration
                }
                if (streams) {
                    streams.map((value) => {
                        // mp4, webm, ogg
                        if (value.codec_type == 'video' && (value.codec_name == 'h264' || 
                        value.codec_name == 'vp8' || value.codec_name == 'theora')) {
                            checkResult.videoCodecSupport = true;
                        }
                        if (value.codec_type == 'audio' && (value.codec_name == 'aac' || 
                        value.codec_name == 'vorbis')) {
                            checkResult.audioCodecSupport = true;
                        }
                    })
                }
                resolve(checkResult)
            });
    });
    return p;
}
複製代碼

對於H5 video標籤不支持的格式,須要ffmpeg轉碼。 Electron應用進程分爲瀏覽器渲染進程,和nodejs主進程。nodejs能夠啓動http server,這個http server使用ffmpeg實時轉碼,返回H5 video標籤能夠識別的fragmeted mp4視頻流。node

this._videoServer = http.createServer((request, response) => {
                var startTime = parseInt(getParam(request.url, "startTime"));
                let videoCodec = this.videoSourceInfo.checkResult.videoCodecSupport ? 'copy' : 'libx264';
                let audioCodec = this.videoSourceInfo.checkResult.audioCodecSupport ? 'copy' : 'aac';
                this.killFfmpegCommand();
                this._ffmpegCommand = ffmpeg()
                    .input(this.videoSourceInfo.videoSourcePath)
                    // read input at native framerate
                    .nativeFramerate()
                    .videoCodec(videoCodec)
                    .audioCodec(audioCodec)
                    .format('mp4')
                    .seekInput(startTime)
                    // fragmeted mp4
                    .outputOptions('-movflags', 'frag_keyframe+empty_moov');
                let videoStream = this._ffmpegCommand.pipe();
                videoStream.pipe(response);
            }).listen(8888);
複製代碼

前端H5 video標籤src屬性設置爲nodejs視頻流的地址git

<video id="video" width="800" height="480" preload>
                <source src="http://127.0.0.1:8888?startTime=0" type='video/mp4'>
            </video>
複製代碼

Fragmented mp4視頻流seek的實現

H5 video>標籤有默認的拖動控制條,支持普通mp4視頻流的seek,通常經過http range實現。可是對fragmented mp4視頻流,http range沒法實現seek。這裏的fragmented mp4視頻流是實時的轉碼流,整個視頻文件的size是未知的。 這裏咱們去掉了H5 video標籤的默認控制條,使用自定義的拖動控制條。經過ffmpeg得到視頻的總時長。拖動的時候在視頻流的請求地址裏面提交seek time。http server得到seek time後,經過ffmpeg命令的seek參數將視頻的播放時間移動。github

開源

github.com/relaxrock/r…web

相關文章
相關標籤/搜索