2013-04-03 12 views
8

Chciałbym tworzyć miniatury dla filmów MPEG-4 AVC za pomocą Gstreamer i Python. Zasadniczo:Tworzenie miniaturek wideo za pomocą Pythona i Gstreamera

  1. Otwórz plik wideo
  2. Szukajcie w pewnym momencie (np 5 sekund)
  3. Grab rama w tym czasie
  4. zapisać ramka na dysk w postaci pliku .jpg

Patrzyłem na this other similar question, ale nie mogę całkiem dowiedzieć się, jak zrobić automatyczne pobieranie i klatka bez wprowadzania danych przez użytkownika.

Podsumowując, w jaki sposób mogę uchwycić miniaturę wideo w Gstreamer i Pythonie zgodnie z powyższymi krokami?

+1

Pamiętaj, że "5 sekund" prawdopodobnie nie będzie działać. W przypadku wielu komercyjnych filmów dostaniesz tylko intro/logo. Spróbuj znaleźć czarne ramki (wskazują zmiany sceny), a następnie poszukaj kilku sekund w scenie. Zaoferuj użytkownikowi 4-5 z nich, aby znaleźć obraz, który jest łatwy do rozpoznania. –

+0

Ta funkcja jest przeznaczona do osobistych filmów wideo, które trwają dłużej niż 5 sekund. W każdym razie, liczba 5 sekund jest po prostu dowolna i ze względu na przykład. Może to być 2, 10 lub jakakolwiek inna wartość poniżej, powiedzmy, 30 sekund. –

Odpowiedz

7

Aby rozwinąć na odpowiedź ensonic „s, oto przykład:

import os 
import sys 

import gst 

def get_frame(path, offset=5, caps=gst.Caps('image/png')): 
    pipeline = gst.parse_launch('playbin2') 
    pipeline.props.uri = 'file://' + os.path.abspath(path) 
    pipeline.props.audio_sink = gst.element_factory_make('fakesink') 
    pipeline.props.video_sink = gst.element_factory_make('fakesink') 
    pipeline.set_state(gst.STATE_PAUSED) 
    # Wait for state change to finish. 
    pipeline.get_state() 
    assert pipeline.seek_simple(
     gst.FORMAT_TIME, gst.SEEK_FLAG_FLUSH, offset * gst.SECOND) 
    # Wait for seek to finish. 
    pipeline.get_state() 
    buffer = pipeline.emit('convert-frame', caps) 
    pipeline.set_state(gst.STATE_NULL) 
    return buffer 

def main(): 
    buf = get_frame(sys.argv[1]) 

    with file('frame.png', 'w') as fh: 
     fh.write(str(buf)) 

if __name__ == '__main__': 
    main() 

ten generuje obraz PNG. Możesz uzyskać surowe dane obrazu za pomocą gst.Caps("video/x-raw-rgb,bpp=24,depth=24") lub coś w tym stylu.

Należy zauważyć, że w GStreamer 1.0 (w przeciwieństwie do 0,10), playbin2 została zmieniona na playbin i sygnał convert-frame nazwie convert-sample.

Mechanizmy wyszukiwania są wyjaśnione w this chapter of the GStreamer Application Development Manual. Dokumentacja 0.10 playbin2 nie jest już dostępna w trybie online, ale dokumentacja dla wersji 1.0 to here.

+0

To jest * doskonałe *, dziękuję! Próbowałem przenieść kod do PyGI i znalazłem problem polegający na tym, że 'gst.Caps ('image/png')' już nie działa, ponieważ nowa Gst.Caps() nie przyjmuje żadnych argumentów, i Nie znalazłem żadnego zamiennika ('gst.caps_from_string ('image/png')' segfaults). Jakieś wskazówki? –

+0

Stworzyłem [istotę z wersją PyGI] (https://gist.github.com/dplanella/5563018) i działa bez błędu. Tworzy jednak nieczytelne pliki .png. Jeśli któryś z ekspertów GStreamer zauważy błąd, każdy wskaźnik będzie mile widziany, dzięki! –

+0

Domyślam się, że 'str (buf)' nie robi już tego, co kiedyś, a teraz daje ci coś w rodzaju '" "'. Czy próbowałeś spojrzeć na wynikowy plik PNG? Zgaduję, że chcesz coś takiego jak "buf.data". – daf

2

Użyj playbin2. ustaw uri na plik multimedialny, użyj gst_element_seek_simple, aby znaleźć żądaną pozycję czasową, a następnie użyj g_signal_emit, aby wywołać sygnał akcji "convert-frame".

+0

Dzięki za odpowiedź. Czy zastanawiałbyś się nad opracowaniem fragmentu kodu? Rozumiem część z 'playbin2', ale ani' gst_element_seek_simple() 'ani' gst.element_seek_simple() 'nie wydają się być dostępne w Pythonie. –

+0

Ok, zorientowałem się, że w Pythonie jest 'gst.Element.seek_simple()' i jak z niego korzystać. Mimo to, fragment kodu Pythona byłby bardzo pomocny, ponieważ teraz następnym krokiem jest znalezienie sposobu użycia odpowiednika 'g_signal_emit'. –

+0

Przepraszam, nie mogę pomóc po stronie Pythona:/ – ensonic

2

Przykładem w Vala, z GStreamer 1.0:

var playbin = Gst.ElementFactory.make ("playbin", null); 
playbin.set ("uri", "file:///path/to/file"); 
// some code here. 
var caps = Gst.Caps.from_string("image/png"); 
Gst.Sample sample; 
Signal.emit_by_name(playbin, "convert-sample", caps, out sample); 
if(sample == null) 
    return; 
var sample_caps = sample.get_caps(); 
if(sample_caps == null) 
    return; 
unowned Gst.Structure structure = sample_caps.get_structure(0); 
int width = (int)structure.get_value ("width"); 
int height = (int)structure.get_value ("height"); 
var memory = sample.get_buffer().get_memory (0); 
Gst.MapInfo info; 
memory.map (out info, Gst.MapFlags.READ); 
uint8[] data = info.data; 
+0

Dzięki! Jednak wciąż szukam przykładu Pythona. Wygląda na to, że z powodu [tego błędu] (https://bugzilla.gnome.org/show_bug.cgi?id=678663) nadal nie jest to możliwe w GStreamer 1.0 i Pythonie: / –

1

To stare pytanie, ale ja nadal nie znalazłem to udokumentowane w dowolnym miejscu.
Okazało się, że następuje pracował na gry wideo z GStreamer 1,0

import gi 
import time 
gi.require_version('Gst', '1.0') 
from gi.repository import Gst 

def get_frame(): 
    caps = Gst.Caps('image/png') 
    pipeline = Gst.ElementFactory.make("playbin", "playbin") 
    pipeline.set_property('uri','file:///home/rolf/GWPE.mp4') 
    pipeline.set_state(Gst.State.PLAYING) 
    #Allow time for it to start 
    time.sleep(0.5) 
    # jump 30 seconds 
    seek_time = 30 * Gst.SECOND 
    pipeline.seek(1.0, Gst.Format.TIME,(Gst.SeekFlags.FLUSH | Gst.SeekFlags.ACCURATE),Gst.SeekType.SET, seek_time , Gst.SeekType.NONE, -1) 

    #Allow video to run to prove it's working, then take snapshot 
    time.sleep(1) 
    buffer = pipeline.emit('convert-sample', caps) 
    buff = buffer.get_buffer() 
    result, map = buff.map(Gst.MapFlags.READ) 
    if result: 
     data = map.data 
     pipeline.set_state(Gst.State.NULL) 
     return data 
    else: 
     return 

if __name__ == '__main__': 
    Gst.init(None) 
    image = get_frame() 
    with open('frame.png', 'wb') as snapshot: 
     snapshot.write(image) 

Kod powinien pracować zarówno python2 i Python3, mam nadzieję, że ktoś pomoże.

Powiązane problemy