40

Я пытаюсь удалить несколько разделов видео с помощью FFmpeg.

Например, представьте, если вы записали шоу по телевидению и хотели вырезать рекламу. Это просто с графическим редактором GUI; Вы просто отмечаете начало и конец каждого клипа, который хотите удалить, и выбираете удалить. Я пытаюсь сделать то же самое из командной строки с FFmpeg.

Я знаю, как вырезать один сегмент для нового видео, например, так:

ffmpeg -i input.avi -ss 00:00:20 -t 00:00:05 -map 0 -codec copy output.avi

Это обрезает пятисекундный клип и сохраняет его как новый видеофайл, но как я могу сделать обратное и сохранить все видео без указанного клипа, и как я могу указать несколько клипов, которые нужно удалить?

Например, если мое видео может быть представлено ABCDEFG, я хотел бы создать новое, которое будет состоять из ACDFG.

4 ответа4

43

Ну, вы все еще можете использовать фильтр trim для этого. Вот пример, давайте предположим, что вы хотите вырезать сегменты 30-40 секунд (10 секунд) и 50-80 секунд (30 секунд):

ffmpeg -i in.ts -filter_complex \
"[0:v]trim=duration=30[a]; \
 [0:v]trim=start=40:end=50,setpts=PTS-STARTPTS[b]; \
 [a][b]concat[c]; \
 [0:v]trim=start=80,setpts=PTS-STARTPTS[d]; \
 [c][d]concat[out1]" -map [out1] out.ts

Что я здесь сделал? Я обрезал сначала 30 секунд, 40-50 секунд и 80 секунд до конца, а затем объединил их в поток out1 с помощью фильтра concat .

Об установках: нам это нужно, потому что обрезка не изменяет время отображения изображения, и когда мы вырезаем 10-секундный счетчик, декодер не видит никаких кадров в течение этих 10-секунд.

Если вы хотите иметь аудио тоже, вы должны сделать то же самое для аудио потоков. Итак, команда должна быть:

ffmpeg -i utv.ts -filter_complex \
"[0:v]trim=duration=30[av];[0:a]atrim=duration=30[aa];\
 [0:v]trim=start=40:end=50,setpts=PTS-STARTPTS[bv];\
 [0:a]atrim=start=40:end=50,asetpts=PTS-STARTPTS[ba];\
 [av][bv]concat[cv];[aa][ba]concat=v=0:a=1[ca];\
 [0:v]trim=start=80,setpts=PTS-STARTPTS[dv];\
 [0:a]atrim=start=80,asetpts=PTS-STARTPTS[da];\
 [cv][dv]concat[outv];[ca][da]concat=v=0:a=1[outa]" -map [outv] -map [outa] out.ts
12

Я никогда не смогу заставить работать решение ptQa, главным образом потому, что никогда не мог понять, что означают ошибки из фильтров или как их исправить. Мое решение кажется немного более грубым, потому что оно может оставить беспорядок, но если вы добавляете его в сценарий, очистка может быть автоматизирована. Мне также нравится этот подход, потому что если на шаге 4 что-то пойдет не так, вы закончите с шагами 1-3, поэтому восстановление после ошибок будет немного более эффективным.

Основная стратегия заключается в использовании -t и -ss для получения видео каждого сегмента, который вы хотите, а затем объедините все части для вашей окончательной версии.

Скажем, у вас есть 6 сегментов ABCDEF каждые 5 секунд, и вы хотите A (0-5 секунд), C (10-15 секунд) и E (20-25 секунд), и вы сделаете следующее:

ffmpeg -i abcdef.tvshow -t 5 a.tvshow -ss 10 -t 5 c.tvshow -ss 20 -t 5 e.tvshow

или же

ffmpeg -i abcdef.tvshow -t 0:00:05 a.tvshow -ss 0:00:10 -t 0:00:05 c.tvshow -ss 0:00:20 -t 0:00:05 e.tvshow

Это создаст файлы a.tvshow, c.tvshow и e.tvshow. -t говорит, как долго длится каждый клип, поэтому, если c составляет 30 секунд, вы можете пройти 30 или 0:00:30. Опция -ss указывает, как далеко пропустить исходное видео, поэтому оно всегда относительно начала файла.

Затем, когда у вас есть куча видеофайлов, я создаю файл ace-files.txt примерно так:

file 'a.tvshow'
file 'c.tvshow'
file 'e.tvshow'

Обратите внимание на "файл" в начале и имя файла после него.

Тогда команда:

ffmpeg -f concat -i ace-files.txt -c copy ace.tvshow

Это объединяет все файлы в файле abe-files.txt , копируя их аудио и видео кодеки, и создает файл ace.tvshow который должен быть просто разделами a, c и e. Тогда просто не забудьте удалить ace-files.txt , a.tvshow , c.tvshow и e.tvshow .

Отказ от ответственности: я понятия не имею, насколько (не) эффективно это по сравнению с другими подходами с точки зрения ffmpeg но для моих целей это работает лучше. Надеюсь, это поможет кому-то.

2

Хотя ответ, предоставленный ptQa, кажется, работает, я разработал другое решение, которое доказало свою работоспособность.

По сути, я делаю одно видео для каждой части оригинального видео, которое я хочу включить в свой результат. Позже я объединяю их с Concat Demuxer, описанным здесь.

Решение такое же, какое я попробовал первым и представил проблемы с синхронизацией. Я добавил команду -avoid_negative_ts 1 при создании разных видео. При таком решении проблемы с синхронизацией исчезают.

1

Я сделал скрипт для ускорения редактирования записанного ТВ. Сценарий запрашивает время начала и окончания сегментов, которые вы хотите сохранить, и разбивает их на файлы. Это дает вам варианты, вы можете:

  • Возьмите один или несколько сегментов.
  • Вы можете объединить сегменты в один результирующий файл.
  • После присоединения вы можете сохранить или удалить файлы детали.
  • Вы можете сохранить исходный файл или заменить его новым файлом.

Видео об этом в действии: здесь

Дайте мне знать, что вы думаете.

 #!/bin/bash
/bin/date >>segmenter.log

function segment (){
while true; do
    echo "Would you like to cut out a segment ?"
    echo -e "1) Yes\n2) No\n3) Quit"
    read CHOICE
    if [ "$CHOICE" == "3" ]; then
        exit
    elif [ "$CHOICE" == "2" ]; then
        clear
        break
    elif [ "$CHOICE" == "1" ]; then
        clear
        ((segments++))
        echo "What time does segment $segments start ?"
        read SEGSTART
        clear
        echo -e "Segment $segments start set to $SEGSTART\n"  
        echo "What time does segment $segments end ?"
        read SEGEND
        clear
        echo -e "Segment $segments end set to $SEGEND\n"
        break
    else
        clear
        echo -e "Bad option"
        segment "$segments"
    fi
done
if [ "$CHOICE" == "1" ]; then
    echo "Cutting file $file video segment $segments starting at $SEGSTART and ending at $SEGEND"
    ffmpeg -i "$file" -ss $SEGSTART -to  $SEGEND -map 0:0 -map 0:1 -c:a copy -c:v copy  "$filename-part$segments.$extension"  >> segmenter.log 2>&1
    clear
    echo -e "Cut file $filename-part$segments.$extension starting at $SEGSTART and ending at $SEGEND\n"                             
    segment "$segments"
fi
}

file="$1"
filename="${file%.*}"
extension="${file##*.}"
clear
segments=0
segment "$segments"
clear
if (("$segments"==1)); then
mv $filename"-part1."$extension "$filename-segmented.$extension"
elif (("$segments">1)); then
echo "Would you like to join the segments into one file ?"      
       OPTIONS="Yes No Quit"
       select opt in $OPTIONS; do
       clear
        if [ "$opt" == "Quit" ]; then
            exit
        elif [ "$opt" == "Yes" ]; then
            clear
            echo "Joining segments"
            ffmpeg -f concat -i <(for f in $filename"-part"*$extension;         do echo "file '$(pwd)/$f'"; done) -c:a copy -c:v copy "$filename-segmented.$extension" >>         segmenter.log 2>&1
            clear
            echo "Would you like to delete the part files ?"
            select opt in $OPTIONS; do
            clear
            if [ "$opt" == "Quit" ]; then
                exit
            elif [ "$opt" == "Yes" ]; then
                for f in $filename"-part"*$extension; do rm $f; done
                break
            elif [ "$opt" == "No" ]; then
                break
            else
                clear
                echo -e "Bad option\n"
            fi
            done
            break
        clear
        elif [ "$opt" == "No" ]; then
            exit
        else
            clear
            echo -e "Bad option\n"
        fi
    done
fi
echo "Would you like to replace the original file with the result of your changes ?"
OPTIONS="Yes No Quit"
select opt in $OPTIONS; do
    clear
    if [ "$opt" == "Quit" ]; then
        exit
    elif [ "$opt" == "Yes" ]; then
        rm $file
        mv "$filename-segmented.$extension" $file
        break
    elif [ "$opt" == "No" ]; then
        break
    else
        clear
        echo -e "Bad option\n"
    fi
done

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .