Использование ffmpeg для получения продолжительности видео в python
Я установил ffprobe с помощью команды pip ffprobe на моем ПК и установил ffmpeg отсюда.
Тем не менее, у меня все еще есть проблемы с запуском кода, указанного здесь.
Я пытаюсь использовать следующий код безуспешно.
SyntaxError: Не-ASCII символ '\xe2' в файле GetVideoDurations.py в строке 12, но кодировка не объявлена; см. http://python.org/dev/peps/pep-0263/ для получения подробной информации.
Кто-нибудь знает в чем дело? Я не правильно ссылаюсь на каталоги? Нужно ли убедиться, что файлы.py и видео находятся в определенном месте?
import subprocess
def getLength(filename):
result = subprocess.Popen(["ffprobe", "filename"],
stdout = subprocess.PIPE, stderr = subprocess.STDOUT)
return [x for x in result.stdout.readlines() if "Duration" in x]
fileToWorkWith = 'C:\Users\PC\Desktop\Video.mkv'
getLength(fileToWorkWith)
Извиняюсь, если вопрос несколько базовый. Все, что мне нужно, это иметь возможность перебирать группу видеофайлов и получать их время начала и окончания.
Спасибо!
9 ответов
Нет необходимости повторять, хотя вывод FFprobe
, Есть одна простая команда, которая выдает только длительность входного файла.
ffprobe -i input_audio -show_entries format=duration -v quiet -of csv="p=0"
Вы можете использовать следующий метод, чтобы получить продолжительность.
def getLength(input_video):
result = subprocess.Popen('ffprobe -i input_video -show_entries format=duration -v quiet -of csv="p=0"', stdout=subprocess.PIPE,stderr=subprocess.STDOUT)
output = result.communicate()
return output[0]
Также вам нужно указать абсолютный путь к каждому вашему файлу.
Надеюсь это поможет!
Я бы предложил использовать FFprobe (поставляется с FFmpeg).
Ответ, который дал Хамат, был довольно близок, но в конечном итоге для меня это не удалось.
Как примечание, я использую Python 3.5 и 3.6, и это то, что мне помогло.
import subprocess
def get_duration(file):
"""Get the duration of a video using ffprobe."""
cmd = 'ffprobe -i {} -show_entries format=duration -v quiet -of csv="p=0"'.format(file)
output = subprocess.check_output(
cmd,
shell=True, # Let this run in the shell
stderr=subprocess.STDOUT
)
# return round(float(output)) # ugly, but rounds your seconds up or down
return float(output)
Если вы хотите бросить эту функцию в класс и использовать ее в Django (1.8 - 1.11), просто измените одну строку и поместите эту функцию в свой класс, например, так:
def get_duration(file):
чтобы:
def get_duration(self, file):
Примечание: использование относительного пути работало для меня локально, но производственному серверу требовался абсолютный путь. Ты можешь использовать os.path.abspath(os.path.dirname(file))
чтобы получить путь к вашему видео или аудио файлу.
Использование пакета Python ffmpeg (https://pypi.org/project/python-ffmpeg)
import ffmpeg
duration = ffmpeg.probe(local_file_path)["format"]["duration"]
гдеlocal_file_path
это относительный или абсолютный путь к вашему файлу.
Обновленное решение с использованием ffprobe
на основе руководства @llogan с указанной ссылкой:
import subprocess
def get_duration(input_video):
cmd = ["ffprobe", "-i", input_video, "-show_entries", "format=duration",
"-v", "quiet", "-sexagesimal", "-of", "csv=p=0"]
return subprocess.check_output(cmd).decode("utf-8").strip()
Хрупкое решение из-за stderr
выход:
то
stderr
выход изffmpeg
не предназначен для машинного разбора и считается хрупким.
Мне помогает следующая документация ( https://codingwithcody.com/2014/05/14/get-video-duration-with-ffmpeg-and-python/) и /questions/7674943/kak-izvlech-dlitelnost-vremeni-iz-vyivoda-ffmpeg/7674953#7674953
Собственно, sed не нужен:
ffmpeg -i file.mp4 2>&1 | grep -o -P "(?<=Duration: ).*?(?=,)"
Вы можете использовать следующий метод, чтобы получить продолжительность в HH:MM:SS
формат:
import subprocess
def get_duration(input_video):
# cmd: ffmpeg -i file.mkv 2>&1 | grep -o -P "(?<=Duration: ).*?(?=,)"
p1 = subprocess.Popen(['ffmpeg', '-i', input_video], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
p2 = subprocess.Popen(["grep", "-o", "-P", "(?<=Duration: ).*?(?=,)"], stdin=p1.stdout, stdout=subprocess.PIPE)
p1.stdout.close()
return p2.communicate()[0].decode("utf-8").strip()
Пример вывода для обоих: 01:37:11.83
Я думаю, что второй комментарий Chamath отвечает на вопрос: у вас есть странный символ где-то в вашем сценарии, потому что вы используете `вместо a 'или у вас есть слово с неанглийскими акцентами, что-то вроде этого.
В качестве примечания, для того, что вы делаете, вы также можете попробовать MoviePy, который анализирует вывод ffmpeg, как вы делаете (но, возможно, в будущем я буду использовать метод ffprobe Chamath, он выглядит чище):
import moviepy.editor as mp
duration = mp.VideoFileClip("my_video.mp4").duration
Вы пытались добавить кодировку? Эта ошибка типична для этого, как сказал Хамат. Добавьте кодировку utf-8 в заголовок вашего скрипта:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
Мне нравится создавать общую библиотеку с помощью ffmpeg и загружать ее в python.
Код С++:
#ifdef __WIN32__
#define LIB_CLASS __declspec(dllexport)
#else
#define LIB_CLASS
#endif
extern "C" {
#define __STDC_CONSTANT_MACROS
#include "libavformat/avformat.h"
}
extern "C" LIB_CLASS int64_t getDur(const char* url) {
AVFormatContext* pFormatContext = avformat_alloc_context();
if (avformat_open_input(&pFormatContext, url, NULL, NULL)) {
avformat_free_context(pFormatContext);
return -1;
}
int64_t t = pFormatContext->duration;
avformat_close_input(&pFormatContext);
avformat_free_context(pFormatContext);
return t;
}
Затем используйте gcc, чтобы скомпилировать его и получить разделяемую библиотеку.
Код Python:
from ctypes import *
lib = CDLL('/the/path/to/your/library')
getDur = lib.getDur
getDur.restype = c_longlong
duration = getDur('the path/URL to your file')
Это хорошо работает в моей программе Python.
Код Python
<code>
cmnd = ['/root/bin/ffmpeg', '-i', videopath]
process = subprocess.Popen(cmnd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
stdout, stderr = process.communicate()
#This matches regex to get the time in H:M:S format
matches = re.search(r"Duration:\s{1}(?P<hours>\d+?):(?P<minutes>\d+?):(?P<seconds>\d+\.\d+?),", stdout, re.DOTALL).groupdict()
t_hour = matches['hours']
t_min = matches['minutes']
t_sec = matches['seconds']
t_hour_sec = int(t_hour) * 3600
t_min_sec = int(t_min) * 60
t_s_sec = int(round(float(t_sec)))
total_sec = t_hour_sec + t_min_sec + t_s_sec
#This matches1 is to get the frame rate of a video
matches1 = re.search(r'(\d+) fps', stdout)
frame_rate = matches1.group(0) // This will give 20fps
frame_rate = matches1.group(1) //It will give 20
</code>
Мы также можем использовать ffmpeg для получения длительности любых видео или аудио файлов.
Для установки ffmpeg перейдите по этой ссылке
import subprocess
import re
process = subprocess.Popen(['ffmpeg', '-i', path_of_video_file], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
stdout, stderr = process.communicate()
matches = re.search(r"Duration:\s{1}(?P<hours>\d+?):(?P<minutes>\d+?):(?P<seconds>\d+\.\d+?),", stdout, re.DOTALL).groupdict()
print matches['hours']
print matches['minutes']
print matches['seconds']