Video 从ffmpeg获取视频尺寸/分辨率/宽度x高度

Video 从ffmpeg获取视频尺寸/分辨率/宽度x高度,video,ffmpeg,ffprobe,Video,Ffmpeg,Ffprobe,如何从ffmpeg的信息输出中获得视频的高度和宽度。例如,使用以下输出: $ ffmpeg -i video.mp4 ... Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'video.mp4': Metadata: major_brand : isom minor_version : 1 compatible_brands: isomavc1 creation_time : 2010-01-24 00:55:

如何从
ffmpeg
的信息输出中获得视频的高度和宽度。例如,使用以下输出:

$ ffmpeg -i video.mp4
...
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'video.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 1
    compatible_brands: isomavc1
    creation_time   : 2010-01-24 00:55:16
  Duration: 00:00:35.08, start: 0.000000, bitrate: 354 kb/s
    Stream #0.0(und): Video: h264 (High), yuv420p, 640x360 [PAR 1:1 DAR 16:9], 597 kb/s, 25 fps, 25 tbr, 25k tbn, 50 tbc
    Metadata:
      creation_time   : 2010-01-24 00:55:16
    Stream #0.1(und): Audio: aac, 44100 Hz, stereo, s16, 109 kb/s
    Metadata:
      creation_time   : 2010-01-24 00:55:17
At least one output file must be specified
我如何获得高度=640,宽度=360?

看看大多数格式的句柄

如果您正在寻找解析ffmpeg输出的方法,请使用regexp
\d+x\d+

使用perl的示例:

$ ./ffmpeg -i test020.3gp 2>&1 | perl -lane 'print $1 if /(\d+x\d+)/'
176x120
使用python的示例(不完美):

[][][][][][][]176x120][]


Python一行程序没有perl一行程序那么吸引人:-)

根据上面Fredrik的提示,下面是我如何使用MediaInfo()实现的:

在python中有一个粗略的解决方案:

import subprocess, re
pattern = re.compile(r'Stream.*Video.*([0-9]{3,})x([0-9]{3,})')

def get_size(pathtovideo):
    p = subprocess.Popen(['ffmpeg', '-i', pathtovideo],
                         stdout=subprocess.PIPE,
                         stderr=subprocess.PIPE)
    stdout, stderr = p.communicate()
    match = pattern.search(stderr)
    if match:
        x, y = map(int, match.groups()[0:2])
    else:
        x = y = 0
    return x, y
但是,假设它是3位x 3位(即854x480),则需要循环遍历可能的尺寸长度,例如(1280x720):

并检查match在每个步骤中是否返回None:

for pattern in possible_patterns:
    match = pattern.search(stderr)
    if match!=None:
        x, y = map(int, match.groups()[0:2])
        break

if match == None:
    print "COULD NOT GET VIDEO DIMENSIONS"
    x = y = 0

return '%sx%s' % (x, y)
可能会更漂亮,但效果不错

坏(\d+x\d+)

好([0-9]{2,}x[0-9]+)

无re模块

out = error_message.split()               # make a list from resulting error string
out.reverse()
for index, item in enumerate(out):        # extract the item before item= "[PAR"
    if item == "[PAR":                      #
        dimension_string = out[i+1]          #
        video_width, video_height = dimension_string.split("x")

编辑:不是一个好答案,因为并非所有视频都有“PAR”信息:(

回答此问题的最佳方式是ffmpeg开发人员准确解释ffmpeg输出的格式,以及我们是否可以一致地假设大小位于其中的指定上下文中。在此之前,我们只能通过示例猜测格式通常是什么

这是我的尝试。与这些“一行程序”相比,这是冗长的,但那是因为我想知道为什么它最终失败了

import subprocess

def get_video_size(video_filename):
    """Returns width, height of video using ffprobe"""
    # Video duration and hence start time
    proc = subprocess.Popen(['ffprobe', video_filename],
        stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    res = proc.communicate()[0]

    # Check if ffprobe failed, probably on a bad file
    if 'Invalid data found when processing input' in res:
        raise ValueError("Invalid data found by ffprobe in %s" % video_filename)

    # Find the video stream
    width_height_l = []
    for line in res.split("\n"):
        # Skip lines that aren't stream info
        if not line.strip().startswith("Stream #"):
            continue

        # Check that this is a video stream
        comma_split = line.split(',')
        if " Video: " not in comma_split[0]:
            continue

        # The third group should contain the size and aspect ratio
        if len(comma_split) < 3:
            raise ValueError("malform video stream string:", line)

        # The third group should contain the size and aspect, separated
        # by spaces
        size_and_aspect = comma_split[2].split()        
        if len(size_and_aspect) == 0:
            raise ValueError("malformed size/aspect:", comma_split[2])
        size_string = size_and_aspect[0]

        # The size should be two numbers separated by x
        width_height = size_string.split('x')
        if len(width_height) != 2:
            raise ValueError("malformed size string:", size_string)

        # Cast to int
        width_height_l.append(map(int, width_height))

    if len(width_height_l) > 1:
        print "warning: multiple video streams found, returning first"
    return width_height_l[0]
导入子流程
def get_video_大小(视频文件名):
“”“使用ffprobe返回视频的宽度、高度”“”
#视频持续时间和开始时间
proc=subprocess.Popen(['ffprobe',video_filename],
stdout=subprocess.PIPE,stderr=subprocess.stdout)
res=proc.communicate()[0]
#检查ffprobe是否失败,可能是在错误的文件上
如果res中的“处理输入时发现无效数据”:
raise VALUERROR(“ffprobe在%s”%video\u filename中找到无效数据)
#查找视频流
宽度\高度\ l=[]
对于res.split(“\n”)中的行:
#跳过不是流信息的行
如果不是line.strip().startswith(“Stream#”):
持续
#检查这是一个视频流
逗号_split=line.split(',')
如果“视频:”不以逗号分隔[0]:
持续
#第三组应包含大小和纵横比
如果len(逗号分割)<3:
raise VALUERROR(“格式错误的视频流字符串:”,第行)
#第三组应该包含大小和纵横比,分开
#按空格
大小和纵横比=逗号分割[2]。分割()
如果len(大小和纵横比)==0:
raise VALUERROR(“格式错误的大小/方面:”,逗号分割[2])
大小\字符串=大小\和\方面[0]
#大小应该是由x分隔的两个数字
宽度\高度=大小\字符串。拆分('x')
如果len(宽度和高度)!=2:
raise VALUERROR(“格式错误的大小字符串:”,大小字符串)
#转换为整数
宽度\高度\ l.附加(映射(整数,宽度\高度))
如果长度(宽度和高度)大于1:
打印“警告:找到多个视频流,先返回”
返回宽度\u高度\u l[0]
使用
ffprobe
示例1:使用键/变量名 示例2:仅宽度x高度 示例3:JSON 示例4:JSON压缩 示例5:XML
ffprobe-v error-select_streams v-show_entries stream=width,height-of xml input.mkv

选项的作用:

  • -v error
    进行安静输出,但允许显示错误。不包括通常的通用FFmpeg输出信息,包括版本、配置和输入详细信息

  • -show_entries stream=width,height
    只需显示
    width
    height
    流信息

  • -of
    选项选择输出格式(默认格式、压缩格式、csv格式、平面格式、ini格式、json格式、xml格式)。有关每种格式的说明,请参阅,并查看其他格式选项

  • -选择\u streams v:0
    如果您的输入包含多个视频流,则可以添加此选项。
    v:0
    将仅选择第一个视频流。否则,您将获得与视频流一样多的
    width
    height
    输出。
    -选择\u streams v
    可用于显示所有视频流的信息铰孔并避免JSON和XML输出中的空音频
    信息

  • 有关更多信息,请参阅和


如本文所述,
ffprobe
提供了一种检索视频文件数据的方法。我发现以下命令非常有用
ffprobe-v quiet-print\u format json-show\u streams input video.xxx
,可以查看您可以签出的数据类型

然后我编写了一个函数,运行上述命令并返回视频文件的高度和宽度:

import subprocess
import shlex
import json

# function to find the resolution of the input video file
def findVideoResolution(pathToInputVideo):
    cmd = "ffprobe -v quiet -print_format json -show_streams"
    args = shlex.split(cmd)
    args.append(pathToInputVideo)
    # run the ffprobe process, decode stdout into utf-8 & convert to JSON
    ffprobeOutput = subprocess.check_output(args).decode('utf-8')
    ffprobeOutput = json.loads(ffprobeOutput)

    # find height and width
    height = ffprobeOutput['streams'][0]['height']
    width = ffprobeOutput['streams'][0]['width']

    return height, width

这是有帮助的,但我认为OP希望捕获python中的值。@Geoff这将提供所需的值,并且比这里显示的其他方法更可靠。它如何与python一起使用取决于用户。事实上,这对我帮助很大。谢谢。使用
子流程
包对ca进行
搜索
非常容易解析p请检查输出。很抱歉听起来是否定的。
-of json
以json格式返回数据,这在Python中更容易访问(避免使用正则表达式)。@SimonSteinberger编辑为提及json以及所有其他可用格式。当我测试时,此格式失败,因为流信息是
stream#0:0:Video:mjpeg(MJPG/0x47504A4D),yuvj420p(pc,bt470bg/unknown/unknown),733x446[SAR 1:1 DAR 733:446],7516 kb/s,60 fps,60 tbr,60 tbn,60 tbc
,因此结果是
[[[[]['0x47504',733x446'][][/code>这很好,但对m4v不起作用
$ echo 'Stream #0:0(eng): Video: mjpeg (jpeg / 0x6765706A), yuvj420p, 1280x720, 19939 kb/s, 30 fps, 30 tbr, 30 tbn, 30 tbc' | perl -lane 'print $1 if /(\d+x\d+)/'
> 0x6765706
$ echo 'Stream #0:0(eng): Video: mjpeg (jpeg / 0x6765706A), yuvj420p, 1280x720, 19939 kb/s, 30 fps, 30 tbr, 30 tbn, 30 tbc' | perl -lane 'print $1 if /([0-9]{2,}x[0-9]+)/'
> 1280x720
out = error_message.split()               # make a list from resulting error string
out.reverse()
for index, item in enumerate(out):        # extract the item before item= "[PAR"
    if item == "[PAR":                      #
        dimension_string = out[i+1]          #
        video_width, video_height = dimension_string.split("x")
import subprocess

def get_video_size(video_filename):
    """Returns width, height of video using ffprobe"""
    # Video duration and hence start time
    proc = subprocess.Popen(['ffprobe', video_filename],
        stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    res = proc.communicate()[0]

    # Check if ffprobe failed, probably on a bad file
    if 'Invalid data found when processing input' in res:
        raise ValueError("Invalid data found by ffprobe in %s" % video_filename)

    # Find the video stream
    width_height_l = []
    for line in res.split("\n"):
        # Skip lines that aren't stream info
        if not line.strip().startswith("Stream #"):
            continue

        # Check that this is a video stream
        comma_split = line.split(',')
        if " Video: " not in comma_split[0]:
            continue

        # The third group should contain the size and aspect ratio
        if len(comma_split) < 3:
            raise ValueError("malform video stream string:", line)

        # The third group should contain the size and aspect, separated
        # by spaces
        size_and_aspect = comma_split[2].split()        
        if len(size_and_aspect) == 0:
            raise ValueError("malformed size/aspect:", comma_split[2])
        size_string = size_and_aspect[0]

        # The size should be two numbers separated by x
        width_height = size_string.split('x')
        if len(width_height) != 2:
            raise ValueError("malformed size string:", size_string)

        # Cast to int
        width_height_l.append(map(int, width_height))

    if len(width_height_l) > 1:
        print "warning: multiple video streams found, returning first"
    return width_height_l[0]
ffprobe -v error -show_entries stream=width,height -of default=noprint_wrappers=1 input.mp4
width=1280
height=720
ffprobe -v error -select_streams v -show_entries stream=width,height -of csv=p=0:s=x input.m4v
1280x720
ffprobe -v error -select_streams v -show_entries stream=width,height -of json input.mkv 
{
    "programs": [

    ],
    "streams": [
        {
            "width": 1280,
            "height": 720
        }
    ]
}
ffprobe -v error -select_streams v -show_entries stream=width,height -of json=compact=1 input.mkv 
{
    "programs": [

    ],
    "streams": [
        { "width": 1280, "height": 720 }
    ]
}
ffprobe -v error -select_streams v -show_entries stream=width,height -of xml input.mkv 
<?xml version="1.0" encoding="UTF-8"?>
<ffprobe>
    <programs>
    </programs>

    <streams>
        <stream width="1280" height="720"/>
    </streams>
</ffprobe>
import subprocess
import shlex
import json

# function to find the resolution of the input video file
def findVideoResolution(pathToInputVideo):
    cmd = "ffprobe -v quiet -print_format json -show_streams"
    args = shlex.split(cmd)
    args.append(pathToInputVideo)
    # run the ffprobe process, decode stdout into utf-8 & convert to JSON
    ffprobeOutput = subprocess.check_output(args).decode('utf-8')
    ffprobeOutput = json.loads(ffprobeOutput)

    # find height and width
    height = ffprobeOutput['streams'][0]['height']
    width = ffprobeOutput['streams'][0]['width']

    return height, width