Obtención de la dimensión de video de ffmpeg -i

¿Cómo obtendría la altura y el ancho de un video a partir de la salida de información de ffmpeg ? Por ejemplo, con la siguiente salida:

 $ 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 

¿Cómo obtendría height = 640, width= 360 ? Gracias.

Echa un vistazo a mediainfo Maneja la mayoría de los formatos que hay.

Si busca una manera de analizar la salida de ffmpeg, use la expresión regular \d+x\d+

Ejemplo usando perl:

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

Ejemplo usando python (no perfecto):

 $ ./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]" 

[] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [‘176×120’] [] [] [] []

Las frases de Python no son tan pegajosas como las de Perl 🙂

Use ffprobe

Ejemplo 1: Con claves / nombres de variables

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

Ejemplo 2: Sólo ancho x alto

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

Ejemplo 3: JSON

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

Lo que hacen las opciones:

  • -v error Realiza una salida silenciosa, pero permite que se muestren los errores. Excluye la información de salida de FFmpeg genérica habitual, incluida la versión, configuración y detalles de entrada.

  • -show_entries stream=width,height Solo muestra la información de stream de width y height .

  • -of opción elige el formato de salida (predeterminado, compacto, csv, plano, ini, json, xml). Consulte la documentación de FFprobe: Escritores para obtener una descripción de cada formato y ver opciones de formato adicionales.

  • -select_streams v:0 Esto se puede agregar en caso de que su entrada contenga múltiples transmisiones de video. v:0 seleccionará solo la primera transmisión de video. De lo contrario, obtendrás tantas salidas de width y height como canales de video.

  • Consulte la documentación de FFprobe y la wiki de FFmpeg: consejos de FFprobe para obtener más información.

De la sugerencia de Fredrik arriba, aquí está cómo lo hice usando 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' 

En esta publicación de blog hay una solución aproximada en 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 

Sin embargo, esto supone que son 3 dígitos x 3 dígitos (es decir, 854×480), tendrá que recorrer las posibles longitudes de dimensión, como (1280×720):

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

y compruebe si el partido devuelve Ninguno en cada paso:

 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) 

Podría ser más bonito, pero funciona.

Como se mencionó aquí, ffprobe proporciona una forma de recuperar datos sobre un archivo de video. Encontré el siguiente comando útil ffprobe -v quiet -print_format json -show_streams input-video.xxx para ver qué tipo de datos puede verificar.

Luego escribí una función que ejecuta el comando anterior y devuelve la altura y el ancho del archivo de video:

 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 

MALO (\ 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 

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

La mejor manera de responder a esta pregunta sería que un desarrollador de ffmpeg explique exactamente cuál es el formato de salida de ffmpeg que se espera que sea y si podemos asumir constantemente que el tamaño está ubicado en un contexto específico dentro de él. Hasta entonces, solo podemos adivinar, por ejemplo, cuál es el formato habitual.

Aquí está mi bash. Es detallado en comparación con estos “one-liners”, pero eso es porque me gustaría saber por qué falla cuando finalmente lo hace.

 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] 

sin re modulo

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

Edición: no es una buena respuesta porque no todos los videos tienen esa información “PAR” 🙁