Подобрение на видеоплейъра ffmpeg

ffmpeg

Внедряване

Кодът на този пример се оказа доста голям, реших да не го представям тук целия. Ще покажа само най-важното. Целият код можете да видите на линка в края на статията.

Първо, нека комбинираме всички основни променливи в един общ контекст:

Възпроизвеждане на аудио

Звукът на компютъра е непрекъснат поток отсемпли. Всяка проба е стойност на формата на вълната. Звуците се записват с определеначестота на дискретизацияи трябва да се възпроизвеждат със същата честота.Честота на вземане на пробипредставлява броя на проби в секунда. Например 44100 семпли в секунда е честотата на семплиране на аудио CD. Освен това аудиото може да съдържа множество канали. Например, за стерео, пробите ще идват две наведнъж. При получаване на данни от файл не е известно колко проби ще бъдат получени, но FFmpeg няма да върне непълни проби. Това също означава, че FFmpeg няма да премахва стерео семпли.

Първата стъпка е да настроите SDL за аудио изход. ФлагътSDL_INIT_AUDIOтрябва да се добави към функцията за инициализация. След това попълнете структуратаSDL_AudioSpecи я предайте на функциятаSDL_OpenAudio:

SDL използва функция за обратно извикване за извеждане на аудио. Структурата има следните параметри:

  • freq: Честота на дискретизация.
  • формат: Формат на предаваните данни. Символът "S" в "AUDIO_S16SYS" означава, че данните ще бъдат подписани, 16 - размерът на извадката е 16 бита, "SYS" - използва се системният ред на байтовете. Именно в този формат FFmpeg връща декодираните данни.
  • канали: Брой аудио канали.
  • тишина: Стойността на "тишина". За подписани данни обикновено се използва 0.
  • проби: Размер на аудио буфераSDL. Нормалните стойности са стойности от 512 до 8192 байта. Ще използваме 1024.
  • обратно извикване: функция за обратно извикване за запълване на буфера с данни.
  • userdata: Потребителски данни, предадени на функцията за обратно извикване. Нека използваме нашия основен контекст тук.
Извикването наSDL_PauseAudio(0)стартира аудио възпроизвеждане. Ако в буфера няма данни, ще се възпроизведе „тишина“.

Аудио декодиране

Ние ще използваме пръстен буфер като такъв буфер. Прототипи на основните функции:

Целта на аргументите трябва да е ясна от името. Аргументътblockуказва дали функцията трябва да блокира, ако няма достатъчно буферно пространство или няма данни за четене.

И така, цялата функция за декодиране изглежда така:

Декодирането на аудио пакета се извършва от функциятаavcodec_decode_audio4Ако целият кадър е декодиран (флагgot_frame), ние определяме размера на буфера в байтове с помощта на функциятаav_samples_get_buffer_sizeи го записваме в нашия пръстен буфер.

Възпроизвеждане на аудио

Остава съвсем малко, а именно да възпроизведем декодираните проби. Това се прави във функцията за обратно извикванеaudio_callback:

Тук всичко е елементарно. Получаваме от буфераlenбайта и ги съхраняваме в предоставения SDL буфер.

Синхронизация

Нека добавим следните полета към нашия основен контекст:

В аудио декодиращия поток съхраняваме аудио честотата, за да можем да я синхронизираме по-късно:

Е, „сърцето“ на нашата синхронизация е функциятаcompute_delay:

Първо изчисляваме закъснението между предишния и текущия кадър и запазваме текущите стойности. След това вземаме предвид възможната десинхронизацияс аудио и изчислете продължителността на необходимото забавяне до следващия кадър.

Заключение

В тази част завършихме разработката на най-простия плейър, подобрихме структурата на програмата, добавихме аудио възпроизвеждане и синхронизация. Остават опции за пренавиване, бързо/бавно възпроизвеждане и други опции за синхронизиране. Има и напълно отделна тема за кодирането и мултиплексирането. Може би ще се опитам да го разгледам в следващата статия.

Благодаря на всички за вниманието!

Hardcore conf в C++. Каним само професионалисти.