2011-12-19 13 views
9

Il problema che ho riferisce al seguente pezzo di codice:Haskell GStreamer elemento a T (1-N) problemi

module Main(main) where 

import qualified Media.Streaming.GStreamer as GS 
import Data.Maybe 
import System.IO 
import System.Exit 
import System.Glib.MainLoop as Glib 
import System.Glib.Signals as Glib 
import System.Glib.Properties as Glib 


makeElement:: String → String → IO GS.Element 
makeElement elementType elementName = do 
    element ← GS.elementFactoryMake elementType (Just elementName) 
    case element of 
     Just element' → return element' 
     Nothing → do 
      hPutStrLn stdout ("Cannot create element!") 
      hFlush stdout 
      exitFailure 

player = do 
    GS.init 

    pipeline ← GS.pipelineNew "video-stream" 

    source ← makeElement "v4l2src" "video-source" 
    color ← makeElement "ffmpegcolorspace" "video-color" 
    tee  ← makeElement "tee" "stream-tee" 
    rQ  ← makeElement "queue" "record-queue" 
    vQ  ← makeElement "queue" "video-queue" 
    encoder ← makeElement "y4menc" "video-encoder" 
    rSink ← makeElement "filesink" "record-sink" 
    sink ← makeElement "ximagesink" "video-sink" 

    let elements = [source,color,encoder,rSink,vQ,rQ,sink,tee] 

    Glib.objectSetPropertyString "location" rSink "rec" 

    mapM_ (GS.binAdd (GS.castToBin pipeline)) elements 

    -- Request Pads from tee 
    dPad ← GS.elementGetRequestPad tee "src%d" 
    rPad ← GS.elementGetRequestPad tee "src%d" 
    -- Request Static Pads from queue 
    sDPad ← GS.elementGetStaticPad vQ "sink" 
    sRPad ← GS.elementGetStaticPad rQ "sink" 
    -- Link tee source to queue sink 
    GS.padLink (fromJust dPad) (fromJust sDPad) 
    GS.padLink (fromJust rPad) (fromJust sRPad) 

    GS.elementReleaseRequestPad tee $ fromJust dPad 
    GS.elementReleaseRequestPad tee $ fromJust rPad 

    GS.elementLink source color 
    GS.elementLink color tee 
    GS.elementLink vQ sink 
    GS.elementLink rQ encoder 
    GS.elementLink encoder rSink 


    GS.elementSetState pipeline GS.StatePlaying 

main = do 
    loop ← Glib.mainLoopNew Nothing False 
    player 
    Glib.mainLoopRun loop 

Il codice compila bene, fotocamera LED accende e il file viene creato ma poi NIENTE. Senza il tee e gli elementi della coda, l'installazione separata per la registrazione/visualizzazione del video funziona bene. Inoltre, la stessa pipeline funziona perfettamente se la collaudo con gst-launch. Mi manca qualcosa qui su come funziona gstreamer ma non riesco a capire cosa.

Inoltre, se aiuta, sto costruendo su ArchLinux usando:
- GHC 7.0.3;
- gstreamer-bindings 0.12.1;
- gtk2hs 0.12.2;
- gstreamer 0.10.35-1;
- glib 1.2.10-9.

+0

Si dovrebbe aggiungere le vostre scoperte come una risposta e accettare che la risposta. Non è considerato maleducato rispondere alla tua stessa domanda qui - se ti è capitato di essere il primo a scoprire cosa c'era che non andava, più potere a te! –

risposta

10

risolto

ho trovato la mia soluzione, e quello che segue è un lungo post, ma per favore, nudo con me, devo condividere la mia frustrazione con qualcuno.

Dopo molti tentativi con il buggy ho deciso di tornare a provare alcune configurazioni usando gst-launch. Questo mi ha aiutato a scoprire che dopo l'elemento della coda che bufferizza la parte che va al filesink avevo bisogno di un altro elemento ffmpegcolorspace per impostare il formato video corretto, credo. A questo punto non stavo tornando a provare questa cosa fuori Haskell di nuovo, pensavo di aver bisogno di "avvicinarmi" così ho deciso di provarlo in C. Come nota a margine, non so C, io posso capire la sintassi ma questo è tutto ... e per l'amor del cielo, sto solo ora cercando di imparare Haskell. Per continuare, ho deciso di provare anche a utilizzare "GS.elementGetCompatiblePad" sull'elemento tee in modo da essere sicuro che i pad si colleghino con la coda.

Il codice C i cuciti insieme è questo:

#include <gst/gst.h> 
#include <glib.h> 

int 
main (int argc,char *argv[]) 
{ 

    GstElement *pipeline, *source, *color, *color2 , *color3, *tee, *rQ, *vQ, *encoder, *fSink , *sink; 
    GMainLoop *loop; 
    loop = g_main_loop_new (NULL,FALSE); 
    /* initialize gstreamer */ 
    gst_init(&argc,&argv); 

    /* creating elements */ 
    pipeline = gst_pipeline_new("stream-pipeline"); 

    source = gst_element_factory_make ("v4l2src","stream-source"); 
    color = gst_element_factory_make ("ffmpegcolorspace","video-color"); 
    tee = gst_element_factory_make ("tee","stream-tee"); 
    rQ = gst_element_factory_make ("queue","record-queue"); 
    vQ = gst_element_factory_make ("queue","video-queue"); 
    encoder = gst_element_factory_make ("theoraenc","video-encoder"); 
    fSink = gst_element_factory_make ("filesink","record-sink"); 
    sink = gst_element_factory_make ("ximagesink","video-sink"); 
    color2 = gst_element_factory_make ("ffmpegcolorspace","video-color2"); 
    color3 = gst_element_factory_make ("ffmpegcolorspace","video-color3"); 
    /*check that the elements were created */ 

    if (!source || !color || !tee || !rQ || !vQ || !encoder || !fSink || !sink){ 
     g_printerr("One element could not be created!"); 
     return -1; 
    } 
    /*set file output location */ 
    g_object_set(G_OBJECT (fSink),"location","rec",NULL); 

    gst_bin_add_many (GST_BIN(pipeline), 
         source,color,color2,color3,tee,rQ,vQ,encoder,fSink,sink,NULL); 

    /* get request pads */ 
    GstPad *dPad, *rPad, *sDPad, *sRPad; 

    sDPad = gst_element_get_static_pad(vQ,"sink"); 
    sRPad = gst_element_get_static_pad(rQ,"sink"); 
    dPad = gst_element_get_compatible_pad(tee,sDPad,GST_CAPS_ANY); 
    rPad = gst_element_get_compatible_pad(tee,sRPad,GST_CAPS_ANY); 

    /*link pads*/ 
    gst_pad_link(dPad,sDPad); 
    gst_pad_link(rPad,sRPad); 

    /*unref pads */ 
    gst_object_unref(GST_OBJECT(dPad)); 
    gst_object_unref(GST_OBJECT(rPad)); 
    gst_object_unref(GST_OBJECT(sDPad)); 
    gst_object_unref(GST_OBJECT(sRPad)); 

    /*link elements */ 
    gst_element_link(source,tee); 
    gst_element_link_many(rQ,color2,encoder,fSink,NULL); 
    gst_element_link_many(vQ,color3,sink),NULL; 

    /*set the pipeline state to playing */ 
    gst_element_set_state(pipeline,GST_STATE_PLAYING); 

    g_main_loop_run (loop); 

    gst_element_set_state(pipeline,GST_STATE_NULL); 
    gst_object_unref(GST_OBJECT(pipeline)); 

    return 0; 

} 


poter utilizzare 'gst_element_get_compatible_pad' i doveva prima ottenere rilievi statici dagli elementi coda mano così i sostituirli con quattro linee correlati. Lo provo, e Abracadabra ... oh no, aspetta ... la fotocamera parte, il file viene creato e una finestra con il 'video' appare, ma una finestra nera che rimane nera!


Nessun problema, esegui il programma con gst-debug-level = 5 (=))) sì, giusto, prova a leggere l'intero output. Mi arrendo per il momento e ho pensato che forse ha qualcosa da fare in modo che gli elementi della mia pipeline non funzionino correttamente, quindi codifico un'altra pipeline in C ma questa volta qualcosa di più semplice solo con i file audio.
Ho avuto lo stesso risultato quindi ho deciso di eseguire nuovamente il debug, questa volta con runlevel 3 e ho iniziato a leggere il tutto, riga per riga.


Da qualche parte in là ho trovato questo:


cercando di collegare flusso-tee: src0 e registrare-coda: affondano
cercando di collegare flusso-tee: src0 e video-coda: affondare


qualcosa di brutto sta accadendo qui


legata flusso-tee: src0 e video-coda: lavabo, di successo
cercando di collegare flusso-tee: src0 e registrare-coda: affondano
src flusso-tee: src0 era già collegato con il video-coda: sink


E si arrende!
Immagino di dover tornare indietro usando gst_element_get_request_pad, ma non ci ho già provato? Così ho tornare alla vim e sostituire tutte le occorrenze di 'gst_element_get_compatible_pad con la controparte richiesta in questo modo:

sDPad = gst_element_get_static_pad(vQ,"sink"); 
sRPad = gst_element_get_static_pad(rQ,"sink"); 
dPad = gst_element_get_request_pad(tee,"src%d"); 
rPad = gst_element_get_request_pad(tee,"src%d"); 


guardo su questo codice e mi dico 'si twit', questo è dove tutto è iniziato ; Fai un respiro profondo ; dopo tutto questo è ciò di cui si lamenta il debugger, quindi compilo, corro e Voila. Ho trovato la mia soluzione.


Quelle quattro righe dovevano essere invertite, ho dovuto prima ottenere un riferimento ai pad statici e quindi richiedere un riferimento a un pad 'richiesta' sull'elemento tee.
Torno ad haskell un uomo felice. Implemento la mia soluzione, compile, accendo, la fotocamera si avvia, il file viene creato e ... proprio così ... niente, nemmeno lo schermo nero.
Pieno di rabbia, mi limito a commentare le righe in cui rilascio i pad di richiesta e decido di compilare ed eseguire ancora una volta, il mio collo ha iniziato a far male qualche tempo fa.
Ancora una volta, per magia funziona tutto, ho un video sullo schermo e nel file.
Immagino che a Haskell piaccia essere sempre più stretta ea volte devi semplicemente andare con qualcosa che non ha senso. I documenti di gstreamer dichiarano chiaramente rilascio, rilascio, rilascio.

Il codice Haskell finale:

module Main(main) where 

import qualified Media.Streaming.GStreamer as GS 
import Data.Maybe 
import System.Exit 
import System.Glib.MainLoop as Glib 
import System.Glib.Signals as Glib 
import System.Glib.Properties as Glib 

makeElement:: String → String → IO GS.Element 
makeElement elementType elementName = do 
     element ← GS.elementFactoryMake elementType (Just elementName) 
     case element of 
      Just element' → return element' 
      Nothing → do 
        putStrLn "Cannot create element!" 
        exitFailure 

linkSPadToStaticSink::(GS.ElementClass object, GS.ElementClass elementT) ⇒ object →  elementT → IO (Glib.ConnectId object) 
linkSPadToStaticSink elSrc elSink = do 
      Glib.on elSrc GS.elementPadAdded (λpad → do 
                sinkPad ← GS.elementGetStaticPad elSink "sink" 
                GS.padLink pad (fromJust sinkPad) 
                return ∅) 

player = do 
     GS.init 
     pipeline ← GS.pipelineNew "video-stream" 
     source ← makeElement "v4l2src" "video-source" 
     color ← makeElement "ffmpegcolorspace" "video-color" 
     color2 ← makeElement "ffmpegcolorspace" "video-color2" 
     tee ← makeElement "tee" "stream-tee" 
     rQ ← makeElement "queue" "record-queue" 
     vQ ← makeElement "queue" "video-queue" 
     encoder ← makeElement "y4menc" "video-encoder" 
     rSink ← makeElement "filesink" "record-sink" 
     sink ← makeElement "ximagesink" "video-sink" 

     let elements = [source,color,color2,encoder,rSink,vQ,rQ,sink,tee] 

     Glib.objectSetPropertyString "location" rSink "rec" 

     mapM_ (GS.binAdd (GS.castToBin pipeline)) elements 

     -- Get static pads from queue elements 
     sDPad ← GS.elementGetStaticPad vQ "sink" 
     sRPad ← GS.elementGetStaticPad rQ "sink" 
     -- Request pads from tee element 
     dPad ← GS.elementGetRequestPad tee "src%d" 
     rPad ← GS.elementGetRequestPad tee "src%d" 
     -- Link tee source to queue sink 
     GS.padLink (fromJust dPad) (fromJust sDPad) 
     GS.padLink (fromJust rPad) (fromJust sRPad) 

     GS.elementLink source color 
     GS.elementLink color tee 
     GS.elementLink vQ sink 
     GS.elementLink rQ color2 
     GS.elementLink color2 encoder 
     GS.elementLink encoder rSink 

     GS.elementSetState pipeline GS.StatePlaying 

main = do 
    loop ← Glib.mainLoopNew Nothing False 
    player 
    Glib.mainLoopRun loop 


Ora vi chiedo, dovrebbe/potrebbe Ho visto questo?
Era così ovvio?


Sono contento che questo mi farà essere più attento e guardare in posti meno ovvi ma ... eww.

In conclusione a tutto questo, ho imparato a conoscere le opzioni di debug gstreamer, ho imparato che mi sussurra e DEVO ascoltare. Ho saputo che GDB è stato forzato ad usare perché quando ho iniziato a ricucire il codice C tutto ciò che ho ottenuto è stato un "difetto di sega".
Ho imparato ad amare lazy-eval e puro codice Haskell.
Un po 'di Haskell, forse un pochino di C e più esperienza. 'Lost' circa mezza giornata, tre classi e diverse ore di sonno, ma dopo tutto ... così va ...

Problemi correlati