В итоге
Работать с Firefox и Chrome очень просто: вам просто нужно добавить аудиокод c в список кодеков! video/webm;codecs=opus,vp8
Заставить его работать в Safari значительно сложнее. MediaRecorder - это «экспериментальная» функция, которую необходимо включить вручную в настройках разработчика. После включения в Safari отсутствует метод isTypeSupported
, поэтому вам нужно с этим справиться. Наконец, независимо от того, что вы запрашиваете у MediaRecorder, Safari будет всегда вручать вам файл MP4 - который не может быть передан потоковым способом, как WEBM. Это означает, что вам необходимо выполнить трансмуксинг в JavaScript для преобразования формата видео контейнера на лету
Android должен работать, если Chrome работает
iOS не поддерживает Media Source Расширения, поэтому SourceBuffer
не определено в iOS, и все решение не будет работать
Исходное сообщение
Глядя на опубликованную вами JSFiddle, одно быстрое исправление, прежде чем мы начнем:
- Вы ссылаетесь на переменную
errorMsgElement
, которая никогда не определяется. Вы должны добавить <div>
на страницу с соответствующим идентификатором, а затем создать строку const errorMsgElement = document.querySelector(...)
, чтобы захватить ее
Теперь при работе с расширениями Media Source и MediaRecorder следует отметить, что поддержка будет сильно отличаться для каждого браузера. Несмотря на то, что это «стандартизированная» часть HTML5 spe c, она не очень согласована на разных платформах. По моему опыту, заставить MediaRecorder работать в Firefox не требуется слишком много усилий, заставить его работать в Chrome немного сложнее, заставить его работать в Safari чертовски почти невозможно, и заставить его работать на iOS буквально не то, что вы можете сделать.
Я прошел и отладил это для каждого браузера и записал свои шаги, чтобы вы могли понять некоторые инструменты, доступные вам при отладке проблем со СМИ
Firefox
Когда я проверил ваш JSFiddle в Firefox, я увидел следующую ошибку в консоли:
NotSupportedError: аудиодорожка не может быть записано: video / webm; codecs = vp8 указывает на неподдерживаемый код c
Я напоминаю, что VP8 / VP9 были большими толчками со стороны Google и поэтому могут не работать в Firefox, поэтому я попытался сделать одну небольшую настройку вашего кода. Я удалил параметр , options)
из вашего звонка на new MediaRecorder()
. Это говорит браузеру использовать любой код c, который он хочет, так что вы, вероятно, получите различный вывод в каждом браузере (но он должен по крайней мере работать в каждом браузере)
Это сработало в Firefox, поэтому я проверил Chrome.
Chrome
На этот раз я получил новую ошибку:
(индекс): 409 Uncaught (в обещании) DOMException: Не удалось выполнить 'appendBuffer' для 'SourceBuffer': этот SourceBuffer был удален из родительского источника мультимедиа. на MediaRecorder.handleDataAvailable (https://fiddle.jshell.net/43rm7258/1/show/: 409: 22 * 1058 *)
Поэтому я направился к chrome: // media-internals / в моем браузере и увидел это:
Код аудиопотока c opus не соответствует кодекам SourceBuffer.
В своем коде вы указываете видеокод c (VP9 или VP8) но не аудиокод c, поэтому MediaRecorder позволяет браузеру выбирать любой аудиокод c. Похоже, что в MediaRecorder Chrome по умолчанию выбирается "opus" в качестве аудиокода c, но SourceBuffer Chrome по умолчанию выбирает что-то другое. Это было тривиально исправлено. Я обновил ваши две строки, которые задают options.mimeType
следующим образом:
options = { mimeType: "video/webm;codecs=opus, vp9" };
options = { mimeType: "video/webm;codecs=opus, vp8" };
Поскольку вы используете тот же options
объект для объявления MediaRecorder и SourceBuffer, добавление аудиокода c в список означает, что SourceBuffer теперь объявлен с допустимым аудиокодом c, а видео воспроизводится
. Для хорошей проверки я протестировал новый код (с аудиокодом c) на Firefox. Это сработало! Таким образом, мы получаем 2 на 2, просто добавив аудиокод c в список options
(и оставив его в параметрах объявления MediaRecorder)
Похоже, что VP8 и opus работают в Firefox, но не являются значениями по умолчанию (хотя в отличие от Chrome, значения по умолчанию для MediaRecorder и SourceBuffer одинаковы, поэтому удаление параметра options
полностью сработало)
Safari
На этот раз мы получили сообщение об ошибке, с которым мы не можем работать:
Необработанное обещание Отклонение: ReferenceError: Невозможно найти переменную: MediaRecorder
Первое Я сделал Google Safari MediaRecorder, который обнаружил эту статью . Я думал, что попробую, поэтому посмотрел. Конечно же:
Я нажал на это, чтобы включить MediaRecorder, и в консоли было встречено следующее:
Необработанное отклонение обещания: TypeError: MediaRecorder.isTypeSupported не является функцией. (В 'MediaRecorder.isTypeSupported (options.mimeType)' MediaRecorder.isTypeSupported не определено)
Так что в Safari нет метода isTypeSupported
. Не волнуйтесь, мы просто скажем: «Если этот метод не существует, предположим, что это Safari, и установите соответствующий тип»
if (MediaRecorder.isTypeSupported) {
options = { mimeType: "video/webm;codecs=vp9" };
if (!MediaRecorder.isTypeSupported(options.mimeType)) {
console.error(`${options.mimeType} is not Supported`);
errorMsgElement.innerHTML = `${options.mimeType} is not Supported`;
options = { mimeType: "video/webm;codecs=vp8" };
if (!MediaRecorder.isTypeSupported(options.mimeType)) {
console.error(`${options.mimeType} is not Supported`);
errorMsgElement.innerHTML = `${options.mimeType} is not Supported`;
options = { mimeType: "video/webm" };
if (!MediaRecorder.isTypeSupported(options.mimeType)) {
console.error(`${options.mimeType} is not Supported`);
errorMsgElement.innerHTML = `${options.mimeType} is not Supported`;
options = { mimeType: "" };
}
}
}
} else {
options = { mimeType: "" };
}
Теперь мне просто нужно было найти mimeType, который поддерживается Safari. Некоторый легкий поиск в Google предполагает, что H.264 поддерживается, поэтому я попытался:
options = { mimeType: "video/webm;codecs=h264" };
Это успешно дало мне MediaRecorder started
, но не получилось в строке addSourceBuffer
с новой ошибкой:
NotSupportedError: Операция не поддерживается.
Я буду продолжать пытаться диагностировать, как это работает в Safari, но пока у меня есть как минимум адреса Firefox и Chrome
Обновление 1
Я продолжал работать над Safari. К сожалению, в Safari не хватает инструментов Chrome и Firefox для углубления во внутренние медиа-ресурсы, поэтому приходится много догадок.
Ранее я обнаружил, что мы получаем ошибку "Операция не поддерживается "при попытке позвонить addSourceBuffer
. Поэтому я создал разовую страницу, чтобы попытаться вызвать только этот метод при других обстоятельствах:
- Может быть, добавить исходный буфер до вызова
play
для видео - Может быть добавить исходный буфер до того, как источник мультимедиа был присоединен к элементу видео
- Возможно, добавьте исходный буфер с разными кодеками
- et c
Я обнаружил, что проблема все еще заключалась в коде c, и сообщение об ошибке «недопустимая операция» немного вводило в заблуждение. Это были параметры , которые не были разрешены. Простая поставка «h264» работала для MediaRecorder, но SourceBuffer требовал, чтобы я передавал параметры code c .
Одна из первых вещей, которые я попробовал, - это Пример страницы MDN и копирование используемых там кодеков: 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"'
. Это дало ту же ошибку «операция не разрешена». Раскрытие значения этих параметров кода c (например, что, черт возьми, делает 42E01E
даже означает ?). В то время как у меня был sh, у меня был лучший ответ, во время поиска в Google я наткнулся на это сообщение StackOverflow , в котором упоминалось использование 'video/mp4; codecs="avc1.64000d,mp4a.40.2"'
в Safari. Я попробовал, и ошибки консоли исчезли!
Хотя ошибки консоли исчезли, я все еще не вижу видео. Так что еще есть над чем работать.
Обновление 2
Дальнейшие исследования в отладчике в Safari (установка нескольких точек останова и проверка переменных на каждом этапе процесса) показали, что handleDataAvailable
никогда не было вызывается в сафари. Похоже, что в Firefox и Chrome mediaRecorder.start(100)
будет правильно следовать за spe c и вызывать ondatavailable
каждые 100 миллисекунд, но Safari игнорирует параметр и буферизует все в один массивный BLOB-объект. Вызов mediaRecorder.stop()
вручную вызвал вызов ondataavailable
со всем, что было записано до этого момента
Я пытался использовать setInterval
для вызова mediaRecorder.requestData()
каждые 100 миллисекунд, но requestData
не было определено в Safari (так же, как isTypeSupported
не было определено). Это поставило меня в тупик.
Затем я попытался очистить весь объект MediaRecorder и создать новый каждые 100 миллисекунд, но это вызвало ошибку в строке await bufferedBlob.arrayBuffer()
. Я до сих пор выясняю, почему это не удалось
Обновление 3
Одна вещь, которую я вспоминаю о формате MP4, это то, что атом "moov" необходим для воспроизведения вернуть любой контент. Вот почему вы не можете скачать среднюю половину файла MP4 и воспроизвести его. Вам необходимо скачать ВЕСЬ файл. Поэтому мне стало интересно, не является ли тот факт, что я выбрал MP4, причиной того, что я не получал регулярные обновления.
Я попытался изменить video/mp4
на несколько разных значений и получил разные результаты:
video/webm
- операция не поддерживается video/x-m4v
- вел себя как MP4, я получал данные только тогда, когда .stop()
вызывался video/3gpp
- вел себя как MP4 video/flv
- Операция не поддерживается video/mpeg
- Вела себя как MP4
Все, что велось как MP4, заставило меня проверить данные, которые были на самом деле передается в handleDataAvailable
. Вот когда я заметил это:
Неважно что Я выбрал для видео формата, Safari всегда давал мне MP4!
Внезапно я вспомнил, почему Safari был таким кошмаром, и почему я мысленно классифицировал его как «чертовски почти невозможное». Чтобы соединить несколько MP4, потребуется JavaScript transmuxer
Именно тогда я вспомнил, , это именно то, что я делал до , Я работал с MediaRecorder и SourceBuffer чуть более года go, чтобы попытаться создать JavaScript RTMP-плеер. Когда проигрыватель был готов, я хотел добавить поддержку DVR (возвращаясь к частям видео, которые уже были переданы в потоковом режиме), что я сделал с помощью MediaRecorder и сохраняя кольцевой буфер в памяти 1-секундных видеоблоков. В Safari я пропустил эти видеоблобы через преобразователь, который я кодировал, чтобы преобразовать их из MP4 в ISO-BMFF, чтобы я мог объединить их вместе.
Я могу sh Я мог бы поделиться с вами кодом, но все принадлежит моему старому работодателю - поэтому на данный момент решение для меня потеряно. Я знаю, что кто-то столкнулся с проблемой компиляции FFMPEG для JavaScript с использованием emscripten, так что вы можете воспользоваться этим.