Я уверен, что это выполнимо, но я не совсем уверен, как этого добиться.
В моей локальной сети постоянно транслируется Raspberry Pi, и я использую этот скрипт ffmpeg
для сохранения видео внутри Pi.
ffmpeg -i http://0.0.0.0:8080/stream/video.mjpeg -vcodec copy -map 0 -f segment -segment_time 5 -segment_format mp4 capture-%05d.mp4
Скрипт довольно прост, он загружает и сохраняет 5 секунд видео непрерывно в локальном каталоге.
Вот что я пытаюсь сделать в конечном итоге
Upload all saved videos to a Cloud Storage, then delete the local copy
Я попытался передать вывод ffmpeg
в сценарий Python, подобный этому, но он не работает так, как я себе представляю.
ffmpeg -i http://0.0.0.0:8080/stream/video.mjpeg -vcodec copy -map 0 -f segment -segment_time 5 -segment_format mp4 capture-%05d.mp4 | py test.py -p capture-%05d.mp4
Это мой сценарий, чтобы получить имя / путь к видео
import argparse
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument('-p', '--videoPath', type=str, help = "Path to recorded video", required=True)
args = parser.parse_args()
print(args.videoPath)
Я предпочитаю вывод в виде строки (имени файла). Например, capture-00001.mp4.
Итак, в основном вы хотите скопировать вновь созданные файлы в облачное хранилище? Один из способов - запустить ffmpeg
как отдельный процесс, а затем использовать модуль inotify
в Python, чтобы узнать, когда новый файл полностью записан на диск.
Другой способ - вызвать команду ffmpeg
из питона, затем захватить ее стандартный вывод, а затем обработать этот вывод почти в реальном времени, а затем получить из него необходимые данные.
Я просматривал справочную страницу ffmpeg
и наткнулся на опцию loglevel.
-loglevel [repeat+]loglevel | -v [repeat+]loglevel
Set the logging level used by the library. Adding "repeat+" indicates that repeated log output should not be compressed to the first line and the "Last message repeated n
times" line will be omitted. "repeat" can also be used alone. If "repeat" is used alone, and with no prior loglevel set, the default loglevel will be used. If multiple
loglevel parameters are given, using 'repeat' will not change the loglevel. loglevel is a string or a number containing one of the following values:
verbose, 40
Same as "info", except more verbose.
Итак, вот простой однострочный обходной путь, чтобы заставить все работать в вашем случае:
ffmpeg -i my_vid_feed -vcodec copy -map 0 -f segment -segment_time 5 -loglevel 40 -segment_format mp4 capture-%05d.mp4 2>&1 | grep --line-buffered -Eo "segment:.+ended" | awk -F "'" '{print $2; system("")}' | xargs -n1 python my_processor.py -p
Я просто разбираю вывод ffmpeg
, когда новый файл записывается полностью, подробный журнал выдает такую строку:
[segment @ 0x7fc253817000] segment:'capture-00002.mp4' count:2 ended
Итак, я просто беру имя файла из строки и передаю его этому файлу python argparse. Параметр -n1
в xargs
указывает ему передавать только один аргумент за раз в файл python, а затем выполнять сценарий python с этим файлом в качестве аргумента.
Вот результат работы команды -
root$ ffmpeg -i my_vid_feed -vcodec copy -map 0 -f segment -segment_time 5 -loglevel 40 -segment_format mp4 capture-%05d.mp4 2>&1 | grep --line-buffered -Eo "segment:.+ended" | awk -F "'" '{print $2; system("")}' | xargs -n1 python my_processor.py -p
started
capture-00000.mp4
ended
started
capture-00001.mp4
ended
started
capture-00002.mp4
ended
started
capture-00003.mp4
ended
Используемый файл python - my_processor.py
import argparse
import time
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument('-p', '--videoPath', type=str, help = "Path to recorded video", required=True)
args = parser.parse_args()
print("started")
print(args.videoPath)
time.sleep(3)
print("ended")
Единственный возможный недостаток этого будет заключаться в том, что в то время, когда будет запущен только один экземпляр python, и ваши задания будут выполняться последовательно после того, как будет выполнено предыдущее задание. Если вы хотите запускать их параллельно, вы тоже можете это сделать.
Превосходство! Вы точно поняли мои сомнения! Оцените усилия, но когда я пытаюсь запустить эти параметры, видео сохраняются, но xargs, похоже, не работает. Я наблюдал за процессами и увидел, что xargs и python работают, но вывода просто нет
ах, это должна быть буферизация awk
и ожидание полного заполнения буфера перед выполнением. Можно просто awk на awk -F "'" '{print $2; system("")}'
сменить? Это должно сработать.
Он по-прежнему ничего не печатает. Вот моя последняя команда. ffmpeg -i http://0.0.0.0:8080/stream/video.mjpeg -vcodec copy -map 0 -f segment -segment_time 5 -loglevel 40 -segment_format mp4 capture-%05d.mp4 2>&1 | grep --line-buffered -Eo "segment:.+ended" | awk -F "'" '{print $2; system("")}' | xargs -n1 python3.6 test.py -p
ох, можешь ли ты попробовать это и посмотреть, получаешь ли ты какой-нибудь выход ffmpeg -i http://0.0.0.0:8080/stream/video.mjpeg -vcodec copy -map 0 -f segment -segment_time 5 -loglevel 40 -segment_format mp4 capture-%05d.mp4 2>&1 | grep --line-buffered -Eo "segment:.+ended"
У меня есть возможность получить segment:'capture-00000.mp4' count:0 ended
, и последующие кадры
Вы также можете получить только имена файлов после добавления части awk
в указанную выше команду?
К сожалению, нет, даже с обоими вашими предложениями awk :(
Вывод $ ffmpeg -i my_vid_feed -vcodec copy -map 0 -f segment -segment_time 5 -loglevel 40 -segment_format mp4 capture-%05d.mp4 2>&1 | grep --line-buffered -Eo "segment:.+ended" | awk -F "'" '{print $2; system("")}'
- capture-00000.mp4 capture-00001.mp4 capture-00002.mp4
Я могу видеть имена файлов в реальном времени, хотя по мере того, как они продолжают поступать, и они не буферизуются для меня. На какой платформе вы находитесь?
Я использую это на Raspberry Pi 3 Model B. armv7l. Распбиан GNU / Linux 8
Можете проверить версию awk? Я предполагаю, что версия awk для Pi 3 очень старая, можете ли вы попробовать gawk
вместо этого или обновить awk
до более новой версии.
Спасибо! Проблема была в awk! Я установил gawk и теперь вижу имена файлов!
np, поэтому теперь весь конвейер, включая часть Python, должен начать работать, как задумано.
Да, в самом деле! Теперь мне нужно будет найти способ загрузить видео в свое облачное хранилище. И я жду недостатка, о котором вы упомянули в ответе. Я думаю, что этот метод потенциально может раздуть мой Pi до смерти, потому что по сути он пытается вызвать новый экземпляр python каждый раз, когда сохраняет видео. У вас есть лучший способ подойти к этому?
Да, но в данный момент одновременно может выполняться только один процесс Python. Другой вариант - запустить процесс ffmpeg
из самого python, а затем обработать его вывод на python и затем загрузить их в облако. Но тогда вам придется управлять множеством крайних случаев и одновременным / асинхронным / тайм-аутом для загрузки. Другим вариантом может быть inotify
в сочетании с многопроцессорностью. inotify
- это, по сути, системная ловушка, которая сообщает вам, создаются ли новые файлы в данном каталоге, а затем обрабатывает эти вновь созданные файлы параллельно, если вы хотите.
Я попробовал первый вариант. Мне удалось создать несколько потоков для одновременной обработки всех запросов. Но наступает время, когда процессы ограничиваются вводом-выводом и сетевым трафиком, поэтому мои последние алгоритмы сильно задерживаются. Попробую второй подход.
Да, параллелизм всегда должен быть ограничен и управляем в подходах. Вы можете сделать это любым подходом. Как и в первом подходе, 3-4 параллельных потока должны быть в порядке (вы можете провести несколько тестов и решить, что лучше всего подходит для вас с точки зрения ввода-вывода и использования ресурсов). Кроме того, вы, вероятно, также можете добавить несколько тайм-аутов / повторных попыток в случае сбоя запроса, чтобы сделать утилиту более надежной.
Собственно мои мысли. Спасибо за ваш ответ на мои сомнения.
нп, рад помочь! :)
Вы хотите вывод команды
ffmpeg
в виде строки на Python?