Getting video dimension from ffmpeg -i

2020-02-08 06:34发布

How would I get the height and width of a video from ffmpeg's information output. For example, with the following output --

$ ffmpeg -i 1video.mp4
...

Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '/Users/david/Desktop/1video.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

How would I get height = 640, width= 360 ? Thank you.

8条回答
别忘想泡老子
2楼-- · 2020-02-08 06:36

In this blog post theres a rough solution in 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

This however assumes it's 3 digits x 3 digits (i.e. 854x480), you'll need to loop through the possible dimension lengths, such as (1280x720):

possible_patterns = [re.compile(r'Stream.*Video.*([0-9]{4,})x([0-9]{4,})'), \
            re.compile(r'Stream.*Video.*([0-9]{4,})x([0-9]{3,})'), \
re.compile(r'Stream.*Video.*([0-9]{3,})x([0-9]{3,})')]

and check if match returns None on each step:

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)

Could be prettier, but works.

查看更多
beautiful°
3楼-- · 2020-02-08 06:42

The best way for to answer this question would be for an ffmpeg developer to explain exactly what the format of the ffmpeg output is expected to be and whether we can consistently assume the size to be located in a specified context within it. Until then we can only guess from example what the format usually is.

Here's my attempt. It's verbose compared to these "one-liners", but that's because I'd like to know why it fails when it eventually does.

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]
查看更多
走好不送
4楼-- · 2020-02-08 06:48

Have a look at mediainfo Handles most of the formats out there.

If you looking for a way to parse the output from ffmpeg, use the regexp \d+x\d+

Example using perl:

$ ./ffmpeg -i test020.3gp 2>&1 | perl -lane 'print $1 if /(\d+x\d+)/'
176x120

Example using python (not perfect):

$ ./ffmpeg -i /nfshome/enilfre/pub/test020.3gp 2>&1 | python -c "import sys,re;[sys.stdout.write(str(re.findall(r'(\d+x\d+)', line))) for line in sys.stdin]"

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

Python one-liners aren't as catchy as perl ones :-)

查看更多
成全新的幸福
5楼-- · 2020-02-08 06:48

BAD (\d+x\d+)

$ 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

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

$ 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
查看更多
SAY GOODBYE
6楼-- · 2020-02-08 06:49

without re module

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")

Edit: not a good answer because not all videos have that "PAR" information :(

查看更多
劫难
7楼-- · 2020-02-08 06:53

As mentioned here, ffprobe provides a way of retrieving data about a video file. I found the following command useful ffprobe -v quiet -print_format json -show_streams input-video.xxx to see what sort of data you can checkout.

I then wrote a function that runs the above command and returns the height and width of the video file:

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
查看更多
登录 后发表回答