hughfenghen.github.io icon indicating copy to clipboard operation
hughfenghen.github.io copied to clipboard

js 构造 H264 自定义 SEI 信息

Open hughfenghen opened this issue 3 years ago • 1 comments

背景 Webcodecs支持了Web编码,加上开源的muxer(如mp4box.js)就能使用原生js封装视频文件了; 而在直播场景经常需要在视频流中插入自定义SEI,开放对视频流的操作能力是Webcodecs的动机之一(WebRTC~~做不到~~); 以下是为了 验证 自定义SEI确实可行,仅是学习笔记,若想在生产使用,需完成标注未完成的任务;

NALU 组成结构 image SEI 是一种特殊的 NALU

SEI 组成结构 image

代码实现

function buildStrSEINALU (str) {
  const txtEncoder = new TextEncoder()
  let uuidStr = ''
  for (let i = 0; i < 16; i++) {
    uuidStr += ((Math.random() * 16) | 0).toString(16)
  }
  const uuidBuf = txtEncoder.encode(uuidStr)
  const strBuf = txtEncoder.encode(str)
  const seiPayloadSize = uuidBuf.byteLength + strBuf.byteLength

  const seiBuf = new Uint8Array([
    // annexb start code;1. 不支持avcC
    0, 0, 0, 1,
    // naul header sei type
    6,
    // payload type, User Data Unregistered
    5,
    // payload size;2. size可能超过255,需要多个字节表示(小端序)
    seiPayloadSize,
    // payload uuid;3. uuidBuf、strBuf 防竞争字节 检查替换
    ...uuidBuf,
    // payload content
    ...strBuf,
    // end flag
    0x80
  ])

  return seiBuf
}

// 使用示例
const encoder = new VideoEncoder({
  output: (chunk) => {
    let buf = new ArrayBuffer(chunk.byteLength)
    chunk.copyTo(buf)
    // 连接H264裸流数据与SEI
    buf = concatAB(buf, buildStrSEINalu('hello Webcodecs'))
    // 查看 mp4box.js 文档
    outputFile.addSample(vTrackId, buf, opts)
  }
})

未完成的任务

  1. 支持 avcC
    • avcC 不需要起始码,[size, seiType(6), seiData] 拼接即可(size 4 字节大端序),更简单
  2. size可能超过255,需要多个字节表示(小端序)
  3. uuidBuf、strBuf 防竞争字节 检查替换
  4. 支持HEVC

参考

hughfenghen avatar Nov 22 '22 06:11 hughfenghen