Большинство медиа-библиотек для Go рано или поздно упираются в одну и ту же проблему.

У них нет собственного декодера.

Вместо этого они полагаются на установленный в системе пакет FFmpeg, shared библиотеки, платформозависимые DLL или внешние исполняемые файлы, которые должны присутствовать на целевой системе.

На этапе разработки всё работает. Затем начинается развертывание.

И внезапно вы отлаживаете отсутствующие DLL в Windows, несовместимые версии FFmpeg в Linux, различия версий из Homebrew на macOS, образы контейнеров без нужных библиотек или продуктовые серверы, где рядовое обновление пакета неожиданно ломает обработку медиа.


Цель

Мне нужен был декодер, который:

  • Работает на чистом коде Go

  • Собирается в единый бинарник

  • Не требует установки FFmpeg или других рантайм зависимостей

  • Поддерживает современные кодеки, такие как AV1, H.264, H.265, VP8, VP9, Opus, AAC, MP3 и другие

  • Может читать из файлов, буферов памяти, HTTP-потоков, пайпов, SSH-потоков и любого io.Reader

Результат — gopeg.

Вместо того чтобы зависеть от того медиа-стека, который установлен на машине, необходимые компоненты FFmpeg и декодер dav1d статически линкуются в приложение на этапе сборки (с использованием cgo).

Когда бинарник готов, всё необходимое для декодирования видео уже находится внутри.

Почему это важно

Огромное количество времени уходит на решение проблем развёртывания, а не прикладных задач. Типичный пайплайн при обработке медиа часто выглядит так:

  • Установить FFmpeg

  • Установить совместимые shared библиотеки

  • Корректно их упаковать

  • Убедиться, что на продуктовых машинах стоят совместимые версии

  • Надеяться, что будущие обновления операционной системы ничего не сломают

Приложение становится зависимым от внешнего состояния. Со статической линковкой сценарий развёртывания становится гораздо проще: go build и всё.

Никаких внешних пакетов кодеков. Никаких DLL. Никакого поиска библиотек во время выполнения и кривых cmd.Exec. Без фраз - «у меня на тачке всё работает».

Поддержка io.Reader

Ещё одной целью дизайна была гибкость. Декодеру не нужен прямой доступ к файлу. Он должен уметь работать с произвольными потоками:

resp, _ := http.Get(url)
dec, err := gopeg.NewDecoder(resp.Body)

Или:

dec, err := gopeg.NewDecoder(os.Stdin)

Или даже с данными, поступающими через SSH-соединение или кастомный транспорт. Библиотека при наличии Seek() у источника дает возможность извлечения метаданных (ps, если видео является стримом то невозможно будет корректно получить длительность).

Простота вместо абстракции

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

Открываем источник:

dec, err := gopeg.NewDecoder(file)

Читаем метаданные:

meta := dec.Meta()

Декодируем кадры:

for {
    frame, err := dec.DecodeFrame()
    if err != nil {
        panic(err)
    }
    if frame == nil {
      break
    }
    // обрабатываем кадр
}

Никаких фоновых воркеров, скрытых процессов, внешних зависимостей. Чистый гошный интерфейс с каноничными типами.

Заключение

FFmpeg — потрясающий продукт, но зависимость от системной установки FFmpeg создаёт эксплуатационную сложность, которая на самом деле не нужна многим приложениям. Для моих задач статически слинкованный подход оказался более осмысленным, также получилось выиграть в размере финальной сборки. Результат — медиа-декодер, который легко встроить, легко развернуть и который предсказуемо работает в любом окружении.

Результат сборки - один self-contained бинарный файл который содержит всё необходимое для декода видео.

Поэтому gopeg - первое законченное решение на go, предоставляющее доступ ко всем современным декодерам, не обязывающее устанавливать платформенные dll или внешние пакеты, что делает библиотеку кратно более удобной при развертывании.


Резервный репозиторий: https://codeberg.org/d1nch8g/gopeg

Комментарии (14)


  1. Void-Cowboy
    02.06.2026 20:58

    круто!

    вопрос только с тестами - насколько качественно проверяли свою реализацию? начиная от гигантских файлов на декодирование и заканчивая всякой дичью

    FFmpeg тем хорош что он вылизан максимально. С другой стороны если вам под видеонаблюдение или что то подобное где известные фиксированного "качества" файлы то тогда вообще никаких проблем - прошло тестовые прогоны значит будет работать в бою.


    1. MonkAlex
      02.06.2026 20:58

      А это и есть FFmpeg. Автор собрал несколько билдов, накрутил сверху обёртку (как я понял, го не знаю).


      1. Void-Cowboy
        02.06.2026 20:58

        да нет, он же пишет что вместо существующей либы где FFmpeg прилинкован он сделал полностью на Го.

        сам код еше не смотрел так как с телефона читал, завтра уже с компа посмотрю, интересно что там


        1. MonkAlex
          02.06.2026 20:58

          Я как раз код посмотрел. Репа - форк FFmpeg, изменений немного, глазами по диагонали посмотрел.


          1. Void-Cowboy
            02.06.2026 20:58

            по идее если форк с линкованой то там нужно будет только заменить линкованные методы на написанные на Го

            другое дело зачем, разве что сохранить обратную совместимость с решениями что уже давно юзают эту либу - например у него готовый продукт и он его "обновлил" не переписывая по факту ничего, а просто перевязав зависимость


          1. dancheg Автор
            02.06.2026 20:58

            Там не совсем ффмпег. Исключительно декодеры (6 МБ против 40+МБ у всех функций). Так же собран AV1 декодер тк он в другой репе, там в основном ассемблер.

            Го библиотека не требует внешних зависимостей тк часть ffmpeg «зашита» и статически слинкована(с использованием cgo), но внешний АПИ чисто гошный. Тесты 80+%, все указанные форматы были проверены.


            1. Void-Cowboy
              02.06.2026 20:58

              аа, ну такое

              cgo бывает разным - потому и линкуют по внешне инсталируемой, что бы проблемы совместимости и тд решались за пределами кода

              как минимум могут быть проблемы на старые сборки с вашим подходом, ведь вы как я понимаю вшили "самое актуальное"

              но вообще было бы интересно посмотреть именно на полноценный порт FFmpeg на Го. У Го хватает фишек оптимизации благодаря которым чистая реализация будет немного медленнее но возможно более управляемее или иные особенности (как минимум контроль памяти более строгий можно сделать из того что вижу сходу)


              1. dancheg Автор
                02.06.2026 20:58

                Если для вас не критичен single-binary, то вот порт использующий зависимость: https://github.com/u2takey/ffmpeg-go


              1. Sap_ru
                02.06.2026 20:58

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


  1. raydac
    02.06.2026 20:58

    а поддержка плейлистов m3u и m3u8 есть? играть TS будет?


    1. dancheg Автор
      02.06.2026 20:58

      Надо добавить флаг при сборке: --enable-demuxer=hls,m3u8, тогда будет работать. Скрипт лежит в cmd/build/main.go. Завтра вечером добавлю в master.


    1. dancheg Автор
      02.06.2026 20:58

      Добавил mpegts демуксер. Теперь можно разбить плейлист на куски и скормить либе:

      resp, err := http.Get(segmentURL)
      if err != nil {
          panic(err)
      }
      defer resp.Body.Close()
      
      dec, err := gopeg.NewDecoder(resp.Body)
      if err != nil {
          panic(err)
      }
      
      for !dec.HasEnded() {
          frame, err := dec.DecodeFrame()
          if err != nil {
              panic(err)
          }
      
          // process frame
      }

      Если дадите url помогу протестировать.


  1. Apoheliy
    02.06.2026 20:58

    ... медиа-библиотек для Go ...

    ... на чистом коде Go ...

    ... и любого Go ...

    Пардонь-те, и с какого ... перепугу вы указали хаб для языка Си?


    1. dancheg Автор
      02.06.2026 20:58

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