2011-09-09 13 views
7

Jak uzyskać wysokość i szerokość wideo z danych wyjściowych ffmpeg? Na przykład, z następującym wyjścia -Uzyskiwanie wymiaru wideo z 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 

Jak dostanę height = 640, width= 360? Dziękuję Ci.

Odpowiedz

7

Spójrz na mediainfo Obsługuje większość formatów tam.

Jeśli szukasz sposobu, aby analizować dane wyjściowe z ffmpeg, należy użyć wyrażenia regularnego \d+x\d+

przykład przy użyciu Perl:

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

przykład przy użyciu python (nie doskonałe):

$ ./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 jednej wkładki nie są tak chwytliwe jak Perl te :-)

+0

doskonały, bardzo dziękuję. – David542

+1

To się nie powiedzie, gdy testowałem, ponieważ informacja o strumieniu to '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 tbs, 60 tbn, 60 tbc', więc wynikiem jest '[] [] [] [] [] [] ['0x47504', '733x446'] [] ' –

3

od czubka Fredrik za powyższym, oto jak to zrobiłem za pomocą 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

W this blog post tam szorstką rozwiązanie w 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 

Zakłada to jednak, że ma 3 cyfry x 3 cyfry (tj. 854x480), musisz pętli możliwych długościach wymiarów, takich jak (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,})')] 

i sprawdzić, czy zwraca mecz Brak na każdym kroku:

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) 

mogłyby być ładniejsze, ale Prace.

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 

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

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

0

bez modułu

ponownie
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: nie jest to dobre rozwiązanie, ponieważ nie wszystkie filmy mają, że "PAR" informacje :(

1

Najlepszym sposobem na udzielenie odpowiedzi na to pytanie jest dla programisty ffmpeg wyjaśnienie, na czym dokładnie polega format wyjściowy ffmpeg i czy możemy konsekwentnie zakładać, że rozmiar ma się znajdować w określonym kontekście. Do tego czasu możemy tylko domyślać się, z jakiego formatu zazwyczaj pochodzi.

Oto moja próba. Jest bardziej gadatliwy w porównaniu do tych "jedno-liniowych", ale to dlatego, że chciałbym wiedzieć, dlaczego zawodzi, kiedy w końcu to robi.

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

Zastosowanie ffprobe:

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

Co zrobić opcje:

  • -v error Zrób ciche wyjście, ale pozwalają błędy mają być wyświetlane. Nie obejmuje zwykłych ogólnych informacji wyjściowych FFmpeg, w tym wersji, konfiguracji i szczegółów wejściowych.

  • -show_entries stream=width,height Po prostu pokaż informacje o strumieniu width i height.

  • -of default=noprint_wrappers=1 Pominie to owijki [STREAM]...[/STREAM], które normalnie pojawią się na wydruku. Jeśli chcesz również pominąć klucze width= i height=, użyj -of default=noprint_wrappers=1:nokey=1.

  • Inne opcje formatu wyjściowego są dostępne w zależności od potrzeb. Można je ustawić za pomocą opcji -of (również jako -print_format), a formatami są: domyślny, kompaktowy, csv, płaski, ini, json, xml. Zobacz FFprobe Documentation: Writers, aby uzyskać opis każdego formatu i wyświetlić dodatkowe opcje.

  • -select_streams v:0 Można to dodać w przypadku, gdy dane wejściowe zawierają wiele strumieni wideo. v:0 wybierze tylko pierwszy strumień wideo. W przeciwnym razie otrzymasz tyle sygnałów wyjściowych, ile jest strumieni wideo.

  • Aby uzyskać więcej informacji, patrz: FFprobe Documentation i FFmpeg Wiki: FFprobe Tips.

+0

Jest to pomocne, ale uważam, że OP chciał przechwycić wartości w pythonie. – Geoff

+0

@Geoff Zapewni to potrzebne wartości i będzie bardziej wiarygodne niż w przypadku innej pokazanej tutaj metody. Sposób korzystania z Pythona zależy od użytkownika. – LordNeckbeard

+0

Rzeczywiście. Bardzo mi to pomogło. Dzięki. Bardzo łatwe do analizowania z 're.search' przy użyciu pakietu' subprocess' do przechwytywania danych wyjściowych. Przepraszamy za negatywne brzmienie. – Geoff

2

Jak wspomniano tutaj, ffprobe zapewnia sposób pobierania danych o pliku wideo. Następujące polecenie okazało się przydatne: ffprobe -v quiet -print_format json -show_streams input-video.xxx, aby zobaczyć, jakie dane można sprawdzić.

I wtedy napisałem funkcję, która biegnie powyższego polecenia i zwraca wysokość i szerokość pliku wideo:

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