[Перевод] Как восстанавливали видео для Full Throttle Remastered. Часть 2

image


В моём предыдущем посте я рассказал, как мы извлекали контент из исходных FMV-файлов и создали инструменты для анализа примерно 67 ГБ архивов в поисках промежуточных составляющих частей, использованных для создания FMV. Эти части являются базисом для создания remastered-контента FMV и использовались в качестве «сборочных чертежей» для начала проекта.

Как сказано в предыдущей статье, рабочий процесс ремастеринга разделён на три ветви: ремастеринг нарисованных вручную кадров, ремастеринг 3D-моделей и ремастеринг звука. Ниже я расскажу об особенностях рабочего процесса и трюках, которые мы использовали для автоматизации создания основной части видео.
Мы увеличили размер всех оригинальных нарисованных вручную кадров, чтобы они соответствовали разрешению 4K (3840×2160). С учётом добавления ширины переделанной сцены и того факта, что игра отображалась неквадратными пикселями, это означало, что все remastered-ресурсы нужно было создавать в разрешении 4440×2400 пикселей.

Для ремастеринга всех нарисованных вручную кадров FMV мы решили использовать Adobe Animate, потому что у нас уже был готовый рабочий процесс после разработки Day of the Tentacle Remastered. Команда художников хорошо освоила этот процесс, поэтому другие варианты мы не рассматривали.

3e2b57098e68ff84ee833c7b56a3ad35.gif


Пример ремастеринга нарисованного вручную кадра

Исходные 3D-модели из архивов были в формате 3D Studio Release 3. К счастью, современные версии 3D Studio Max оказались способны импортировать все данные мешей и кинематографических ключевых кадров с помощью ещё одного скрипта автоматизации. После этого мы преобразовывали этот промежуточный файл для работы в Autodesk Maya, где художники занимаются своей магией ремастеринга.

Для придания поверхностям мешей нового стиля были применены новые шейдеры, нанесены текстуры повышенного качества, а данные мешей были значительно дополнены, чтобы придать модели более гладкий вид. Кроме того, было расширено кадровое окно для всех камер видеовставок, чтобы оно соответствовало рабочему разрешению 4440×2400 пикселей, потому что камера в оригинале была рассчитана на более узкое соотношение сторон.

df99497bdfb6c540ef07e330cb9142b8.gif


Пример ремастеринга 3D-моделей

Что касается аудио, то нам удалось найти большинство оригинальных высококачественных версий, но были и исключения. Записи студии англоязычной озвучки были упакованы в архивы, но озвучка на других языках, которой занимались внешние партнёры, была нам недоступна. Кроме того, нам удалось найти оригинальную музыку The Gone Jackals, которая использовалась в FMV. Некоторые версии звуковых эффектов (SFX) были заменены более «плотно» звучащими с похожим типом звука.

Ниже показана блок-схема, приблизительно объясняющая, как мы обрабатывали исходные ресурсы и привязывали их к remastered-контенту. Оригинальные извлечённые (с помощью SanExtract.exe) кадры видео использовались в качестве «первоисточника» для сравнения со всеми файлами данных архивов. Файлы манифестов архивов сгенерированы при помощи рекурсивного поиска по всем архивным данным; они применялись для быстрого нахождения всех уникальных файлов определённого типа.

Инструмент SanWrangler использовался для визуального сравнения оригинального «первоисточника» кадров и архивных данных. Пользователь мог визуально привязать архивные файлы к оригинальным кадрам и сохранить их как карту зависимостей в формате XML. После создания карты зависимостей было достаточно использовать скрипт на Python для автоматической генерации нарисованных вручную кадров из оригинальных ресурсов файлов-«чертежей», а также «сборочных чертежей» для Maya 3D. Эти файлы стали отправной точкой для команды художников, приступившей затем к ремастерингу.

c2dfa030a1899e9fb679ebd17caf1ee2.png


Извлечение оригинальных ресурсов и создание «сборочных чертежей»

Это был первый из множества шагов, в результате позволивших получить нам готовые FMV remastered-версии. Да, разумеется, теперь у нас есть начальная точка всех файлов, которые нужно переделать, но как соединить вместе все эти фрагменты?

Ниже я расскажу о способах автоматизации, использованных в рабочем процессе изготовления FMV. Эти способы можно использовать не только для генерирования FMV и применять не только для одной игры; мне кажется, они достаточно универсальны, и ими можно пользоваться во многих аспектах разработки игр.

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

Мы совершенно точно знали, как должны выглядеть и звучать видео для Full Throttle Remastered, поэтому нам просто нужно было улучшить их графику и звук. Все видео должны были соответствовать оригиналам, кадр за кадром, в том числе пути движения камер, громкость звуков, панорамирование и т.д. Чтобы добиться этого, нам нужно было знать, как выглядел рабочий процесс создания оригинальных FMV. И эти 67 ГБ данных из архивов LucasArts содержали множество подсказок о том, как всё работало в оригинале. Они стали для нас отличным стартом.


Пусть это звучит немного ностальгически, но я считаю, что важно обсудить аспекты «цифровой археологии» такого ремастеринга игр. В конце концов, понимание процесса создания оригинала позволить ответить на множество вопросов и даст подсказки о том, как ресурсы превращались в готовый результат. И при создании новых переделанных FMV нам нужно применять к нашим исходным remastered-ресурсам те же преобразования, чтобы готовый продукт выглядел как можно более близким к оригиналу. В том числе нам нужно было следующее:

  • Расположение аудиодорожек на временной шкале
  • Настройки громкости и панорамирования аудиодорожек при воспроизведении в игре
  • Композиция кадра и размещение каждого кадра видео в готовом продукте


Инструмент под названием SMUSHFT (SMUSH for Full Throttle) позволял создателю FMV размещать ресурсы видео и звука на временной шкале, а затем кодировать получившийся FMV-ролик (в формате .san), который считывался игровым движком. Все видео были разделены на серии кадров, которые склеивались при создании готового результата. SMUSHFT позволял пользователю визуально перемещать эти ресурсы вдоль временной шкалы и при необходимости переделывать видео.

Можно и не упоминать, что я не принимал участия в создании оригинальной игры. Я мог только догадываться, как создавались оригинальные ресурсы, изучая архивные данные и просматривая форматы и исполняемые файлы, упакованные в эти данные. Похоже, что 3D-модели создавались в Autodesk 3D Studio Release 3, а нарисованные от руки части — в DeluxePaint Animation v1.0. Также мне неизвестно, какие из каких этапов состояла генерация данных о форме сигналов для аудио, но в каждом использованном аудиоклипе (в формате .sad) содержится информация о громкости и панорамировании по ключевым кадрам, применяемая для микширования звука в процессе выполнения игры.

c0392161ae29aa540fe78d7a6485a232.png


Процесс создания оригинальных FMV

После создания этих отдельных частей кадра выполнялся процесс комбинирования кадра. Этот процесс комбинировал 3D-рендеры кадра с нарисованными вручную кадрами анимации (вместе со всем остальным), создавая готовый продукт, используемый инструментом SMUSHFT (файлы .nut). После того, как проект был готов к кодированию, видео обрабатывалось и готовый результат (.san) уже можно было воспроизводить в игровом движке.

SMUSHFT выполнял окончательное кодирование файлового формата оригинального видео (.san), а у каждого видеофайла был файл проекта (.pro), описывавший сборку видео (звук, видео, расположение субтитров). Мы хотели извлечь эту информацию, чтобы можно было сгенерировать файл проекта Adobe Premiere Pro и использовать его для кодирования переделанной версии видео в разрешении 4K. Для этого нам нужно было выполнить реверс-инжиниринг файла проекта SMUSHFT.


Здорово иметь исходный код, ведь можно просто изучить его и понять, как создавался/считывался файл проекта. Без исходного кода приходится открывать файл проекта в hex-редакторе и анализировать паттерны внутри файла. Именно этим способом мы воспользовались для извлечения полезного контента из файла проекта SMUSHFT.

Поскольку мы могли запускать оригинальный SMUSHFT в DOSBox, то видели пользовательский интерфейс программы, который дал нам подсказки о формате файлов. Посмотрите на этот скриншот открытия оригинального файла .pro:

cbb85463b67ad09d81d939f442f9fdc0.png


Пример проекта SMUSHFT

Здесь можно заметить следующее: в файле есть именованные ресурсы (2027.NUT, 2027.SAD, IN_06A.NUT и т.д.). Такие именованные ресурсы скорее всего внутри файла будут отображаться символами ASCII. Кроме того в верхней части временной шкалы есть счётчики кадров, а слева от шкалы есть увеличивающиеся номера слоёв. И последнее — каждый ресурс на шкале времени находится на конкретном номере кадра и имеет определённую длительность. Если мы сможем извлечь эту информацию из оригинальных файлов проекта, то она позволит нам узнать, где автоматически располагать новые ресурсы на временной шкале Adobe Premiere Pro.

3e5de59049c14a72bb8373a0c72b48a0.png


Пример проекта Adobe Premiere Pro

Открыв оригинальный файл проекта в hex-редакторе, можно получить довольно полезную информацию. Посмотрите на показанный выше пример в шестнадцатеричном виде:

b5f00805485c3d4a8af811c4dc359063.png


Файл проекта SMUSHFT в Hex-редакторе

Мы можем начать просматривать файл .pro с помощью hex-редактора (я предпочитаю Hexplorer) и попробовать поискать паттерны. Можно легко найти именованные ресурсы в формате ASCII с нулевым байтом в конце. Примерно в той же области памяти есть группа значений, хранящихся как shorts (двухбайтные integer). Сравнение чисел, отображаемых в инструменте SMUSHFT, с
числами из файла проекта в hex-формате даёт нам базис для правильного преобразования оригинального файла проекта в современный видеоредактор наподобие Adobe Premiere Pro.


Основная часть этого рабочего процесса была автоматизирована и не требовала вмешательства человека. Одна из причин этого заключалась в том, что содержимое всех видео полностью скопировано с оригинала; на самом деле мы делали просто апгрейд контента. А поэтому у нас практически не было было возможности полностью изменить формат FMV. Нам требовалось всего лишь найти способ воссоздания видео с помощью ресурсов высокого разрешения, минимизировав при этом время работы над продуктом.

Во-первых, нужно сказать, что серьёзным начальным шагом перед автоматизацией всего процесса должен стать разговор с коллективом создателей контента (графики и аудио). Причина заключается в том, что большинство процессов автоматизации требует от создателей придерживаться определённого набора правил о подготовке проектов, расположении файлов, используемых инструментах и т.д. В нашем проекте это означало, что мы должны были обговорить инструменты создания контента рисуемых вручную кадров, 3D-моделей и звуков, а затем и видеоредактора для сборки всего этого вместе. Также нужно было прийти к согласию о том, какие части рабочего процесса будут выполняться вручную, а какие будут автоматизированы.

В результате мы решили следующее:

  • Вручную рисуемые кадры будут создаваться в Adobe Animate с разрешением 4440×2400 пикселей
  • 3D-модели и анимации будут создаваться в Autodesk Maya и рендериться вручную, тоже с разрешением 4440×2400 пикселей
  • Аудиофайлы будут создаваться в формате .wav с параметрами 48КГц и 16-бит
  • Фрагменты видео изначально будут генерироваться автоматически, а художник сможет изменять любую нужную ему часть (за некоторыми исключениями)
  • Финальные этапы сшивки и кодирования FMV будут автоматизированы


Чтобы сделать инструменты как можно более автоматизированными, мы использовали несколько способов. В качестве «клея», соединяющего всё вместе, был выбран Python, потому что он хорошо расширяется различными библиотеками, а код легко писать и поддерживать. Также мы воспользовались его внутренней поддержкой платформонезависимых манипуляций с файлами (копирования, перемещения, удаления).

Python — вызов исполняемых файлов, получение результатов


Нам идеально подошла библиотека subprocess языка Python, потому что она позволяет изменять выполнение других исполняемых файлов и даже ждать завершения выполнения их задач. Она позволяет получать возвращаемый программой код и получать доступ к буферу stdout & stderr.

import subprocess
 
# The command to execute
command = 'SanExtract.exe -f -i credits.san -o \"C:/output_dir/\" '
 
# Execute the command via subprocess
child = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 
 
# Wait for process to complete, returns stdout & stderr buffers
stdout, stderr = child.communicate() 
 
# Retrieve the return code from the process
return_code = child.returncode


Пример взаимодействия с исполняемыми файлами на Python

Python — Win32 API


Win32 API очень полезен, потому что он дал нам доступ к передаче из скрипта сообщений клавиатуры и мыши ОС Windows. Например, можно создать функцию, щёлкающую мышью в определённых координатах X, Y экрана:

import win32api
 
def ClickXY(x,y):
    win32api.SetCursorPos((x,y))
    win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN,x,y,0,0)
    win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP,x,y,0,0)


Пример симуляции щелчка мышью на Python

Можно даже отправлять события нажатий на клавиатуру (с модификаторами или без них):

import win32api
import win32con
 
def PressKey(code, modifierCode=None):
    if modifierCode:
        win32api.keybd_event(modifierCode, 0, 0, 0)
 
    win32api.keybd_event(code, 0, win32con.KEYEVENTF_EXTENDEDKEY | 0, 0)
    time.sleep(0.021)
    win32api.keybd_event(code, 0, win32con.KEYEVENTF_EXTENDEDKEY | win32con.KEYEVENTF_KEYUP, 0)
 
    if modifierCode:
        win32api.keybd_event(modifierCode, 0, win32con.KEYEVENTF_KEYUP, 0)


Пример симуляции нажатий на клавиатуру на Python

Есть и множество других возможностей, но для достижении наших целей очень помогли показанные выше примеры. Можно передать любой активной программе события клавиатуры и она начнёт печатать их, как будто мы вводим что-то с клавиатуры, в том числе и нажатия горячих клавиш.

Python — компьютерное зрение для нажатия на кнопки


Самым уникальным опытом было использование ПО компьютерного зрения в тех инструментах, которые невозможно было автоматизировать через внутренние скрипты. Большинство современных инструментов имеет поддержку скриптинга, но всё равно требует вмешательства пользователя. Например, 3D Studio Max позволяет запускать файлы MAXScript из командной строки. В нашем случае мы запускаем скрипт автоматического импорта файла 3D-меша, после чего автоматически запускается 3D Studio Max и отображает диалговое окно Shape Import, в котором пользователь должен щёлкать по кнопкам:

ddcb3e4f9a830a8e72d9697eacf19b74.png


Пример диалгового окна Shape Import

Так что же — мы написали скрипт для автоматизации, и теперь нам придётся сидеть перед экраном, нажимая на клавиши? Вместо того, чтобы сидеть за клавиатурой и ждать появления всплывающего окна, мы можем заставить скрипт сделать скриншот, воспользоваться привязкой OpenCV к Python для поиска шаблона изображения кнопки и автоматического нажатия на неё. Вот как выглядит шаблон изображения для описанного выше примера.

b1e67caf30b4ea94761063bb6ead063c.png


Шаблон изображения для ok_button.png

Стоит заметить, что шаблон изображения содержит дополнительные черты (текст для «Single Object» и «Multiple Objects»). Это позволяет нам получать более детерминированный результат поиска. Ниже показан пример скрипта на Python, использованный для автоматического нажатия на найденном расположении шаблона изображения:

import cv2
import ImageGrab
 
# "Constants"
TEMPLATE_THRESHOLD = 0.25
CLICK_OFFSET = 20
 
# Read the template image to search for
template_image = cv2.imread('images/ok_button.png', 0)
 
# Screenshot the current desktop and load it to a cv2 format
screen = ImageGrab.grab()
screen.save('screen.png')
screen_image = cv2.imread('screen.png', 0)
 
# Search for the template within the screenshot and retrieve search results
match_result = cv2.matchTemplate(screen_image, template_image, cv2.TM_SQDIFF_NORMED)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(match_result)
 
# If below the threshold, it's likely we know where to click
if min_val < TEMPLATE_THRESHOLD:
    ClickXY(min_loc[0]+CLICK_OFFSET, min_loc[1]+CLICK_OFFSET)


Пример нажатия на экранный элемент с помощью OpenCV, написанный на Python

Все приведённые выше примеры основаны на Python. Но бывают случаи, когда нам нужен более точный контроль над оконной системой ОС Windows. Это заставило нас разработать нативные инструменты, использующие Windows Automation API.

Windows Native (C++) — Windows Automation API


Windows Automation API даёт доступ к устаревшему Microsoft Active Accessibility API (MSAA), а также к Microsoft UI Automation API. Подробнее об этом можно прочитать на странице Microsoft.

В результате мы добились того, что смогли осуществлять запросы к определённым элементам интерфейса Windows (кнопкам, текстовым полям, вкладкам, пунктам меню), узнавать, где пространственно расположены эти элементы на экране и нажимать их/взаимодействовать с ними. В Windows SDK также есть инструменты тестирования, позволяющие видеть, к каким свойствам имеется доступ. Они позволили нам выяснить, что можно автоматизировать в каждой конкретной программе.

Для отображения иерархии управления окнами программы довольно полезно приложение Inspect.exe; оно позволяет получить примерное представление о том, где находятся такие объекты, как элементы управления меню, и понять, как ссылаться на элементы окон с помощью вызовов API автоматизации.

0f2d3f650f30c4982f10d9d31b94c35c.png


Пример Inspect.exe

После того, как вы узнаете иерархию управления программы Windows, вы будете знать, как найти её из дескриптора основного окна и научитесь нажимать на разные элементы через API:

#include 
#include 
 
// Click on a sub-menu item given the Window & Menu handles.
void ClickSubMenu(HWND hwnd, HMENU hmenu, const char *pMenuName)
{
    // Iterate through the menu items of the window
    int menu_item_count = GetMenuItemCount(hmenu);
    for(int menu_id = 0; menu_id < menu_item_count; ++menu_id)
    {
        char menu_name[MAX_PATH];
        int len = GetMenuString(hmenu, menu_id, reinterpret_cast(&menu_name[0]), sizeof(menu_name), MF_BYPOSITION);
 
        // Look for the specific menu you're searching for and click it
        // Make sure to set the window active before doing it...
        if(!strcmp(pMenuName, menu_name)) {
            // now get the rect and click the center
            RECT rect;
            BOOL success = GetMenuItemRect(hwnd, hmenu, menu_id, &rect);
            if(success) {
                SetActiveWindow(hwnd);
                POINT point = GetMiddlePoint(rect);
                SetCursorPos(point.x, point.y);
                mouse_event(MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_LEFTDOWN, point.x, point.y, 0, 0);
                mouse_event(MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_LEFTUP, point.x, point.y, 0, 0);
                Sleep(DO_TASK_INTERVAL_WAIT_MS);
            }
        }
    }
}


Пример нажатия элемента управления окном на C++

И разумеется, передача нажатий клавиатуры активному окну тоже выполняется просто:

#include 
#include 
 
// Type the character string to the given window handle
static void TypeCharacters(HWND window_handle, const char *pString) {
    int len = strlen(pString);
    for(int count = 0; count < len; ++count)
    {
        SendMessage(window_handle, WM_CHAR, (WPARAM)pString[count], (LPARAM)0);
        Sleep(CHARACTER_REPEAT_INTERVAL_MS);
    }
}


Пример симуляции нажатий клавиатуры на C++

Разумеется, эти API обладают гораздо более широкими возможностями. Я выяснил, что благодаря инструменту Inspect.exe можно пролить свет на то, к каким элементам окна программы можно получить доступ.

Промежуточные текстовые форматы


Часть нашего рабочего процесса заключалась в сохранении файлов в текстовом виде и в изменении значений в этих текстовых файлах. В конце концов, инструменты имеют пользовательский интерфейс для изменения состояния вспомогательных данных. И если знать, какими должны быть эти вспомогательные данные, то необязательно работать с инструментом, достаточно просто изменять вспомогательные данные. Хитрость в том, что нужно знать, как манипулировать этими вспомогательными данными; при изменении проприетарных форматов файлов это может оказаться сложной задачей. Разве не было бы здорово, если бы у всех имелся простой текстовый файл, с которым можно работать?

Хитрость в том, что нужно найти способ обхода проприетарных форматов файлов, используемых большинством инструментов. Решение обычно заключается в применении опций Import и Export, присутствующих в большинстве современных коммерческих инструментов. Вот несколько примеров:

Adobe Premiere Pro сохраняет файлы в проприетарном формате, но можно импортировать/экспортировать проекты как Final Cut Pro XML. После экспорта в XML можно изменить XML нужным нам образом и заново импортировать проект обратно в Adobe Premiere Pro.

Ещё один пример — исправление ссылок на текстуры, используемых в устаревшем формате 3D-мешей Autodesk 3D Studio Release 3. При импорте оригинального файла меша мы сохраняем только что преобразованный меш в промежуточный файл .fbx, использующий символы ASCII. В этом формате можно обработать текстовый файл и заменить все строки ссылок текстур на правильные.

Adobe Animate/Flash довольно забавен, поскольку оказывается, что файлы .fla на самом деле являются немного «сломанными» файлами .zip. В несжатом виде они хранятся в формате XFL, который может ссылаться на другие объекты XFL (например, на битовые изображения) из локальной папки. Ведущий инженер Double Fine Оливер Францке создал модифицированный скрипт на Python для упаковки/распаковки файлов .fla с помощью ZIP, чтобы мы могли создавать/изменять эти файлы.


3D Studio Max


Современная версия 3D Studio Max использовалась для импорта оригинального файла .prj в сцену и для сохранения в ASCII-формат .fbx. Для каждого файла .prj, который нужно было конвертировать, из скрипта Python автоматически генерировался файл MaxScript (.ms), который выглядел примерно так:

importFile "G:\FullThrottle_Backup\FullThrottle_SourceAssets\BENBIKE.PRJ" #noPrompt


Пример импорта 3d-модели с помощью MaxScript

После чего этот файл .ms просто вызывался командой Python для запуска в 3dsmax.exe:

3dsmax.exe -U MAXScript "C:\FullThrottleRemastered\import_prj.ms"


Пример консольной команды для вызова исполняемого файла с указанным файлом MaxScript

Как сказано выше, в этом случае в 3D Studio Max открывалось диалоговое окно, на которое нужно было нажать. Связка OpenCV с Python помогла нажимать на кнопку в этом окне, чтобы оригинальный файл импортировался без вмешательства пользователя. После импорта файла нажималась серия клавиш меню (с помощью win32api Python) для запуска ещё одного файла MAXScript, который экспортировал модель как файл .fbx в ASCII-формате. Так как .fbx сохранялся как обычный текстовый файл, все строки зависимостей текстур модели заменялись ссылками на изображения в современном формате. Затем изменённый файл .fbx снова автоматически загружался в 3DSMax и экспортировался как файл .max. На этом этапе файл .max можно было отправлять художнику для ремастеринга.

Adobe Animate/Flash


Adobe Animate/Flash использовался для ремастеринга всех нарисованных вручную ресурсов FMV. Мы взяли оригинальные нарисованные вручную кадры (размером 320×200 пикселей), найденные инструментом SanWrangler, и использовали их в качестве «сборочных чертежей». Масштаб изображений был увеличен, чтобы соответствовать размеру 4440×2400 пикселей, после чего с помощью скрипта на Python автоматически генерировался файл .fla.

Затем достаточно было автоматически сгенерировать файл .fla с нуля, воспользовавшись нашими знаниями формата XFL Adobe Animate/Flash. Мы смогли использовать набор инструментов, уже созданный Оливером Францке, для генерации сборочных чертежей файлов нарисованной вручную анимации.

Adobe Premiere Pro


Для определения того, какие элементы управления Premiere Pro находятся на экране, нам очень помог Windows Automation API. В некоторых случаях у них не было горячих клавиш. После получения координат элементов меню нужно было переместить курсор в эти координаты и отправить событие щелчка мыши.

Всё это замечательно, но некоторые элементы управления рендерятся другими способами, и поэтому невидимы для Windows Automation API. Для этого случая мы решили использовать связку OpenCV и Python, чтобы иметь возможность использования OpenCV в среде скриптов. Особенно полезно это было при работе с Adobe Premiere Pro: хотя в нём имеется частичная поддержка скриптов на JavaScript, тип нужного элемента управления не был доступен через API.

Кроме того, файлы проекта Adobe Premiere Pro хранятся в проприетарном двоичном формате. Следовательно, мы не могли просто волшебным образом создать файл Premiere Pro, зато могли воспользоваться функцией импорта, позволившей нам импортировать данные в файл Final Cut Pro, имеющий формат XML. Затем достаточно было сгенерировать правильный файл XML, надлежащим образом располагавший все ресурсы на временной шкале, после чего автоматически импортировать этот .xml Final Cut Pro для преобразования в нужный формат. Потом мы могли поставить экспортированные кадры в автоматизированную очередь, чтобы можно было скомбинировать их в готовое видео.


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

f262c77cf9d06f1fb6828e356ce40cc8.png


Упрощённая блок-схема автоматизации Remastered FMV

Можно заметить, что бОльшая часть работы с Adobe Premiere Pro требует использования Python, а также специализированного нативного кода Windows. Причина заключается в сложной структуре окон Premiere Pro, а также в необходимости использования нативного Windows Automation API для обеспечения правильного взаимодействия со всеми зависимыми дочерними окнами этого приложения.


Используя описанные выше методы, мы смогли настроить несколько машин автоматизации, чтобы разделить на части работу над всеми видео. Также в рабочий процесс был интегрирован Slack Bot для передачи обратной связи об автоматизации в наш канал Slack по состоянию видео, проходящих по конвейеру обработки, чтобы мы знали, когда что-то пойдёт не так.

9b536df197475f6235282ac084c2efc8.gif


Пример автоматизации Adobe Premiere Pro
Всё это звучит отлично, но на деле при реализации проекта мы столкнулись с проблемами. Я перечислю только основные пункты.

1) Итерация микширования готового аудио. Ремастеринг всех аудиофайлов выполнялся постепенно. Поэтому, когда у нас появлялся, например, звуковой эффект «БУМ!», инженер по звуку понятия не имел, куда его вставить в аудиомиксе, поэтому ему приходилось ждать кодирования видео, чтобы узнать, что же там бабахнуло.

2) Хранение несжатых промежуточных файлов. Кадры хранились в несжатом формате до самого последнего момента кодирования в готовое видео. Поэтому приходилось хранить в локальном хранилище большое количество кадров, часть из которых сохранялась в системе контроля версий. Такое разрастание хранимого объёма было очень заметным и при использовании некоторых систем управления версиями может стать довольно затратным (мы пользовались Perforce).

3) Время выполнения работы. Солидная часть рабочего процесса была автоматизирована, и это позволило инженерам заниматься другими вещами. Однако время создания одного видео может быть довольно долгим. Самая затратная по времени часть — это кодирование кадров в разрешении 4k. У нас были способы исследования состояния ресурсов внутри Perforce, чтобы понять, какие этапы нужно выполнить заново, но этот метод был не настолько разделён на части, как бы того хотелось.


Да, статья получилась объёмной! Хотя наша реализация этого рабочего процесса достаточно специфична для проекта, я считаю, что отдельные методы автоматизации можно использовать при разработке любой игры. Разобравшись с видео, можно рассмотреть смежную тему — воспроизведение FMV во время выполнения игры. Сюда относятся такие вопросы, как кодирование многоязыкового аудиопотока, а также синхронизация кадров при воспроизведении оригинальных FMV. Ждите выхода третьей части статьи!

© Habrahabr.ru