Пользователь прислал два клипа и скриншот. Инструмент для склейки видео отработал до 100%, написал «Applying transitions…» и упал с ошибкой: FS error: readFile 'merged.mp4'.
Ошибка честная и бесполезная. merged.mp4 действительно не существует. Но почему — непонятно, потому что процесс, который должен был его создать, уже завершился и ушёл дальше.
Знакомо? Разберём, как такое получается.
Суть проблемы: проверяли не то
Инструмент сначала приводит клипы к одному размеру, частоте кадров и кодеку, а потом склеивает. Если нужен переход — картинка через xfade, звук через acrossfade.
Для каждого клипа после нормализации стояла проверка: попытаться прочитать выходной файл. Если чтение падает — значит, в клипе нет аудио, и надо пересобрать его с тишиной.
Задумано было одно: если кодирование не удалось из-за отсутствия аудиодорожки, повторить с генератором тишины. Реализовано другое: если выходной файл отсутствует, повторить. Это не одно и то же.
ffmpeg, получив видео без звука и флаг -c:a libmp3lame, не падает. Он просто кодирует видео, не пишет аудиодорожку и выходит успешно. Файл существует. catch не срабатывает. А переход дальше строит фильтр [0:a][1:a]acrossfade — и не находит [0:a]. Всё падает уже на этапе склейки, а ошибка приходит поздно и показывает не ту строку.
Почему баг не всплывал раньше
Клипы со звуком работали идеально. Я тестировал на записях экрана с микрофоном и на телефонных видео. А вот файлы вообще без аудиодорожки — это AI-генерации, большинство экранных записей, видео, из которых звук уже вырезали. Это не экзотика, а целый класс обычных файлов.
Вторая причина интереснее. ffmpeg.wasm не отклоняет промис при ошибке ffmpeg. Метод run() разрешается независимо от того, успешно ли выполнилась команда. Поэтому любая ошибка внутри ffmpeg приходит поздно и валит не ту строку.
Что делать: проверять свойство, а не факт существования
Нельзя вывести «есть аудио» из «появился файл». Надо спросить напрямую. Функция hasAudio делает пробу: ffmpeg с параметрами -i, -vn, -map 0:a:0, -c copy, -t 0.05 пишет крошечный файл. Если в исходнике есть первая аудиодорожка — файл создаётся. Нет — не создаётся. Это стоит копейки по времени и отвечает на нужный вопрос.
Дальше команда выбирается один раз, без попытки починить результат: если звука нет, сразу добавляется anullsrc. Такой подход надёжнее, чем сначала запустить, потом ловить ошибку и переделывать.
Как тестировать код, который работает только в браузере
Ни на машине, ни на сервере ffmpeg-бинаря нет — весь смысл в том, что код исполняется в браузере пользователя через WebAssembly. Обычный headless-сценарий зависает, потому что виртуальное время в headless Chrome не сдвигает web worker.
Сработала страница, которая собирает фикстуры через lavfi, гоняет реальные проверки и отправляет результаты в PHP-файл POST-запросом. Один из тестов — проверка диагноза: acrossfade на двух клипах без звука не даёт выходного файла. Это важнее, чем тест самого исправления. Сначала докажи, что виноват именно тот компонент, который ты собрался чинить.
Общий паттерн ошибки
Завершение операции — не доказательство, что она сделала то, что нужно. Это доказательство, что она не упала.
Тот же паттерн встречается в другом виде:
- файл существует — значит, запись прошла успешно
- HTTP вернул 200 — значит, ответ содержит нужный ресурс
- команда вышла с кодом 0 — значит, она выдала результат
- catch не сработал — значит, всё пошло по плану
Каждая из этих проверок смотрит не на тот объект. Лечится одинаково: назвать свойство, от которого реально зависит код, и проверять именно его. Это всегда выглядит как лишняя работа, но именно она спасает от ошибок.
| Косвенная проверка | Прямой вопрос |
|---|---|
| Выходной файл существует | В исходнике есть аудиодорожка? |
| HTTP-статус 200 | В теле ответа нужные данные? |
| Код возврата 0 | В выводе есть результат? |
| catch не выполнился | Сценарий завершился без ошибки? |
И добавляем подстраховку: если переход теперь упадёт по другой причине, инструмент склеит клипы без перехода и скажет об этом, а не выдаст бесполезное FS error.
Так что правило простое: спрашивайте о том, что вам нужно знать, а не о том, что удобно проверить.
Комментарии (0)
Войдите, чтобы комментировать.
Пока нет комментариев. Будьте первым.