简体   繁体   English

在python中使用ffmpeg获取视频时长

[英]Using ffmpeg to obtain video durations in python

I've installed ffprobe using the pip ffprobe command on my PC, and installed ffmpeg from here .我已经在我的 PC 上使用 pip ffprobe 命令安装了 ffprobe,并从这里安装了 ffmpeg。

However, I'm still having trouble running the code listed here .但是,我仍然无法运行此处列出的代码。

I try to use the following code unsuccessfully.我尝试使用以下代码失败。

SyntaxError: Non-ASCII character '\xe2' in file GetVideoDurations.py
on line 12, but no encoding declared; see
http://python.org/dev/peps/pep-0263/ for details

Does anyone know what's wrong?有谁知道出了什么问题? Am I not referencing the directories correctly?我没有正确引用目录吗? Do I need to make sure the .py and video files are in a specific location?我是否需要确保.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)

Apologies if the question is somewhat basic.如果问题有点基本,请道歉。 All I need is to be able to iterate over a group of video files and get their start time and end time.我所需要的只是能够遍历一组视频文件并获得它们的开始时间和结束时间。

Thank you!谢谢!

There is no need to iterate though the output of FFprobe .无需迭代FFprobe的输出。 There is one simple command which returns only the duration of the input file:一个简单的命令只返回输入文件的持续时间:

ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 <input_video>

You can use the following method instead to get the duration:您可以改用以下方法来获取持续时间:

def get_length(input_video):
    result = subprocess.run(['ffprobe', '-v', 'error', '-show_entries', 'format=duration', '-of', 'default=noprint_wrappers=1:nokey=1', input_video], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    return float(result.stdout)

I'd suggest using FFprobe (comes with FFmpeg).我建议使用 FFprobe(与 FFmpeg 一起提供)。

The answer Chamath gave was pretty close, but ultimately failed for me. Chamath 给出的答案非常接近,但最终对我来说失败了。

Just as a note, I'm using Python 3.5 and 3.6 and this is what worked for me.请注意,我使用的是 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)

If you want to throw this function into a class and use it in Django (1.8 - 1.11), just change one line and put this function into your class, like so:如果你想把这个函数放到一个类中并在 Django (1.8 - 1.11) 中使用它,只需更改一行并将这个函数放入你的类中,如下所示:

def get_duration(file):

to:至:

def get_duration(self, file):

Note: Using a relative path worked for me locally, but the production server required an absolute path.注意:使用相对路径在本地对我有用,但生产服务器需要绝对路径。 You can use os.path.abspath(os.path.dirname(file)) to get the path to your video or audio file.您可以使用os.path.abspath(os.path.dirname(file))获取视频或音频文件的路径。

I think Chamath's second comment answers the question: you have a strange character somewhere in your script, either because you are using a ` instead of a ' or you have a word with non-english accents, something like this.我认为 Chamath 的第二条评论回答了这个问题:你的脚本中某处有一个奇怪的字符,要么是因为你使用的是 ` 而不是 a ',要么是因为你有一个带有非英语口音的单词,比如这样。

As a remark, for what you are doing you can also try MoviePy which parses the ffmpeg output like you do (but maybe in the future I'll use Chamath's ffprobe method it looks cleaner):作为一个评论,对于你正在做的事情,你也可以尝试像你一样解析 ffmpeg 输出的MoviePy (但也许将来我会使用 Chamath 的 ffprobe 方法,它看起来更干净):

import moviepy.editor as mp
duration =  mp.VideoFileClip("my_video.mp4").duration

Updated solution using ffprobe based on @llogan guidance with the pointed link :使用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()

Fragile Solution due to stderr output:由于stderr输出导致的脆弱解决方案:

the stderr output from ffmpeg is not intended for machine parsing and is considered fragile. ffmpegstderr输出不适用于机器解析,被认为是脆弱的。

I get help from the following documentation ( https://codingwithcody.com/2014/05/14/get-video-duration-with-ffmpeg-and-python/ ) and https://stackoverflow.com/a/6239379/2402577我从以下文档( https://codingwithcody.com/2014/05/14/get-video-duration-with-ffmpeg-and-python/ )和https://stackoverflow.com/a/6239379/中获得帮助2402577

Actually, sed is unnecessary: ffmpeg -i file.mp4 2>&1 | grep -o -P "(?<=Duration: ).*?(?=,)"实际上,sed 是不必要的: ffmpeg -i file.mp4 2>&1 | grep -o -P "(?<=Duration: ).*?(?=,)" ffmpeg -i file.mp4 2>&1 | grep -o -P "(?<=Duration: ).*?(?=,)"


You can use the following method to get the duration in HH:MM:SS format:您可以使用以下方法获取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()

Example output for both: 01:37:11.83两者的示例输出: 01:37:11.83

Have you tried adding the encoding?您是否尝试过添加编码? That error is typical of that, as Chamath said.正如查马斯所说,这个错误是典型的。 Add the utf-8 encoding to your script header:将 utf-8 编码添加到脚本头中:

#!/usr/bin/env python
# -*- coding: utf-8 -*- 

I like to build a shared library with ffmpeg, and load it in python.我喜欢用 ffmpeg 构建一个共享库,并在 python 中加载它。
C++ code: C++ 代码:

#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;
}

Then use gcc to compile it and get a shared library.然后使用 gcc 编译它,得到一个共享库。
Python code: 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')

It works well in my python program.它在我的 python 程序中运行良好。

Using the python ffmpeg package ( https://pypi.org/project/python-ffmpeg )使用 python ffmpeg 包 ( https://pypi.org/project/python-ffmpeg )

import ffmpeg
duration = ffmpeg.probe(local_file_path)["format"]["duration"]

where local_file_path is a relative or absolute path to your file.其中local_file_path是文件的相对或绝对路径。

Python Code 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>

we can also use ffmpeg to get the duration of any video or audio files.我们还可以使用 ffmpeg 来获取任何视频或音频文件的持续时间。

To install ffmpeg follow this link要安装 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'])

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM