使用 ffmpeg 获取 python 中的视频持续时间

Using ffmpeg to obtain video durations in python

我在我的电脑上使用 pip ffprobe 命令安装了 ffprobe,并从 here.

安装了 ffmpeg

但是,运行 列出的代码 here

我仍然遇到问题

我尝试使用下面的代码没有成功。

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

有谁知道这是怎么回事?我没有正确引用目录吗?我是否需要确保 .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)

如果问题有点基础,我们深表歉意。我所需要的只是能够遍历一组视频文件并获取它们的开始时间和结束时间。

谢谢!

无需遍历 FFprobe 的输出。有one simple command其中returns只有输入文件的持续时间:

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

您可以使用以下方法获取时长:

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)

我认为 Chamath 的第二条评论回答了这个问题:您的脚本中某处有一个奇怪的字符,要么是因为您使用的是 ` 而不是 ',或者您的单词带有非英语口音,例如这样。

顺便说一下,对于你正在做的事情,你也可以尝试 MoviePy 像你一样解析 ffmpeg 输出(但也许将来我会使用 Chamath 的 ffprobe 方法,它看起来更干净):

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

我们还可以使用 ffmpeg 获取任何视频或音频文件的持续时间。

要安装 ffmpeg,请遵循此 link

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'])

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>

我建议使用 FFprobe(FFmpeg 附带)。

Chamath 给出的答案非常接近,但最终对我来说失败了。

请注意,我使用的是 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)

如果您想将此函数放入 class 并在 Django (1.8 - 1.11) 中使用它,只需更改一行并将此函数放入您的 class,如下所示:

def get_duration(file):

至:

def get_duration(self, file):

注意: 在本地使用相对路径对我有效,但生产服务器需要绝对路径。您可以使用 os.path.abspath(os.path.dirname(file)) 获取视频或音频文件的路径。

您是否尝试过添加编码?正如 Chamath 所说,该错误是典型的错误。 将 utf-8 编码添加到您的脚本 header:

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

根据@llogan 指导使用 ffprobe 的更新解决方案和指向 link:

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 输出的脆弱解决方案:

the stderr output from ffmpeg is not intended for machine parsing and is considered fragile.

我从以下文档中获得帮助 (https://codingwithcody.com/2014/05/14/get-video-duration-with-ffmpeg-and-python/) and

Actually, sed is unnecessary: 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

我喜欢用ffmpeg构建一个共享库,并加载到python。
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;
}

然后用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 程序中运行良好。