2011-12-19 27 views
9

我的問題涉及以下的代碼:Haskell中的GStreamer三通元件(1-N)的麻煩

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接通,並創建該文件,但然後沒有。 如果沒有三通和隊列元素,錄製/顯示視頻的單獨設置工作得很好。同樣,如果我使用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。

+0

您應該添加您的發現作爲一個答案和接受的答案。在這裏回答你自己的問題並不被認爲是無禮的 - 如果你碰巧是第一個發現錯誤,給你更多的權力! – 2011-12-19 13:21:00

回答

10

議決

,我發現我的解決方案,以及接踵而來的是一個漫長的文章,但請,裸陪我,我一定要分享我的人無奈地說。

經過更多的越野車嘗試後,我決定回去使用gst-launch測試一些設置。 這幫助我發現,在隊列元素緩衝到文件鏈接的部分之後,我需要另一個ffmpegcolorspace元素來設置我認爲正確的視頻格式。 在這一點上,我不會再嘗試這件事,它再次哈斯克爾,我想我需要'接近',所以我決定嘗試在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-調試級運行程序= 5(=)))是啊,沒錯,嘗試閱讀全output.I放棄的那一刻,我想,也許它有話與我的管道中的元素不一起工作,所以我在C編寫另一個管道,但這次更簡單的只是音頻文件。
我有相同的結果,所以我決定再次調試,這次用runlevel 3,我開始逐行閱讀整個事情。


某處在那裏,我發現這一點:


試圖鏈接流三通:SRC0和記錄隊列:沉
試圖鏈接流三通:SRC0和視頻隊列:沉


討厭的東西發生在這裏


鏈接流的發球:SRC0和視頻隊列:水槽,成功
試圖鏈接流三通:SRC0和記錄隊列:沉
SRC流三通:SRC0已經有視頻隊列鏈接:匯


它放棄了!
我想我必須回去使用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"); 


我凝望着這個代碼,我對自己說‘你蠢’,這是在這一切開始;深吸一口氣畢竟這是調試器抱怨的,所以我編譯,我跑,和瞧。我發現我的解決方案。


這四行必須顛倒過來,我必須首先獲得靜態焊盤的引用,然後請求引用tee元素上的'請求'焊盤。
我回到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 


現在我問你,應/可我已經看到了這一點?
這是明顯的嗎?


我很高興這會讓我更加小心,看起來不是那麼明顯的地方,但是...... eww。

總而言之,我瞭解了gstreamer調試選項,我知道它對我耳語,我必須聽。我瞭解到GDB被迫使用,因爲當我開始拼接C代碼時,我所得到的只是一個'seg故障'。
我學會了愛lazy-eval和純Haskell代碼。有點Haskell,也許只有C和更多的經驗。 「迷失」半天左右,三等幾個小時的睡眠時間,但畢竟...... 如此這般...