使用 MediaSource API 的视频显示无休止的加载屏幕

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

我正在尝试使用 MediaSource API 构建一个小型流媒体项目。
我有一个名为“地球”的分段视频,分为 6 段,每段大约 6 秒。
根据当前的项目结构

vids/  
 earth/  
    playlist.json  
    segments/
      segment-000.mp4
      segment-001.mp4
      segment-002.mp4
      segment-003.mp4
      segment-004.mp4
      segment-005.mp4
      segment-006.mp4
index.js
index.html

playlist.json
文件就是这样

{
  "segments": [
    {
      "url": "http://localhost:3000/vids/earth/segments/segment-000.mp4"
    },
    {
      "url": "http://localhost:3000/vids/earth/segments/segment-001.mp4"
    },
    {
      "url": "http://localhost:3000/vids/earth/segments/segment-002.mp4"
    },
    {
      "url": "http://localhost:3000/vids/earth/segments/segment-003.mp4"
    },
    {
      "url": "http://localhost:3000/vids/earth/segments/segment-004.mp4"
    },
    {
      "url": "http://localhost:3000/vids/earth/segments/segment-005.mp4"
    },
    {
      "url": "http://localhost:3000/vids/earth/segments/segment-006.mp4"
    }
  ]
}

index.js文件是服务器代码

const express = require('express');
const path = require('path');

const app = express();
const PORT = 3000;

app.get('/index', (req, res)=> res.sendFile(path.join(__dirname, 'index.html')));
app.get('/earth', (req, res)=> res.sendFile(path.join(__dirname, 'earth.mp4')))
app.use('/vids', express.static(path.join(__dirname, 'vids')));
app.listen(PORT, () => {
  console.log(`Server is running on http://localhost:${PORT}`);
});

最后是index.html文件

<!DOCTYPE html>
<html>
<head>
  <title>Streaming App</title>
  <style>
    video {
      width: 100%;
      max-width: 800px;
    }
  </style>
</head>
<body>
  <h1>Streaming App</h1>
  <div id="video-container">
    <video id="video-player" controls></video>
  </div>
  <script>
    const videoPlayer = document.getElementById('video-player');

    let playlist;
    let currentSegmentIndex = 0;
    let mediaSource = null;
    let sourceBuffer = null;

    // Fetch playlist
    fetch('/vids/earth/playlist.json')
        .then(response => response.json())
        .then(data => {
            playlist = data;
            initMediaSource();
        })
        .catch(error => console.error('Error fetching playlist:', error));

    // Initialize the MediaSource API
    function initMediaSource() {
        mediaSource = new MediaSource();
        videoPlayer.src = URL.createObjectURL(mediaSource);
        mediaSource.addEventListener('sourceopen', () => {
            sourceBuffer = mediaSource.addSourceBuffer('video/mp4; codecs="avc1.42E01E"');
            loadNextVideoSegment();
        });
    }

    // Load the next video segment
    function loadNextVideoSegment() {
        if (currentSegmentIndex < playlist.segments.length) {
            const segmentUrl = playlist.segments[currentSegmentIndex].url;
            fetch(segmentUrl)
                .then(response => response.arrayBuffer())
                .then(data => {
                    sourceBuffer.appendBuffer(data);
                    currentSegmentIndex++;
                })
                .catch(error => console.error('Error loading video segment:', error));
        } else {
            mediaSource.endOfStream();
        }
    }

    // Move to the next segment when the current one ends
    videoPlayer.addEventListener('ended', () => {
        loadNextVideoSegment();
    });
  </script>
</body>
</html>

使用此代码,当单击播放按钮时,在 FF 中会显示无休止的加载屏幕

javascript html node.js express media-source
1个回答
0
投票

您正在使用

video/mp4; codecs="avc1.42E01E"
。如果您的视频片段与此确切的编解码器不匹配,则可能会导致问题。尝试删除编解码器规范以简化它。

sourceBuffer = mediaSource.addSourceBuffer('video/mp4');

您需要等待

updateend
上的
sourceBuffer
事件才能添加下一个视频片段。否则,段可能会附加得太快,从而导致无休止的加载屏幕。您可以在此处阅读有关
updateend
事件的更多信息:媒体源扩展中“update”和“updateend”事件之间的区别

<script>
  const videoPlayer = document.getElementById('video-player');
  let playlist;
  let currentSegmentIndex = 0;
  let mediaSource = null;
  let sourceBuffer = null;

  fetch('/vids/earth/playlist.json')
      .then(response => response.json())
      .then(data => {
          playlist = data;
          initMediaSource();
      }).catch(error => console.error('Error fetching playlist:', error));

  function initMediaSource() {
      mediaSource = new MediaSource();
      videoPlayer.src = URL.createObjectURL(mediaSource);
      mediaSource.addEventListener('sourceopen', () => {
          sourceBuffer = mediaSource.addSourceBuffer('video/mp4');
          loadNextVideoSegment();
      });
  }

function loadNextVideoSegment() {
    if (currentSegmentIndex < playlist.segments.length) {
        const segmentUrl = playlist.segments[currentSegmentIndex].url;
        fetch(segmentUrl)
            .then(response => response.arrayBuffer())
            .then(data => {
        
                if (sourceBuffer.buffered.length === 0) {
                    sourceBuffer.appendBuffer(data);
                    currentSegmentIndex++;
                }

                // Wait for buffer to be ready before appending next segment
                sourceBuffer.addEventListener('updateend', () => {
                    if (currentSegmentIndex < playlist.segments.length) {
                        sourceBuffer.appendBuffer(data);
                        currentSegmentIndex++;
                    }
                });
            })
            .catch(error => console.error('Error loading video segment:', error));
    } else {
        mediaSource.endOfStream();
    }
}

  videoPlayer.addEventListener('ended', () => {
      loadNextVideoSegment();
  });
</script>

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