Как стать автором
Обновить

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

Уровень сложностиСредний
Время на прочтение3 мин
Количество просмотров2.4K

Введение

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 — там куча примеров и идей. Пора сделать ваши проекты ещё круче!

Теги:
Хабы:
Всего голосов 10: ↑8 и ↓2+9
Комментарии5

Публикации

Работа

Rust разработчик
10 вакансий

Ближайшие события