# Что отложено Список того, что известно и сознательно не сделано. Не «когда-нибудь починим», а «знаем, чего это стоит, и решили пока не платить». ## macOS: собирается, но работает наполовину Сборка проверена. В тулчейне fpcupdeluxe уже стоит всё нужное: кросс-компиляторы, Apple SDK (10.13, 11.0, 12.3) и виджетсет cocoa для обеих архитектур. Обе цели собираются с первого раза: ./build.sh macos → nlve_intel (Mach-O x86_64) nlve_arm (Mach-O arm64) Чего не будет, пока не сделано: **Предпросмотра нет.** Встраивание mpv написано под два случая: X11 (под gtk2 создаётся своё дочернее окно и его номер отдаётся mpv в `wid`) и Windows (там у панели есть настоящий HWND). Под cocoa нужен третий путь — отдать mpv указатель на NSView. Это не правка на десять строк: нужно разобраться, как LCL под cocoa отдаёт NSView панели, и проверить, что mpv рисует именно в неё. **Окно зависимостей врёт.** Списки в `uDeps.pas` разделены на два случая: Windows и всё остальное. Мак попадает во второй и получает совет `sudo apt install ffmpeg`. Нужен свой список: `brew install ffmpeg mpv` или готовые сборки. **Проверить нечем.** У нас нет мака. Собранный, но ни разу не запущенный файл — это предположение, а не сборка. Всё, что можно утверждать сейчас: компилятор и компоновщик отработали без ошибок. **Двух файлов может оказаться мало.** Intel и Apple Silicon сейчас раздаются отдельно. Склеить их в один универсальный умеет `lipo`, но в тулчейне он есть только для powerpc — для x86_64 и arm64 его надо доставить. **Обёртка .app не настроена.** lazbuild её создаёт, но внутри лежит ссылка на файл с именем `nlve`, которого после переименования нет. Сейчас она просто удаляется. Настоящему приложению нужны свой Info.plist, значок и, для раздачи, подпись и нотаризация у Apple. ## Лицензия не выбрана libmpv грузится в наш процесс, а её сборки — GPL (в Ubuntu GPL-3+ из-за libsmbclient, у shinchiro тоже GPL). По толкованию FSF это делает совместную работу производной, и при раздаче программа должна быть под GPL-3+ или совместимой. Пока ничего не раздаётся — вопрос не стоит. Решать его перед первой раздачей сборок. Возможный обход: отказаться от libmpv в пользу своего вывода кадров через ffmpeg, но это большая работа и заметно хуже по плавности. ffmpeg проблемой не является: он запускается отдельной программой. ## Настоящая прозрачность в исходном файле Цветовой ключ выбивает цвет, но бывает и прозрачность, записанная в самом файле: WebM с VP8/VP9, ProRes 4444, QuickTime Animation. ffmpeg их распаковывает в кадр с альфа-каналом, и ключ таким файлам не нужен — достаточно не выбрасывать альфу по дороге. Что для этого потребуется, когда дойдут руки: - при добавлении файла запоминать, есть ли у него альфа (`pix_fmt` с буквой «a»: yuva420p, yuva444p10le, argb); - такой клип считать несплошным так же, как клип с ключом, — то есть собирать участок слоями; - в цепочке фильтров следить, чтобы альфа не терялась: `scale` её сохраняет, а `pad` — только с прозрачным цветом полей; - аппаратное декодирование к таким файлам не применять: альфа в VP9 лежит отдельным потоком, и видеокарта его не отдаёт. Чего не будет в любом случае: раздать готовый ролик с прозрачностью в MP4/H.264 нельзя — контейнер и кодек альфу не хранят. Для этого нужен отдельный вывод в VP9 или ProRes 4444. ## Предпросмотр не показывает кадрирование обычного клипа Кадрирование и поворот видны в окне только у клипов с ключом или прозрачностью: их плеер кладёт поверх основы сам и применяет к ним цепочку фильтров. Обычный клип идёт списком кусков, а список фильтровать нечем — он играется как есть, во весь кадр. В готовом ролике при этом всё верно: такой кусок помечен на пересборку и обкладывается полями. Проверено опытом: у клипа выключен только ключ, кадрирование оставлено — окно показывает его во весь кадр. Почему нельзя просто добавить фильтр. Цепочка у mpv одна на весь список кусков, а кадрирование задаётся каждому клипу своё. Включить фильтр на одном куске и выключить на следующем нечем: из фильтров ffmpeg по времени переключаются только те, у кого есть поддержка временной шкалы, а у `crop` и `scale` её нет — есть только у `overlay`. Значит время включения выражается единственным способом: раздвоить поток, одну ветку обрезать и растянуть, и наложить её на другую с `enable='between(t,...)'`. Ветка при этом работает на каждом кадре фильма, а не только там, где клип виден. Замер (DJI 2688x1512, HEVC 55 Мбит/с, 600 кадров, `--vo=null`): | | время | кадров в секунду | |---|---|---| | без фильтра | 1.82 с | 330 | | ветка «обрезать и растянуть» с `enable` | 2.81 с | 214 | Нужно 60, то есть запас трёхкратный: путь через цепочку по деньгам проходит. Раньше здесь было написано, что для 2688x1512 это уже не пустяк, — написано по памяти о замере вписывания, а не об этом случае. Но есть путь дешевле. mpv умеет обрезать и увеличивать на выводе, силами видеокарты: свойства `video-crop`, `video-zoom`, `video-pan-x/y`, `video-rotate` есть в нашей версии 0.37. Они действуют на всё окно сразу, но плеером управляем мы и знаем, где курсор: зашли в клип с кадрированием — выставили, вышли — сняли. Ни цепочки, ни копирования кадров из памяти видеокарты в обычную. Ограничения: одно преобразование на всё окно, так что при одновременном наложении всё равно нужна цепочка; отражения таким свойством не задать; переключение на границе клипа придёт с запозданием в кадр-другой. ## Два видео рядом в одном кадре Два ролика 16:9, каждый обрезан до половины кадра: один слева до середины, другой от середины вправо. Никакого смешивания, просто два куска рядом. Сборке для этого не нужно ничего нового — только числа. Проверено на настоящих файлах, кадр получается с первого раза: [0:v]crop=1344:1512:672:0,pad=2688:1512:0:0,setsar=1[l]; [1:v]crop=1344:1512:672:0,setsar=1[r]; [l][r]overlay=1344:0[out] То есть каждому источнику своя обрезка, затем оба кладутся на свои места. Именно такой граф и строит `ArgsRenderLayers`: у слоя уже есть и своя цепочка фильтров, и координаты, куда его положить. Не хватает трёх вещей, и первая — главная. **Клипу негде записать, какое место в кадре он занимает.** Преобразование сейчас описывает только, как источник ложится в кадр целиком: вписать, заполнить с обрезкой, увеличение, смещение, поворот. Масштаб при этом всегда равномерный, поэтому из кадра 2688x1512 никакими настройками не получить полосу 1344x1512 — для неё нужно сжать вдвое по ширине и не трогать высоту. Нужен прямоугольник назначения: четыре числа в долях кадра проекта. Тогда всё остальное — вписывание, увеличение, смещение — начинает работать внутри него, а `BuildTransform` меняется только в аргументах: размер прямоугольника вместо размера кадра, а возвращаемые координаты сдвигаются на его начало. **Уплощение считает непрозрачный клип закрывающим всё.** Нижний клип подхватывается, только когда верхний полупрозрачный или с ключом. Значит половинка на верхней дорожке сегодня закроет собой нижнее видео чёрными полями. Условие должно смотреть на прямоугольник назначения: не накрывает кадр — значит под ним видно то, что ниже. **Предпросмотру нужна вторая дорожка наложения.** Сейчас плеер добавляет одну: основа — список кусков, поверх неё одна внешняя дорожка. Для двух половинок обе должны идти через цепочку над чёрной основой, то есть внешних дорожек нужно две. Механика та же самая — ещё один `video-add` и ещё один вход `[vidN]` в цепочке. Переключателей, которые стоят машинного времени, становится больше, а живут они кто где: прилипание и схлопывание — кнопками внизу, ключ в предпросмотре — в меню «Вид», выбор кодировщика вообще нигде (берётся NVENC, если он есть). Это разрозненно и не даёт увидеть общую цену. Нужно одно окно, где собрано всё, что можно выключить ради скорости: - ключ и прозрачность в предпросмотре (сейчас в меню «Вид»); - наложение в предпросмотре вообще — на слабой машине может не хватать и его, тогда честнее показывать одну основу; - кодировщик для пересборки: аппаратный или процессорный, и какой именно; - где держать кэш и когда его убирать; - прилипание клипов и курсора (сейчас кнопками, но им место и здесь). Почему это важно: разработка идёт на машине с быстрой видеокартой, и всё, что здесь считается «недорогим», на другой может оказаться неподъёмным. Пока цифры замеряны только на одной машине, у человека должна быть возможность выключить любую из этих трат. ## Сборка потоком: чего она не даёт Ролик собирается потоком — куски идут сразу в готовый файл, кэш не создаётся. За это заплачено тремя вещами, и все три известны заранее. **Продолжение стоит места.** Дописать в конец существующего MKV нельзя: Matroska этого не даёт. Продолжение всегда пишется в новый файл, куда сперва переливается целая часть старого, так что на диске в этот момент лежат оба — места нужно вдвое больше готового ролика. Обойти это можно только разбором и правкой самого контейнера, а это уже своя маленькая библиотека Matroska. **Отступ назад — до целого куска.** Продолжают не с последнего записанного кадра, а с границы последнего целого куска: кусок — это неделимая единица, у него свои метки времени и своё число кадров. На замерах терялось от нуля до нескольких секунд работы. Мельче отступать можно было бы, храня рядом с файлом карту стыков, но выигрыш в секундах не стоит нового файла, который надо держать в согласии с роликом. **MP4 продолжать нельзя вовсе.** Оглавление пишется в конец, оборванный файл не открывается — `moov atom not found`. Программа предупреждает об этом до начала сборки и предлагает MKV. Теоретически недописанный MP4 можно восстановить, собрав оглавление по кускам самому (так делают untrunc и подобные), но это отдельная задача другого размера. **Потоком идёт не всё.** MPEG-TS несёт не любой кодек, и пересборка всего ролика под площадку требует списка кусков. В этих случаях сборка идёт по-старому, через кэш — со всеми его 110 ГБ на часе материала. ## Мелочи, до которых не дошли руки **Вид дорожки не виден в её заголовке.** Дорожки картинки, звука и текста подписаны V1, A1, Т1, и по букве вид угадывается, но не более того. Клип, попавший на дорожку чужого вида, теперь не принимается и не теряется, но само различие стоило бы показать явно — значком или цветом полосы заголовка. **Значок файла программы под Windows.** Значок окна задаётся из `uIconData`, а значок самого `.exe` в проводнике берётся из ресурса при сборке — там он до сих пор стандартный. **Кэш наложений не убирается.** Каждая правка наплыва создаёт в кэше проекта новый файл; старые остаются лежать. Клипы с ключом и прозрачностью сюда больше не попадают — их показывает сам плеер, — так что расти кэшу теперь почти не с чего. **Окно кадрирования открывается около четырёх секунд.** Оно синхронно достаёт два кадра ffmpeg-ом (по 2.2 с каждый на шестигигабайтном файле) и только потом показывается. Лечится показом окна сразу и дорисовкой кадра по готовности, либо одним кадром вместо двух.