· 5 min read

Как мы создали нативный браузерный MP4-экспорт — не требуется сервер

PinePaper экспортирует видео MP4 полностью в браузере с помощью WebCodecs. Вот как работает конвейер H.264 — от холстовых кадров до воспроизводимого видеофайла, не загружая ничего.

Проблема

Традиционные веб-инструменты анимации экспортируют видео, отправляя кадры на сервер, кодируя их с помощью ffmpeg и возвращая результат. Это требует трех затрат: загрузка пропускной способности (отправка мегабайт данных кадра), вычисление сервера (время CPU / GPU для кодирования) и конфиденциальность (ваша творческая работа проходит через инфраструктуру третьей стороны).

PinePaper этого не делает. Файл MP4 полностью создан в вашем браузере. Никакие кадры не покидают ваше устройство. Кодирование происходит на аппаратном видеокодере вашей машины. Эта статья объясняет, как.

WebCodecs: аппаратное кодирование видео в браузере

WebCodecs API [W3C, 2021] обеспечивает низкоуровневый доступ к встроенному видеокодеру и декодеру браузера. Он был отправлен в Chrome 94 (сентябрь 2021 года) и теперь доступен в Chrome, Edge и Opera. Safari и Firefox имеют частичную или экспериментальную поддержку [Can I Use, 2026].

WebCodecs предлагает два ключевых интерфейса:

  • VideoEncoder — берет необработанные видеокадры, выводит закодированный H.264 (или VP8/VP9/AV1) битовый поток
  • VideoDecoder — берет закодированные фрагменты, выводит необработанные кадры (используется для воспроизведения, а не экспорта)

Для экспорта MP4 мы используем VideoEncoder. Рабочий процесс:

  1. Создайте VideoEncoder, сконфигурированный для H.264 с требуемым разрешением и битрейтом
  2. Для каждого кадра анимации: захват холста в виде VideoFrame, подача его к кодеру
  3. Соберите закодированные фрагменты (сырые единицы Н.264 NAL)
  4. Смешайте куски в контейнер MP4
  5. Предложите файл MP4 для загрузки

Шаг 1: Конфигурация кодера

const encoder = new VideoEncoder({
  output: (chunk, metadata) => {
    // chunk.data contains encoded H.264 bytes
    // metadata.decoderConfig contains SPS/PPS on first chunk
    muxer.addVideoChunk(chunk, metadata);
  },
  error: (e) => console.error('Encoder error:', e)
});

encoder.configure({
  codec: 'avc1.42E01E',  // H.264 Baseline Profile Level 3.0
  width: 1080,
  height: 1080,
  bitrate: 5_000_000,    // 5 Mbps
  framerate: 30
});

Строка кодека avc1.42E01E определяет базовый профиль H.264. Это наиболее совместимый профиль H.264 — он воспроизводится на каждом телефоне, браузере и платформе социальных сетей. Более высокие профили (Main, High) обеспечивают лучшее сжатие, но меньшую совместимость [Richardson, 2010].

Битрейт контролирует качество и размер файла. При 5 Мбит/с для 3-секундного клипа: 5,000,000 bits/s × 3s = 15,000,000 bits = ~1.8 MB. Фактический размер варьируется в зависимости от сложности контента — статические сцены сжимаются лучше, чем быстрое движение.

Шаг 2: захват кадра и кодирование

Для каждого кадра в временной шкале анимации:

for (let frameNum = 0; frameNum < totalFrames; frameNum++) {
  const frameTime = frameNum / fps;

  // Advance animation to this time
  app.setPlaybackTime(frameTime);
  paper.view.draw();  // Full render (not view.update!)
  await new Promise(r => requestAnimationFrame(r));  // Wait for paint

  // Create VideoFrame from canvas
  const frame = new VideoFrame(canvas, {
    timestamp: frameNum * (1_000_000 / fps)  // microseconds
  });

  // Encode (keyframe every 2 seconds)
  encoder.encode(frame, {
    keyFrame: frameNum % (fps * 2) === 0
  });
  frame.close();  // Release GPU memory
}

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

Шаг 3: MP4 Muxing

VideoEncoder выводит необработанные фрагменты H.264 (единицы NAL). Это не воспроизводимый файл — он должен быть завернут в контейнер MP4, который хранит время, метаданные и конфигурацию кодека.

PinePaper использует библиотеку mp4-muxer [Vani, mp4-muxer] для этого шага. Муксер получает закодированные фрагменты с метками времени и производит действительный файл MP4 с:

  • ftyp box: декларация типа файла (isom, iso2, mp41)
  • moov box: метаданные фильма, описания треков, таблицы времени
  • mdat box: фактические закодированные видеоданные

Результатом является стандартный MP4, который воспроизводится в каждом видеоплеере, браузере и платформе социальных сетей.

Шаг 4: Скачать

Завершенный MP4 собирается как Blob, преобразуется в URL через URL.createObjectURL() и запускается как загрузка:

await encoder.flush();  // Wait for all frames to encode
const mp4Blob = muxer.finalize();
const url = URL.createObjectURL(new Blob([mp4Blob], { type: 'video/mp4' }));

const a = document.createElement('a');
a.href = url;
a.download = 'animation.mp4';
a.click();
URL.revokeObjectURL(url);

Весь конвейер — захват кадра, кодирование H.264, MP4 и загрузка — происходит в браузере. Никакого сервера. Не загружать. Никакой обработки третьей стороной.

Выступление

На 2023 MacBook Pro (M2), кодирующий анимацию 1080×1080 на 30 FPS:

Продолжительность Каркас Кодировать время Размер файла
3 секунды 90 2 секунды ~1.8 MB
10 секунд 300 6 секунд ~5 МБ
30 секунд 900 18 секунд ~14 МБ

Кодирование происходит быстрее, чем в реальном времени, потому что аппаратные кодеры H.264 (Intel Quick Sync, Apple VideoToolbox, NVIDIA NVENC) обрабатывают тяжелые вычисления. Веб-кодеки браузера API делегируют эти аппаратные ускорители прозрачно [McIlroy, 2021].

Поддержка браузера

Браузер WebCodecs H.264 Код Статус
Chrome 94+ Да Да Полная поддержка
Edge 94+ Да Да Полная поддержка (хром)
Опера 80+ Да Да Полная поддержка (хром)
Сафари 16.4+ Частичный Только декодировать Код недоступен
Firefox За флагом Нет Экспериментальный

Для браузеров без WebCodecs PinePaper возвращается к экспорту GIF, который использует чистый кодер JavaScript (gif.js) и работает везде.

Ссылки

  • Можно ли использовать (2026) WebCodecs API таблица поддержки браузера. caniuse.com/webcodecs.
  • Макилрой, Д. (2021). W3C WICG. github.com/nicerobot/nicerobot.github.io/blob/master/nicerobot-explainer-webcodecs.md.
  • Ричардсон, I.E.G. (2010). H.264 Advanced Video Compression Standard (2-е изд.). Уайли.
  • Vani, A. mp4-muxer — JavaScript MP4 muxer для WebCodecs. github.com/nicerobot/nicerobot.github.io.
  • W3C (2021). Спецификация WebCodecs API. w3c.github.io/webcodecs/.

Экспорт MP4 видео бесплатно — без сервера, без регистрации, без водяного знака. Откройте [pinepaper.studio/editor] (/editor) и попробуйте.

Ready to create?

Start making animated GIFs, videos, and graphics — free, no signup.

Open PinePaper Editor