2011-09-09 18 views
7

Come ottenere l'altezza e la larghezza di un video dall'output di informazioni di ffmpeg. Ad esempio, con il seguente risultato -Come ottenere dimensione video da ffmpeg -i

$ 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 

Come potrei ottenere height = 640, width= 360? Grazie.

risposta

7

Dai un'occhiata a mediainfo Gestisce la maggior parte dei formati disponibili.

Se stai cercando un modo per analizzare l'output da ffmpeg, utilizzare l'espressione regolare \d+x\d+

Esempio con perl:

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

Esempio con python (non perfetto):

$ ./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 non sono così orecchiabili come quelli perl :-)

+0

Perfetto, vi ringrazio molto. – David542

+1

Questo fallisce quando ho provato, perché le informazioni di flusso sono 'Stream # 0: 0: Video: mjpeg (MJPG/0x47504A4D), yuvj420p (pc, bt470bg/sconosciuto/sconosciuto), 733x446 [SAR 1: 1 DAR 733: 446], 7516 kb/s, 60 fps, 60 tbr, 60 tbn, 60 tbc', quindi il risultato è '[] [] [] [] [] [] [] [] [] [] [] [] [] ['0x47504', '733x446'] [] ' –

3

dalla punta di Fredrik sopra, ecco come ho fatto 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' 
3

In this blog post theres una soluzione di massima 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 

Questo tuttavia presuppone che sia 3 cifre x 3 cifre (cioè 854x480), avrete bisogno di un ciclo tra i possibili lunghezze di quota, come ad esempio (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,})')] 

e controllare se partita restituisce None su ogni passo:

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) 

Potrebbe essere più bella, ma lavori.

1

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 

Buono ([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 
+0

o (\ d {2,} x \ d +) –

0

senza modulo

ri
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: non è una buona risposta, perché non tutti i video hanno quelle informazioni "PAR" :(

1

Il modo migliore per rispondere a questa domanda sarebbe che uno sviluppatore di ffmpeg spieghi esattamente quale sia il formato dell'output ffmpeg e se sia possibile assumere in modo coerente la dimensione da localizzare in un contesto specificato all'interno di esso. Fino ad allora possiamo solo supporre dall'esempio quale sia il formato di solito.

Ecco il mio tentativo. È prolisso rispetto a questi "one-liners", ma è perché mi piacerebbe sapere perché fallisce quando alla fine lo fa.

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] 
29

Uso ffprobe:

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

Quali le opzioni fanno:

  • -v error fare un'uscita tranquilla, ma permettono gli errori da visualizzare. Esclude le solite informazioni generiche sull'output di FFmpeg tra cui versione, configurazione e dettagli di input.

  • -show_entries stream=width,height Basta mostrare le informazioni sullo streaming width e height.

  • -of default=noprint_wrappers=1 Questo ometterà i wrapper [STREAM]...[/STREAM] che verrebbero normalmente visualizzati nell'output. Se si desidera omettere le chiavi width= e height=, utilizzare -of default=noprint_wrappers=1:nokey=1.

  • Altre opzioni di formato di output sono disponibili per soddisfare le vostre esigenze. Questi possono essere impostati tramite l'opzione -of (alias -print_format) ei formati sono: predefinito, compatto, csv, flat, ini, json, xml. Vedi FFprobe Documentation: Writers per una descrizione di ogni formato e per visualizzare ulteriori opzioni.

  • -select_streams v:0 Questo può essere aggiunto nel caso in cui l'input contenga più flussi video. v:0 selezionerà solo il primo flusso video. Altrimenti riceverai altrettante uscite width e height in quanto ci sono flussi video.

  • Vedere FFprobe Documentation e FFmpeg Wiki: FFprobe Tips per ulteriori informazioni.

+0

Ciò è utile, ma penso che OP abbia voluto acquisire i valori in python. – Geoff

+0

@Geoff Fornirà i valori necessari e sarà più affidabile rispetto all'altro metodo mostrato qui. Il modo in cui viene utilizzato con Python dipende dall'utente. – LordNeckbeard

+0

Infatti. Mi ha aiutato molto. Grazie. Molto facile da analizzare con 're.search' usando il pacchetto' subprocess' per catturare l'output. Mi dispiace per sembrare negativo. – Geoff

2

Come accennato qui, ffprobe fornisce un modo di recuperare i dati su un file video. Ho trovato il seguente comando utile ffprobe -v quiet -print_format json -show_streams input-video.xxx per vedere che tipo di dati è possibile verificare.

Ho quindi scritto una funzione che esegue il comando sopra e restituisce l'altezza e la larghezza del file 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