Запись видеофайла с помощью FFmpeg

Запись видеофайла с помощью 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: Добавление кадров видео и аудиосемплов

Запись состоит из следующих этапов:

  1. Преобразование первичных данных, например для видео - это преобразование кадра в YUV.
  2. Кодирование данных, т.е. сжатие кодеком.
  3. Запись закодированного буфера данных в файл.

Стоит отметить, что аудиосемплы могут быть разбиты на несколько пакетов. А также могут оставаться маленькие кусочки, которые будут записаны со следующей партией семплов.

Преобразование видеокадра:

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".

Ссылки

Теги: C++ Видео FFmpeg