Как синхронизировать аудио и видео с помощью библиотек ffmpeg?

Застрял в написании очень простого медиаплеера на C с использованием библиотек SDL и ffmpeg. Первоначально следил за теорией на этой странице, чтобы получить представление обо всей программе и использовании библиотек. После написания кода с нуля, благодаря этому руководству и многим другим ресурсам, я, наконец, заставил свой код работать, используя последние библиотеки ffmpeg и SDL (2.0). Но в моем коде отсутствует надлежащий механизм синхронизации (на самом деле ему не хватает механизма синхронизации!).

У меня до сих пор нет четкого представления о том, как синхронизировать аудио и видео вместе, поскольку теория, представленная в ссылке, только частично верна (по крайней мере, когда речь идет об использовании последних библиотек разработчиков).
Например, предложение на этой странице выглядит следующим образом:

Однако ffmpeg переупорядочивает пакеты так, что DTS пакета, обрабатываемого avcodec_decode_video(), всегда будет таким же, как PTS кадра, который он возвращает.

Я использую avcodec_decode_video2(), и DTS пакета определенно не совпадает с точками кадра, который он декодирует (в целом).

Я прочитал этот очень информативный отчет BBC, и он делает полный смысл. У меня есть четкое представление о PTS и DTS. Но значения PTS и DTS, которые ffmpeg использует для пакетов и декодированных кадров, сбивают с толку. Я хотел бы, чтобы была какая-то документация по этому аспекту.

Может ли кто-нибудь объяснить шаги по синхронизации аудио и видео? Мне нужны только шаги. Мне вполне комфортно их реализовывать. Любая помощь приветствуется. Спасибо !

PS: Вот скриншот того, о чем я говорю:

введите здесь описание изображения

Огромное отрицательное значение, я предполагаю, AV_NOPTS_VALUE.


person progammer    schedule 19.10.2013    source источник


Ответы (1)


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

Я предоставил файл .mpg в качестве входных данных, и это мои наблюдения:

BBC RD 1996/3 в своем очень информативном отчете говорит:

Чтобы сделать возможным обратное предсказание из будущего кадра, кодер изменяет порядок изображений с естественного порядка отображения на порядок «передачи» (или «потока битов»), так что B-изображение передается после прошлого и будущего изображений, на которые оно ссылается. (См. рис. 14). Это вводит задержку, которая зависит от количества последовательных B-изображений.

  • Предоставленный входной файл имел первые несколько видеокадров следующим образом: (в их естественном порядке отображения)

    I0 B0 B1 P0 B2 B3 P1 B4 B5 P2 B6 B7 P3 B8 B9 I1 ...

  • Но кодировщик (во время процесса кодирования, когда-то в прошлом, когда файл был закодирован) помещает пакеты в видеопоток как: (это необходимо для декодирования кадров P и B)

    I0 P0 B0 B1 P1 B2 B3 P2 B4 B5 P3 B6 B7 I1 B8 B9 ...

  • Теперь, когда av_read_frame() читает пакеты из видеопотока, они получаются в том же порядке, что и выше:

    I0 P0 B0 B1 P1 B2 B3 P2 B4 B5 P3 B6 B7 I1 B8 B9 ...

  • Вот что делает avcodec_decode_video2() (или, по крайней мере, делает в данном случае):

    Ввод I0 (pts_I0, dts_I0) -----> DECODER ----> Нет выходного кадра
    Ввод P0 (pts_P0, dts_P0) ----- > DECODER ----> Вывод I0 (pts_I0, dts_P0)
    Ввод B0 (pts_B0, dts_B0) -----> DECODER ----> Выход B0 (pts_B0, dts_B0)
    Ввод B1 (pts_B1, dts_B1) -----> DECODER ----> Вывод B1 (pts_B1, dts_B1)
    Ввод P1 (pts_P1, dts_P1) -----> DECODER ----> Вывод P0 (pts_P0, dts_P1)
    Ввод B2 (pts_B2, dts_B2) -----> DECODER ----> Вывод B2 (pts_B2, dts_B2)
    Ввод B3 (pts_B3, dts_B3) -----> DECODER ----> Вывод B3 (pts_B3, dts_B3)
    Ввод< /em> P2 (pts_P2, dts_P2) -----> DECODER ----> Вывод P1 (pts_P1, dts_P2)
    Ввод B4 (pts_B4, dts_B4) -----> DECODER --- -> Вывод B4 (pts_B4, dts_B4)
    Ввод B5 (pts_B5, dts_B5) -----> DECODER ----> Вывод B5 (pts_B5, dts_B5)
    Ввод P3 (pts_P3, dts_P3) -----> DECODER ----> Вывод P2 (pts_P2, dts_P3)
    Вход B6 (pts_B6, dts_B6) ----- > DECODER ----> Вывод B6 (pts_B6, dts_B6)
    Ввод B7 (pts_B7, dts_B7) -----> DECODER ----> Вывод B7 (pts_B7, dts_B7)
    Ввод I1 (pts_I1, dts_I1) -----> DECODER -- --> Вывод P3 (pts_P3, dts_I1)
    Ввод B8 (pts_B8, dts_B8) -----> DECODER ----> Вывод B8 (pts_B8, dts_B8)
    Ввод B9 (pts_B9, dts_B9) -----> DECODER ----> Выход B9 (pts_B9, dts_B9)

      Next Input Packet ---------> DECODER ---------->  Next Output Frame   
     (pts_PKT, dts_PKT)                                I1 (pts_I1, dts_PKT) 

Я думаю, теперь вы можете заметить, что на каждом шаге декодирования декодер уже имеет другие кадры (прошлые кадры или будущие кадры естественного порядка отображения) для успешного выполнения. декодировать входной пакет. Декодер выводит кадры в естественном порядке отображения. Кроме того, насколько я заметил, обычно pts для блоков доступа (пакетов), содержащих кадры I или P, имеет значение AV_NOPTS_VALUE.

PS: я не знаю ASCII арт! Извините, если иллюстрация не слишком хороша. Надеюсь, это помогло другим.
Теперь, зная это, я думаю, что это помогает лучше понять pts и dts.
Эта ссылка и эта ссылка — другие, которые я нашел полезными.

person progammer    schedule 19.10.2013