类型错误:无法在“SourceBuffer”上执行“appendBuffer”:找不到与提供的签名匹配的函数

Fif*_*oud 7 javascript media-source

编辑:为了帮助说明我不断收到的错误,我创建了我所看到的问题的 CodePen。打开控制台,您将看到错误。[ https://codepen.io/FifthCloud/pen/eYpqJLN ]

我想使用 React/Node 在家里设计自己的流媒体摄像头服务。到目前为止,我已经在客户端/服务器方法方面取得了很大进展。服务器是一个带有摄像头的树莓派。使用 FFMpeg 我可以看到其中的所有视频,使用 websockets 我可以成功发送数据(我的意思是我看到发送到客户端的数据将了解为什么它不会渲染)。

我遇到的问题是为什么我不能将数据附加到缓冲区。首先,我使用这个有关媒体源的演示作为我应该做什么的指南和示例。http://nickdesaulniers.github.io/netfix/demo/bufferAll.html我从我关于媒体源的研究中得到了这个链接: https: //developer.mozilla.org/en-US/docs/Web/API/MediaSource /readyState 还想提一下,我从这篇文章中获得了很多灵感,并且由于这个答案HTML5 Video: Streaming Video with Blob URLs取得了很大的进展

考虑到这一点,我可以成功创建MediaSource并打开缓冲区,但我不明白的是为什么我无法附加到缓冲区?我收到的错误是这样的:

类型错误:无法在“SourceBuffer”上执行“appendBuffer”:找不到与提供的签名匹配的函数。

客户端代码如下

class ProductDetail extends React.Component {
  constructor(props) {
    super(props);
    this.handleData = this.handleData.bind(this);
    this.handleOpen = this.handleOpen.bind(this);
    this.appendToSourceBuffer = this.appendToSourceBuffer.bind(this);
    this.mediaStreaming = new MediaSource();
    this.blobArr = [];
    this.buffer = null;
    this.myRef = React.createRef();

    console.log("buffer initialized");
    console.log("ReadyState [Initialized]: " + this.mediaStreaming.readyState);
    this.state = {
      msg: "",
      stream: "",
      streaming: URL.createObjectURL(this.mediaStreaming),
    };
  }

  componentDidMount() {
    this.mediaStreaming.addEventListener("sourceopen", () => {
      console.log(
        "ReadyState [Source Open]: " + this.mediaStreaming.readyState
      );
      this.buffer = this.mediaStreaming.addSourceBuffer(
        'video/mp4;codecs="avc1.42E01E"'
      );
      this.buffer.addEventListener("updateend", () => {
        this.mediaStreaming.endOfStream();
        document.getElementById("streaming").play();
        console.log(
          "ReadyState [UpdateEnd]: " + this.mediaStreaming.readyState
        );
      });
    });
  }

  handleData(data) {
    const videoStream = JSON.parse(data);
    if (videoStream.msg === "videoStream") {
      this.blobArr.push(videoStream.chunk.data);
      if (
        this.mediaStreaming.readyState === "open" &&
        this.buffer &&
        this.buffer.updating === false &&
        this.blobArr.length > 0
      ) {
        console.log(
          "ReadyState [AppendBuffer]: " + this.mediaStreaming.readyState
        );
        this.buffer.appendBuffer(this.blobArr.shift()); // Error message shows at this line!
        document.getElementById("streaming").play();
        console.log("Buffer Updating", this.buffer.updating);
      }
    }
  }

  handleOpen() {
    console.log("Status: connected");
  }

  handleClose() {
    console.log("Status: disconnected");
  }

  render() {
    return (
      <div>
        <Websocket
          url="ws://192.168.1.20:5000"
          onMessage={this.handleData}
          onOpen={this.handleOpen}
          onClose={this.handleClose}
          reconnect={true}
          debug={true}
          ref={(Websocket) => {
            this.refWebSocket = Websocket;
          }}
          protocol="stream-protocol"
        />
        <video width="640" height="480" id="streaming" controls autoPlay>
          <source
            ref={this.myRef}
            src={this.state.streaming}
            type="video/mp4"
          />
          Your browser does not support the video tag.
        </video>
      </div>
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

handleData当服务器发送下一个流字节数组数据时,该错误来自我的 WebSocket 事件。

正如我提到的示例和我发布的链接中的指南,我查看了他们的代码并逐步完成了它。根据他们的说法,附加缓冲区应该可以正常工作,但是即使在他们的代码中也只在原型appendbuffer()部分中列出,请参阅此处:https://drive.google.com/open ?id=1vOU4oM-XoKe71DofQuLU2THxMdgiown_ 但代码并没有抱怨他们的appendbuffer()。当我控制台记录我的缓冲区时,它看起来像他们的https://drive.google.com/open?id=1T4Ix-y124NgQJ9xu97xv4U2yFTn2k7vF。我缺少什么?

我觉得答案很明显,但我却不知道我做错了什么。

小智 4

我自己正在构建一个类似的项目,使用多个支持 RTSP 的高端 IP 摄像机,今天刚刚遇到了同样的错误。首先,请记住,根据 Mozilla 开发者网络 (MDN) 文档(下面的链接),此 API 是实验性的。

话虽这么说,我似乎已经找到了问题的根本原因,尽管我绝对不是 JavaScript 专家。事实证明,您不能直接将“Blob”对象从data.datain传递handleData()appendBuffer()方法中。相反,您需要先将 Blob 转换为该appendBuffer()方法支持的数据类型,然后再将其传入。

  1. 将事件处理程序转变为async函数
  2. 使用 将Blob.arrayBuffer()数据 blob 转换为JavaScriptArrayBuffer

改变这个:

  handleData(data) {
    const videoStream = JSON.parse(data);
    if (videoStream.msg === "videoStream") {
      this.blobArr.push(videoStream.chunk.data);
      if (
        this.mediaStreaming.readyState === "open" &&
        this.buffer &&
        this.buffer.updating === false &&
        this.blobArr.length > 0
      ) {
        console.log(
          "ReadyState [AppendBuffer]: " + this.mediaStreaming.readyState
        );
        this.buffer.appendBuffer(this.blobArr.shift()); // Error message shows at this line!
        document.getElementById("streaming").play();
        console.log("Buffer Updating", this.buffer.updating);
      }
    }
  }
Run Code Online (Sandbox Code Playgroud)

进入这个:

  async handleData(event) {
    var buffer = await event.data.arrayBuffer(); // convert the message Blob into an ArrayBuffer
    appendBuffer(buffer);
    document.getElementById("streaming").play();
    console.log("Buffer Updating", this.buffer.updating);
  }
Run Code Online (Sandbox Code Playgroud)

问题是,一旦执行此操作,您将开始收到新错误,因为有太多数据传递SourceBufferMediaSource. 由于它无法跟上输入流,您将看到类似于以下错误的内容:

无法在“SourceBuffer”上执行“appendBuffer”:此 SourceBuffer 仍在处理“appendBuffer”或“删除”操作

看起来我们需要“缓冲缓冲区”,尽管听起来很奇怪。

我还没有解决这个新错误。如果您找到解决方案,我希望得到一些帮助。

相关阅读

  • “无法在‘SourceBuffer’上执行‘appendBuffer’:此 SourceBuffer 仍在处理‘appendBuffer’或‘删除’操作”我遇到了这个问题,并意识到我的“sourceopen”回调被多次调用......不知道为什么但看看它是否不会让你的错误消失。 (5认同)
  • 谢谢您的帮助。至于你关于缓冲缓冲区问题的答案。我提前找到了这个帮助,因为我所做的所有研究我知道我必须达到你所说的这一点。&lt;/sf/answers/3524792771/&gt; 这个人想出了一个好主意,一旦缓冲区达到一定数量,就删除缓冲区的项目。你是对的,这都是实验性的,但请阅读以下内容: &lt;https://developer.mozilla.org/en-US/docs/Web/API/SourceBuffer/buffered&gt; 它使用 TimeRange 数据类型。用它来看看你的缓冲区是否会很高。 (2认同)
  • 感谢您提供其他问答的链接。看起来他只是将数据块缓冲到通用 JavaScript 数组中,然后每秒最多将它们出队一次。我可能必须将 1000 毫秒的间隔减少到 100 毫秒左右,以确保我有稳定的输入数据流,但理论上这可能有效。当我有更多时间时,我必须玩它。干杯 (2认同)