sourceBuffer.appendBuffer 成功但 h5 视频播放器卡住

问题描述 投票:0回答:1

这是我的 React.js 字体代码

import React, { useEffect, useRef } from 'react';

const VideoPage = () => {
  const videoInited = useRef(false)

  useEffect(() => {
    const video = document.querySelector("#stream-media-video") as HTMLMediaElement;

    // Using Bento4 to parse my mp4 video file
    // mp4info test.mp4 | grep Codec
    const mimeCodec = 'video/mp4; codecs="avc1.64081F, mp4a.40.2"';

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

    function sourceOpen(_) {
      console.log('[mediaSource sourceopen event trigger]: ', this.readyState); // open
      const mediaSource = this;

      const playBtn = document.querySelector('.play-btn');
      const init = () => {
        const sourceBuffer = mediaSource.addSourceBuffer(mimeCodec);

        // Get some video clips through xhr request (the video file is 1.5M in total, first get the first 1M part, and then get the next 0.5M part)
        fetchAB("/api/media/testmp4/part-v2?start=0&end=1000000", function (buf) {
          sourceBuffer.addEventListener('error', (e) => {
            console.error("sourceBuffer error", e);
          });
          
          sourceBuffer.addEventListener("updateend", function (_) {
            // mediaSource.endOfStream();

            video.play();
            videoInited.current = true;
            playBtn.removeEventListener("click", init);
  
          });
          sourceBuffer.appendBuffer(buf);

          // get the next 0.5M part
          fetchAB("/api/media/testmp4/part-v2?start=1000000&end=2000000", function (secondBuf){
            sourceBuffer.appendBuffer(secondBuf);
          });

        });
      }
      playBtn.addEventListener("click", init)

    }

    function fetchAB(url, cb) {
      const xhr = new XMLHttpRequest();
      xhr.open("get", url);
      xhr.responseType = "arraybuffer";
      xhr.onload = function () {
        cb(xhr.response);
      };
      xhr.send();
    }

  }, [])

  const handleClickPlay = () => {
    const video = document.querySelector("video")
    if (videoInited.current) {
      video.play()
    }
  }

  return (
    <div>
      <video 
        id='stream-media-video'
        width="400px"
        height="400px"
        style={{
          objectFit: 'contain',
        }}
        controls
      />
      <div>
        <button className='play-btn' onClick={handleClickPlay}>click to play video</button>
      </div>
    </div>
  )
}

export default VideoPage

这是我的 Express.js 后端代码

  app.get("/api/media/testmp4/part-v2", function (req, res) {
    const {
      start,
      end,
    } = req.query;
    const mp4FilePath = "test.mp4";
    const _start = Number(start);
    const videoSize = fs.statSync(mp4FilePath).size;
    const _end = Math.min(Number(end), videoSize - 1);

    // Get video clips and return them to the front end
    const videoStream = fs.createReadStream(mp4FilePath, { 
      start: _start, 
      end: _end,
    });

    videoStream.pipe(res);
  });

视频播放器进度条显示剩余视频片段尚未加载,无法继续播放。这是我的问题截图。

控制台没有错误,如何让视频继续播放?

reactjs express html5-video media-source
1个回答
0
投票

“我已经在服务器端控制了返回的文件字节范围了

Math.min(Number(end), videoSize - 1)

看着:

const _end = Math.min(Number(end), videoSize - 1);

Math.min 将返回这两个输入数字中的最小的一个
您的

end
小于
videoSize-1
,因此现在它被用作返回到您的应用程序的字节限制:

 var End  : 1000000
(Size-1)  : 1499999
file Size : 1500000

“视频播放器进度条显示剩余视频片段数据尚未加载,无法继续播放。”

修复:

  • 使用已知的文件大小(获取所有数据,没有剩余):

    fetchAB(“/api/media/testmp4/part-v2?start=0&end=1000000”

  • 如果文件大小未知,请使用一个非常大的数字(然后真实的持续时间成为新的MIN):

    fetchAB(“/api/media/testmp4/part-v2?start=0&end=999999999999”

© www.soinside.com 2019 - 2024. All rights reserved.