Javascript MediaSource API и видео H264
У меня проблема с воспроизведением видео H264 с использованием API расширения MediaSource на JavaScript.
Я опишу сценарий с деталями ниже.
Я уже успешно достиг результата воспроизведения аудио и видео источника кодеков vp8, vp9, opus и vorbis, а также из запроса диапазона (если у сервера есть возможность, используя любой диапазон байтов) или фрагментированных файлов, фрагментов, выполненных с помощью упаковщика Shaka.
Проблема возникает, когда источником является видео H264, подробно в моем случае кодеки avc1.64001e и mp4a.40.2, полная строка кодека - video/mp4;codecs="avc1.64001e, mp4a.40.2", но проблема все еще возникает с любым другим кодеком AVC1.
То, что я пытаюсь сделать, это воспроизвести 10-мегабайтный фрагмент полного видео, порцию, сгенерированную по запросу скручивания в байтовом диапазоне, сохраняя ответ локально, используя -o.
Ниже информации о потоке от упаковщика Shaka, передающего этот файл в качестве входных данных
[0530/161459:INFO:demuxer.cc(88)] Demuxer::Run() on file '10mega.mp4'.
[0530/161459:INFO:demuxer.cc(160)] Initialize Demuxer for file '10mega.mp4'.
File "10mega.mp4":
Found 2 stream(s).
Stream [0] type: Video
codec_string: avc1.64001e
time_scale: 17595
duration: 57805440 (3285.3 seconds)
is_encrypted: false
codec: H264
width: 720
height: 384
pixel_aspect_ratio: 1:1
trick_play_factor: 0
nalu_length_size: 4
Stream [1] type: Audio
codec_string: mp4a.40.2
time_scale: 44100
duration: 144883809 (3285.3 seconds)
is_encrypted: false
codec: AAC
sample_bits: 16
num_channels: 2
sampling_frequency: 44100
language: und
Packaging completed successfully.
Блок может быть воспроизведен с помощью приложений внешнего медиаплеера (например, VLC) и, что более важно, он воспроизводится без проблем, добавляя его на веб-страницу с помощью тега
Это ошибка, которую я вижу в консоли Chrome
Uncaught (in promise) DOMException: Failed to load because no supported source was found.
Здесь ниже HTML и JS-код, если вы хотите воспроизвести (я сделал все локальные тесты, используя встроенный сервер php7.2 dev)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>VideoTest</title>
<link rel="icon" href="/favicon.ico" />
<script type="text/javascript" src="/script.js"></script>
<style>
video {
width: 98%;
height: 300px;
border: 0px solid #000;
display: flex;
}
</style>
</head>
<body>
<div id="videoContainer">
<video controls></video>
</div>
<video controls>
<source src="/media/10mega.mp4" type="video/mp4">
</video>
</body>
</html>
А вот ниже код JS (scripjs)
class MediaTest {
constructor() {
}
init(link) {
this.link = link;
this.media = new MediaSource();
this.container = document.getElementsByTagName('video')[0];
this.container.src = window.URL.createObjectURL(this.media);
return new Promise(resolve => {
this.media.addEventListener('sourceopen', (e) => {
this.media = e.target;
return resolve(this);
});
});
}
addSourceBuffer() {
let codec = 'video/mp4;codecs="avc1.64001e, mp4a.40.2"';
let sourceBuffer = this.media.addSourceBuffer(codec);
// These are the same headers sent by the < source > tag
// with or without the issue remains
let headers = new Headers({
'Range': 'bytes=0-131072',
'Accept-Encoding': 'identity;q=1, *;q=0'
});
let requestData = {
headers: headers
};
let request = new Request(this.link, requestData);
return new Promise(resolve => {
fetch(request).then((response) => {
if(200 !== response.status) {
throw new Error('addSourceBuffer error with status ' + response.status);
}
return response.arrayBuffer();
}).then((buffer) => {
sourceBuffer.appendBuffer(buffer);
console.log('Buffer appended');
return resolve(this);
}).catch(function(e) {
console.log('addSourceBuffer error');
console.log(e);
});
});
}
play() {
this.container.play();
}
}
window.addEventListener('load', () => {
let media = new MediaTest();
media.init('/media/10mega.mp4').then(() => {
console.log('init ok');
return media.addSourceBuffer();
}).then((obj) => {
console.log('play');
media.play();
});
});
Чего я хочу добиться, так это воспроизвести файл с помощью MediaSource API, поскольку он хорошо воспроизводится с использованием тега
Вот ниже дамп ошибки, взятый из chrome: // media-internals
render_id: 180 player_id: 11 pipe_state: kStopped событие: WEBMEDIAPLAYER_DESTROYED
Я думаю, что для воспроизведения можно использовать любое видео H264, в котором есть аудио и видео дорожка.
Этот вопрос строго связан с другим вопросом. Я обнаружил, что видео H264 работает с использованием атрибута src. В том же видео не удается использовать MediaSource API (Chromium), но это было сделано 4 года назад, поэтому я решил не отвечать там.
Кто-нибудь имеет представление об этой проблеме? Есть ли способ ее решить или h264 просто не совместим с MSE?
заранее спасибо
1 ответ
Это не кодек, это контейнер. MSE требует фрагментированных файлов mp4. Стандартный mp4 не поддерживается. для стандартного mp4 вы должны использовать <video src="my.mp4">