【问题标题】:Can I send an arbitrary chunk of a WebM (starting at a byte offset) to a mediaSource buffer to be played?我可以将 WebM 的任意块(从字节偏移量开始)发送到要播放的 mediaSource 缓冲区吗?
【发布时间】:2022-02-16 11:21:15
【问题描述】:

我正在尝试仅发送 WebM 文件的特定截断部分,从任意关键帧开始,从 Node.js 服务器由客户端使用 MediaSource 缓冲播放,但我不确定这是否是可能的或如何去做。

到目前为止,这是我正在尝试的:

  1. 使用来自https://github.com/acolwell/mse-toolsmse_json_manifest查找初始化段+关键帧簇的字节偏移和大小
  2. 初始化段和随机选择的媒体段的连接流
  3. 通过 HTTP 请求或套接字事件将流发送到客户端

看起来发送初始化段总是有效的,因为客户端的 HTMl5 视频播放器显示原始文件的持续时间,但它不缓冲之后发送的连接媒体段。

这是相关的服务器代码:

const merge = (...streams: ReadStream[]) => {
    let pass = new PassThrough();
    let waiting = streams.length;
    for (let stream of streams) {
        pass = stream.pipe(pass, {end: false});
        stream.once("end", () => --waiting === 0 && pass.emit("end"));
    }
    return pass;
}

io.on("connection", (socket) => {
    const streams = [
        fs.createReadStream(file, {
            start: audioJson.init.offset,
            end: audioJson.init.size,
        }),
        fs.createReadStream(file, {
            start: audioJson.media[150].offset,
        })
    ];
    merge(...streams).on("data", (data) => socket.emit("audio-data", data));
});

客户:

      const streamVideo = document.getElementById("webmStream");
      const mediaSource = new MediaSource();
      const streamSource = URL.createObjectURL(mediaSource);
      streamVideo.src = streamSource;

      const audioMime = `audio/webm; codecs="opus"`;
      const videoMime = `video/webm; codecs="vp9"`;

      mediaSource.addEventListener("sourceopen", () => {
        const audioBuffer = mediaSource.addSourceBuffer(audioMime);
        const audioChunks = [];

        function appendOrQueueChunk(chunk) {
          if (!audioBuffer.updating && !audioChunks.length) {
            audioBuffer.appendBuffer(chunk);
          } else {
            audioChunks.push(chunk);
          }
        }

        socket.on("audio-data", appendOrQueueChunk);

        audioBuffer.addEventListener("updateend", () => {
          if (audioChunks.length) audioBuffer.appendBuffer(audioChunks.shift());
        });

还有一个 JSON 的 sn-p:

{
  "type": "audio/webm;codecs=\"opus\"",
  "duration": 93100.000000,
  "init": { "offset": 0, "size": 526},
  "media": [
    { "offset": 526, "size": 10941, "timecode": 0.000000 },
    { "offset": 11467, "size": 10382, "timecode": 0.260000 },
    { "offset": 21849, "size": 10301, "timecode": 0.520000 },
    { "offset": 32150, "size": 10495, "timecode": 0.780000 },
...

只要我直接从整个 WebM 文件的 fs.ReadStream 发出套接字事件,套接字流就可以正常工作,所以它可能与按顺序发送流有关,但我觉得完全超出了我的深度并认为我我在概念上遗漏了一些东西。

【问题讨论】:

    标签: node.js typescript socket.io webm media-source


    【解决方案1】:

    您甚至不需要 MediaSource。常规视频元素可以通过简单的 HTTP 请求从您的 Node.js 服务器流式传输。不需要 Socket.IO,什么也不需要。

    <video src="https://nodejs-stream-server.example.com/something"></video>
    

    我不知道你正在使用的库,所以我会用更通用的术语告诉你我过去是如何完成这项确切任务的,也许你可以调整或重新实现它。

    首先,当媒体流请求进入您的 Node.js 服务器时,您必须发送一些初始化数据。听起来你已经成功地做到了。这个初始化数据基本上是流中的所有内容,直到第一个Cluster element

    因此,当您的编码器启动时,请务必将数据缓冲到那时,以便您准备好将其发送给新客户端。

    接下来,您可以从任意集群元素开始只要该集群以关键帧开始(用于视频)。如果这现在不起作用,我怀疑您的集群不是从关键帧开始的,或者它们有一些奇怪的地方。在您的 JSON 中,您显示了一个音频流……这是故意的吗?

    我建议阅读 EBML,它本质上是 Matroska/WebM 的基本容器格式。 Matroska 只是 EBML 文档的一种模式。 WebM 只是 Matroska,但指定为一组核心编解码器。

    所以,是的,总而言之,我认为您有这个概念,但可以简化。

    其他一些您可能会觉得有帮助的事情:

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-14
      • 2014-03-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多