Основная проблема: отображение живого потока H264 в браузере.
Решение: давайте просто конвертируем его в фрагментированный mp4 и загружаем порцию через порцию websocket (или XHR) в MSE.
Звучит слишком просто. Но я хочу сделать фрагментацию на стороне клиента с чистым JS.
, поэтому я пытаюсь использовать MP4Box. js. На странице readme он заявляет: у него есть демо: «Игрок, который выполняет фрагментацию на лету».
Однако производимые им фрагменты (сегменты) вызывают decodeErrors на Chrome и FireFox ( на Windows 10):
<html>
<head>
<title>WebSocket and MSE test</title>
<script src="https://gpac.github.io/mp4box.js/dist/mp4box.all.js"></script>
</head>
<body>
<video id="livestream" width="640" height="480" autoplay />
</body>
<script>
var ws; // websocket
var mp4box; // fragmentation
var ms; // media source
var sb; // source buffer
var nextBufferStart = 0;
var forceStart = true;
var queue = [];
function startVideo() {
Log.setLogLevel(Log["debug"]);
mp4box = MP4Box.createFile();
mp4box.onError = function(e) {
console.log("mp4box failed to parse data.");
};
mp4box.onMoovStart = function () {
console.log("Starting to receive File Information");
};
mp4box.onReady = function(info) {
console.log(info.mime);
mp4box.onSegment = function (id, user, buffer, sampleNum) {
console.log("Received segment on track "+id+" for object "+user+" with a length of "+buffer.byteLength+",sampleNum="+sampleNum);
mp4box_onSegment(buffer);
}
var options = { nbSamples: 200 };
mp4box.setSegmentOptions(info.tracks[0].id, null, options); // I don't need user object this time
var initSegs = mp4box.initializeSegmentation();
mp4box.start();
};
ms = new MediaSource();
ms.addEventListener('sourceopen', ms_SourceOpened, false);
var livestream = document.getElementById('livestream');
livestream.src = window.URL.createObjectURL(ms);
}
function ms_SourceOpened() {
sb = ms.addSourceBuffer("video/mp4;codecs=\"avc1.4d4028\"");
sb.addEventListener("updateend", sb_UpdateEnd);
ws = new WebSocket("ws://a_websocket_server_which_serves_h264_file");
ws.binaryType = "arraybuffer";
ws.onmessage = function (event) {
event.data.fileStart = nextBufferStart; //tried also with event.data.byteOffset, but resulted error.
nextBufferStart = mp4box.appendBuffer(event.data);
mp4box.flush(); //tried commenting out - unclear documentation!
};
}
function sb_UpdateEnd() { // called when sourceBuffer is ready for more
if (!sb.updating) { // really, really ready
if (queue.length > 0) {
data = queue.shift();
console.log("queue PULL:", queue.length);
var view = new Uint8Array(data);
console.log(" writing buffer with", view[0], view[1], view[2], view[3], view[4]);
sb.appendBuffer(data);
}
else {
forceStart = true;
}
}
}
function mp4box_onSegment(buffer) {
var view = new Uint8Array(buffer);
console.log("got", buffer.byteLength, "bytes. Values=", view[0], view[1], view[2], view[3], view[4]);
if (forceStart && !sb.updating) {
console.log("Streaming started with", view[0], view[1], view[2], view[3], view[4]);
sb.appendBuffer(buffer);
forceStart = false;
return;
}
queue.push(buffer);
console.log("queue push:", queue.length);
}
window.onload = function() {
startVideo();
}
</script>
</html>
Что я делаю не так с кодом здесь? Chrome и FF оба с удовольствием воспроизводят файлы fmp4. Я уверен, что у меня есть легкая распространенная ошибка здесь. Но я не мог продолжать дальше.
Обновление
Я попытался воспроизвести мой файл mp4 с помощью проигрывателя на их сайте, и он работает, как и предполагалось.
Так что, очевидно, я ' Я здесь ошибаюсь.
Я прилагаю сюда вывод журнала как официального, так и моего игрока, пытаясь воспроизвести один и тот же источник. (Только важная часть, перед этим все линии равны):
Официально:
[MultiBufferStream] Appending new buffer (fileStart: 2028784 - Length: 4000)
[MultiBufferStream] 2 stored buffer(s) (48/8000 bytes): [0-3999], [2028784-2032783]
[MultiBufferStream] Found position in existing buffer #1
[MultiBufferStream] Repositioning parser at buffer position: 0
[MultiBufferStream] Found position in existing buffer #1
[MultiBufferStream] Repositioning parser at buffer position: 0
[ISOFile] Found 'mdat' end in buffered data
[BoxParser] Found box of type 'moov' and size 13572 at position 2028784
[MultiBufferStream] Found position in existing buffer #1
[MultiBufferStream] Repositioning parser at buffer position: 0
[BoxParser] Not enough data in stream to parse the entire 'moov' box
[Application] Starting to parse movie information
[ISOFile] Done processing buffer (fileStart: 2028784) - next buffer to fetch should have a fileStart position of 2032784
Мой игрок:
[MultiBufferStream] Appending new buffer (fileStart: 2028784 - Length: 4096)
[MultiBufferStream] 2 stored buffer(s) (48/8192 bytes): [0-4095], [2028784-2032879]
[MultiBufferStream] Found position in existing buffer #1
[MultiBufferStream] Repositioning parser at buffer position: 0
[MultiBufferStream] Found position in existing buffer #1
[MultiBufferStream] Repositioning parser at buffer position: 0
[ISOFile] Found 'mdat' end in buffered data
[BoxParser] Found box of type 'FJé' and size 27781302 at position 2028784
[MultiBufferStream] Found position in existing buffer #1
[MultiBufferStream] Repositioning parser at buffer position: 0
[BoxParser] Not enough data in stream to parse the entire 'FJé' box
[ISOFile] Done processing buffer (fileStart: 2028784) - next buffer to fetch should have a fileStart position of 29810086
Как вы видите, мой проигрыватель не распознает атом 'moov', и поэтому он испортил весь поток мультимедиа.
mp4box. js библиотеки все одинаковые.
Что может вызвать это?