Запись видеофайла с помощью FFmpeg
Введение
При создании мультимедийных программ иногда возникает необходимость записи видеофайла. В видеофайл может быть записана созданная сцена или фильм, а если вы пишете конвертер видеофайлов, то запись в файл вам точно необходима. Решение задачи должно быть максимально кроссплатформенным. Для решения данной задачи идеально подходит FFmpeg.
Старую версию статьи вы можете найти по ссылке: http://unick-soft.ru/Articles.cgi?id=20, также если вас интересует не запись в файл, а чтение из файла, то Декодирование видео с помощью FFmpeg.
Для статьи был переработан пример, чтобы он работал с новым API ffmpeg-а.
О библиотеке FFmpeg, подготовке FFmpeg и кратко о видеофайлах
Кратко о библиотеке FFmpeg, о подготовке FFmpeg для использования в Visual Studio и краткую информацию о видеофайлах можно узнать в первой статье Декодирование видео с помощью FFmpeg.
Создание видеофайлов с помощью FFmpeg
Запись в видеофайл с помощью FFmpeg осуществляется довольно просто. Первое, что необходимо - это задать формат файла, кодек и задать количество потоков (видео и аудио). После задания форматов файлов, необходимо добавить кадры в видеопотоки и звуковые семплы в аудиопотоки. После добавления информации необходимо закрыть файл, в него будут добавлены индексы.
Шаг 0: Инициализация FFmpeg
// Регистрируем все компоненты FFmpeg av_register_all();
Шаг 1: Создаём файл с заголовком и добавляем потоки
Во-первых, необходимо выбрать контейнер (контейнеры бывают avi, wmv, mov) и создать контекст.
AVOutputFormat *pOutFormat; AVFormatContext *pFormatContext; pOutFormat = guess_format(NULL, filename, NULL); pFormatContext = avformat_alloc_context(); pFormatContext->oformat = pOutFormat;
После добавляем видео и аудиопотоки:
st = avformat_new_stream(pFormatContext, 0); pCodecContext = st->codec; pCodecContext->codec_id = (CodecID) pOutFormat->video_codec; ...
Более подробно о добавлении потоков, можно узнать из примера, который прилагается к статье.
После этого необходимо будет открыть файл и записать заголовок:
if (avio_open(&pFormatContext->pb, filename, AVIO_FLAG_WRITE) < 0) { res = false; printf("Cannot open file\n"); } avformat_write_header(pFormatContext, NULL);
Шаг 2: Добавление кадров видео и аудиосемплов
Запись состоит из следующих этапов:
- Преобразование первичных данных, например для видео - это преобразование кадра в YUV.
- Кодирование данных, т.е. сжатие кодеком.
- Запись закодированного буфера данных в файл.
Стоит отметить, что аудиосемплы могут быть разбиты на несколько пакетов. А также могут оставаться маленькие кусочки, которые будут записаны со следующей партией семплов.
Преобразование видеокадра:
AVFrame* frame; AVFrame* pCurrentPicture frame; struct SwsContext *pImgConvertCtx; // Convert RGB to YUV. sws_scale(pImgConvertCtx, frame->data, frame->linesize, 0, pVideoCodec->height, pCurrentPicture->data, pCurrentPicture->linesize);
Кодирование видеоданных:
AVPacket packet; AVCodecContext *pVideoCodec; AVFrame * pOutputFrame; int nOutputSize = 0; // Encode int error = avcodec_encode_video2(pVideoCodec, &packet, pOutputFrame, &nOutputSize);
Запись видеоданных:
AVPacket pkt; // Write frame bool res = (av_interleaved_write_frame(pFormatContext, &pkt) == 0)
Шаг 3: Завершение
На этом этапе записывается конец файла, файл закрывается и высвобождаются ресурсы.
av_write_trailer(pFormatContext); for(size_t i = 0; i < pFormatContext->nb_streams; i++) { av_freep(&pFormatContext->streams[i]->codec); av_freep(&pFormatContext->streams[i]); } if (!(pFormatContext->flags & AVFMT_NOFILE) && pFormatContext->pb) { url_fclose(pFormatContext->pb); } av_free(pFormatContext);
Стоит отметить, что большая часть кода пропущена, смотрите его в прилагаемом примере.
Настройки записи
Для того, чтобы настроить выходной файл, например, степень сжатия, количество ключевых кадров и тому подобное, необходимо изменять настройки кодеков. Ниже приведены наиболее значимые из настроек.
Настройки записи видео
- pCodecCxt->bit_rate - cредний битрейт в байтах в секунду. Чем больше, тем лучше видео, хотя значение может не совпадать с выходным значением.
- pCodecCxt->width и pCodecCxt->height - высота и ширина видео.
- pCodecCxt->time_base - обычно с помощью него задаётся количество кадров в секунду. Например для FPS 25: (time_base.den = 25; time_base.num = 1;)
- pCodecCxt->gop_size - максимальное расстояние между двумя кадрами. Чем больше, тем меньше будет весить конечный файл.
- pCodecCxt->pix_fmt - формат выходного видео, обычно PIX_FMT_YUV420P.
- pCodecCxt->qcompress - сжатие, значение от 0.0 до 1.0. 1.0 для большего качества. По умолчанию 0.5.
- pCodecCxt->qblur- сглаживание, значение от 0.0 до 1.0.
- pCodecCxt->qmin - минимальный квантователь. Значение от 0 до 100.
- pCodecCxt->qmax - максимальный квантователь. Значение от 0 до 100.
Настройки записи аудио
- pCodecCxt->bit_rate - битрейт аудио, обычно 128000 байт в секунду, или 256000. Чем больше, тем качественнее.
- pCodecCxt->sample_fmt - формат семпла:
- AV_SAMPLE_FMT_U8 - семпл равен 1 байт (0..255).
- AV_SAMPLE_FMT_S16 - семпл 2 байта, от -0x7FFF до 0x7FFF.
- AV_SAMPLE_FMT_S32 - семпл 4 байта от -0x7FFFFFFF до 0x7FFFFFFF.
- AV_SAMPLE_FMT_FLT - семпл float. Значение от 0.0 до 1.0.
- AV_SAMPLE_FMT_DBL - семпл double. Значение от 0.0 до 1.0.
- pCodecCxt->channels - количество каналов: для стерео необходимо 2 канала.
- pCodecCxt->sample_rate - частота семплов, обычно 44100, 28050...
Заключение
Из статьи вы могли узнать, как использовать FFmpeg для создания видеофайлов. Стоит отметить, что FFmpeg поддерживает большое количество форматов и кодеков.
Пример
Да, без примера статья была бы не закончена. Вы можете скачать пример использования ffmpeg. Пример не имеет полную функциональность, а только демонстрирует основы создания файла с помощью FFmpeg. Программа создаёт видеофайл со звуком (похожим на сирену). Ниже представлены настройки, которые вы можете поменять.
// Размер видео. #define W_VIDEO 320 #define H_VIDEO 240 // Имя выходного файла. #define FILE_NAME "c:\\temp\\1.avi" // Количество кадров в ролике. #define FRAME_COUNT 150 // Контенер. #define CONTAINER "auto"
CONTAINER - какой использовать контенер. "auto" - автоматически выбирается по расширению файла. Также может иметь значения: "avi", "mp4", "mpeg", "wmv", "mov".
Ссылки
- http://ffmpeg.org/ - официальный сайт проекта FFmpeg.
- http://en.wikipedia.org/wiki/FFmpeg - о FFmpeg на Википедии.
- http://ffmpeg.arrozcru.org/ - проект FFmpeg для Windows.