Как реализовать конвертацию видеофайлов в формат MP4 силами 1С и FFmpeg?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

В современной практике автоматизации бизнес-процессов часто возникает задача хранения медиаконтента непосредственно в информационной базе или во внешних хранилищах, связанных с 1С. Пользователи могут прикреплять к карточкам товаров, отчетам о выполненных работах или карточкам контрагентов видеофайлы самых разных форматов: .avi, .mkv, .mov, .wmv и другие. Однако для унификации отображения видео на различных устройствах (включая мобильные клиенты, тонкие клиенты и веб-интерфейс в браузере) требуется единый стандарт. Таким стандартом де-факто стал формат MP4 (с видеокодеком H.264 и аудиокодеком AAC).

В этой статье мы подробно разберем, как силами платформы 1С и свободно распространяемой кроссплатформенной консольной утилиты FFmpeg организовать надежную, производительную и полностью автоматическую конвертацию любых входящих видеофайлов в формат .mp4.

Архитектурные подходы: как организовать процесс конвертации?

Прежде чем перейти к написанию программного кода, проанализируем ситуацию и выберем оптимальную архитектуру. Конвертация видео — это крайне ресурсоемкая операция, которая нагружает центральный процессор и дисковую подсистему сервера. Если выполнять конвертацию в основном потоке непосредственно в момент прикрепления файла пользователем, интерфейс программы зависнет, что вызовет негативную реакцию.

Рассмотрим два основных сценария реализации этой задачи:

  1. Интерактивный помощник (для небольших файлов). Если бизнес-процесс предполагает загрузку коротких видеороликов (до 10-15 секунд, например, отчет мерчандайзера), мы можем использовать пошаговый помощник. На первом шаге пользователь выбирает файл, на втором — программа запускает фоновое задание и выводит индикатор ожидания. По завершении конвертации пользователю выдается результат.
  2. Асинхронная фоновая обработка (рекомендуемый вариант). Независимо от размера файла пользователь сразу прикрепляет его к карточке в исходном формате. Файл помечается специальным статусом (например, "В очереди на конвертацию"). Специальное регламентное задание периодически выбирает необработанные файлы, запускает процесс конвертации на сервере в фоновом режиме, заменяет исходный двоичный файл на готовый .mp4 и меняет статус на "Сконвертировано". В случае ошибки фиксируется лог для администратора. Такой подход гарантирует, что работа пользователей не будет заблокирована.

Подготовка окружения: кроссплатформенность сервера 1С

Разберем по шагам, как подготовить утилиту FFmpeg к работе. Часто разработчики совершают ошибку, сохраняя Windows-версию утилиты (ffmpeg.exe) в макет конфигурации в виде двоичных данных и выгружая ее на диск перед вызовом. В современных реалиях, когда многие серверы 1С работают под управлением операционных систем семейства Linux (Ubuntu, Astra Linux, РЕД ОС), такой подход приведет к неработоспособности системы.

Для обеспечения кроссплатформенности мы применим комбинированный метод: выясним тип платформы сервера и построим путь к утилите динамически. Если сервер работает на Linux, правильнее использовать системный пакет FFmpeg, установленный администратором через стандартный менеджер пакетов (например, с помощью команды sudo apt install ffmpeg). Для Windows-сервера мы можем выгружать исполняемый файл из общего макета или обращаться к заранее установленному пути.

Посмотрим на пример функции, определяющей путь к исполняемому файлу FFmpeg на сервере:


Функция ПолучитьПутьКFFmpeg() Экспорт
    
    СистемнаяИнфо = Новый СистемнаяИнформация;
    ТипПлатформы = СистемнаяИнфо.ТипПлатформы;
    
    // Проверяем, под какой ОС запущен сервер 1С
    Если ТипПлатформы = ТипПлатформыКомпьютера.Windows_x86 
        Или ТипПлатформы = ТипПлатформыКомпьютера.Windows_x86_64 Тогда
        
        // Для Windows выгружаем из макета во временный каталог, если файла там еще нет
        ПутьКФайлу = КаталогВременныхФайлов() + "ffmpeg.exe";
        ФайлНаДиске = Новый Файл(ПутьКФайлу);
        Если Не ФайлНаДиске.Существует() Тогда
            ДвоичныеДанныеМакет = УправлениеФайламиПереопределяемый.ПолучитьМакетFFmpeg();
            ДвоичныеДанныеМакет.Записать(ПутьКФайлу);
        КонецЕсли;
        Возврат """" + ПутьКФайлу + """";
        
    ИначеЕсли ТипПлатформы = ТипПлатформыКомпьютера.Linux_x86 
        Или ТипПлатформы = ТипПлатформыКомпьютера.Linux_x86_64 Тогда
        
        // В Linux утилита должна быть установлена в системе. Обращаемся напрямую по имени команды
        Возврат "ffmpeg";
    Иначе
        ВызватьИсключение "Неподдерживаемая операционная система сервера для конвертации видео.";
    КонецЕсли;
    
КонецФункции

Тонкости оптимизации параметров конвертации

Процесс конвертации можно настроить по-разному. Если бездумно перекодировать каждый файл, процессор сервера будет постоянно загружен на 100%. Выясним причину, как можно этого избежать.

Очень часто исходные файлы уже содержат видеопоток H.264 и аудиопоток AAC, но упакованы в контейнеры .mkv или .mov. В этом случае нам не нужно выполнять декодирование и повторное сжатие. Достаточно выполнить операцию ремуксинга (remuxing) — быстрой смены контейнера без изменения самих потоков данных. Это происходит практически мгновенно (за доли секунды) и не создает нагрузки на процессор. Команда для этого выглядит так:

ffmpeg -i input.mkv -c:v copy -c:a copy output.mp4

Если же исходный файл записан в старых форматах (например, MPEG-4 Visual, DivX или WMV), нам придется провести полноценное перекодирование. Для того чтобы сконвертированное видео могло воспроизводиться в веб-клиенте 1С без предварительного скачивания всего файла целиком, критически важно использовать флаг -movflags +faststart. Этот флаг переносит индексную таблицу (moov atom) в начало файла, позволяя браузеру запускать потоковое видео мгновенно.

Рассмотрим оптимальную универсальную команду конвертации:

ffmpeg -i input.avi -c:v libx264 -preset fast -movflags +faststart -c:a aac -b:a 128k output.mp4

Реализация запуска и перехват ошибок

При интеграции внешних программ разработчики часто сталкиваются с проблемой: как понять, успешно ли завершилась операция? Обычный метод ЗапуститьПриложение в синхронном режиме возвращает код возврата, но не показывает текстовое описание ошибки. Кроме того, утилита FFmpeg выводит весь технический лог и сообщения об ошибках в поток стандартного вывода ошибок (stderr), а не в стандартный вывод (stdout).

Разберем подробнее, как запустить процесс конвертации, дождаться его окончания и проанализировать возникшие ошибки. Мы перенаправим поток вывода ошибок в отдельный текстовый файл, который затем прочитаем средствами 1С.

Реализуем процедуру конвертации на сервере:


Функция СконвертироватьВидеоВMP4(ПутьКИсходномуФайлу, ПутьКВыходномуФайлу, СообщениеОбОшибке) Экспорт
    
    ПутьКFFmpeg = ПолучитьПутьКFFmpeg();
    КаталогВременныхФайлов = КаталогВременныхФайлов();
    ИмяФайлаЛогов = КаталогВременныхФайлов + "ffmpeg_error_" + Строка(Новый УникальныйИдентификатор) + ".log";
    
    // Формируем параметры запуска. 
    // Перенаправляем поток stderr (2) в файл логов. 
    // Флаг -y автоматически перезаписывает выходной файл, если он существует.
    ПараметрыЗапуска = СтрШаблон("%1 -i ""%2"" -c:v libx264 -preset fast -movflags +faststart -c:a aac -y ""%3"" 2>""%4""", 
        ПутьКFFmpeg, 
        ПутьКИсходномуФайлу, 
        ПутьКВыходномуФайлу, 
        ИмяФайлаЛогов);
    
    СистемнаяИнфо = Новый СистемнаяИнформация;
    ТипПлатформы = СистемнаяИнфо.ТипПлатформы;
    
    // Запускаем через командную строку операционной системы
    Если ТипПлатформы = ТипПлатформыКомпьютера.Windows_x86 
        Или ТипПлатформы = ТипПлатформыКомпьютера.Windows_x86_64 Тогда
        СтрокаЗапуска = "cmd.exe /c " + ПараметрыЗапуска;
    Иначе
        СтрокаЗапуска = "sh -c '" + ПараметрыЗапуска + "'";
    КонецЕсли;
    
    КодВозврата = Неопределено;
    
    // Запуск процесса с ожиданием завершения
    ЗапуститьПриложение(СтрокаЗапуска, , Истина, КодВозврата);
    
    // Анализируем результаты работы
    Успешно = (КодВозврата = 0);
    
    ФайлЛогов = Новый Файл(ИмяФайлаЛогов);
    Если ФайлЛогов.Существует() Тогда
        Если Не Успешно Тогда
            // Читаем текст ошибки из лог-файла
            ТекстовыйДокументЛога = Новый ТекстовыйДокумент;
            ТекстовыйДокументЛога.Прочитать(ИмяФайлаЛогов, КодировкаТекста.UTF8);
            СообщениеОбОшибке = ТекстовыйДокументЛога.ПолучитьТекст();
        КонецЕсли;
        
        // Удаляем временный файл лога
        Попытка
            УдалитьФайлы(ИмяФайлаЛогов);
        Исключение
            // Запись в журнал регистрации, если не удалось удалить временный файл
            ЗаписьЖурналаРегистрации("КонвертацияВидео.ОчисткаВременныхФайлов", 
                УровеньЖурналаРегистрации.Предупреждение, , , 
                ОписаниеОшибки());
        КонецПопытки;
    КонецЕсли;
    
    Возврат Успешно;
    
КонецФункции

Интеграция с подсистемами 1С: фоновая обработка

Для того чтобы встроить этот механизм в типовую или самописную конфигурацию, логично использовать функционал фонового выполнения задач. Если в вашей конфигурации используется Библиотека стандартных подсистем (БСП), мы можем задействовать подсистему "Файловые функции" или стандартный механизм регламентных заданий.

Опишем типовой алгоритм работы фонового регламентного задания:

  1. Регламентное задание выбирает из справочника присоединенных файлов (например, Справочник.НоменклатураПрисоединенныеФайлы) записи, у которых расширение файла отличается от mp4, а в специальном добавленном реквизите СтатусКонвертации установлено значение Перечисление.СтатусыКонвертацииВидео.ОжидаетОбработки.
  2. Для каждого файла создается временное имя на сервере, и двоичные данные файла выгружаются из базы данных на диск сервера 1С.
  3. Вызывается описанная выше функция СконвертироватьВидеоВMP4.
  4. В случае успешного завершения сконвертированный файл загружается обратно в хранилище 1С, расширение файла в карточке меняется на mp4, а статус переводится в Обработано. Старый исходный файл удаляется (или перемещается в архив для подстраховки).
  5. Если произошла ошибка, статус меняется на ОшибкаОбработки, а подробное описание ошибки записывается в Журнал регистрации 1С с указанием ссылки на карточку файла.

Посмотрим на пример реализации такого фонового обработчика:


Процедура ВыполнитьКонвертациюВидеоНаСервере() Экспорт
    
    // Запрос для выбора файлов в очереди
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ РАЗРЕШЕННЫЕ
        |	Файлы.Ссылка КАК Ссылка,
        |	Файлы.Наименование КАК Наименование,
        |	Файлы.Расширение КАК Расширение
        |ИЗ
        |	Справочник.НоменклатураПрисоединенныеФайлы КАК Файлы
        |ГДЕ
        |	Файлы.СтатусКонвертации = ЗНАЧЕНИЕ(Перечисление.СтатусыКонвертацииВидео.ОжидаетОбработки)
        |	И Файлы.ПометкаУдаления = ЛОЖЬ";
    
    РезультатЗапроса = Запрос.Выполнить();
    Выборка = РезультатЗапроса.Выбрать();
    
    Пока Выборка.Следующий() Цикл
        
        СсылкаНаФайл = Выборка.Ссылка;
        ИмяФайла = Выборка.Наименование;
        Расширение = Выборка.Расширение;
        
        // Создаем уникальные имена файлов на диске сервера
        УникальныйИдентификатор = Новый УникальныйИдентификатор;
        ВременныйВходнойФайл = КаталогВременныхФайлов() + "input_" + Строка(УникальныйИдентификатор) + "." + Расширение;
        ВременныйВыходнойФайл = КаталогВременныхФайлов() + "output_" + Строка(УникальныйИдентификатор) + ".mp4";
        
        // Получаем двоичные данные исходного файла и записываем на диск
        ДвоичныеДанныеФайла = РаботаСФайлами.ПолучитьДвоичныеДанныеФайла(СсылкаНаФайл);
        ДвоичныеДанныеФайла.Записать(ВременныйВходнойФайл);
        
        СообщениеОбОшибке = "";
        Успешно = СконвертироватьВидеоВMP4(ВременныйВходнойФайл, ВременныйВыходнойФайл, СообщениеОбОшибке);
        
        Если Успешно Тогда
            // Загружаем готовый mp4 файл обратно в 1С
            НовыеДвоичныеДанные = Новый ДвоичныеДанные(ВременныйВыходнойФайл);
            
            ОбъектФайл = СсылкаНаФайл.ПолучитьОбъект();
            ОбъектФайл.ЗаписатьДанныеФайла(НовыеДвоичныеДанные);
            ОбъектФайл.Расширение = "mp4";
            ОбъектФайл.СтатусКонвертации = Перечисления.СтатусыКонвертацииВидео.Обработано;
            ОбъектФайл.Записать();
            
            ЗаписьЖурналаРегистрации("КонвертацияВидео.Успех", 
                УровеньЖурналаРегистрации.Информация, 
                СсылкаНаФайл.Метаданные(), СсылкаНаФайл, 
                "Файл успешно сконвертирован в формат MP4: " + ИмяФайла);
        Иначе
            // Фиксируем ошибку в карточке файла и журнале регистрации
            ОбъектФайл = СсылкаНаФайл.ПолучитьОбъект();
            ОбъектФайл.СтатусКонвертации = Перечисления.СтатусыКонвертацииВидео.ОшибкаОбработки;
            ОбъектФайл.ОписаниеОшибкиКонвертации = СообщениеОбОшибке;
            ОбъектФайл.Записать();
            
            ЗаписьЖурналаРегистрации("КонвертацияВидео.Ошибка", 
                УровеньЖурналаРегистрации.Ошибка, 
                СсылкаНаФайл.Метаданные(), СсылкаНаФайл, 
                "Не удалось сконвертировать файл: " + ИмяФайла + Символы.ПС + СообщениеОбОшибке);
        КонецЕсли;
        
        // Обязательно очищаем за собой временные файлы на диске сервера
        Попытка
            УдалитьФайлы(ВременныйВходнойФайл);
            Если Успешно Тогда
                УдалитьФайлы(ВременныйВыходнойФайл);
            КонецЕсли;
        Исключение
            ЗаписьЖурналаРегистрации("КонвертацияВидео.ОчисткаВременныхФайлов", 
                УровеньЖурналаРегистрации.Предупреждение, , , 
                ОписаниеОшибки());
        КонецПопытки;
        
    КонецЦикла;
    
КонецПроцедуры

Подведем итоги

Мы спроектировали и детально разобрали отказоустойчивое решение по конвертации видеофайлов в формат MP4 силами платформы 1С и утилиты FFmpeg. Такой подход позволяет полностью удовлетворить требования бизнеса, не нагружая пользователей ручной конвертацией и сторонними инструментами.

Для успешного внедрения этого решения помните о следующих правилах:

← На главную