Rust и FFmpeg: Новый способ создания пользовательских видеофильтров

от автора

Введение

FFmpeg — это мощный инструмент для работы с мультимедиа, который используют для кодирования, декодирования, перекодирования и применения фильтров к видео и аудио. Но если вы работаете с Rust, интеграция с C API FFmpeg может стать настоящей головной болью: управление памятью, проблемы безопасности и крутая кривая обучения. Особенно сложно реализовать пользовательские фильтры — для этого обычно нужно писать код на C и разбираться во внутренностях FFmpeg. А что, если я скажу, что с Rust и библиотекой ez-ffmpeg вы можете забыть про эти трудности и писать фильтры прямо на любимом языке?

В этой статье мы разберём, как использовать Rust и ez-ffmpeg для создания собственных видеофильтров. Мы начнём с основ, дойдём до продвинутых решений и покажем, как это может пригодиться именно вам. Готовы упростить свою жизнь? Тогда поехали!

Почему это сложно и где пригодится?

Проблемы старого подхода

  • Сложность: C API FFmpeg заставляет вас вручную управлять памятью. Один неверный шаг — и привет, утечки или краш программы!

  • Безопасность: В Rust для работы с C нужно использовать FFI и unsafe-блоки. Это как играть с огнём — ошибки дорого обходятся.

  • Высокий порог входа: Чтобы сделать свой фильтр, нужно знать, как FFmpeg устроен внутри. Не каждый готов копаться в документации и коде на C.

Где это нужно?

  • Видео в реальном времени: Добавляйте эффекты вроде яркости или серого тона прямо во время стрима.

  • Машинное обучение: Преобразуйте видео для создания данных для нейросетей.

  • Игры: Делайте крутые визуальные эффекты для видеоконтента.

  • Аудио: Настраивайте громкость или добавляйте звуковые эффекты.

  • Системы наблюдения: Анализируйте видео для обнаружения движения или объектов.

Если вы хотите надёжное и простое решение, ez-ffmpeg и Rust — это то, что вам нужно.

Основа: Фильтр яркости для YUV420

Давайте начнём с простого — создадим фильтр, который регулирует яркость видео в формате YUV420 (его использует большинство видео). Это отличный способ понять, как всё работает.

Настраиваем проект

Добавьте в Cargo.toml:

[dependencies] ez-ffmpeg = "*"

Убедитесь, что у вас установлены FFmpeg 7.0+ и Rust 1.80.0+.

Пишем код

Этот фильтр увеличит яркость, изменяя Y-компоненту:

use ez_ffmpeg::core::filter::frame_filter::FrameFilter; use ez_ffmpeg::core::frame::Frame; use ez_ffmpeg::core::filter::frame_filter::FrameFilterContext; use ffmpeg_sys_next::AVMediaType;  struct BrightnessFilter {     increment: i32, // На сколько увеличиваем яркость }  impl FrameFilter for BrightnessFilter {     fn media_type(&self) -> AVMediaType {         AVMediaType::AVMEDIA_TYPE_VIDEO     }      fn filter_frame(&self, mut frame: Frame, _ctx: &FrameFilterContext) -> Result<Option<Frame>, String> {         if frame.format() != ffmpeg_sys_next::AVPixelFormat::AV_PIX_FMT_YUV420P {             return Err("Формат пикселей не поддерживается".to_string());         }         let data = frame.get_data_mut(0).ok_or("Не удалось получить данные кадра")?;         for y in data.iter_mut() {             *y = (*y as i32 + self.increment).clamp(0, 255) as u8; // Регулируем Y, не выходя за пределы         }         Ok(Some(frame))     } }

Применяем фильтр

Пример полной программы:

uuse ez_ffmpeg::{FfmpegContext, Output};  fn main() -> Result<(), Box<dyn std::error::Error>> {     let brightness = BrightnessFilter { increment: 50 };     FfmpegContext::builder()         .input("input.mp4")         .filter(Box::new(brightness))         .output(Output::from("output.mp4"))         .build()?         .start()?         .wait()?;     Ok(()) }

Видео станет ярче — и всё это без единой строчки C!

Продвинутый уровень: Фильтры на GPU

Простые фильтры на CPU — это круто, но что делать, если нужно обрабатывать видео в реальном времени? Тут на помощь приходит GPU и OpenGL в ez-ffmpeg.

Проблемы

  • Скорость: CPU может не справляться с большими потоками данных.

  • Совместимость: Разные видеокарты по-разному поддерживают OpenGL.

Решаем с помощью GPU: Серый фильтр

Добавим поддержку OpenGL в Cargo.toml:

[dependencies] ez-ffmpeg = { version = "*", features = ["opengl"] }

Шейдер для серого тона:

#version 330 core in vec2 TexCoord; out vec4 FragColor; uniform sampler2D texture1;  void main() {     vec4 color = texture(texture1, TexCoord);     float gray = 0.299 * color.r + 0.587 * color.g + 0.114 * color.b;     FragColor = vec4(gray, gray, gray, color.a); }

Применяем в Rust:

let fragment_shader = r#" #version 330 core in vec2 TexCoord; out vec4 FragColor; uniform sampler2D texture1;  void main() {     vec4 color = texture(texture1, TexCoord);     float gray = 0.299 * color.r + 0.587 * color.g + 0.114 * color.b;     FragColor = vec4(gray, gray, gray, color.a); } "#;  let filter = OpenGLFrameFilter::new_simple(fragment_shader); frame_pipeline_builder.filter("opengl", Box::new(filter));

Теперь ваше видео станет чёрно-белым, а обработка пойдёт на GPU — быстро и эффективно!

Что мы получили и что дальше?

С Rust и ez-ffmpeg вы можете легко создавать фильтры для FFmpeg, не мучаясь с C. От простых эффектов на CPU до мощных решений на GPU — всё в ваших руках. Это идеально для стримов, анализа данных или просто экспериментов с видео.

Хотите больше? Загляните в ez-ffmpeg на GitHub — там куча примеров и идей. Пора сделать ваши проекты ещё круче!


ссылка на оригинал статьи https://habr.com/ru/articles/901958/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *