Створення конвертера відео в GIF за допомогою ffmpeg і WebAssembly

pic

Привіт, makkals,

Ця публікація є частиною серії статей про WebAssembly. Ознайомтесь з іншими частинами серії тут

Оригінальна публікація — https://hemath.dev/blog/webassembly/build-video-to-gif-converter-with-ffpmeg-webassembly/

Отже, ми вже ознайомились з теоретичними основами і навіть створили маленький практичний додаток за допомогою WebAssembly. Тепер давайте піднімемо планку і спробуємо побудувати додаток навколо рідної бібліотеки і подивимось, як це буде працювати.

У цій публікації ми створимо додаток, що використовує відому мультимедійну бібліотеку FFmpeg. Вона написана рідною мовою C++. Оскільки ми маємо інструмент Emscripten, ми можемо легко портати цю бібліотеку на веб.

Отже, давайте створимо додаток, який конвертує відео в GIF, не залишаючи браузера!

УВАГА: Ми не будемо компілювати бібліотеку FFMPEG у цій публікації. Ми скоріше використаємо попередньо скомпільовану версію, яка широко використовується в індустрії.

Ось швидкий перегляд додатку, який ми побудуємо.

pic

Налаштування

Перш ніж почати, нам потрібно налаштувати ffmpeg WASM у нашому проекті. На щастя, хтось вже зробив важку роботу, скомпілювавши всю бібліотеку C++ FFMPEG в WASM. Ми будемо використовувати проект ffmpeg.wasm. Все, що нам потрібно зробити, це завантажити та підключити код зв'язки до нашого проекту, щоб почати його використовувати.

Завантажте та розпакуйте наступний архів — https://registry.npmjs.org/@ffmpeg/ffmpeg/-/ffmpeg-0.12.15.tgz

Перемістіть розпаковану директорію в папку проекту.

Створіть HTML файл з наступною розміткою.



Convert Video to GIF
Convert to GIF            

Інтеграція ffmpeg.wasm

Бібліотека ffmpeg.wasm може використовуватися як модуль. Це означає, що ми можемо використовувати імпорти ES6 для підключення бібліотеки наступним чином,


Давайте створимо новий екземпляр FFMPEG прямо зараз і завантажимо WASM.  

Зверніть увагу, що ffmpeg.load() є асинхронною функцією. Щоб спростити приклад, я не обробляю асинхронну частину.
Отже, якщо ви пробуєте той самий код, дайте додатку кілька секунд перед тим, як спробувати конвертувати відео.

Налаштуємо необхідні DOM ідентифікатори, щоб мати змогу зручно працювати з DOM.


Тепер налаштуємо прослуховувач подій (Event Listener) для кнопки конвертації та створимо заготовку для методу.

async function convertToGif(videoFile) {  
 // TODO: Реалізувати  
}  

convertButton.addEventListener('click', async () => {  
 const videoFile = videoInput.files[0];  
 if (videoFile) {  
 await convertToGif(videoFile);  
 } else {  
 alert('Будь ласка, виберіть відеофайл!');  
 }  
});

Реалізація методу конвертації

Тепер, коли все налаштовано і чисто, настав час реалізувати функцію конвертації.

Прочитаємо вміст файлу як масив буферу.

const videoFileName = videoFile.name;  
const fileReader = new FileReader();  

const readFilePromise = new Promise((resolve, reject) => {  
 fileReader.onload = () => resolve(fileReader.result);  
 fileReader.onerror = reject;  
});  

fileReader.readAsArrayBuffer(videoFile);  

const fileBuffer = await readFilePromise;

Код зв'язки, який ми імпортували, управляє пам'яттю за кулісами для нас. Тому ми можемо просто передати звичайний типізований масив цілих чисел, а решта буде автоматично оброблена.

FFmpeg має свою внутрішню файлову систему. Щоб обробити файл, нам спочатку потрібно записати його у віртуальну файлову систему FFmpeg, після чого ми можемо виконувати операції з ним.

На щастя, код зв'язки надає нам метод writeFile, щоб зробити саме це.

await ffmpeg.writeFile(videoFileName, new Uint8Array(fileBuffer));

Після того, як ми записали файл, з яким будемо працювати, можемо передати параметри до ffmpeg, які визначають нашу операцію.

Зверніть увагу, що FFMPEG фактично є інтерфейсом командного рядка (CLI). Але його також можна використовувати як звичайну бібліотеку. Однак код зв'язки дає нам спосіб працювати як з CLI інтерфейсом. Це набагато простіше, ніж мати справу з численними функціями, які надає FFMPEG.

await ffmpeg.exec([  
 '-i', videoFileName, // Вхідний файл  
 '-vf', 'fps=10,scale=320:-1', // Відеофільтр: 10 кадрів за секунду, ширина 320px (висота автоматична)  
 '-c:v', 'gif', // Формат виводу: GIF  
 'output.gif' // Ім'я файлу виводу  
]);

Ця команда, очевидно, конвертує відеофайл у GIF. Я додав коментарі, що описують кожен параметр.

FFMPEG виконує операцію і записує результат у свою внутрішню файлову систему. Тому нам потрібно прочитати файл з її пам'яті. У нашому випадку ім'я файлу — output.gif.

Як ми мали функцію для запису файлу, так ми маємо і функцію для читання з файлової системи.

const data = await ffmpeg.readFile('output.gif');

Змінна data містить сирі байти. Щоб відобразити їх, нам потрібно перетворити їх на об'єкт URL.

const gifBlob = new Blob([data.buffer], { type: 'image/gif' });  
const gifUrl = URL.createObjectURL(gifBlob);

І, зрештою, встановимо цей URL як джерело для нашого елементу `` щоб ми могли побачити, як GIF відтворюється.

gifOutput.src = gifUrl;

Цього разу нам не потрібно піклуватися про зборку сміття чи інше.
Все добре обробляється файлом WASM і кодом зв'язки.

Об'єднуємо все разом



Convert Video to GIF
Convert to GIF                   

Висновок

Отже, ми побудували додаток з рідною бібліотекою, яка працює прямо в браузері. Тепер ми можемо по-справжньому побачити, що WebAssembly може привнести в веб. Раніше такі медіа-операції вимагали серверу для обробки. Але ми змогли створити конвертер без виходу з браузера.

Ви можете отримати вихідний код цього проекту з цього репозиторію — https://github.com/djhemath/Webassembly-demos/tree/main/video-to-gif

Слідкуйте за новим контентом про WebAssembly!

Оригінально опубліковано на https://hemath.dev.

Перекладено з: Build a video to gif converter with ffmpeg using webassembly

Leave a Reply

Your email address will not be published. Required fields are marked *