Я делаю приложение для 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)