技术分享:目前主流视频分片技术

首先来看一下几个视频网站的截图:
(腾讯视频)
技术分享:目前主流视频分片技术_第1张图片

(爱奇艺视频)
技术分享:目前主流视频分片技术_第2张图片

(哔哩哔哩)
技术分享:目前主流视频分片技术_第3张图片

腾讯视频和爱奇艺在视频播放的时候都加载了一个格式为ts和文件(B站的格式为m4s)

一,什么是ts呢?

TS是高清格式,全称为MPEG2-TS。MPEG是一个视频和音频编码技术标准(百度一下),ts即"Transport Stream"的缩写。MPEG2-TS格式的特点就是要求从视频流的任一片段开始都是可以独立解码的。

MPEG-TS则主要应用于实时传送的节目,比如实时广播的电视节目。电视节目是要求任何时候打开电视机都能解码(收看)的,所以,MPEG2-TS格式的特点就是要求从视频流的任一片段开始都是可以独立解码的。

ts格式是一种新兴的高清封装格式,对ts格式解码,即将ts格式解码再编码成其他格式,常见的转换模式有:ts转rmvb,ts转mp4、ts转avi、ts转wmv;对ts格式编码,即指将其他格式转换成ts格式。

二,MSE(Media Source Extensions)

普通web应用采用html5的

代码示例: 参考MDN在线DEMO bufferAll

var video = document.querySelector('video');

var assetURL = 'frag_bunny.mp4';
// Need to be specific for Blink regarding codecs
// ./mp4info frag_bunny.mp4 | grep Codec
var mimeCodec = 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"';

if ('MediaSource' in window && MediaSource.isTypeSupported(mimeCodec)) {
  var mediaSource = new MediaSource();
  //console.log(mediaSource.readyState); // closed
  video.src = URL.createObjectURL(mediaSource);
  mediaSource.addEventListener('sourceopen', sourceOpen);
} else {
  console.error('Unsupported MIME type or codec: ', mimeCodec);
}

function sourceOpen (_) {
  //console.log(this.readyState); // open
  var mediaSource = this;
  var sourceBuffer = mediaSource.addSourceBuffer(mimeCodec);
  fetchAB(assetURL, function (buf) {
    sourceBuffer.addEventListener('updateend', function (_) {
      mediaSource.endOfStream();
      video.play();
      //console.log(mediaSource.readyState); // ended
    });
    sourceBuffer.appendBuffer(buf);
  });
};

function fetchAB (url, cb) {
  console.log(url);
  var xhr = new XMLHttpRequest;
  xhr.open('get', url);
  xhr.responseType = 'arraybuffer';
  xhr.onload = function () {
    cb(xhr.response);
  };
  xhr.send();
};

遇到的问题:一开始用的是自己本地随便找的一个视频文件,结果报错:Uncaught DOMException: Failed to execute ‘endOfStream’ on ‘MediaSource’: The MediaSource’s readyState is not ‘open’.原因是该MP4文件不是 framented mp4,需要特定的工具进行转换。

对于fragment mp4,mp4文件被分成多个frag分片,而原来的meta数据大大变小,且没个frag都可以单独索引、传输和播放,这样就可以解决mp4不能流式传输播放的问题。对用户体验比较好。然而目前这种格式并不被多数解码器完整支持,部分播放器加载文件时间过长,而且浏览器内嵌播放器也可能不支持播放。

三, 咱们PC端实现视频播放的逻辑
后端代码:

// 一次解码1M
const highWaterMark = 1024 * 1024
function decodefiletostream (req, res, fileInfo) {
   //  log.debug('decodefiletostream', fileInfo.filepath)
    var file = path.resolve(fileInfo.filepath) // 源文件
    var rs = fs.createReadStream(file, {encoding: null, highWaterMark, autoClose: true})
    let head = {
      'Content-Type': fileInfo.c
    }
    let skey = decrypt(fileInfo.s)
    // log.debug('decodefiletostream-->skey', skey)
    // 需要设置HTTP HEAD
    res.writeHead(206, head)
    var bufferStream = new Stream.PassThrough()
    rs.on('data', function (chunk) {
        // 如果加密标志是0,则是非加密文件
        // 功能更新: 视频头部加密1M内容, 所以highWaterMark的数值以后都不能改了 
        if (fileInfo.f === '0' || skey === '') {
            bufferStream.write(chunk)
        } else {
            // 否则是加密文件
            let tmp = new Array(chunk.length)
            for (var i = 0; i < chunk.length; i++) {
                tmp[i] = chunk[i] - parseInt(skey.charAt((i + 1) % 32), 16)
            }
            skey = ''
            bufferStream.write(Buffer(tmp))
        }
    })
    rs.on('end', function () {
        bufferStream.end()
    })
    bufferStream.pipe(res)
}

前端代码:

var video = document.getElementById('video')
var xhr = null
sendRequest((res) => {
  // 创建BLOB大数据对象
  video.src = URL.createObjectURL(res)
    loading.style.display = 'none'
})
//xhr请求
function sendRequest (cb) {
  if (!xhr) xhr = new XMLHttpRequest()
  xhr.open('get', `http://127.0.0.1:8888/video/${reqId}?sign=${sign}`, true)
  xhr.responseType = 'blob'
  xhr.onload = function () {
    // if (xhr.status === 206)
      cb(this.response)
  }
  xhr.send()
}

你可能感兴趣的:(html5前端mse)