Как сохранить синхронизацию живого видеопотока MediaSource?

У меня есть серверное приложение, которое отображает видеопоток со скоростью 30 кадров в секунду, затем кодирует и мультиплексирует его в реальном времени в Поток байтов WebM.

На стороне клиента страница HTML5 открывает сервер WebSocket, который начинает генерировать поток, когда соединение принимается. После доставки заголовка каждый последующий фрейм WebSocket состоит из одного простого блока WebM. Ключевой кадр происходит каждые 15 кадров, и когда это происходит, запускается новый кластер.

Клиент также создает MediaSource, и при получении кадра от WS добавляет содержимое в свой активный буфер. <video> начинает воспроизведение сразу после добавления первого кадра.

Все работает достаточно хорошо. Моя единственная проблема заключается в том, что из-за дрожания сети через некоторое время позиция воспроизведения смещается от фактического времени. Мое текущее решение - подключиться к событию updateend, проверить разницу между video.currentTime и тайм-кодом на входящем кластере и вручную обновить currentTime, если он выходит за пределы допустимого диапазона. К сожалению, это вызывает заметную паузу и скачок воспроизведения, что довольно неприятно.

Решение также кажется немного странным: я точно знаю, где находится последний ключевой кадр, но мне нужно преобразовать его в целую секунду (согласно спецификации W3C), прежде чем я смогу передать его в currentTime, где, по-видимому, должен идти браузер. вокруг и найдите ближайший ключевой кадр.

У меня такой вопрос: есть ли способ указать элементу мультимедиа всегда искать последний доступный ключевой кадр или синхронизировать время воспроизведения с системными часами?


person Saran    schedule 25.04.2014    source источник
comment
Вы нашли решение?   -  person Keyne Viana    schedule 15.12.2017
comment
Я понял, что ваше решение по изменению currentTime является лучшим, сбои, которые оно вызывает, приемлемы, потому что до этого сбой сети вызывал увеличение буфера, поэтому еще один сбой для его исправления является нормальным ... он останется только с глюки, если во время стрима последовательно возникают проблемы с подключением.   -  person Keyne Viana    schedule 21.12.2017
comment
Есть ли способ преобразовать WebM SimpleBlock в автономный файл webm с заголовком?   -  person Suman Bogati    schedule 05.06.2020


Ответы (1)


джиттер сети приводит к смещению позиции воспроизведения

Это не твоя проблема. Если вы испытываете пропадание в потоке, значит, перед воспроизведением недостаточно буферизации, и воспроизведение имеет только буфер подходящего размера, даже если на несколько секунд отстает от реального времени (что нормально).

Мое текущее решение - подключиться к событию updateend, проверить разницу между video.currentTime и тайм-кодом на входящем кластере.

Это близко к правильному методу. Я предлагаю вам игнорировать временной код входящего кластера и вместо этого проверять свои буферизованные временные диапазоны. То, что вы получили в кластере WebM, и то, что было декодировано, - это две разные вещи.

К сожалению, это вызывает заметную паузу и скачок воспроизведения, что довольно неприятно.

Как еще ты бы это сделал? Вы можете перейти в режим реального времени или увеличить скорость воспроизведения до уровня реального времени. В любом случае, если вы хотите наверстать упущенное в реальном времени, вам нужно пропустить время, чтобы сделать это.

Решение также кажется немного странным: я точно знаю, где находится последний ключевой кадр.

Вы можете, но проигрыватель этого не сделает, пока этот носитель не будет декодирован. В любом случае ключевой кадр не имеет значения ... вы можете искать места, не являющиеся ключевыми кадрами. Браузер при необходимости выполнит декодирование перед P / B-кадрами.

Я должен преобразовать его в целую секунду (согласно спецификации W3C), прежде чем я смогу передать его в currentTime

Это совершенно неверно. currentTime указан как double. https://www.w3.org/TR/2011/WD-html5-20110113/video.html#dom-media-currenttime

У меня такой вопрос: есть ли способ указать элементу мультимедиа всегда искать последний доступный ключевой кадр или синхронизировать время воспроизведения с системными часами?

Последний буфер будет воспроизводиться автоматически. Вам не нужно ничего делать. Вы делаете свою работу, обеспечивая попадание мультимедийных данных в буфер и настраивая воспроизведение как можно ближе к этому значению. Вы всегда можете продвинуться вперед, если изменится состояние сети, которое позволяет вам это сделать, но, честно говоря, это звучит так, как если бы у вас только что был сломанный код и неработающая стратегия буферизации. В противном случае воспроизведение было бы просто плавным.

Если вы отстаете, то это не произойдет автоматически, да и не должно. Если проигрыватель приостанавливается из-за опустошения буфера, перед возобновлением воспроизведения необходимо снова создать резервную копию буфера. В этом весь смысл буфера.

Более того, ваше ожидание того, что что-либо будет синхронизировано с системными часами, не является хорошей идеей и неразумно. Разные устройства имеют разную частоту обновления и обрабатывают видео с разной скоростью. Просто нажмите "Играть" и дайте ему поиграть. Если вы в конечном итоге опаздываете на несколько секунд, установите currentTime, но будьте очень уверены в том, что вы добавили в буфер, прежде чем делать это.

person Brad    schedule 15.12.2017
comment
Не уверен, что у вас возникла проблема, но если вы доставляете mp3-файл, например, из узла с сокетами в пакетах по 2,7 секунды, например, проигрыватель запускается так, как должен, но если вы приостановите его вручную, буфер начнет увеличиваться и когда вы снова сыграете, он начнется с того места, где вы его остановили. Это приводит к рассинхронизации воспроизведения с потоком nodejs. Вот что происходит, если дать воспроизведению несколько часов, оно автоматически приостанавливается из-за сбоев, и буфер начинает увеличиваться. - person Keyne Viana; 16.12.2017
comment
Nodejs отправляет 2,7 секунды, ожидает воспроизведения и затем отправляет следующий пакет. Но с увеличением буфера вы больше не можете контролировать, воспроизводились ли потоковые данные или нет. Я попытался отправить подтверждение о том, что пакет был воспроизведен, чтобы можно было доставить следующий, но возникли другие проблемы. Вроде остановка воспроизведения. Итак, вопрос в том, чтобы передавать данные в потоковом режиме и воспроизводить их сразу же непрерывно в течение нескольких часов. - person Keyne Viana; 16.12.2017
comment
@KeyneViana Зачем вам ждать отправки следующего блока данных? Просто продолжай посылать это. Кроме того, не стоит ждать 2,7 секунды ... Фреймы MP3 могут иметь размер всего 576 отсчетов. - person Brad; 16.12.2017
comment
Поскольку он прямой, передача должна быть синхронизирована в разных браузерах. Если я отправлю только те кадры, которые будут воспроизводиться, любой, кто начнет прослушивать передачу, получит нужную точку, например 00:56. Если вы доставите все кадры без ожидания, вы не сможете контролировать этот аспект. - person Keyne Viana; 17.12.2017
comment
@KeyneViana Нет. Именно потому, что он в прямом эфире, вы должны продолжить потоковую передачу данных. Вы не можете отправить фрагмент, дождаться его воспроизведения, получить подтверждение об этом и затем отправить следующий фрагмент. Данные не могут быть отправлены, проанализированы и декодированы мгновенно. Интернет - это не сеть с коммутацией каналов. Вы должны постоянно отправлять данные, если ожидаете, что они будут непрерывно воспроизводиться. Для любых людей, которые подключаются к середине потока, вы просто отправляете данные из этой точки вперед. - person Brad; 21.12.2017
comment
Я понимаю вашу точку зрения, но в моем случае у меня нет уникального потока для каждого клиента, мой сервер nodejs имеет один поток, который передается во все подключенные сокеты, этот поток также передается по каналу в жидкое мыло, сокет - это аудио-возврат то, что передается, и трубка для жидкого мыла контролирует противодавление потока, который отправляет данные непрерывно, но с задержкой + -2,7 секунды между каждым кадром, что отлично работает. Проблема, описанная OP, на самом деле может быть решена, просто настроив currentTime, как он сказал (я сделал это сейчас, после нескольких тестов). - person Keyne Viana; 21.12.2017
comment
Проблема, указанная OP, возникает только в том случае, если интернет-соединение остается медленным или недоступным во время всего воспроизведения. - person Keyne Viana; 21.12.2017
comment
@KeyneViana Если вы передаете поток по конвейеру, то вы выполняете потоковую передачу, и нет никакой другой проблемы, кроме того, что ваш источник отправляет 2,7 фрагмента. В этих случаях я настоятельно рекомендую сохранить последний фрагмент в буфере на стороне сервера, а затем очищать весь буфер при подключении нового клиента. Это обеспечивает быстрый запуск для клиента, гарантируя, что у него есть полный 2,7-секундный буфер для воспроизведения как раз вовремя, чтобы поступил следующий фрагмент. - person Brad; 21.12.2017
comment
Вы, кажется, далеко впереди в концепциях звука, поэтому иногда трудно понять вашу точку зрения, я все еще непрофессионал, когда дело доходит до звука :). Этот конкретный случай 2.7 обрабатывается библиотекой под названием nodeshout (которая является оболочкой для libshout). Пока я бы сказал, что у меня нет проблем с этой архитектурой, как описано. Я просто передаю читаемый поток, и противодавление контролирует как сокет (который обрабатывается. ('Data' ...), так и поток в жидкое мыло (с pipe ()). - person Keyne Viana; 21.12.2017
comment
Я пытаюсь реализовать поиск с помощью MediaSource (см.), но currentTime при этом ошибается. Вы говорите и установите currentTime, но будьте очень уверены в том, что вы буферизовали, прежде чем делать это - но как мы можем начать воспроизведение аудиофайла с середины и в то же время получить правильное currentTime ? - person Stefan Falk; 27.09.2020