Недавно пришлось собирать ffmpeg под Windows компилятором MSVC. И знаете — я чуть не помер. Официальная документация по сборке проекта под Windows безнадежно устарела. В Интернете есть даже статьи, которые так и заявляют: "Официальная документация по сборке ffmpeg под Windows безнадежно устарела — вот как теперь это делается". И смех в том, что эти статьи уже тоже устарели и не дают работающего решения "press X to compile".

Поэтому я просто оставлю здесь инструкцию, которая работает на февраль 2026. И, возможно, устареет, как и все предыдущие. Но вы тогда мне просто об этом напишете, и я попробую актуализировать эту инструкцию.

Ставим MSYS2

В первую очередь мы поставим MSYS2, который позволит нам иметь Unix-подобное окружение в Windows: в частности возможность запускать configure и make

  • Загружаем и запускаем MSYS2

  • Идем в файл c:/msys64/msys2_shell.cmd и удаляем rem из строки rem set MSYS2_PATH_TYPE=inherit

  • Запускаем x64 Native Tools Command Prompt for VS 2022 (или ту версию VS, которая у вас есть)

  • Из под этого терминала запускаем c:/msys64/msys2_shell.cmd, запустится еще один терминал, в котором выполняем оставшиеся команды

  • pacman -Syu

  • pacman -S make

  • pacman -S nasm

  • Запускаем mv /usr/bin/link.exe /usr/bin/link.exe.bak. Да-да — фактически удаляем местный link.exe, поскольку он будет конфликтовать с link.exe тулчейна msvc

Поздравляем, вы настроили MSYS2 на возможность собрать ffmpeg тулчейном msvc в Unix-like окружении

Качаем ffmpeg

Клонируем ffmpeg-репозиторий командой

git clone https://git.ffmpeg.org/ffmpeg.git <ffmpeg-folder>

Собираем ffmpeg

Для начала снова запускаем "терминал через терминал":

  • Запускаем x64 Native Tools Command Prompt for VS 2022

  • Из под этого терминала запускаем терминал c:/msys64/msys2_shell.cmd

  • В этом терминале переходим в папку с ffmpeg-репозиторием

  • Для того, чтобы проверить, что все идет по плану, запустите команду cl. Вы должны увидеть что-то в духе:

Microsoft (R) C/C++ Optimizing Compiler Version 19.43.34809 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.

usage: cl [ option... ] filename... [ /link linkoption... ]

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

Дальнейшая работа происходит в этом, втором MSYS2-терминале.

Дефолтная сборка

Самый минималистичный вариант сборки ffmpeg:

./configure --target-os=win64 --arch=x86_64 --toolchain=msvc
make -j16

Кастомная сборка

При желании вы можете добавлять в configure различные конфигурационные флаги, которые можно узнать из ./configure --help. Ffmpeg имеет очень обширную кастомизацию.

Пример:

./configure \
  --target-os=win64 \
  --arch=x86_64 \
  --toolchain=msvc \
  --disable-programs \
  --disable-doc \
  --disable-encoders \
  --disable-muxers \
  --disable-filters \
  --disable-devices \
  --disable-network \
  --disable-avfilter \
  --disable-avdevice \
  --disable-mediafoundation \
  --enable-decoder=aac,ac3,adpcm_ima_wav,adpcm_ms,alac,av1,bmp,eac3,dnxhd,ffv1,ffvhuff,flac,flc,flic,flv1,gif,h263,h263p,h264,hevc,indeo3,indeo4,indeo5,mjpeg,mp3,mpeg1video,mpeg2video,mpeg4,msmpeg4v2,msmpeg4v3,opus,pal8,paletteuse,pcm_s16le,pcm_s24le,prores,png,rawvideo,rv10,rv20,svq1,svq3,theora,tiff,vc1,vorbis,vp8,vp9,webp,wmv1,wmv2,wmv3 \
  --enable-demuxer=asf,avi,flc,flic,flv,gif,image2,image2pipe,matroska,mjpeg,mov,mp3,mp4,mpegps,mpegts,ogg,png,wav,webm,webp \
  --enable-parser=aac,ac3,flac,h263,h264,hevc,mpeg4video,mpegvideo,rawvideo,vorbis,vp8,vp9 \
  --enable-protocol=file \
  --enable-swscale \
  --enable-swresample \
  --enable-avformat \
  --enable-avcodec \
  --enable-avutil \
  --enable-zlib \
  --extra-cflags="-I../thirdparty/zlib" \
  --extra-ldflags="-LIBPATH:../bin/obj/thirdparty/zlib"

make -j16

Сборка динамической библиотеки

По умолчанию make собирает статические библиотеки. Если вам нужны dll, нужно добавить следующие флаги к configure:

./configure \
  ...
  --enable-shared \
  --disable-static

make -j16

Куда все собирается

Отдельный квест — найти собранные библиотеки и заголовочные файлы для того, чтобы потом можно было их использовать в своем проекте.

Библиотеки *.lib разбросаны по следующим папкам:

ffmpeg/libavcodec/avcodec.lib
ffmpeg/libavdevice/avdevice.lib
ffmpeg/libavfilter/avfilter.lib
ffmpeg/libavformat/avformat.lib
ffmpeg/libavutil/avutil.lib
ffmpeg/libswresample/swresample.lib
ffmpeg/libswscale/swscale.lib

При желании можете написать скрипт, который просто по всему репозиторию найдет все *.lib, *.dll, *.pdb и подложит в ваш проект.

Для заголовочников все немного сложнее. Вы должны, барабанная дробь.. Скопировать все заголовочные файлы *.h и *.hpp из репозитория и подложить их себе в проект с сохранением папочной структуры. Так же при желании можете написать скрипт, который сделает эту работу за вас. Задача со звездочкой для задротов — проанализировать скриптом каждый заголовочный файл, составить дерево зависимостей заголовочных файлов друг от друга и удалить те заголовочные файлы, на которые никто не ссылается %).


Раз уж я так козыряю возможностью написать под это все дело скрипты, было бы странно не показать, как с этим справляюсь лично я. Я делаю это питоном:

def make_dir(path):
    os.makedirs(path, exist_ok=True)

def remove_dir(path):
    shutil.rmtree(path, ignore_errors=True)

def copy_files(src, dst, extensisons: list[str], preserve_structure: bool = True):
    make_dir(dst)
    for root, dirs, files in os.walk(src):
        for file in files:
            if any(file.endswith(ext) for ext in extensisons):
                src_file = os.path.join(root, file)
                if preserve_structure:
                    rel_path = os.path.relpath(root, src)
                    dst_dir = os.path.join(dst, rel_path)
                    make_dir(dst_dir)
                    dst_file = os.path.join(dst_dir, file)
                else:
                    dst_file = os.path.join(dst, file)
                shutil.copy2(src_file, dst_file)

def copy_ffmpeg():
    remove_dir('app/ffmpeg_lib')
    remove_dir('app/ffmpeg_include')

    copy_files('ffmpeg', 'app/ffmpeg_lib', ['.lib', '.dll', '.pdb'], preserve_structure=False)
    copy_files('ffmpeg', 'app/ffmpeg_include', ['.h', '.hpp'], preserve_structure=True)

Выводы

Сборка ffmpeg под Windows — не самое приятное дело. Я хочу, чтобы эта инструкция сделала вашу жизнь с ffmpeg чуточку радостнее.

Любые поправки или альтернативные более простые способы сборки ffmpeg под Windows приветствуются в комментариях. Если вы просто хотите пожаловаться на ffmpeg — тоже пишите. Если вы хотите сказать, какой я нуб, и на самом деле все очень просто — это все я тоже с удовольствием почитаю.