Haskell GStreamer三通元素(1-N)麻烦

时间:2011-12-19 00:09:31

标签: haskell gstreamer

我遇到的问题与以下代码有关:

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

代码编译精细,相机LED开关打开,文件被创建,但后来没有。 没有tee和队列元素,用于录制/显示视频的单独设置工作正常。如果我使用gst-launch测试它,同样的管道也能正常工作。 我在这里遗漏了一些关于gstreamer如何工作但我无法弄清楚是什么的东西。

此外,如果它有帮助,我正在使用ArchLinux构建:
- GHC 7.0.3;
- gstreamer-bindings 0.12.1;
- gtk2hs 0.12.2;
- gstreamer 0.10.35-1;
- glib 1.2.10-9。

1 个答案:

答案 0 :(得分:10)

<强>分辨

我找到了我的解决方案,接下来是一篇很长的帖子,但是请耐心等待。我必须与某人分享我的挫折感。

经过更多的错误尝试后,我决定回去使用gst-launch测试一些设置。 这有助于我发现在缓冲部分的队列元素之后,我需要另一个ffmpegcolorspace元素来设置正确的视频格式。 在这一点上,我再也没有回过头来尝试Haskell,我认为我需要“更接近”所以我决定在C中尝试它。 作为一个附注,我不知道C,我可以理解语法,但这是关于它...为了善良的缘故,我现在只是想学习Haskell。 为了继续,我决定尝试在tee元素上使用'GS.elementGetCompatiblePad',这样我就可以确定垫将与队列链接。

我拼凑的C代码就是:

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

}


为了使用'gst_element_get_compatible_pad',我必须首先从队列元素中获取静态打击垫,这样我就可以切换这四个相关的行。 我试了一下,然后Abracadabra ......哦不,等等......相机开始,文件被创建,一个带有'视频'的窗口弹出,但是一个黑色的窗口仍然是黑色的!


我说没问题,用gst-debug-level = 5(=)运行程序))是的,对,尝试阅读整个输出。我放弃了当下,我想也许它有与管道中的元素无法正常工作有关,所以我在C中编写另一个管道,但这次只是使用音频文件更简单。 我得到了相同的结果,所以我再次决定调试,这次是运行级别3,我开始逐行阅读整个事情。


在某处我发现了这个:

  

尝试链接stream-tee:src0和record-queue:sink   
试图链接stream-tee:src0和video-queue:sink

这里发生了令人讨厌的事情

  


链接的stream-tee:src0和video-queue:sink,成功   
试图链接stream-tee:src0和record-queue:sink   
src stream-tee:src0已与video-queue:sink

链接

它放弃了! 我想我必须回去使用gst_element_get_request_pad,但我还没试过吗? 所以我切换回vim并将所有出现的'gst_element_get_compatible_pad替换为请求对应方,如下所示:

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

我凝视这段代码,我对自己说'你蠢',这就是一切开始的地方;深呼吸;毕竟这是调试器所抱怨的,所以我编译,我运行,和Voila。我找到了解决方案。

这四条线必须颠倒,我必须首先获得静态垫的参考,然后请求引用T形元件上的“请求”垫。 我回到haskell一个快乐的人。我实现我的解决方案,编译,启动,启动摄像头,创建文件......就像那样......没什么,甚至不是黑屏。
充满了愤怒我只是注释掉我发布请求垫的行,并决定再次编译和运行,我的脖子开始受伤了。 再次,通过魔术一切正常,我在屏幕和文件中有视频。 我想Haskell只是喜欢紧张,有时候你必须选择一些毫无意义的东西。 gstreamer文档清楚地说明了发布,发布和发布。

最终的haskell代码:

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


现在我问你,我能不能看到这个?
这是显而易见的吗?

我很高兴这会让我更加小心,并且看不到那么明显的地方,但是......哇。

总而言之,我了解了gstreamer调试选项,我了解到它对我耳语,我必须听。我了解到GDB被迫使用,因为当我开始拼接C代码时,我得到的只是一个'段错误'。我学会了喜欢懒惰的eval和纯Haskell代码。
一点Haskell ,也许是一点点C和更多的经验。 '迷失'大约半天,三节课和几个小时的睡眠但毕竟...... 所以它会......