Динамическое обрезка FFmpeg с использованием правильного синтаксиса sendcmd?

Я пытаюсь динамически обрезать видео с помощью фильтра sendcmd FFmpeg на основе координат, указанных в текстовом файле, но команды обрезки, похоже, не действуют. Вот формат команд, которые я пробовал, и соответствующая команда FFmpeg, которую я использую.

Следуя документации https://ffmpeg.org/ffmpeg-filters.html#sendcmd_002c-asendcmd, команды в текстовом файле (coordinates.txt) выглядят следующим образом:

0.05 [enter] crop w=607:h=1080:x=0:y=0;
0.11 [enter] crop w=607:h=1080:x=0:y=0;
...

Команда ffmpeg:

ffmpeg -i '10s.mp4' -filter_complex "[0:v]sendcmd=f=coordinates.txt" -c:v libx264 -c:a copy -r 30 output.mp4

Кажется, это ничего не дает.

А с командами в текстовом файле (coordinates.txt) вот так:

0.05    crop w 607, crop h 1080, crop x 0, crop y 0;
0.11    crop w 607, crop h 1080, crop x 0, crop y 0;
...

Команда ffmpeg:

ffmpeg -i '10s.mp4' -filter_complex "[0:v]sendcmd=f=coordinates.txt,crop" -c:v libx264 -c:a copy -r 30 output.mp4

(после этого ответа https://stackoverflow.com/a/67508233/1967110)

Этот что-то делает, но что-то очень грязное. Похоже, что он обрезает правильный x, но не учитывает y, w или h и помещает обрезку в правую часть входного видео.

Редактировать: я пытаюсь создать видео 607x1080 (портретный формат, 9:16) из видео 1920x1080 с параметром x, меняющимся во времени (представьте, что кадр 9:16 скользит по горизонтали по видео 16:9) . Итак, фиксированные w, h и y, меняется только x.

Я использую эту версию ffmpeg:

ffmpeg version 6.0 Copyright (c) 2000-2023 the FFmpeg developers
built with gcc 9 (Ubuntu 9.4.0-1ubuntu1~20.04.1)
configuration: --prefix=/home/ffmpeg-builder/release --pkg-config-flags=--static --extra-libs=-lm --disable-doc --disable-debug --disable-shared --disable-ffprobe --enable-static --enable-gpl --enable-version3 --enable-runtime-cpudetect --enable-avfilter --enable-filters --enable-nvenc --enable-nvdec --enable-cuvid --toolchain=hardened --disable-stripping --enable-opengl --pkgconfigdir=/home/ffmpeg-builder/release/lib/pkgconfig --extra-cflags='-I/home/ffmpeg-builder/release/include -static-libstdc++ -static-libgcc ' --extra-ldflags='-L/home/ffmpeg-builder/release/lib -fstack-protector -static-libstdc++ -static-libgcc ' --extra-cxxflags=' -static-libstdc++ -static-libgcc ' --extra-libs='-ldl -lrt -lpthread' --enable-ffnvcodec --enable-gmp --enable-libaom --enable-libass --enable-libbluray --enable-libdav1d --enable-libfdk-aac --enable-libfontconfig --enable-libfreetype --enable-libfribidi --enable-libgme --enable-libkvazaar --enable-libmp3lame --enable-libopus --enable-libopencore_amrnb --enable-libopencore_amrwb --enable-libopenh264 --enable-libopenjpeg --enable-libshine --enable-libsoxr --enable-libsrt --enable-libsvtav1 --enable-libtheora --enable-libvidstab --ld=g++ --enable-libvmaf --enable-libvorbis --enable-libvpx --enable-libx264 --enable-libx265 --enable-libxvid --enable-libzimg --enable-openssl --enable-zlib --enable-nonfree --extra-libs=-lpthread --enable-pthreads --extra-libs=-lgomp

в моем случае это работает правильно, если команды начинаются с 0 (а не 0,05) и имеют одинаковые значения w и h во всех строках

Баяр Гончикжапов 14.04.2024 05:20

@БаярГончижапов первый или второй формат я упоминаю?

Sulli 14.04.2024 10:57

например: 0 crop w 640, crop h 640, crop x 0, crop y 0; 2 crop x 100; 4 crop x 200; 6 crop x 300; 8 crop x 400;. не обязательно писать w и h в каждой строке

Баяр Гончикжапов 15.04.2024 04:18

@БаярГончижапов, а ты запускаешь этот файл с ffmpeg -i 'input.mp4' -filter_complex "[0:v]sendcmd=f=coordinates.txt,crop" -c:v libx264 -c:a copy -r 29.97 output.mp4,crop в конце) ? Если да, можете ли вы опубликовать полный пример, я не могу заставить эту команду работать, она либо не работает (без ,crop), либо обрезает с неприятным результатом (с ,crop)

Sulli 15.04.2024 09:52
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
4
179
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Итак, единственная команда, которая у меня пока работает, взята из https://video.stackexchange.com/posts/19403/revisions, это:

ffmpeg -i in.mp4 -filter_complex_script file.txt -map "[out]" output.mp4

с file.txt вот так

nullsrc=WxH:r=FPS[cv];
[cv][0]overlay=-X0:-Y0:shortest=1:enable='eq(n\,0)'[b0];
[b0][0]overlay=-X1:-Y1:shortest=1:enable='eq(n\,1)'[b1];
[b1][0]overlay=-X2:-Y2:shortest=1:enable='eq(n\,2)'[b2];
...
[bm-1][0]overlay=-Xm:-Ym:shortest=1:enable='eq(n\,m)'[out]

для обрезки видео 1920x1080, 5 с, 30 кадров в секунду до видео 606x1080 требуется около 40 секунд (в Google Colab, поэтому процессор низкого уровня и без графического процессора). НО это также вызывает ошибки «Недостаточно памяти», как только необходимо обрезать более 900 кадров на компьютере с ОЗУ 12 ГБ (см. https://superuser.com/questions/1839180/ffmpeg-out-of-memory-issues -with-filter-complex-script).

Еще я попробовал сначала разложить видео на каждый кадр, обрезать каждый кадр и собрать видео заново. Вот код:

def decompose_video(video_path, frames_dir):
    if not os.path.exists(frames_dir):
        os.makedirs(frames_dir)
    command = [
        'ffmpeg', '-i', video_path, 
        os.path.join(frames_dir, 'frame_%04d.png')
    ]
    subprocess.run(command, check=True)

def read_crop_values(crop_file):
    with open(crop_file, 'r') as file:
        crops = [line.strip().split(',') for line in file]
    return crops

def apply_crop(frames_dir, crops):
    cropped_frames_dir = frames_dir + '_cropped'
    if not os.path.exists(cropped_frames_dir):
        os.makedirs(cropped_frames_dir)
    
    for i, crop in enumerate(crops, 1):
        x, y, w, h = crop
        input_frame = os.path.join(frames_dir, f'frame_{i:04d}.png')
        output_frame = os.path.join(cropped_frames_dir, f'frame_{i:04d}.png')
        command = [
            'ffmpeg', '-i', input_frame,
            '-filter:v', f'crop = {w}:{h}:{x}:{y}',
            output_frame
        ]
        subprocess.run(command, check=True)

def recreate_video(cropped_frames_dir, output_video_path):
    command = [
        'ffmpeg', '-y', '-loglevel', 'verbose', '-r', '29.97', '-f', 'image2', '-i', 
        os.path.join(cropped_frames_dir, 'frame_%04d.png'),
        '-vcodec', 'libx264', '-crf', '23', '-pix_fmt', 'yuv420p',
        output_video_path
    ]
    try:
        subprocess.run(command, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    except subprocess.CalledProcessError as e:
        print("FFmpeg failed with error:")
        print(e.stderr.decode()) 

video_path = 'input.mp4'
frames_dir = 'frames'
crop_file = 'crop_values.txt'
output_video_path = 'output.mp4'

decompose_video(video_path, frames_dir)
crops = read_crop_values(crop_file)
apply_crop(frames_dir, crops)
recreate_video(frames_dir + '_cropped', output_video_path)

и в crop_values.txt просто ставишь x, y, w, h:

0,0,606,1080
8,0,606,1080
17,0,606,1080

Это тоже работает, но немного медленнее (1 минута 40 минут для того же видео).

проверенный вариант:

#!/bin/bash
echo "#test crop
0 crop w 607, crop h 1080, crop x 0, crop y 0;
1 crop x 200;
2 crop x 400;
3 crop x 600;
" > coordinates.txt
ffmpeg -loop 1 -t 4 -r 30000/1001 -i "1920x1080.jpg" -filter_complex "sendcmd=f=coordinates.txt,crop" /tmp/out.mp4 -y
ffplay /tmp/out.mp4
  1. не добавляйте -pix_fmt ... эта опция сбрасывает выходное разрешение на входное.

Другие вопросы по теме