【问题标题】:Getting video dimension / resolution / width x height from ffmpeg从ffmpeg获取视频尺寸/分辨率/宽度x高度
【发布时间】:2011-11-13 19:07:51
【问题描述】:

如何从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

我如何获得height = 640, width= 360

【问题讨论】:

    标签: video ffmpeg ffprobe


    【解决方案1】:

    使用ffprobe

    示例 1:使用键/变量名

    ffprobe -v error -show_entries stream=width,height -of default=noprint_wrappers=1 input.mp4
    width=1280
    height=720
    

    示例 2:宽度 x 高度

    ffprobe -v error -select_streams v -show_entries stream=width,height -of csv=p=0:s=x input.m4v
    1280x720
    

    示例 3:JSON

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

    示例 4:JSON 压缩

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

    示例 5:XML

    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>
    

    选项的作用:

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

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

    • -of 选项选择输出格式(默认、紧凑、csv、flat、ini、json、xml)。请参阅FFprobe Documentation: Writers 了解每种格式的说明并查看其他格式选项。

    • -select_streams v:0 如果您的输入包含多个视频流,则可以添加此项。 v:0 将只选择第一个视频流。否则,您将获得与视频流一样多的widthheight 输出。 -select_streams v 可用于显示来自所有视频流的信息,并避免在 JSON 和 XML 输出中出现空音频 stream 信息。

    • 请参阅FFprobe DocumentationFFmpeg Wiki: FFprobe Tips 了解更多信息。

    【讨论】:

    • 这很有帮助,但我认为 OP 想要捕获 python 中的值。
    • -of json 以 JSON 格式返回数据,在 Python 中更容易访问(避免使用正则表达式)。
    • @SimonSteinberger 编辑提及 json 以及所有其他可用格式。
    • @HashimAziz 答案中提到:“-select_streams v:0 如果您的输入包含多个视频流,则可以添加。v:0 将仅选择第一个视频流。否则您会得到与视频流一样多的宽度和高度输出。-select_streams v 可用于显示来自所有视频流的信息,并避免 JSON 和 XML 输出中的空音频流信息。因此添加它是为了避免出现在某些输出格式中的空白音频信息出现额外的空行。
    • @HashimAziz 我什至不记得它在那里,直到我要回复。我猜 98% 的读者还是会跳过这些笔记。
    【解决方案2】:

    看看mediainfo 处理大多数格式。

    如果您正在寻找一种方法来解析 ffmpeg 的输出,请使用正则表达式 \d+x\d+

    使用 perl 的示例:

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

    使用python的示例(不完美):

    $ ./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 的单行代码不如 perl 的吸引人 :-)

    【讨论】:

    • 这个我测试的时候失败了,因为stream info是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'][]
    【解决方案3】:

    正如这里提到的,ffprobe 提供了一种检索视频文件数据的方法。我发现以下命令很有用 ffprobe -v quiet -print_format json -show_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
    

    【讨论】:

    • 这很好,但它不适用于将维度存储在第二个数组中的 m4v。所以只有这样,尺寸必须由height = ffprobeOutput['streams'][1]['height']width = ffprobeOutput['streams'][0]['width']检索
    【解决方案4】:

    根据上面 Fredrik 的提示,这是我使用 MediaInfo (http://mediainfo.sourceforge.net/en) 的方法:

    >>> p1 = subprocess.Popen(['mediainfo', '--Inform=Video;%Width%x%Height%',         
        '/Users/david/Desktop/10stest720p.mov'],stdout=PIPE)
    >>> dimensions=p1.communicate()[0].strip('\n')
    >>> dimensions
    '1280x688'
    

    【讨论】:

      【解决方案5】:

      this blog post有一个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):

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

      并检查 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)
      

      可能更漂亮,但有效。

      【讨论】:

        【解决方案6】:

        不好 (\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
        

        好([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
        

        【讨论】:

          【解决方案7】:

          回答这个问题的最佳方法是让 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]
          

          【讨论】:

            【解决方案8】:

            没有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”信息:(

            【讨论】:

              猜你喜欢
              • 2012-03-19
              • 1970-01-01
              • 2010-10-15
              • 1970-01-01
              • 2016-11-11
              • 1970-01-01
              • 1970-01-01
              • 2011-11-02
              相关资源
              最近更新 更多