FFmpeg: Записать экран, но помните только последние 5 минут?

Я использую Ffmpeg для непрерывной записи видео с экрана на моем ПК. Тем не менее, мне нужны последние 5 минут видео.

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

Есть ли способ запомнить только последние 5 минут захвата видео и забыть все предыдущее до сохранения файла? (Вроде как сделал бы TiVO)

я обнаружил

-fs limit_size

а также

-timelimit duration

... но они, кажется, прекращаются, как только предел достигнут. Может быть, есть обратный переключатель? Как сохранить только последние 1000000 байтов или что-то.

2 ответа

Спасибо user704244 за правильный трек.

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

Альтернативы

  • Наивным решением был бы круговой буфер . Это может быть возможно, но это, безусловно, не кажется практичным, поскольку я ничего не могу сделать в Интернете.

  • Вы также можете каким-то образом удалить данные из начала файла, когда он становится слишком длинным, но я не думаю, что это возможно, пока файл записывается.

  • Ответ @Sepero - отличный обходной путь, но я действительно хотел иметь возможность в конечном итоге включать аудио, поэтому я изучил полностью собственное решение ffmpeg.

Вот тут и появляется формат ffmpeg.

Концепция

Допустим, мы хотим сохранить только последние 5 секунд данных.

Идея состоит в том, что мы записываем данные за 5 секунд в файл A , а затем начинаем записывать следующие 5 секунд в файл B. Когда мы достигаем 10 секунд, мы начинаем перезаписывать следующие 5 секунд в файл A (поскольку у нас уже есть последние 5 секунд в файле B ) и так далее. У нас всегда будут последние 5 секунд в любом из двух файлов, и у нас будет максимум 10 секунд накладных расходов. Это избавляет нас от необходимости хранить часы записи экрана только для того, чтобы обрезать последние N секунд/минут.

После того, как у нас есть два сегмента, мы можем объединить их в один файл <= 10 секунд. Затем мы можем обрезать последние 5 секунд из этого файла.


Я использую Windows 11 и версию ffmpeg n4.3.1-29.

1. Запись экрана на сегменты

Это будет постоянно записывать ваш рабочий стол с помощью gdigrab и передавать этот ввод в сегмент. Сегмент создаст два файла с именами segment0.mp4 и segment1.mp4, а также файл catfile.ffcat, который поможет их объединить позже.

Вы можете остановить эту команду, нажав Ctrl+ cили набрав q, а затем enter.

      ffmpeg -y -f gdigrab -video_size 1920x1080 -show_region 1 -i desktop \
  -f segment -segment_time 300 -segment_format mp4 -segment_list catfile.ffcat \
  -segment_wrap 2 -reset_timestamps 1 segment%d.mp4

Я не эксперт по ffmpeg, но попытаюсь объяснить, что делает каждая часть команды:

- Отвечает да (Y) на любые запросы ffmpeg. Я использую его для автоматической перезаписи любых существующих файлов из предыдущих запусков.

- Обозначает формат . Он используется для принудительного ввода/вывода следующего ввода/вывода в указанный формат ffmpeg. Насколько я могу судить, этот флаг часто является необязательным, поэтому некоторые люди его опускают. Я думаю, что это действительно помогает улучшить читаемость, поэтому я бы рекомендовал включить его в команду.

- Формат только для Windows, используемый для записи рабочего стола. Вы можете попробовать переключить это на один из форматов для macOS или Linux, обратившись к этому руководству .

— Опция для gdigrab, определяющая размер экрана (у gdigrab есть масса полезных опций, которые могут вам понравиться, см. эту ссылку ).

- Опция для gdigrab, которая показывает контур вокруг записываемой в данный момент части экрана.

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

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

- Сколько длится каждый сегмент видео в секундах. Я установил его на 300 секунд, что составляет 5 минут. Обратите внимание, что это, вероятно, будет отключено на несколько секунд (предположительно из-за требований к кодировке). Я попытался установить его на 5 секунд, и вместо этого мои видеосегменты стали длиной ~ 7 секунд. Не должно быть большой проблемой, но это стоит отметить.

- Формат файла, в котором вы собираетесь выводить. Я использовал mp4, и я видел, как другие используют mkv, но я не уверен, что другие поддерживаются сегментом.

- Эта часть команды очень крутая. Он создает специальный файл .ffcat (я выбрал имя «catfile», но вы можете называть его как угодно). Он отслеживает порядок ваших выходных сегментов. В противном случае вам придется выяснить, в каком порядке их рекомбинировать, что не очень весело.

- Создайте только до двух сегментов. Заполнив второй сегмент, он начинает перезаписывать первый. Это гарантирует, что вы никогда не потеряете данные новее, чем. Если вы не укажете это значение, он будет продолжать создавать новые файлы сегментов и никогда не удалять старые данные, что противоречит цели этой стратегии.

- Я не совсем понимаю, что это делает, но, похоже, это помогает при объединении сегментов вместе.

- Это имя вашего выходного файла. важно, чтобы формат сегмента работал корректно. По сути, он создает новые сегменты, используя это имя файла, заменяя %d текущим индексом сегмента. У вас должно получиться два файла: «segment0.mp4» и «segment1.mp4».

2. Объедините сегменты вместе

Из ответа @Gyan здесь

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

Я не знаю тонкостей этого, нообъясняется здесь.

      ffmpeg -y -i catfile.ffcat -map 0 -c copy combined.mp4

3. Получите последние 5 минут

Из ответа @llogan здесь.

Обрежьте последние 5 минут. Как я уже сказал, у нас есть видео, которое гарантированно длится от 5 до 10 минут, поэтому у нас не должно возникнуть проблем с обрезкой последних 5 минут.

      ffmpeg -y -sseof -300 -i combined.mp4 output.mp4

4. Удалите временные файлы

Вам нужно будет самостоятельно удалить эти лишние файлы после операции. Вы можете запустить:

      rm catfile.ffcat segment0.mp4 segment1.mp4 combined.mp4

Очень многословный ответ, но мне очень хотелось, чтобы у меня было что-то подобное, когда я искал, поэтому я надеюсь, что эти знания помогут кому-то еще!

Я согласен, что я хотел бы видеть эту функцию в ffmpeg.

В качестве обходного решения я создал скрипт для записи экрана на изображения и непрерывного удаления старых изображений. К сожалению, это не сохраняет аудио. Вот сценарий.

#!/bin/bash 
set -e -u

mkdir "$HOME/history" || true
rm "$HOME"/history/img*.png || true

# Get screen resolution.
RES="$(xwininfo -root | grep -Po 'geometry[^+]*' | sed 's/^\S* //')"

# Record the screen into images into /home/username/history/ one per second.
avconv -s "$RES" -f x11grab -i :0.0 -r 1  -f image2 "$HOME/history/img%06d.png" &

AVCONV_PID=$!

trap "kill $AVCONV_PID" INT TERM EXIT

while true; do
    # Delete screen images older than 5 minutes.
    find "$HOME/history" -name "img*.png" -mmin +5 -exec rm {} +
    sleep 10
done

Если вы хотите 5 кадров в секунду, измените часть -r 1 в -r 5, Посмотрите эту ссылку, как собрать изображения в видео (avi, mpeg) файл.

PS.
Вы также можете использовать ffmpeg вместо avconv.

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