2013-04-03 12 views
8

Mi piacerebbe creare miniature per video MPEG-4 AVC usando Gstreamer e Python. In sostanza:Come creare miniature video con Python e Gstreamer

  1. Apri file video
  2. Seek ad un certo punto nel tempo (ad esempio 5 secondi)
  3. Afferrare il telaio in quel momento
  4. Salva il telaio su disco come file .jpg

Ho guardato allo this other similar question, ma non riesco a capire come eseguire automaticamente la cattura e il frame capture senza l'input dell'utente.

Quindi, in sintesi, come posso acquisire una miniatura del video con Gstreamer e Python come da procedura sopra riportata?

+1

Si noti che "5 secondi" probabilmente non funzionerà. Per molti film commerciali, avrai solo l'introduzione/logo. Prova a trovare cornici nere (indicano i cambi di scena) e poi cerca alcuni secondi nella scena. Offri all'utente 4-5 di quelli per trovare un'immagine che sia facile da riconoscere. –

+0

Questo è per i video personali che durano più di 5 secondi. In ogni caso, la cifra di 5 secondi è arbitraria e per l'esempio. Potrebbe essere 2, 10 o qualsiasi altro valore sotto, diciamo, 30 secondi. –

risposta

7

di approfondire la risposta ensonic s', ecco un esempio:

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

Questo genera un'immagine PNG. È possibile ottenere dati di immagini grezzi utilizzando gst.Caps("video/x-raw-rgb,bpp=24,depth=24") o qualcosa del genere.

Si noti che in GStreamer 1.0 (al contrario di 0,10), playbin2 è stata rinominata in playbin e il segnale convert-frame è chiamato convert-sample.

I meccanismi di ricerca sono spiegati in this chapter of the GStreamer Application Development Manual. La documentazione 0.10 playbin2 non sembra essere più in linea, ma la documentazione per 1.0 è here.

+0

Questo è * eccellente *, grazie! Ho provato a portare il codice su PyGI, e ho trovato un problema per il quale 'gst.Caps ('image/png')' non funziona più, dato che il nuovo Gst.Caps() non accetta argomenti, e Non ho trovato alcuna sostituzione ('Gst.caps_from_string ('image/png')' segfaults). Qualche indicazione? –

+0

Ho creato [un gist con la versione PyGI] (https://gist.github.com/dplanella/5563018) e funziona senza errori. Tuttavia, crea file .png illeggibili. Se qualche esperto di GStreamer riuscisse a individuare l'errore, qualsiasi puntatore sarebbe benvenuto, grazie! –

+0

La mia ipotesi è che 'str (buf)' non fa più ciò che era solito e ora ti dà qualcosa come '" "'. Hai provato a guardare il file PNG risultante? Immagino che tu voglia qualcosa come "buf.data". – daf

2

Utilizzare playbin2. imposta l'uri sul file multimediale, usa gst_element_seek_simple per cercare la posizione temporale desiderata e poi usa g_signal_emit per invocare il segnale di azione "convert-frame".

+0

Grazie per la risposta. Ti piacerebbe elaborare un po 'con un frammento di codice forse? Capisco la parte con 'playbin2', ma né' gst_element_seek_simple() 'né' gst.element_seek_simple() 'sembrano essere disponibili in Python. –

+0

Ok, ho capito che c'è 'gst.Element.seek_simple()' in Python, e come usarlo. Tuttavia, uno snippet Python sarebbe davvero utile, poiché ora la prossima cosa da capire è come usare l'equivalente 'g_signal_emit'. –

+0

Spiacente, non posso aiutare n lato python:/ – ensonic

2

Un esempio in Vala, con 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

Grazie! Tuttavia, sto ancora cercando un esempio Python. Sembra che a causa di [questo bug] (https://bugzilla.gnome.org/show_bug.cgi?id=678663) questo non sia ancora possibile con GStreamer 1.0 e Python: / –

1

Si tratta di una vecchia questione, ma non ho ancora trovato documentato da nessuna parte.
Ho trovato che la seguente lavorato su un video gioco con 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) 

Il codice dovrebbe funzionare sia con python2 e python3, spero che aiuta qualcuno.