Frage Haskell GStreamer T-Stück (1-N) Ärger


Das Problem, das ich habe, bezieht sich auf das folgende Stück Code:

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

Der Code wird korrekt kompiliert, die Kamera-LED leuchtet auf und die Datei wird erstellt, aber dann NICHTS. Ohne die T- und Queue-Elemente funktioniert das separate Setup zum Aufzeichnen / Anzeigen von Video einwandfrei. Auch funktioniert die gleiche Pipeline einwandfrei, wenn ich es mit gst-launch teste. Mir fehlt hier etwas daran, wie Gstreamer funktioniert, aber ich kann nicht herausfinden, was.

Wenn es hilft, baue ich auf ArchLinux mit:
 - GHC 7.0.3;
 - gstreamer-bindings 0.12.1;
 - gtk2hs 0.12.2;
 - gstreamer 0.10.35-1;
 - glib 1.2.10-9.


9
2017-12-19 00:09


Ursprung


Antworten:


AUFGELÖST

Ich fand meine Lösung, und was folgt, ist ein langer Post, aber bitte, ertragen Sie mit mir. Ich muss meine Frustration mit jemandem teilen.

Nach vielen weiteren Buggy-Versuchen habe ich mich entschieden, einige Setups mit gst-launch zu testen. Dies half mir herauszufinden, dass ich nach dem queue-Element, das den Teil puffert, der zum filesink geht, ein anderes ffmpegcolorspace-Element brauchte, um das richtige Videoformat zu erstellen, denke ich. An diesem Punkt würde ich nicht wieder versuchen, dieses Ding aus Haskell auszuprobieren, ich dachte, ich müsste näher kommen, also beschloss ich, es in C zu versuchen. Als Nebenbemerkung weiß ich nicht, C, ich kann die Syntax verstehen, aber das ist es ... und um Himmels willen versuche ich gerade jetzt, Haskell zu lernen. Um fortzufahren, entschied ich mich, auch 'GS.elementGetCompatiblePad' auf dem Tee-Element zu verwenden, damit ich sicher sein kann, dass die Pads mit der Warteschlange verbunden werden.

Der C-Code, den ich zusammenstecke, ist dies:

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

}


Um 'gst_element_get_compatible_pad' zu verwenden, musste ich zuerst statische Pads von den Queue-Elementen holen, um diese vier verknüpften Zeilen zu wechseln. Ich probiere es aus, und Abracadabra ... oh nein, warte ... Die Kamera startet, die Datei wird erstellt und ein Fenster mit dem "Video" erscheint, aber ein schwarzes Fenster, das schwarz bleibt!


Kein Problem, sage ich, führe das Programm mit gst-debug-level = 5 (=))) yea, right, versuche den ganzen output zu lesen. Ich gebe für den Moment auf und ich dachte vielleicht hat es etwas mit den Elementen zu tun meine Pipeline funktioniert nicht richtig zusammen, also programmiere ich eine andere Pipeline in C, aber dieses Mal etwas einfacher, nur mit Audiodateien.
 Ich hatte das gleiche Ergebnis, also entschied ich mich erneut für das Debuggen, dieses Mal mit Runlevel 3, und ich fing an, das Ganze Zeile für Zeile zu lesen.


Irgendwo da drin habe ich folgendes gefunden:


versuchen, Stream-tee zu verknüpfen: src0 und record-queue: sink   
versuchen, stream-tee zu verbinden: src0 und video-queue: sink


 hier passiert etwas Scheußliches


linked stream-tee: src0 und video-queue: sink, erfolgreich   
versuchen, Stream-tee zu verknüpfen: src0 und record-queue: sink   
src stream-tee: src0 wurde bereits mit video-queue: sink verknüpft


 Und es gibt auf!
    Ich denke, ich muss mit gst_element_get_request_pad zurückgehen, aber habe ich das nicht schon versucht? Also wechsle ich zurück zu vim und ersetze alle Vorkommen von 'gst_element_get_compatible_pad mit dem Request-Counterpart so:

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");


 Ich schaue auf diesen Code und ich sage zu mir selbst "Du verdammelst", hier begann alles; tief durchatmen ; Nach all dem beschwert sich der Debugger, also kompiliere ich, ich renne und Voila. Ich habe meine Lösung gefunden.


Diese vier Zeilen mussten umgekehrt werden, ich musste zuerst einen Verweis auf die statischen Pads bekommen und dann einen Verweis auf ein "Anfrage" Pad auf dem T-Element anfordern.
Ich gehe zurück zu Haskell ein glücklicher Mann.Ich implementiere meine Lösung, kompiliere, feuere, Kamera startet, die Datei wird erstellt und ... einfach so ... nichts, nicht einmal der schwarze Bildschirm.
Gefüllt mit Ärger kommentiere ich nur die Zeilen aus, in denen ich die Request-Pads freigebe und beschließe, noch einmal zu kompilieren und zu laufen, mein Nacken schmerzt schon vor einiger Zeit.
Auch hier funktioniert alles, ich habe Video auf dem Bildschirm und in der Datei.
Ich denke, Haskell mag es einfach, enger zu bleiben und manchmal muss man einfach mit etwas gehen, das keinen Sinn ergibt. Der gstreamer docs Zustand deutlich freigeben, freigeben, freigeben.

Der endgültige Haskell-Code:

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


Jetzt frage ich dich, sollte / könnte ich das gesehen haben?
War es so offensichtlich?


Ich bin froh, dass ich dadurch vorsichtiger werde und an nicht so offensichtlichen Orten nachschaue, aber ... Eww.

Zum Schluss habe ich über die gstreamer-Debug-Optionen gelernt, ich habe gelernt, dass es zu mir flüstert und ich muss hören. Ich erfuhr, dass GDB gezwungen war, verwendet zu werden, denn als ich anfing, C-Code zu nähen, war alles, was ich bekam, ein "Seg-Fehler".
Ich lernte, Lazy-Eval und reinen Haskell-Code zu lieben.
 Ein bisschen Haskell, vielleicht ein bisschen C und mehr Erfahrung. 'Lost' etwa einen halben Tag, drei Klassen und mehrere Stunden Schlaf, aber immerhin ...So geht es ...


10
2017-12-19 13:26