最近在看英文字幕的電影,聽力水平一般,有些字幕對話想多回放幾遍。這個是一個比較小眾的需求,發現目前的播放器都不支援。於是就想自己實現個有字幕回放功能的播放器。跨平臺的開源播放器,比如VLC、MPV,開發的門檻都挺高的。如果能用Electron做播放器的話,新增一些個性的功能,應該會比較簡單,寫一些html、js就可以。使用Electron製作播放器碰到的最大問題是,H5 video標籤只支援部分的視訊格式。經過一段時間的研究,這個問題已經解決。目前基於Electron的跨平臺全能播放器已經實現,並加上了我最想要的字幕對話回放功能。
使用ffmpeg支援所有視訊格式
在Electron應用裡,H5 video標籤支援視訊的本地路徑。
H5 video標籤只支援部分的視訊格式(mp4、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視訊流。
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視訊流的地址
<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引數將視訊的播放時間移動。