Почему видео ломается во Flutter
Про anamorphic video, SAR/DAR и странности мобильных плееров
Поймали странную историю с видео во Flutter.
Видео нормально играет в VLC и QuickTime, а в приложении на Flutter — сплющено.
Никаких ошибок, просто выглядит неправильно.
Первое ощущение — где-то накосячили с layout или AspectRatio.
Но дальше оказалось, что проблема вообще не в UI.
Материал подготовил Егор, Flutter-разработчик в нашей команде.
Разбирались с этим кейсом в боевом проекте.
Что за видео такое
Смотрим видео через ffprobe:
resolution: 1080×1080
SAR: 9:16
DAR: 9:16
То есть физически видео квадратное, но каждый пиксель не квадратный.
После применения SAR картинка должна быть вертикальной (9:16).
Такой формат называется anamorphic video.
Небольшое отступление, что это вообще значит.
Anamorphic encoding — это когда реальное разрешение и визуальное разрешение не совпадают.
Идея старая, пришла из телевидения и DVD: хранить меньше пикселей, а растягивать их при воспроизведении.
Раньше это имело смысл. Сейчас — почти всегда источник проблем.
Почему это вообще происходит?
Чаще всего такие видео прилетают либо со старых камер/архивов, либо (что куда актуальнее в 2026) — после кривого экспорта из профессионального софта:
Premiere
DaVinci
Media Encoder
Там легко забыть выставить Square Pixels (1.0) в настройках sequence / render — и в файл улетает SAR ≠ 1:1.
Короче: это такой привет от монтажёров.
Снаружи всё выглядит как обычный MP4, а внутри начинается магия с пикселями.
Почему VLC всё показывает правильно
VLC — это не просто оболочка над системным плеером. Он сам:
парсит видеопоток
читает H.264 VUI
учитывает SAR/DAR
сам решает, как рисовать кадр
То есть VLC корректирует геометрию изображения ещё до рендера.
Что происходит во Flutter
В стандартном стеке всё выглядит примерно так:
video_player / chewie / better_player
→ ExoPlayer
→ MediaCodec
Flutter получает от плеера только одно — width и height.
Никакого SAR, никакого DAR.
Для Flutter это просто видео 1080×1080.
Где именно всё ломается
MediaCodec про SAR знает и применяет его внутри декодера
ExoPlayer считает это внутренней деталью и не отдаёт наружу
Flutter Video API вообще не имеет понятия, что пиксели могут быть неквадратными
В итоге layout во Flutter строится по «сырым» размерам контейнера.
Важная оговорка: ExoPlayer в целом знает про pixelWidthHeightRatio,
но в типичном Flutter-стеке эта информация до Dart просто не доезжает или не используется.
На практике эффект один — SAR потерялся по дороге.
А что на iOS?
iOS (AVPlayer / AVFoundation) в среднем “умнее” в таких вещах и часто сам разруливает SAR и трансформы.
Поэтому в QuickTime всё и выглядит нормально.
Но дальше включается кроссплатформенность:
Flutter-плагин video_player пытается унифицировать API между платформами и в итоге часто отдаёт наверх просто размер кадра, без метаданных о том, как его правильно растягивать.
Получается классический «глухой телефон»:
на нативе всё понятно, а на уровне Flutter — уже нет.
Можно ли взять другой плеер
Да, есть flutter_vlc_player, который использует libVLC.
Он показывает такое видео корректно, потому что применяет SAR сам.
Но есть нюанс: libVLC не работает в Android Emulator.
Он ожидает:
реальное железо
нормальный GPU
полноценный surface
Эмулятор этого не даёт.
на реальном устройстве — всё ок
в эмуляторе — нет
В итоге получается вилка
Либо - стандартные Flutter-плееры
всё работает в эмуляторе
видео искажено
Либо - VLC
картинка правильная
эмулятор мёртв
Одновременно получить и то и другое нельзя.
Важно: это не баг конкретной библиотеки
Это архитектурное ограничение:
Flutter Video API сильно упрощён
ExoPlayer не экспортирует SAR/DAR наружу (в нашем сценарии)
anamorphic video плохо вписывается в mobile-first мир
Что в итоге решили
Видео перекодировать.
Привести всё к:
визуальному размеру “как должно выглядеть”
SAR = 1:1 (квадратные пиксели)
Post #57
533
- ❤ 1