Получение размера видео из ffmpeg -i
Как я могу получить высоту и ширину видео от ffmpeg
Вывод информации. Например, со следующим выводом -
$ 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
Как бы я получил height = 640, width= 360
? Спасибо.
8 ответов
Взгляните на 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:-)
использование ffprobe
Пример 1: с ключами / именами переменных
ffprobe -v error -show_entries stream=width,height -of default=noprint_wrappers=1 input.mp4
width=1280
height=720
Пример 2: только ширина х высота
ffprobe -v error -show_entries stream=width,height -of csv=p=0:s=x input.m4v
1280x720
Пример 3: JSON
ffprobe -v error -show_entries stream=width,height -of json input.mkv
{
"programs": [
],
"streams": [
{
"width": 1280,
"height": 720
},
{
}
]
}
Что делают варианты:
-v error
Сделайте тихий вывод, но разрешите отображение ошибок. Исключает обычную общую информацию о выводе FFmpeg, включая версию, конфигурацию и детали ввода.-show_entries stream=width,height
Просто покажиwidth
а такжеheight
потоковая информация.-of
опция выбирает формат вывода (по умолчанию, компактный, CSV, плоский, INI, JSON, XML). См. FFprobe Documentation: Writers для описания каждого формата и просмотра дополнительных параметров форматирования.-select_streams v:0
Это может быть добавлено в случае, если ваш вход содержит несколько видеопотоков.v:0
выберет только первый видеопоток. В противном случае вы получите столькоwidth
а такжеheight
выводит как есть видеопотоки.См. Документацию FFprobe и FFmpeg Wiki: советы FFprobe для получения дополнительной информации.
Как уже упоминалось здесь, 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
ПЛОХО (\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
В этом сообщении блога есть грубое решение в 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 цифры х 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,})')]
и проверьте, возвращает ли совпадение 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)
Может быть красивее, но работает.
Из приведенного выше совета Фредрика, вот как я это сделал с помощью 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'
Лучший способ ответить на этот вопрос - дать разработчику 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]
Без повторного модуля
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":(