LINUX.ORG.RU

Изменение параметров кодирования(разрешения) на лету

 , , , ,


0

1

Я делаю приложение для Android, которое передает в реальном времени видео и звук по протоколу RTMP. Для этого я захватываю звук и камеру и отправляю их буферы по кусочкам в MediaCodec для кодирования, далее оформляю все это в FLV пакеты и отправляю в созданный RTMP-поток.

Все хорошо работает, за исключением следующего: если на «лету» изменять параметры кодирования, в моем случае это разрешение, то мне приходится переконфигурировать этот самый MediaCodec

public void reconfigure(){

    //сначала останавливаю кодировщик
    vencoder.stop();
    vencoder.release();
    vencoder = null;

    //затем создаю новый, в настройках меняю только разрешение
    vencoder = MediaCodec.createByCodecName("OMX.MTK.VIDEO.ENCODER.AVC"); //MediaCodec
    MediaFormat videoFormat = MediaFormat.createVideoFormat("video/avc", 640, 480);
    videoFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, 21);
    videoFormat.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, 0);
    videoFormat.setInteger(MediaFormat.KEY_BIT_RATE, 1200 * 1024);
    videoFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 24);
    videoFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 2);
    vencoder.configure(videoFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
    vencoder.start()
}


и продолжаю в этом же Thread, кодирование. Далее кодировщик отправляет новый SPS (nal_unit_type = 7) в поток и ключевой кадр(nal_unit_type = 5, IDR). Кодирование продолжается, но плееры «падают» в этот момент, либо идет только звук, а видео нет. С временными метками(DTS, PTS) все нормально, они продолжают увеличиваться. Единственный плеер который корректно производит поток это ffplay, этот мамонт все сжирает.

Ссылка на исходник, где идет кодирование видео https://github.com/begeekmyfriend/yasea/blob/f118e6e1c30460215dde6de37a899c29...

В чем может быть дело?


UDP: если передавать только видео, то проблемы со сменой разрешения нет

UDP2:
FFMPEG выдает ошибку на переходном AAC фрейме (с которого все начинает глючить)
Input buffer exhausted before END element found

В исходниках это
https://github.com/FFmpeg/FFmpeg/blob/master/libavcodec/aacdec_template.c#L3382

и ещё в логах появляется
stereo with SCE

Похоже не нравится малый размер AAC пакета, что-ли

≈=======
Решил проблему так:

Останавливаю видео-кодировщик не сразу, а после того, когода он отправит все predicted (P) фреймы, которые начинаются от Intra. Теперь Хром и ФФ проглатывают это и видео, меняют разрешение и не останавливаются.
Аудио-кодировщик не перезапускаю

Не понимаю до сих пор почему это помогло. После перезапуска ведь отправляется sps, pps и idr пакет. Там вся инфа содержится. Кодеку нужно лишь переконфигурироваться. Как влияют P фоеймы?

И еще, если декодировать в ффмпег h264_qsv, то видео все равно зависает. С чем связано пока не понял.


UDP. Нашел проблему. В начале потока отсылался только AVC SequenceHeader(в FLV type=0), в последущем отсылался также он, что не правильно: игнорировался FLV-демультиплексором и не обрабатывался h264 декодером. Нужно в середине потока посылать NAL unit(в FLV type=1)

★★★★

может делается как-то по-другому или вообще запрещено налету менять так? по идее если такое разрешено, то точно был бы какой-то resume метод для продолжения, а не просто запуск кодировщика.

xmikex ★★★★ ()
Ответ на: комментарий от ergo

возможно, там есть некий хендшейк, где согласуется формат кодирования и его изменение на ходу, очевидно, ломает этот контракт.

Да, это и есть SPS. Он один на стрим/файл должен быть.

Вот тут чуть подробнее описано, см. первый ответ: https://stackoverflow.com/questions/20682275/h264-with-multiple-pps-and-sps/20689847

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

hateyoufeel ★★★★★ ()
Ответ на: комментарий от hateyoufeel

Да, это и есть SPS. Он один на стрим/файл должен быть.

Почему должен? SPS отсылается в аккурат после изменения формата изображения. Сколько угодно раз

стримеры все с него давно слезли

Стримеры или зрители? Все стримерские платформы основаны на rtmp. Ну, еще webrtc. Других вариантов нет, кроме экзотических

В HLS всё гораздо проще: плеер забирает плейлист с кусками стрима и

Я делаю не плеер. Я делаю кодировщик

gobot ★★★★ ()

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

bl00dy ()