2011-12-19 18 views
9

El problema que tengo se refiere a la siguiente pieza de código:Haskell GStreamer tee elemento (1-N) problemas

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 

El código compila bien, cámara LED se enciende y el archivo se crea pero luego NADA. Sin los elementos de te y cola, la configuración por separado para grabar/mostrar video funciona bien. También, la misma tubería funciona perfectamente si la pruebo con gst-launch. Me falta algo aquí sobre cómo funciona gstreamer, pero no puedo entender qué.

Además, si ayuda, estoy construyendo en 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

Debe añadir sus descubrimientos como una respuesta y aceptar esa respuesta. No se considera grosero responder a su propia pregunta aquí: si resultó ser el primero en descubrir lo que estaba mal, ¡más poder para usted! –

Respuesta

10

RESUELVE

encontré mi solución, y lo que sigue es un post largo, pero por favor, desnuda conmigo, debo compartir mi frustración con alguien.

Después de muchos más intentos fallidos, decidí volver a probar algunas configuraciones usando gst-launch. Esto me ayudó a descubrir que después del elemento de la cola que almacena en búfer la parte que va al filesink, necesitaba otro elemento ffmpegcolorspace para configurar el formato de video correcto, creo. En este punto no iba a volver a probar Haskell otra vez, pensé que necesitaba acercarme, así que decidí probarlo en C. Como nota al margen, no sé C, yo puede entender la sintaxis, pero eso es todo ... y por Dios, ahora estoy tratando de aprender Haskell. Para continuar, decidí también intentar usar 'GS.elementGetCompatiblePad' en el elemento de salida, así puedo estar seguro de que los pads se vincularán con la cola.

El código C i cosidos entre sí es la siguiente:

#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; 

} 


Para utilizar 'gst_element_get_compatible_pad' que tenía que conseguir primero almohadillas estáticos a partir de los elementos de la cola de la mano, así que para cambiar esas cuatro líneas relacionadas. Lo pruebo, y Abracadabra ... oh no, espera ... la cámara se inicia, se crea el archivo y aparece una ventana con el 'video', ¡pero una ventana negra que permanece negra!


No hay problema, digo, ejecute el programa con gst-debug-level = 5 (=))) Sí, correcto, intente leer toda la salida. Me rindo por el momento y pensé que tal vez tenía algo que hacer con los elementos en mi tubería que no funcionan bien juntos así que código otra tubería en C, pero esta vez algo más simple solo con archivos de audio.
Tuve el mismo resultado, así que decidí depurar de nuevo, esta vez con el nivel de ejecución 3 y comencé a leer todo, línea por línea.


En alguna parte he encontrado esto:


tratar de vincular corriente-T: src0 y el archivo de cola: se hunden
tratar de vincular corriente-T: src0 y el video-cola: hundirse


algo desagradable que está pasando aquí


ligado corriente-T: src0 y el video-cola: fregadero, éxito
tratar de vincular corriente-T: src0 y el archivo de cola: se hunden
src corriente-T: src0 ya estaba vinculado con el vídeo-cola: fregadero


¡Y se da por vencido!
Supongo que debo volver usando gst_element_get_request_pad, pero ¿no lo he intentado ya? Así Puedo volver a vim y reemplazar todas las ocurrencias de 'gst_element_get_compatible_pad con la solicitud de contraparte de este 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"); 


contemplo este código y me digo 'que Twit', esto es donde empezó todo ; Tomar una respiración profunda ; después de todo esto es de lo que se queja el depurador así compilo, corro y Voila. Encontré mi solución.


Esas cuatro líneas tuvieron que invertirse, primero tuve que hacer una referencia a las almohadillas estáticas y luego solicitar una referencia a una almohadilla de 'solicitud' en el elemento tee.
Vuelvo a tener a Haskell como un hombre feliz. Implemento mi solución, compilo, enciendo, la cámara se inicia, el archivo se crea y ... así ... nada, ni siquiera la pantalla en negro.
Lleno de enojo, solo comento las líneas en las que lanzo los paneles de solicitud y decido compilar y ejecutar una vez más, mi cuello comenzó a doler hace un tiempo.
Nuevamente, por arte de magia, todo funciona, tengo video en la pantalla y en el archivo.
Supongo que a Haskell le gusta apretarse más y a veces solo tiene que ir con algo que no tiene sentido. El estado de los documentos gstreamer libera, libera y libera claramente.

El código Haskell definitiva:

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 


Ahora te pregunto, debería/podría yo haber visto esto?
¿Era tan obvio?


Me alegra que esto me haga ser más cuidadoso y buscar en lugares no tan obvios, pero ... eww.

Como conclusión de todo esto, aprendí sobre las opciones de depuración gstreamer, aprendí que me susurra y DEBO escuchar. Aprendí sobre GDB forzado a usar porque cuando comencé a coser código C, todo lo que obtuve fue un "fallo seg".
Aprendí a amar lazy-eval y el código Haskell puro.
Un poco de Haskell, tal vez un poquito de C y más experiencia. 'perdido' alrededor de la mitad de un día, tres clases y varias horas de sueño, pero después de todo ... por lo que pasa ...

Cuestiones relacionadas