Розробка онлайн-редактора відео
Ми розробили кілька браузерних відеоредакторів, використовуючи різні підходи до рендерингу, і готові поділитися найкращими практиками для створення онлайн редактора відео. Відзначимо: коли клієнт просить зробити монтаж відео прямо в браузері — перше, з чим стикається команда: рендеринг фінального результату. Якщо одну хвилину ролика можна обробити на клієнті через FFmpeg.wasm, то десятихвилинне відео «зависне» навіть на потужному ноутбуці. Ми пройшли цей шлях на кількох проектах і виробили архітектуру, яка працює для будь-якого масштабу. У цій статті розберемо ключові архітектурні рішення: від типу рендерингу до реалізації таймлайну та завантаження файлів. Ви дізнаєтеся, як вибрати стек, щоб не переплачувати за сервери і не втрачати користувачів через гальма. Ми також розглянемо типові помилки, такі як створення тисяч запитів на один проект, і як їх уникнути. Якщо плануєте створити браузерний відеоредактор — ця стаття стане вашою архітектурною картою.
Ключові технології: Для розробки онлайн редактора відео з браузерним відеоредактором ми використовуємо таймлайн для відео, FFmpeg.wasm та WebCodecs API для клієнтського рендерингу, а для серверного — Remotion. Такий підхід дозволяє робити монтаж відео в браузері з обрізкою відео онлайн, накладанням тексту на відео та переходами для відео. Експорт відео в браузері відбувається через хмарний рендеринг відео.
Браузер vs Сервер: де рендерити?
Вибір між клієнтським і серверним рендерингом визначає весь стек і UX. Розглянемо обидва варіанти в таблиці.
| Параметр | Client-side (WebCodecs + FFmpeg.wasm) | Server-side (Remotion + FFmpeg) |
|---|---|---|
| Залежність від CPU користувача | Так | Ні |
| Максимальна тривалість відео | ~2 хв | Не обмежена |
| Час рендерингу 10 хв (CPU i7) | 5–15 хв | ~2 хв на GPU |
| Масштабування | Одне відео за раз | Паралельні завдання (Lambda) |
| Підтримка браузерів | Chrome 94+, Firefox 130+, Safari 16.4+ | Будь-який браузер (файл за посиланням) |
| Вартість інфраструктури | Нульова | Витрати на сервер (економія до 40% при високому навантаженні) |
Client-side рендеринг (WebCodecs API + FFmpeg.wasm): не потребує серверних потужностей, все навантаження на CPU користувача. FFmpeg.wasm рендерить 10 хвилин відео за 5–15 хвилин реального часу (залежить від CPU). WebCodecs API підтримується в Chrome 94+, Firefox 130+, Safari 16.4+. Ідеальний для коротких кліпів до 2 хвилин — без затримок, без серверних витрат. Server-side рендеринг (Remotion + FFmpeg): рендеринг на серверах з GPU, користувач отримує готовий файл за посиланням. Remotion дозволяє описувати відео як React-компоненти, що дає гнучкість і повторне використання. Масштабується через AWS Lambda — рендеринг паралельними чанками. Для комерційного продукту з відео більше 2 хвилин — це єдиний надійний шлях. Серверний рендеринг до 3 разів швидший для відео понад 5 хвилин. Наприклад, для десятихвилинного відео серверний рендеринг займає ~2 хвилини, тоді як клієнтський — 5–15 хвилин, тобто в 2.5–7.5 разів швидше. У офіційній документації Remotion (https://remotion.dev/docs/) описано всі деталі.
Влаштування часової шкали (таймлайн)
Центральна UI-концепція — таймлайн з доріжками (треками). Структура даних:
interface VideoProject {
id: string;
duration: number; // секунды
fps: number; // 24 | 30 | 60
width: number;
height: number;
tracks: Track[];
}
interface Track {
id: string;
type: 'video' | 'audio' | 'text' | 'image' | 'effect';
clips: Clip[];
muted: boolean;
locked: boolean;
volume: number; // 0–1
}
interface Clip {
id: string;
trackId: string;
assetId: string; // ссылка на загруженный файл
startTime: number; // позиция на таймлайне (секунды)
duration: number; // длительность клипа
trimStart: number; // обрезка начала исходного файла
trimEnd: number; // обрезка конца
speed: number; // 0.25 – 4.0
opacity: number;
transform?: ClipTransform;
filters?: VideoFilter[];
}
Дані зберігаються в сторі (Zustand або Redux) і синхронізуються з базою при збереженні. Drag-and-drop реалізуємо через @dnd-kit — він надійно працює з перетягуванням кліпів по треках.
Як розрізати кліп на таймлайні?
Split (розрізати кліп) — одна з базових операцій. Ось покроковий алгоритм:
- Визначте точку розрізу в секундах відносно таймлайну (наприклад, при перетягуванні маркера).
- Розрахуйте splitPoint = (atTime - clip.startTime) + clip.trimStart.
- Створіть два нових кліпи: лівий з trimEnd = splitPoint і правий з trimStart = splitPoint.
- Видаліть вихідний кліп і додайте нові.
Код розрізання кліпу
```ts const splitClip = (clipId: string, atTime: number) => { const clip = getClip(clipId); const splitPoint = atTime - clip.startTime + clip.trimStart;const leftClip: Clip = { ...clip, id: uuid(), duration: atTime - clip.startTime, trimEnd: splitPoint }; const rightClip: Clip = { ...clip, id: uuid(), startTime: atTime, duration: clip.startTime + clip.duration - atTime, trimStart: splitPoint, };
removeClip(clipId); addClip(leftClip); addClip(rightClip); };
</details>
### Попередній перегляд в браузері
Для попереднього перегляду використовуємо HTML5 `<video>` з синхронізацією через `currentTime`. Ось ключовий hook:
```tsx
const PreviewPlayer: React.FC = () => {
const { currentTime, isPlaying, tracks } = useEditorStore();
const videoRefs = useRef<Map<string, HTMLVideoElement>>(new Map());
useEffect(() => {
// Синхронизируем все видео-клипы с таймлайном
tracks.forEach(track => {
track.clips.forEach(clip => {
const video = videoRefs.current.get(clip.id);
if (!video) return;
const clipTime = currentTime - clip.startTime;
const isActive = clipTime >= 0 && clipTime <= clip.duration;
video.style.display = isActive ? 'block' : 'none';
if (isActive) {
const targetTime = clip.trimStart + clipTime * clip.speed;
if (Math.abs(video.currentTime - targetTime) > 0.05) {
video.currentTime = targetTime;
}
isPlaying ? video.play() : video.pause();
} else {
video.pause();
}
});
});
}, [currentTime, isPlaying]);
// ...
};
Скробінг по таймлайну робимо через mousedown/mousemove — розрахунок позиції в секундах від ширини контейнера.
Кліпи: drag, trim, split
Перетягування: при drag кліпу обчислюємо дельту і оновлюємо startTime з урахуванням пікселів на секунду. Обмежуємо межами проекту і сусідніми кліпами.
Trim (обрізка) реалізується аналогічно split, але без видалення вихідного кліпу: достатньо змінити trimStart/trimEnd.
Серверний рендеринг через Remotion
Remotion дозволяє описати відео як React-компонент. Передаємо проект через inputProps і рендеримо на сервері:
// Компонент для рендеринга
const VideoComposition: React.FC<{ project: VideoProject }> = ({ project }) => {
const frame = useCurrentFrame();
const { fps } = useVideoConfig();
const currentTime = frame / fps;
return (
<AbsoluteFill style={{ background: '#000' }}>
{project.tracks.flatMap(track =>
track.clips.map(clip => {
const clipTime = currentTime - clip.startTime;
if (clipTime < 0 || clipTime > clip.duration) return null;
return (
<OffthreadVideo
key={clip.id}
src={clip.assetUrl}
startFrom={Math.round(clip.trimStart * fps)}
style={{ opacity: clip.opacity }}
/>
);
})
)}
</AbsoluteFill>
);
};
Запуск рендерингу через API з використанням renderMediaOnLambda для масштабування.
Завантаження ассетів
Крупні файли (відео, аудіо) завантажуємо напряму в S3 через presigned URL — минаємо сервер додатку:
// 1. Запрашиваем presigned URL
const { uploadUrl, key } = await api.post('/api/editor/upload-url', {
filename: file.name,
contentType: file.type,
size: file.size,
});
// 2. Загружаем напрямую в S3 з прогрессом
const xhr = new XMLHttpRequest();
xhr.upload.addEventListener('progress', (e) => {
setProgress(Math.round(e.loaded / e.total * 100));
});
xhr.open('PUT', uploadUrl);
xhr.setRequestHeader('Content-Type', file.type);
xhr.send(file);
Цей підхід розвантажує сервер і підвищує швидкість завантаження.
Строки та що входить в роботу
Мінімальний редактор (таймлайн, обрізка, попередній перегляд, експорт через Remotion) — від 13 до 17 робочих днів. Повний функціонал з ефектами, переходами та аудіомікшером — 20–25 днів. Вартість базової версії — від 2000 доларів США. Економія на серверній інфраструктурі при використанні Remotion складає до 40%, що може становити близько 800 доларів на місяць при середньому навантаженні. Витрати на серверну інфраструктуру залежать від обсягу.
Відзначимо: Що входить в результат:
- Архітектура та код проекту з документацією API.
- Інструкція з розгортання (Docker Compose, .env).
- Доступи до репозиторію та CI/CD.
- 12 місяців гарантії на код та підтримка при впровадженні.
Орієнтовна вартість розраховується індивідуально після брифу.
| Етап | Час |
|---|---|
| Таймлайн (drag, trim, split) | 4–5 днів |
| Попередній перегляд (синхронізація відео) | 3–4 дні |
| Завантаження ассетів (S3 presigned) | 1 день |
| Текстові оверлеї, зображення | 2–3 дні |
| Remotion рендеринг + статус завдання | 3–4 дні |
| Аудіо (гучність, mute, fade) | 2 дні |
| Ефекти та фільтри (brightness, contrast) | 2–3 дні |
Мінімальний редактор (без ефектів і складних фільтрів): 13–17 робочих днів. Якщо ви шукаєте надійного партнера для створення онлайн редактора відео, звертайтеся — ми маємо досвід у розробці браузерних відеоредакторів для різних завдань.







