Найдите лучшие параметры VP8 для надежности потоковой передачи UDP с помощью libav/ffmpeg.

Я столкнулся с некоторыми проблемами в своем приложении видеочата, которое использует библиотеки libav. Я отправляю видео 1080p, закодированные в VP8, как контейнер WebM через UDP, и это работает довольно хорошо. В большинстве случаев декодер с обеих сторон восстанавливает потери пакетов из-за передачи.

Однако в какой-то момент он просто замерзает и больше никогда не восстанавливается. В конечном итоге это происходит с обеих сторон. Я искал параметры кодека VP8 для повышения надежности при отправке по каналам передачи с потерями. И я объединил некоторые из найденных, чтобы повысить надежность. Тем не менее, он все еще зависает после некоторого времени видеочата.

Вот параметры, которые я сейчас использую.

  pVidCodecCtx->codec_id     = AV_CODEC_ID_VP8;
  pVidCodecCtx->codec_type   = AVMEDIA_TYPE_VIDEO;
  pVidCodecCtx->width        = frmQ->pCodecCtx->width; //1920
  pVidCodecCtx->height       = frmQ->pCodecCtx->height; //1080
  pVidCodecCtx->time_base    = frmQ->pCodecCtx->time_base;
  pVidCodecCtx->pix_fmt      = PIX_FMT_YUV420P;
  pVidCodecCtx->qmin         = 4;
  pVidCodecCtx->qmax         = 56;
  pVidCodecCtx->bit_rate     = pVidCodecCtx->width * pVidCodecCtx->height * 6;
  pVidCodecCtx->slices       = 8;
  pVidCodecCtx->profile      = 3;
  pVidCodecCtx->thread_count = 3;
  pVidCodecCtx->keyint_min   = 5;
  av_dict_set(&pDictCodecOpts, "rc_lookahead", "0", 0);
  av_dict_set(&pDictCodecOpts, "quality", "realtime", 0);
  av_dict_set(&pDictCodecOpts, "deadline", "realtime", 0);
  av_dict_set(&pDictCodecOpts, "max-intra-rate", "0", 0);
  av_dict_set(&pDictCodecOpts, "qcomp", "0", 0);
  av_dict_set(&pDictCodecOpts, "default", "er", 0);
  av_dict_set(&pDictCodecOpts, "error_resilient", "er", 0);
  av_dict_set(&pDictCodecOpts, "partitions", "er", 0);

Большинство параметров я извлек из кода ffmpeg для кодировщика vpx.

Нужно ли также устанавливать параметры для декодера, чтобы повысить устойчивость к ошибкам? Или я пропускаю какие-то параметры в энкодере или неправильно их устанавливаю. Любая помощь или подсказки приветствуются.


person lmNt    schedule 25.06.2014    source источник


Ответы (1)


Я отвечу на свой вопрос, потому что мне в конце концов удалось запустить видеочат без зависаний.

Оказывается, эти параметры действительно хороши для устойчивости к ошибкам.

Проблема заключалась в том, что некоторые вызовы функций, например.

av_read_frame()
avformat_open_input()

в потоке декодера были блокировки при повреждении пакета, что приводило к зависанию видео.

Итак, в итоге я написал класс таймера и позволил таймеру измерять время выполнения указанных функций. Я написал функцию обратного вызова прерывания и передал ее в контекст формата моего декодера следующим образом:

static int interrupt_cb (void *p)
{
    unsigned int expTime = 1000;
    Uint32 elapsedTime = pVidConfTimer.elapsedTimeInMs();
    if (elapsedTime > expTime) 
    {
       return 1;
    }
    return 0;
}

static const AVIOInterruptCB cb = {interrupt_cb, &dummy};
frmQ.pFormatCtx->interrupt_callback = cb;

Это вернется из функции, если время выполнения займет больше времени, чем expTime. Вы также можете передать пользовательский параметр через void *p в функцию обратного вызова.

В моем потоке декодирования/отображения я просто вызываю что-то вроде

timer.tic();
ret = av_read_frame(...);
timer.reset();

if (ret<0)
{
    //received corrupted frame
    //reinitialize format context
    //open input
    //find decoder and open codec
    ...
}

Надеюсь, это поможет любому, у кого есть подобные проблемы.

person lmNt    schedule 24.10.2014