РАЗРЕШЕНО
Я нашел свое решение, и далее следует длинный пост, но, пожалуйста, потерпите меня.Я должен поделиться своим разочарованием с кем-то.
После многих попыток с ошибками я решил вернуться к тестированию некоторых настроек с помощью gst-launch.Это помогло мне выяснить, что после элемента очереди, который буферизует часть, которая отправляется в файловую систему, мне понадобился еще один элемент ffmpegcolorspace для настройки правильного формата видео, как мне кажется.В этот момент я не собирался снова пробовать это на Хаскеле, я подумал, что мне нужно «приблизиться», поэтому я решил попробовать это на C. Как примечание, я не знаю C, я могу понятьсинтаксис, но это все ... и ради бога, я только сейчас пытаюсь выучить Haskell.Чтобы продолжить, я решил также попробовать использовать «GS.elementGetCompatiblePad» на элементе tee, чтобы я мог быть уверен, что пэды будут связываться с очередью.
Код 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», мне сначала нужно было получить статические пэды из элементов очереди, чтобы я мог переключить эти четыре связанные строки.Я пробую это, и Абракадабра ... о нет, подожди ... камера запускается, файл создается, и появляется окно с видео, но черное окно остается черным!
Нет проблем, я говорю, запустите программу с gst-debug-level = 5 (=))) да, правильно, попробуйте прочитать весь вывод. Я сдаюсь на данный момент, и я подумал, что может бытьэто связано с тем, что элементы в моем конвейере не работают вместе, поэтому я кодирую другой конвейер на C, но на этот раз что-то более простое только с аудио-файлами.
У меня был тот же результат, поэтому я решил снова выполнить отладку, на этот раз с уровнем запуска 3, и я начал читать все это построчно.
Где-то там я нашел это:
пытается связать поток-тройку: src0 и очередь записей: сток
пытается связать поток-тройку: src0 и видео-очередь: приемник
здесь происходит что-то неприятное
связанный поток-тройник: src0 и видео-очередь: сток, успешно
пытается связать поток-тройник:src0 и очередь записей: сток
src stream-tee: 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. Я внедряю свое решение, компилирую, запускаю, камера запускается, файл создается и ... просто так ... ничего, даже черный экран.
Наполненный гневом, я просто комментирую строки, где я освобождаю планшеты с запросами и решаю снова скомпилировать и запустить, моя шея некоторое время назад начала болеть.
Опять же, по волшебству все это работает, у меня есть видео на экране и в файле.
Полагаю, Хаскеллу просто нравится держаться крепче, и иногда вам просто нужно пойти с чем-то бесполезным.Документ 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, все, что я получил, было «ошибкой сегмента».
Я научился любить lazy-eval и чистый код Haskell.
Немного Haskell, возможно немного C и больше опыта.
«Потерял» примерно полдня, три урока и несколько часов сна, но в конце концов ... Так и происходит ...