Код: Выделить всё
_app.get('/video/:id', async (req, res) => {
if (!res.locals.authed && !process.env._DEBUG) return rpjson(res, ServerResponse.authFail);
var id, byteDifference, byteStart, byteEnd = 0;
try {
id = parseInt(req.params.id);
byteStart = req.query.byteStart ? parseInt(req.query.byteStart) : 0;
if (req.query.byteEnd) byteEnd = parseInt(req.query.byteEnd);
if(byteEnd == 0)
byteEnd = byteStart + VIDEO_CHUNK_SIZE - 1;
byteDifference = byteEnd - byteStart + 1;
if (id === undefined) return rpjson(res, ServerResponse.invalidPayload);
} catch (err) {
return rpjson(res, ServerResponse.invalidPayload)
}
const video = await dbGetVideoData(id, byteStart + 1, byteDifference);
if (video === null) return rpjson(res, ServerResponse.invalidPayload);
if (video.chunk === null) return rpjson(res, ServerResponse.invalidPayload);
const contentLength = Math.min(byteDifference, video.data_length - byteStart);
var statusCode = 206;
var headers = {
'Content-Range': `bytes ${byteStart}-${byteEnd}/${video.data_length}`,
'Accept-Ranges': 'bytes',
'Content-Length': `${contentLength}`,
'Content-Type': 'video/mp4',
'Access-Control-Expose-Headers': 'Content-Range, Content-Length'
};
if (byteEnd > video.data_length) {
byteEnd = video.data_length;
statusCode = 200;
delete headers['Content-Range'];
}
res.writeHead(statusCode, headers);
res.end(video.chunk);
});
export default function ChunkedVideoPlayer({ videoID, url = null,
chunkSizeb = 1000000,
codecStr = 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"',
...videoProps }) {
if (url == null)
{
url = process.env.CONTENT_SERVER_URL + "/video";
}
const currentVideo = {
rawUrl: null,
size: null,
nextChunkIndex: 0,
nextChunkStart: 0,
nextChunkEnd: chunkSizeb
};
const [mediaSource, setMediaSource] = useState();
const prepareChunkUrl = () => {
if (!currentVideo.rawUrl)
currentVideo.rawUrl = url + videoID;
return `${currentVideo.rawUrl}?byteStart=${currentVideo.nextChunkStart}&byteEnd=${currentVideo.nextChunkEnd}`;
}
function fetchNextChunk(srcBuffer) {
const nurl = prepareChunkUrl();
console.log(nurl)
fetch(nurl)
.then((res) => {
if (!res.ok || (res.status !== 200 && res.status != 206)) {
setError("Something Unexpected happened.");
// try again
return setTimeout(fetchNextChunk(srcBuffer), 1000);
}
if (res.headers.has('content-length')) currentVideo.size = parseInt(res.headers.get('content-length'));
res.arrayBuffer().then((data) =>
{
srcBuffer.appendBuffer(data)
});
});
}
function getVideo() {
const video = document.querySelector('video');
if (!video || !('MediaSource' in window)) return;
const ms = new MediaSource();
setMediaSource(ms);
video.src = URL.createObjectURL(ms);
currentVideo.rawUrl = `${url}/${videoID}`;
ms.addEventListener('sourceopen', () => {
const srcbuffer = ms.addSourceBuffer(codecStr);
srcbuffer.addEventListener('updateend', () => {
console.log('ended');
if (currentVideo.nextChunkStart + chunkSizeb < currentVideo.size)
{
currentVideo.nextChunkStart += chunkSizeb;
currentVideo.nextChunkEnd += chunkSizeb;
fetchNextChunk(srcbuffer);
}
else ms.endOfStream();
});
fetchNextChunk(srcbuffer);
})
}
useEffect(getVideo, [videoID]);
if (videoID === undefined || videoID == -1) return ;
return ;
}
< /code>
Я напечатал байты, полученные к конечной точке, и он был успешно получен. Однако буфер MediaSource не воспроизводит видео и дает эту ошибку консоли: < /p>
InvalidStateError: Failed to execute 'appendBuffer' on 'SourceBuffer': This SourceBuffer has been removed from the parent media source.
< /code>
Я искал документы и другие вопросы, похожие на это, и ни один из них не решает мою проблему. Я думаю, что я правильно использую API MediaSource? Я бы признателен за любую помощь.
Подробнее здесь: https://stackoverflow.com/questions/794 ... rom-parent
Мобильная версия