我正在尝试使用 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 中会显示无休止的加载屏幕
您正在使用
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>