解决MediaRecorder录制视频不支持进度条

757 阅读1分钟

背景

录制video/canvas上的视频然后下载到本地,但是遇到问题还是比较多的,进度条问题是最主要的一个。

录制代码

解决思路

因为是Matroska容器,在录制的时候少了一些媒体信息,所以播放器无法使用进度条。chrome官方不认为这是一个bug/issue.

额外

Matroska

基于EBML(Extensible Binary Meta Language 可扩展的二进制元语言),旨在成为多媒体格式容器的标准。 Matroska aims to become THE standard of multimedia container formats. It was derived from a project called MCF, but differentiates from it significantly because it is based on EBML (Extensible Binary Meta Language), a binary derivative of XML. EBML enables the Matroska Development Team to gain significant advantages in terms of future format extensibility, without breaking file support in old parsers.来自matroska官网。

支持的扩展名

目前Matroska支持5种扩展名的格式:mkv、mka、mk3d、mks、webm

  • ffmpeg

ffmpeg.js也尝试了,但是问题比较多,因为使用了ffmpeg.wasm,其中SharedArrayBuffer在chrome默认中不支持。设置支持见

 //ffmpge 命令确实好用呢 
 //但是在前端中性能不好以及一些API比较新有些浏览器不太支持
 
 ffmpeg -i input_video.webm -c:v copy -c:a copy output_video.mp4
  • 前端library

chatgpt有时候也害人啊,ts-embl库文件不全,好久没更新,解决出来还是有bug。于是找啊找,终于找到了。ebml.js

    //使用的ebml.js
    //mkv容器格式封装
    
    const EBML=require ('./libs/EBML.js');
     getSeekableBlob(inputBlob, cb) {
        try{
          if (typeof EBML === 'undefined') {
            throw new BuildError('EBMLError', CONSTANT.EBML.LOAD_ERROR);
          }
          let reader = new EBML.Reader(),
          decoder = new EBML.Decoder(),
          tools = EBML.tools,
          fileReader = new FileReader();
          fileReader.onload = function(e) {
              var ebmlElms = decoder.decode(this.result);
              ebmlElms.forEach(function(element) {
                  reader.read(element);
              });
              reader.stop();
              var refinedMetadataBuf = tools.makeMetadataSeekable(reader.metadatas, reader.duration, reader.cues);
              var body = this.result.slice(reader.metadataSize);
              var newBlob = new Blob([refinedMetadataBuf, body], {
                  type: 'video/webm'
              });
              cb(newBlob);
              if(!newBlob||newBlob.size<1){
                throw new BuildError('EBMLError', CONSTANT.EBML.TRANSFER_ERROR);
              }
          };
          fileReader.readAsArrayBuffer(inputBlob);
        }catch(error){
          console.error(`[${error.type}]>${error.code}>${error}`);
        }
    }
    // 处理过后的blob是带有duration的流

小结

前端处理不同的容器格式需要扎实的基础以及对容器格式的熟悉。比如flv.js 各种.wasm 等等。