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 ...
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! –