12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568 |
- /*\
- |*| Copyright 2015-2016 bill-auger <https://github.com/bill-auger/av-caster/issues>
- |*|
- |*| This file is part of the AvCaster program.
- |*|
- |*| AvCaster is free software: you can redistribute it and/or modify
- |*| it under the terms of the GNU General Public License version 3
- |*| as published by the Free Software Foundation.
- |*|
- |*| AvCaster is distributed in the hope that it will be useful,
- |*| but WITHOUT ANY WARRANTY; without even the implied warranty of
- |*| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- |*| GNU General Public License for more details.
- |*|
- |*| You should have received a copy of the GNU General Public License
- |*| along with AvCaster. If not, see <http://www.gnu.org/licenses/>.
- \*/
- #include <gst/video/videooverlay.h>
- #include <gst/video/gstvideosink.h>
- #include "AvCaster.h"
- #include "Gstreamer.h"
- #include "../Trace/TraceGstreamer.h"
- /* Gstreamer private class variables */
- GstElement* Gstreamer::Pipeline = nullptr ; // Initialize()
- GstElement* Gstreamer::ScreencapBin = nullptr ; // Initialize()
- GstElement* Gstreamer::ScreenRealSource = nullptr ; // BuildScreencapBin()
- GstElement* Gstreamer::ScreenFauxSource = nullptr ; // BuildScreencapBin()
- GstElement* Gstreamer::ScreenCapsfilter = nullptr ; // BuildScreencapBin()
- GstElement* Gstreamer::CameraBin = nullptr ; // Initialize()
- GstElement* Gstreamer::CameraRealSource = nullptr ; // BuildCameraBin()
- GstElement* Gstreamer::CameraFauxSource = nullptr ; // BuildCameraBin()
- GstElement* Gstreamer::CameraCapsfilter = nullptr ; // BuildCameraBin()
- GstElement* Gstreamer::TextBin = nullptr ; // Initialize()
- GstElement* Gstreamer::ImageBin = nullptr ; // Initialize()
- GstElement* Gstreamer::CompositorBin = nullptr ; // Initialize()
- GstPad* Gstreamer::CompositorScreenSinkpad = nullptr ; // BuildCompositorBin()
- GstPad* Gstreamer::CompositorCameraSinkpad = nullptr ; // BuildCompositorBin()
- GstPad* Gstreamer::CompositorTextSinkpad = nullptr ; // BuildCompositorBin()
- GstPad* Gstreamer::CompositorImageSinkpad = nullptr ; // BuildCompositorBin()
- #ifndef GST_COMPOSITOR_BUG
- GstElement* Gstreamer::CompositorCapsfilter = nullptr ; // BuildCompositorBin()
- #endif // GST_COMPOSITOR_BUG
- GstElement* Gstreamer::PreviewBin = nullptr ; // Initialize()
- GstElement* Gstreamer::PreviewQueue = nullptr ; // BuildPreviewBin()
- GstElement* Gstreamer::PreviewFauxSink = nullptr ; // BuildPreviewBin()
- GstElement* Gstreamer::PreviewRealSink = nullptr ; // BuildPreviewBin()
- GstElement* Gstreamer::AudioBin = nullptr ; // Initialize()
- GstElement* Gstreamer::AudioAlsaSource = nullptr ; // BuildAudioBin()
- GstElement* Gstreamer::AudioPulseSource = nullptr ; // BuildAudioBin()
- GstElement* Gstreamer::AudioJackSource = nullptr ; // BuildAudioBin()
- GstElement* Gstreamer::AudioFauxSource = nullptr ; // BuildAudioBin()
- GstElement* Gstreamer::AudioCaps = nullptr ; // BuildAudioBin()
- GstElement* Gstreamer::MuxerBin = nullptr ; // Initialize()
- GstElement* Gstreamer::OutputBin = nullptr ; // Initialize()
- GstElement* Gstreamer::OutputQueue = nullptr ; // BuildOutputBin()
- GstElement* Gstreamer::OutputFileSink = nullptr ; // BuildOutputBin()
- GstElement* Gstreamer::OutputRtmpSink = nullptr ; // BuildOutputBin()
- GstElement* Gstreamer::OutputFauxSink = nullptr ; // BuildOutputBin()
- ValueTree Gstreamer::ConfigStore = ValueTree::invalid ; // Initialize()
- guintptr Gstreamer::PreviewXwin = 0 ; // Initialize()
- /* Gstreamer private class methods */
- bool Gstreamer::Initialize(ValueTree config_store , void* x_window ,
- NamedValueSet& disabled_features )
- {
- ConfigStore = config_store ;
- PreviewXwin = (guintptr)x_window ;
- DEBUG_TRACE_GST_INIT_PHASE_1
- // initialize gStreamer (NOTE: this will terminate the application on failure)
- InitializeGst(nullptr , nullptr) ;
- DEBUG_TRACE_GST_INIT_PHASE_2
- // determine static pipeline macro configuration
- // TODO: ideally it should be robust to always build all bins
- // with Is*Enabled() vars merely guarding config/re-config
- // but perhaps it is more efficient to simply not build unused bins
- // (ASSERT: the 'link bins' section below and Shutdown() reflect the current implementation)
- bool is_media_enabled = !disabled_features.contains(CONFIG::OUTPUT_ID ) ;
- bool is_screen_enabled = !disabled_features.contains(CONFIG::SCREEN_ID ) ;
- bool is_camera_enabled = !disabled_features.contains(CONFIG::CAMERA_ID ) ;
- bool is_text_enabled = !disabled_features.contains(CONFIG::TEXT_ID ) ;
- bool is_image_enabled = !disabled_features.contains(CONFIG::IMAGE_ID ) ;
- bool is_preview_enabled = !disabled_features.contains(CONFIG::PREVIEW_ID) ;
- bool is_audio_enabled = !disabled_features.contains(CONFIG::AUDIO_ID ) ;
- bool is_vmixer_enabled ;
- // assert dependent compositor elements (TODO: remove these restrictions allowing any configuration)
- int n_video_inputs = ((is_screen_enabled) ? 1 : 0) + ((is_camera_enabled) ? 1 : 0) +
- ((is_text_enabled ) ? 1 : 0) + ((is_image_enabled ) ? 1 : 0) ;
- is_vmixer_enabled = is_media_enabled && n_video_inputs == GST::N_COMPOSITOR_INPUTS ;
- is_preview_enabled = is_preview_enabled && is_vmixer_enabled ;
- bool is_config_sane = !is_media_enabled || is_vmixer_enabled || n_video_inputs == 1 ;
- DEBUG_DUMP_MEDIA_SWITCHES
- if (!is_config_sane) return false ;
- // instantiate pipeline
- if ((is_media_enabled && !(Pipeline = NewPipeline(GST::PIPELINE_ID ))) ||
- (is_screen_enabled && !(ScreencapBin = NewBin (GST::SCREENCAP_BIN_ID ))) ||
- (is_camera_enabled && !(CameraBin = NewBin (GST::CAMERA_BIN_ID ))) ||
- (is_text_enabled && !(TextBin = NewBin (GST::TEXT_BIN_ID ))) ||
- (is_image_enabled && !(ImageBin = NewBin (GST::IMAGE_BIN_ID ))) ||
- (is_vmixer_enabled && !(CompositorBin = NewBin (GST::COMPOSITOR_BIN_ID))) ||
- (is_preview_enabled && !(PreviewBin = NewBin (GST::PREVIEW_BIN_ID ))) ||
- (is_audio_enabled && !(AudioBin = NewBin (GST::AUDIO_BIN_ID ))) ||
- (is_media_enabled && !(MuxerBin = NewBin (GST::MUXER_BIN_ID ))) ||
- (is_media_enabled && !(OutputBin = NewBin (GST::OUTPUT_BIN_ID ))) )
- { AvCaster::Error(GUI::GST_PIPELINE_INST_ERROR_MSG) ; return false ; }
- SetMessageHandler(GST_PIPELINE(Pipeline) , (GstBusSyncHandler)HandleMessage) ;
- DEBUG_TRACE_GST_INIT_PHASE_3
- // configure pipeline
- if ((is_screen_enabled && !AddBin(ScreencapBin )) ||
- (is_camera_enabled && !AddBin(CameraBin )) ||
- (is_text_enabled && !AddBin(TextBin )) ||
- (is_image_enabled && !AddBin(ImageBin )) ||
- (is_vmixer_enabled && !AddBin(CompositorBin)) ||
- (is_preview_enabled && !AddBin(PreviewBin )) ||
- (is_audio_enabled && !AddBin(AudioBin )) ||
- (is_media_enabled && !AddBin(MuxerBin )) ||
- (is_media_enabled && !AddBin(OutputBin )) )
- { AvCaster::Error(GUI::GST_ADD_ERROR_MSG) ; return false ; }
- DEBUG_TRACE_GST_INIT_PHASE_4 DEBUG_TRACE_DISABLED_BINS
- // configure bins
- if ((is_screen_enabled && !BuildScreencapBin ()) ||
- (is_camera_enabled && !BuildCameraBin ()) ||
- (is_text_enabled && !BuildTextBin ()) ||
- (is_image_enabled && !BuildImageBin ()) ||
- (is_vmixer_enabled && !BuildCompositorBin()) ||
- (is_preview_enabled && !BuildPreviewBin ()) ||
- (is_audio_enabled && !BuildAudioBin ()) ||
- (is_media_enabled && !BuildMuxerBin ()) ||
- (is_media_enabled && !BuildOutputBin ()) )
- { AvCaster::Error(GUI::GST_PIPELINE_INIT_ERROR_MSG) ; return false ; }
- DEBUG_TRACE_GST_INIT_PHASE_5
- // link bins
- if (is_vmixer_enabled)
- {
- if ((is_screen_enabled && !LinkElements(ScreencapBin , CompositorBin)) ||
- (is_camera_enabled && !LinkElements(CameraBin , CompositorBin)) ||
- (is_text_enabled && !LinkElements(TextBin , CompositorBin)) ||
- (is_image_enabled && !LinkElements(ImageBin , CompositorBin)) ||
- (is_vmixer_enabled && !LinkElements(CompositorBin , MuxerBin )) ||
- (is_preview_enabled && !LinkElements(CompositorBin , PreviewBin )) )
- { AvCaster::Error(GUI::VMIXER_BIN_LINK_ERROR_MSG) ; return false ; }
- }
- else
- {
- if ((is_screen_enabled && !LinkElements(ScreencapBin , MuxerBin)) ||
- (is_camera_enabled && !LinkElements(CameraBin , MuxerBin)) ||
- (is_text_enabled && !LinkElements(TextBin , MuxerBin)) ||
- (is_image_enabled && !LinkElements(ImageBin , MuxerBin)) )
- { AvCaster::Error(GUI::VMIXER_BIN_LINK_ERROR_MSG) ; return false ; }
- }
- if ((is_audio_enabled && !LinkElements(AudioBin , MuxerBin )) ||
- (is_media_enabled && !LinkElements(MuxerBin , OutputBin)) )
- { AvCaster::Error(GUI::MUXER_BIN_LINK_ERROR_MSG) ; return false ; }
- DEBUG_TRACE_GST_INIT_PHASE_6
- // set rolling
- if (!SetState(Pipeline , GST_STATE_PLAYING)) return false ;
- DEBUG_TRACE_GST_INIT_PHASE_7
- // DEBUG_MAKE_GRAPHVIZ
- return true ;
- }
- void Gstreamer::Shutdown()
- {
- // DEBUG_MAKE_GRAPHVIZ
- // TODO: to shut down correctly (flushing the buffers)
- // gst_element_send_event(Pipeline , gst_event_eos()) ;
- // then wait for EOS message on bus before setting pipeline state to NULL
- // FIXME: setting (ScreencapBin to state null here may cause X to throw error:
- // "ERROR: X returned BadShmSeg (invalid shared segment parameter) for operation Unknown"
- if (!IsInBin(ScreencapBin , ScreenRealSource)) DestroyElement(ScreenRealSource) ;
- if (!IsInBin(ScreencapBin , ScreenFauxSource)) DestroyElement(ScreenFauxSource) ;
- if (!IsInBin(CameraBin , CameraRealSource)) DestroyElement(CameraRealSource) ;
- if (!IsInBin(CameraBin , CameraFauxSource)) DestroyElement(CameraFauxSource) ;
- if (!IsInBin(PreviewBin , PreviewRealSink )) DestroyElement(PreviewRealSink ) ;
- if (!IsInBin(PreviewBin , PreviewFauxSink )) DestroyElement(PreviewFauxSink ) ;
- if (!IsInBin(AudioBin , AudioAlsaSource )) DestroyElement(AudioAlsaSource ) ;
- if (!IsInBin(AudioBin , AudioPulseSource)) DestroyElement(AudioPulseSource) ;
- if (!IsInBin(AudioBin , AudioJackSource )) DestroyElement(AudioJackSource ) ;
- if (!IsInBin(AudioBin , AudioFauxSource )) DestroyElement(AudioFauxSource ) ;
- if (!IsInBin(OutputBin , OutputFileSink )) DestroyElement(OutputFileSink ) ;
- if (!IsInBin(OutputBin , OutputRtmpSink )) DestroyElement(OutputRtmpSink ) ;
- if (!IsInBin(OutputBin , OutputFauxSink )) DestroyElement(OutputFauxSink ) ;
- DestroyElement(Pipeline) ;
- }
- bool Gstreamer::BuildScreencapBin()
- {
- DEBUG_TRACE_BUILD_SCREENCAP_BIN
- GstElement *initial_source , *converter , *queue ;
- // instantiate elements
- if (!(ScreenRealSource = NewElement(GST::SCREEN_PLUGIN_ID , "screen-real-source")) ||
- !(ScreenFauxSource = NewElement(GST::TESTVIDEO_PLUGIN_ID , "screen-faux-source")) ||
- !(ScreenCapsfilter = NewElement("capsfilter" , "screen-capsfilter" )) ||
- !(converter = NewElement("videoconvert" , "screen-converter" )) ||
- !(queue = NewElement("queue" , "screen-queue" )) )
- { AvCaster::Error(GUI::SCREENCAP_INIT_ERROR_MSG) ; return false ; }
- // configure elements
- initial_source = ConfigureScreenBin() ;
- ConfigureQueue(queue , 0 , 0 , 0) ;
- // link elements
- if (!AddElement (ScreencapBin , initial_source ) ||
- !AddElement (ScreencapBin , ScreenCapsfilter) ||
- !AddElement (ScreencapBin , converter ) ||
- !AddElement (ScreencapBin , queue ) ||
- !LinkElements (initial_source , ScreenCapsfilter) ||
- !LinkElements (ScreenCapsfilter , converter ) ||
- !LinkElements (converter , queue ) ||
- !NewGhostSrcPad(ScreencapBin , queue , "screen-source"))
- { AvCaster::Error(GUI::SCREENCAP_LINK_ERROR_MSG) ; return false ; }
- return true ;
- }
- bool Gstreamer::BuildCameraBin()
- {
- DEBUG_TRACE_BUILD_CAMERA_BIN
- GstElement *initial_source , *converter , *queue ;
- // instantiate elements
- if (!(CameraRealSource = NewElement(GST::CAMERA_PLUGIN_ID , "camera-real-source")) ||
- !(CameraFauxSource = NewElement(GST::TESTVIDEO_PLUGIN_ID , "camera-faux-source")) ||
- !(CameraCapsfilter = NewElement("capsfilter" , "camera-capsfilter" )) ||
- !(converter = NewElement("videoconvert" , "camera-converter" )) ||
- !(queue = NewElement("queue" , "camera-queue" )) )
- { AvCaster::Error(GUI::CAMERA_INIT_ERROR_MSG) ; return false ; }
- // configure elements
- initial_source = ConfigureCameraBin() ;
- // link elements
- if (!AddElement (CameraBin , initial_source ) ||
- !AddElement (CameraBin , CameraCapsfilter) ||
- !AddElement (CameraBin , converter ) ||
- !AddElement (CameraBin , queue ) ||
- !LinkElements (initial_source , CameraCapsfilter) ||
- !LinkElements (CameraCapsfilter , converter ) ||
- !LinkElements (converter , queue ) ||
- !NewGhostSrcPad(CameraBin , queue , "camera-source") )
- { AvCaster::Error(GUI::CAMERA_LINK_ERROR_MSG) ; return false ; }
- return true ;
- }
- bool Gstreamer::BuildTextBin()
- {
- DEBUG_TRACE_BUILD_TEXT_BIN
- #ifdef TEXT_BIN_NYI
- return false ;
- #endif // TEXT_BIN_NYI
- GstElement *filesrc , *subparser , *source , *converter , *queue ;
- // bool is_enabled = bool (ConfigStore[CONFIG::TEXT_ID ]) ;
- String motd_text = STRING(ConfigStore[CONFIG::MOTD_TEXT_ID ]) ;
- int text_style_idx = int (ConfigStore[CONFIG::TEXT_STYLE_ID ]) ;
- int text_pos_idx = int (ConfigStore[CONFIG::TEXT_POSITION_ID]) ;
- // String display_text = (is_enabled) ? motd_text : String::empty ;
- /* TODO: include custom font
- #include <fontconfig/fontconfig.h>
- std::string yourFontFilePath = "/home/testUser/bla.ttf"
- const FcChar8 * file = (const FcChar8 *)yourFontFilePath.c_str();
- FcBool fontAddStatus = FcConfigAppFOntAddFile(FcConfigGetCurrent(),file);
- */
- // instantiate elements
- if (!(filesrc = gst_element_factory_make("filesrc" , "text-filesrc" )) ||
- !(subparser = gst_element_factory_make("subparse" , "text-subparser")) ||
- !(source = gst_element_factory_make("textrender" , "text-input" )) ||
- !(converter = gst_element_factory_make("videoconvert" , "text-converter")) ||
- !(queue = gst_element_factory_make("queue" , "text-queue" )) )
- { AvCaster::Error(GUI::TEXT_INIT_ERROR_MSG) ; return false ; }
- DEBUG_TRACE_CONFIGURE_TEXT_BIN
- // configure elements
- ConfigureTextSource(source , "Purisa Normal 40" ) ;
- ConfigureFileSource(filesrc , "/code/av-caster/deleteme.srt") ;
- // link elements
- if (!AddElement (TextBin , filesrc ) ||
- !AddElement (TextBin , subparser) ||
- !AddElement (TextBin , source ) ||
- !AddElement (TextBin , converter) ||
- !AddElement (TextBin , queue ) ||
- !LinkElements (filesrc , subparser) ||
- !LinkElements (subparser , source ) ||
- !LinkElements (source , converter) ||
- !LinkElements (converter , queue ) ||
- !NewGhostSrcPad(TextBin , queue , "text-source"))
- { AvCaster::Error(GUI::TEXT_LINK_ERROR_MSG) ; return false ; }
- return true ;
- }
- bool Gstreamer::BuildImageBin()
- {
- DEBUG_TRACE_BUILD_IMAGE_BIN
- //#define STATIC_IMAGE
- # ifdef STATIC_IMAGE
- /*
- GstElement *source , *decoder , *converter ,
- *scaler , *scaler_filter ,
- *freezer , *freezer_filter , *queue ;
- GstCaps *scaler_caps , *freezer_caps ;
- bool is_enabled = bool(ConfigStore[CONFIG::IMAGE_ID ]) ;
- int interstitial_w = int (ConfigStore[CONFIG::SCREENCAP_W_ID]) ;
- int interstitial_h = int (ConfigStore[CONFIG::SCREENCAP_H_ID]) ;
- int framerate_idx = int (ConfigStore[CONFIG::FRAMERATE_ID ]) ;
- int framerate = CONFIG::FRAMERATES[framerate_idx].getIntValue() ;
- String image_filename = "/home/bill/img/tech-diff.png" ;
- String scaler_caps_str = String("video/x-raw, ") +
- "width=(int)" + String(interstitial_w) + ", " +
- "height=(int)" + String(interstitial_h) + ", " +
- "framerate=(fraction)0/1, " +
- "format=(string)YUY2," +
- "interlace-mode=(string)progressive, " +
- "pixel-aspect-ratio=(fraction)1/1" ;
- String freezer_caps_str = String("video/x-raw, ") +
- "width=(int)" + String(interstitial_w) + ", " +
- "height=(int)" + String(interstitial_h) + ", " +
- "framerate=(fraction)" + String(framerate ) + "/1, " +
- "format=(string)YUY2," +
- "interlace-mode=(string)progressive, " +
- "pixel-aspect-ratio=(fraction)1/1" ;
- // instantiate elements
- if (!(source = NewElement("filesrc" , "interstitial-real-source" )) ||
- !(decoder = NewElement("pngdec" , "interstitial-decoder" )) ||
- !(converter = NewElement("videoconvert" , "interstitial-converter" )) ||
- !(scaler = NewElement("videoscale" , "interstitial-scaler" )) ||
- !(scaler_filter = NewElement("capsfilter" , "interstitial-scaler-caps" )) ||
- !(freezer = NewElement("imagefreeze" , "interstitial-freezer" )) ||
- !(freezer_filter = NewElement("capsfilter" , "interstitial-freezer-caps")) ||
- !(queue = NewElement("queue" , "interstitial-queue" )) ||
- !(scaler_caps = NewCaps (scaler_caps_str) ) ||
- !(freezer_caps = NewCaps (freezer_caps_str) ) )
- { AvCaster::Error(GUI::IMAGE_INIT_ERROR_MSG) ; return false ; }
- DEBUG_TRACE_CONFIGURE_IMAGE_BIN
- // configure elements
- ConfigureFile (source , image_filename ) ;
- ConfigureCaps (scaler_filter , scaler_caps ) ;
- ConfigureCaps (freezer_filter , freezer_caps ) ;
- ConfigureQueue(queue , 0 , 0 , 0) ;
- // link elements
- if (!AddElement (ImageBin , source ) ||
- !AddElement (ImageBin , decoder ) ||
- !AddElement (ImageBin , converter ) ||
- !AddElement (ImageBin , scaler ) ||
- !AddElement (ImageBin , scaler_filter ) ||
- !AddElement (ImageBin , freezer ) ||
- !AddElement (ImageBin , freezer_filter) ||
- !AddElement (ImageBin , queue ) ||
- !LinkElements (source , decoder ) ||
- !LinkElements (decoder , converter ) ||
- !LinkElements (converter , scaler ) ||
- !LinkElements (scaler , scaler_filter ) ||
- !LinkElements (scaler_filter , freezer ) ||
- !LinkElements (freezer , freezer_filter) ||
- !LinkElements (freezer_filter , queue ) ||
- !NewGhostSrcPad(ImageBin , queue , "interstitial-source"))
- { AvCaster::Error(GUI::IMAGE_LINK_ERROR_MSG) ; return false ; }
- */
- # else // STATIC_IMAGE
- GstElement *source , *capsfilter , *converter , *queue ;
- // TODO: static image src
- int interstitial_w = int(ConfigStore[CONFIG::SCREENCAP_W_ID]) ;
- int interstitial_h = int(ConfigStore[CONFIG::SCREENCAP_H_ID]) ;
- int framerate_idx = int(ConfigStore[CONFIG::FRAMERATE_ID ]) ;
- int framerate = CONFIG::FrameRates()[framerate_idx].getIntValue() ;
- String plugin_id = GST::TESTVIDEO_PLUGIN_ID ;
- String faux_caps_str = MakeVideoCapsString (interstitial_w , interstitial_h , framerate) ;
- //DEBUG_TRACE_CONFIGURE_IMAGE
- // instantiate elements
- if (!(source = NewElement(plugin_id , "interstitial-real-source")) ||
- !(capsfilter = NewElement("capsfilter" , "interstitial-capsfilter" )) ||
- !(converter = NewElement("videoconvert" , "interstitial-converter" )) ||
- !(queue = NewElement("queue" , "interstitial-queue" )) )
- { AvCaster::Error(GUI::IMAGE_INIT_ERROR_MSG) ; return false ; }
- // configure elements
- ConfigureTestVideo(source , 18 ) ;
- ConfigureCaps(capsfilter , faux_caps_str) ;
- // link elements
- if (!AddElement (ImageBin , source ) ||
- !AddElement (ImageBin , capsfilter) ||
- !AddElement (ImageBin , converter ) ||
- !AddElement (ImageBin , queue ) ||
- !LinkElements (source , capsfilter) ||
- !LinkElements (capsfilter , converter ) ||
- !LinkElements (converter , queue ) ||
- !NewGhostSrcPad(ImageBin , queue , "image-source"))
- { AvCaster::Error(GUI::IMAGE_LINK_ERROR_MSG) ; return false ; }
- # endif // STATIC_IMAGE
- return true ;
- }
- bool Gstreamer::BuildCompositorBin()
- {
- DEBUG_TRACE_BUILD_COMPOSITOR_BIN
- GstElement *screen_queue , *camera_queue , *image_queue ,
- #ifndef GST_COMPOSITOR_BUG
- *compositor , *converter ,
- #else // GST_COMPOSITOR_BUG
- *compositor ,
- #endif // GST_COMPOSITOR_BUG
- *composite_tee , *composite_sink_queue , *composite_thru_queue ;
- // instantiate elements
- if (!(screen_queue = NewElement("queue" , "compositor-screen-queue")) ||
- !(camera_queue = NewElement("queue" , "compositor-camera-queue")) ||
- !(image_queue = NewElement("queue" , "compositor-image-queue" )) ||
- !(compositor = NewElement("compositor" , "compositor" )) ||
- #ifndef GST_COMPOSITOR_BUG
- !(CompositorCapsfilter = NewElement("capsfilter" , "compositor-capsfilter" )) ||
- !(converter = NewElement("videoconvert" , "compositor-converter" )) ||
- #endif // GST_COMPOSITOR_BUG
- !(composite_tee = NewElement("tee" , "compositor-tee" )) ||
- !(composite_sink_queue = NewElement("queue" , "compositor-sink-queue" )) ||
- !(composite_thru_queue = NewElement("queue" , "compositor-thru-queue" )) )
- { AvCaster::Error(GUI::VMIXER_INIT_ERROR_MSG) ; return false ; }
- // configure elements
- ConfigureQueue (screen_queue , 0 , 0 , 0) ;
- ConfigureQueue (camera_queue , 0 , 0 , 0) ;
- ConfigureQueue (image_queue , 0 , 0 , 0) ;
- ConfigureCompositor(compositor , 3 ) ;
- ConfigureQueue (composite_sink_queue , 0 , 0 , 0) ;
- ConfigureQueue (composite_thru_queue , 0 , 0 , 0) ;
- // link elements
- if (!AddElement (CompositorBin , screen_queue ) ||
- !AddElement (CompositorBin , camera_queue ) ||
- !AddElement (CompositorBin , image_queue ) ||
- !AddElement (CompositorBin , compositor ) ||
- #ifndef GST_COMPOSITOR_BUG
- !AddElement (CompositorBin , CompositorCapsfilter) ||
- !AddElement (CompositorBin , converter ) ||
- #endif // GST_COMPOSITOR_BUG
- !AddElement (CompositorBin , composite_tee ) ||
- !AddElement (CompositorBin , composite_sink_queue) ||
- !AddElement (CompositorBin , composite_thru_queue) ||
- #ifndef GST_COMPOSITOR_BUG
- !LinkElements(compositor , CompositorCapsfilter) ||
- !LinkElements(CompositorCapsfilter , converter ) ||
- !LinkElements(converter , composite_tee) )
- #else // GST_COMPOSITOR_BUG
- !LinkElements(compositor , composite_tee) )
- #endif // GST_COMPOSITOR_BUG
- { AvCaster::Error(GUI::VMIXER_LINK_ERROR_MSG) ; return false ; }
- // instantiate request pads
- GstPad *composite_tee_thru_srcpad , *composite_tee_monitor_srcpad ;
- if (!NewGhostSinkPad(CompositorBin , screen_queue , "compositor-screen-sink") ||
- !NewGhostSinkPad(CompositorBin , camera_queue , "compositor-camera-sink") ||
- !NewGhostSinkPad(CompositorBin , image_queue , "compositor-image-sink" ) ||
- !(CompositorScreenSinkpad = NewRequestSinkPad(compositor ) ) ||
- !(CompositorCameraSinkpad = NewRequestSinkPad(compositor ) ) ||
- !(CompositorImageSinkpad = NewRequestSinkPad(compositor ) ) ||
- !(composite_tee_thru_srcpad = NewRequestSrcPad (composite_tee) ) ||
- !(composite_tee_monitor_srcpad = NewRequestSrcPad (composite_tee) ) )
- { AvCaster::Error(GUI::VMIXER_PAD_INIT_ERROR_MSG) ; return false ; }
- // configure sink pads
- ConfigureCompositorBin() ;
- // link ghost pads and request pads
- GstPad *screen_thru_srcpad , *camera_thru_srcpad , *image_thru_srcpad ,
- *composite_thru_sinkpad , *composite_sink_sinkpad ;
- if (!(screen_thru_srcpad = NewStaticSrcPad (screen_queue ) ) ||
- !(camera_thru_srcpad = NewStaticSrcPad (camera_queue ) ) ||
- !(image_thru_srcpad = NewStaticSrcPad (image_queue ) ) ||
- !(composite_thru_sinkpad = NewStaticSinkPad(composite_thru_queue) ) ||
- !(composite_sink_sinkpad = NewStaticSinkPad(composite_sink_queue) ) ||
- !LinkPads (screen_thru_srcpad , CompositorScreenSinkpad) ||
- !LinkPads (camera_thru_srcpad , CompositorCameraSinkpad) ||
- !LinkPads (image_thru_srcpad , CompositorImageSinkpad ) ||
- !LinkPads (composite_tee_thru_srcpad , composite_thru_sinkpad ) ||
- !LinkPads (composite_tee_monitor_srcpad , composite_sink_sinkpad ) ||
- !NewGhostSrcPad(CompositorBin , composite_thru_queue , "compositor-source") ||
- !NewGhostSrcPad(CompositorBin , composite_sink_queue , "preview-source" ) )
- { AvCaster::Error(GUI::VMIXER_PAD_LINK_ERROR_MSG) ; return false ; }
- return true ;
- }
- bool Gstreamer::BuildPreviewBin()
- {
- DEBUG_TRACE_BUILD_PREVIEW_BIN
- GstElement* initial_sink ;
- // instantiate elements
- if (!(PreviewQueue = NewElement("queue" , "preview-queue" )) ||
- !(PreviewRealSink = NewElement(GST::PREVIEW_PLUGIN_ID , GST::PREVIEW_SINK_ID )) ||
- !(PreviewFauxSink = NewElement(GST::FAUXSINK_PLUGIN_ID , GST::PREVIEW_FAUXSINK_ID)) )
- { AvCaster::Error(GUI::PREVIEW_INIT_ERROR_MSG) ; return false ; }
- // configure elements
- ConfigureQueue(PreviewQueue , 0 , 0 , 0) ;
- initial_sink = ConfigurePreviewBin() ;
- // link elements
- if (!AddElement (PreviewBin , PreviewQueue ) ||
- !AddElement (PreviewBin , initial_sink ) ||
- !NewGhostSinkPad(PreviewBin , PreviewQueue , GST::PREVIEW_SINKPAD_ID) ||
- !LinkElements (PreviewQueue , initial_sink) )
- { AvCaster::Error(GUI::PREVIEW_LINK_ERROR_MSG) ; return false ; }
- return true ;
- }
- bool Gstreamer::BuildAudioBin()
- {
- DEBUG_TRACE_BUILD_AUDIO_BIN
- GstElement *initial_source , *converter , *queue ;
- // instantiate elements
- if (!(AudioAlsaSource = NewElement(GST::ALSA_PLUGIN_ID , "audio-alsa-source" )) ||
- !(AudioPulseSource = NewElement(GST::PULSE_PLUGIN_ID , "audio-pulse-source")) ||
- !(AudioJackSource = NewElement(GST::JACK_PLUGIN_ID , "audio-jack-source" )) ||
- !(AudioFauxSource = NewElement(GST::TESTAUDIO_PLUGIN_ID , "audio-test-source" )) ||
- !(AudioCaps = NewElement("capsfilter" , "audio-capsfilter" )) ||
- !(converter = NewElement("audioconvert" , "audio-converter" )) ||
- !(queue = NewElement("queue" , "audio-queue" )) )
- { AvCaster::Error(GUI::AUDIO_INIT_ERROR_MSG) ; return false ; }
- // configure elements
- initial_source = ConfigureAudioBin() ;
- ConfigureTestAudio(AudioFauxSource) ;
- ConfigureQueue(queue , 0 , 0 , 0) ;
- // link elements
- if (!AddElement (AudioBin , initial_source) ||
- !AddElement (AudioBin , AudioCaps ) ||
- !AddElement (AudioBin , converter ) ||
- !AddElement (AudioBin , queue ) ||
- !LinkElements (initial_source , AudioCaps) ||
- !LinkElements (AudioCaps , converter) ||
- !LinkElements (converter , queue ) ||
- !NewGhostSrcPad(AudioBin , queue , "audio-source"))
- { AvCaster::Error(GUI::AUDIO_LINK_ERROR_MSG) ; return false ; }
- return true ;
- }
- bool Gstreamer::BuildMuxerBin()
- {
- DEBUG_TRACE_BUILD_MUXER_BIN
- GstElement *video_in_queue , *video_converter , *video_encoder , *video_parser ,
- *video_enc_caps , *video_enc_queue ;
- GstElement *audio_in_queue , *audio_converter , *audio_encoder , *audio_parser ,
- *audio_enc_caps , *audio_enc_queue ;
- GstElement *muxer ;
- int output_w = int(ConfigStore[CONFIG::OUTPUT_W_ID ]) ;
- int output_h = int(ConfigStore[CONFIG::OUTPUT_H_ID ]) ;
- int video_bitrate_idx = int(ConfigStore[CONFIG::VIDEO_BITRATE_ID]) ;
- int audio_bitrate_idx = int(ConfigStore[CONFIG::AUDIO_BITRATE_ID]) ;
- int framerate_idx = int(ConfigStore[CONFIG::FRAMERATE_ID ]) ;
- int n_channels = int(ConfigStore[CONFIG::N_CHANNELS_ID ]) ;
- int samplerate_idx = int(ConfigStore[CONFIG::SAMPLERATE_ID ]) ;
- guint video_bitrate = CONFIG::VideoBitRates() [video_bitrate_idx].getIntValue() ;
- guint audio_bitrate = CONFIG::AudioBitRates() [audio_bitrate_idx].getIntValue() ;
- int framerate = CONFIG::FrameRates() [framerate_idx ].getIntValue() ;
- int samplerate = CONFIG::AudioSampleRates()[samplerate_idx ].getIntValue() ;
- String h264_caps_str = MakeH264CapsString(output_w , output_h , framerate) ;
- String mp3_caps_str = MakeMp3CapsString(samplerate , n_channels) ;
- String video_caps_str = h264_caps_str ;
- String audio_caps_str = mp3_caps_str ;
- if (!(video_in_queue = NewElement("queue" , "mux-video-queue" )) ||
- !(video_converter = NewElement("videoconvert" , "mux-video-converter")) ||
- !(video_encoder = NewElement("x264enc" , "mux-video-encoder" )) ||
- !(video_parser = NewElement("h264parse" , "mux-video-parser" )) ||
- !(video_enc_caps = NewElement("capsfilter" , "mux-video-enc-caps" )) ||
- !(video_enc_queue = NewElement("queue" , "mux-video-enc-queue")) ||
- !(audio_in_queue = NewElement("queue" , "mux-audio-queue" )) ||
- !(audio_converter = NewElement("audioconvert" , "audio-converter" )) ||
- !(audio_encoder = NewElement("lamemp3enc" , "mux-audio-encoder" )) ||
- !(audio_parser = NewElement("mpegaudioparse" , "mux-audio-parser" )) ||
- !(audio_enc_caps = NewElement("capsfilter" , "mux-audio-enc-caps" )) ||
- !(audio_enc_queue = NewElement("queue" , "mux-audio-enc-queue")) ||
- !(muxer = NewElement("flvmux" , "mux-flvmux" )) )
- { AvCaster::Error(GUI::MUXER_INIT_ERROR_MSG) ; return false ; }
- DEBUG_TRACE_CONFIGURE_MUXER_BIN
- ConfigureX264Encoder(video_encoder , video_bitrate ) ;
- ConfigureCaps (video_enc_caps , video_caps_str) ;
- ConfigureLameEncoder(audio_encoder , audio_bitrate ) ;
- ConfigureCaps (audio_enc_caps , audio_caps_str) ;
- ConfigureQueue (audio_enc_queue , 0 , 0 , 0 ) ;
- ConfigureFlvmux (muxer) ;
- if (!AddElement (MuxerBin , video_in_queue ) ||
- !AddElement (MuxerBin , video_converter) ||
- !AddElement (MuxerBin , video_encoder ) ||
- !AddElement (MuxerBin , video_enc_caps ) ||
- !AddElement (MuxerBin , video_parser ) ||
- !AddElement (MuxerBin , video_enc_queue) ||
- !AddElement (MuxerBin , audio_in_queue ) ||
- !AddElement (MuxerBin , audio_converter) ||
- !AddElement (MuxerBin , audio_encoder ) ||
- !AddElement (MuxerBin , audio_parser ) ||
- !AddElement (MuxerBin , audio_enc_caps ) ||
- !AddElement (MuxerBin , audio_enc_queue) ||
- !AddElement (MuxerBin , muxer ) ||
- !LinkElements (video_in_queue , video_converter) ||
- # ifdef FAKE_MUX_ENCODER_SRC_AND_SINK
- !LinkElements (video_converter , fake_enc_sink ) ||
- !LinkElements (fake_enc_src , video_encoder ) ||
- # else // FAKE_MUX_ENCODER_SRC_AND_SINK
- !LinkElements (video_converter , video_encoder ) ||
- # endif // FAKE_MUX_ENCODER_SRC_AND_SINK
- !LinkElements (video_encoder , video_enc_caps ) ||
- !LinkElements (video_enc_caps , video_parser ) ||
- !LinkElements (video_parser , video_enc_queue) ||
- !LinkElements (video_enc_queue , muxer ) ||
- !NewGhostSinkPad(MuxerBin , video_in_queue , "mux-video-sink") ||
- !LinkElements (audio_in_queue , audio_converter) ||
- !LinkElements (audio_converter , audio_encoder ) ||
- !LinkElements (audio_encoder , audio_enc_caps ) ||
- !LinkElements (audio_enc_caps , audio_parser ) ||
- !LinkElements (audio_parser , audio_enc_queue) ||
- !LinkElements (audio_enc_queue , muxer ) ||
- !NewGhostSinkPad(MuxerBin , audio_in_queue , "mux-audio-sink") ||
- !NewGhostSrcPad (MuxerBin , muxer , "mux-source" ) )
- { AvCaster::Error(GUI::MUXER_LINK_ERROR_MSG) ; return false ; }
- return true ;
- }
- bool Gstreamer::BuildOutputBin()
- {
- DEBUG_TRACE_BUILD_OUTPUT_BIN
- GstElement* initial_sink ;
- if (!(OutputQueue = NewElement("queue" , "output-queue" )) ||
- !(OutputFileSink = NewElement(GST::FILESINK_PLUGIN_ID , "output-file-sink")) ||
- !(OutputRtmpSink = NewElement(GST::RTMPSINK_PLUGIN_ID , "output-rtmp-sink")) ||
- !(OutputFauxSink = NewElement(GST::FAUXSINK_PLUGIN_ID , "output-faux-sink")) )
- { AvCaster::Error(GUI::OUTPUT_INIT_ERROR_MSG) ; return false ; }
- ConfigureQueue(OutputQueue , 0 , 0 , 0) ;
- initial_sink = ConfigureOutputBin() ;
- if (!AddElement (OutputBin , OutputQueue ) ||
- !AddElement (OutputBin , initial_sink) ||
- !LinkElements (OutputQueue , initial_sink) ||
- !NewGhostSinkPad(OutputBin , OutputQueue , "output-sink"))
- { AvCaster::Error(GUI::OUTPUT_LINK_ERROR_MSG) ; return false ; }
- return true ;
- }
- bool Gstreamer::Reconfigure(const Identifier& config_key)
- {
- bool is_config_pending = AvCaster::GetIsConfigPending() ;
- bool configure_all = (config_key == CONFIG::PRESET_ID ||
- config_key == CONFIG::IS_PENDING_ID) && !is_config_pending ;
- bool configure_screen = config_key == CONFIG::SCREEN_ID || configure_all ;
- bool configure_camera = config_key == CONFIG::CAMERA_ID || configure_all ;
- bool configure_text = config_key == CONFIG::TEXT_ID || configure_all ;
- bool configure_image = config_key == CONFIG::IMAGE_ID || configure_all ;
- bool configure_compositor = configure_screen || configure_camera ||
- configure_text || configure_image || configure_all ;
- bool configure_preview = config_key == CONFIG::PREVIEW_ID ||
- config_key == CONFIG::IS_PENDING_ID || configure_all ;
- bool configure_audio = config_key == CONFIG::AUDIO_ID || configure_all ;
- bool configure_output = config_key == CONFIG::OUTPUT_ID || configure_all ;
- DEBUG_TRACE_RECONFIGURE_IN
- SetState(Pipeline , GST_STATE_READY) ;
- bool is_error = (configure_screen && ConfigureScreenBin() == nullptr) ||
- (configure_camera && ConfigureCameraBin() == nullptr) ||
- (configure_text && ConfigureTextBin() == nullptr) ||
- (configure_image && ConfigureImageBin() == nullptr) ||
- (configure_compositor && ConfigureCompositorBin() == false ) ||
- (configure_preview && ConfigurePreviewBin() == nullptr) ||
- (configure_audio && ConfigureAudioBin() == nullptr) ||
- (configure_output && ConfigureOutputBin() == nullptr) ;
- DEBUG_TRACE_RECONFIGURE_OUT
- // NOTE: an error here should cause Gstreamer::HandleErrorMessage() to fire
- // which should attempt recovery to a same configuration
- is_error = !SetState(Pipeline , GST_STATE_PLAYING) || is_error ;
- // DEBUG_MAKE_GRAPHVIZ
- return !is_error ;
- }
- GstElement* Gstreamer::ConfigureScreenBin()
- {
- bool is_active = bool(ConfigStore[CONFIG::SCREEN_ID ]) ;
- int screencap_w = int (ConfigStore[CONFIG::SCREENCAP_W_ID]) ;
- int screencap_h = int (ConfigStore[CONFIG::SCREENCAP_H_ID]) ;
- int framerate_idx = int (ConfigStore[CONFIG::FRAMERATE_ID ]) ;
- int framerate = CONFIG::FrameRates()[framerate_idx].getIntValue() ;
- String screen_caps_str = MakeScreenCapsString(screencap_w , screencap_h , framerate) ;
- String faux_caps_str = MakeVideoCapsString (screencap_w , screencap_h , framerate) ;
- String caps_str = (is_active) ? screen_caps_str : faux_caps_str ;
- GstElement* next_source = (is_active) ? ScreenRealSource : ScreenFauxSource ;
- GstElement* current_source = (IsInBin(ScreencapBin , ScreenRealSource)) ? ScreenRealSource :
- (IsInBin(ScreencapBin , ScreenFauxSource)) ? ScreenFauxSource :
- nullptr ;
- DEBUG_TRACE_CONFIGURE_SCREENCAP_BIN
- // configure elements
- ConfigureScreenSource(ScreenRealSource , screencap_w , screencap_h) ;
- ConfigureTestVideo (ScreenFauxSource , 1 ) ;
- ConfigureCaps (ScreenCapsfilter , caps_str ) ;
- // swap source elements
- if (IsInBin(ScreencapBin , current_source) && next_source != current_source)
- {
- if (!RemoveElement(ScreencapBin , current_source ) ||
- !AddElement (ScreencapBin , next_source ) ||
- !LinkElements (next_source , ScreenCapsfilter) )
- { AvCaster::Error(GUI::SCREENCAP_LINK_ERROR_MSG) ; return nullptr ; }
- }
- return next_source ;
- }
- GstElement* Gstreamer::ConfigureCameraBin()
- {
- // TODO: query device for resolutions (eliminate CONFIG::CAMERA_RESOLUTIONS)
- String device_path = AvCaster::GetCameraPath() ;
- int framerate = AvCaster::GetCameraRate() ;
- Point<int> resolution = AvCaster::GetCameraResolution() ;
- int camera_w = resolution.getX() ;
- int camera_h = resolution.getY() ;
- bool is_active = bool(ConfigStore[CONFIG::CAMERA_ID]) ;
- bool use_real_src = is_active && device_path.isNotEmpty() ;
- String camera_caps_str = MakeCameraCapsString(camera_w , camera_h , framerate) ;
- String faux_caps_str = MakeVideoCapsString (camera_w , camera_h , framerate) ;
- String caps_str = (use_real_src) ? camera_caps_str : faux_caps_str ;
- GstElement* next_source = (use_real_src) ? CameraRealSource : CameraFauxSource ;
- GstElement* current_source = (IsInBin(CameraBin , CameraRealSource)) ? CameraRealSource :
- (IsInBin(CameraBin , CameraFauxSource)) ? CameraFauxSource :
- nullptr ;
- DEBUG_TRACE_CONFIGURE_CAMERA_BIN
- // configure elements
- ConfigureCameraSource(CameraRealSource , device_path) ;
- ConfigureTestVideo (CameraFauxSource , 0 ) ;
- ConfigureCaps (CameraCapsfilter , caps_str ) ;
- // swap source elements
- if (IsInBin(CameraBin , current_source) && next_source != current_source)
- {
- if (!RemoveElement(CameraBin , current_source ) ||
- !AddElement (CameraBin , next_source ) ||
- !LinkElements (next_source , CameraCapsfilter) )
- { AvCaster::Error(GUI::CAMERA_LINK_ERROR_MSG) ; return nullptr ; }
- }
- return next_source ;
- }
- GstElement* Gstreamer::ConfigureTextBin() { return Pipeline ; } // FIXME: should return aTextSource
- GstElement* Gstreamer::ConfigureImageBin() { return Pipeline ; } // FIXME: should return anImageSource
- bool Gstreamer::ConfigureCompositorBin()
- {
- bool is_screen_active = bool(ConfigStore[CONFIG::SCREEN_ID ]) ;
- bool is_camera_active = bool(ConfigStore[CONFIG::CAMERA_ID ]) ;
- #ifndef TEXT_BIN_NYI
- bool is_text_active = bool(ConfigStore[CONFIG::TEXT_ID ]) ;
- #endif // TEXT_BIN_NYI
- bool is_image_active = bool(ConfigStore[CONFIG::IMAGE_ID ]) ;
- int screen_w = int (ConfigStore[CONFIG::SCREENCAP_W_ID]) ;
- int screen_h = int (ConfigStore[CONFIG::SCREENCAP_H_ID]) ;
- int output_w = int (ConfigStore[CONFIG::OUTPUT_W_ID ]) ;
- int output_h = int (ConfigStore[CONFIG::OUTPUT_H_ID ]) ;
- int framerate_idx = int (ConfigStore[CONFIG::FRAMERATE_ID ]) ;
- int framerate = CONFIG::FrameRates()[framerate_idx].getIntValue() ;
- Point<int> resolution = AvCaster::GetCameraResolution() ;
- int screen_x = 0 ;
- int screen_y = 0 ;
- int image_w = output_w ;
- int image_h = output_h ;
- int image_x = 0 ;
- int image_y = 0 ;
- int camera_w = resolution.getX() ;
- int camera_h = resolution.getY() ;
- int camera_x = screen_w - camera_w ;
- int camera_y = screen_h - camera_h ;
- int screen_z = ( is_screen_active ) ? 2 : 0 ;
- int camera_z = ( !is_screen_active || is_camera_active) ? 3 : 0 ;
- int image_z = ((!is_screen_active && !is_camera_active) || is_image_active) ? 4 : 1 ;
- String caps_str = MakeVideoCapsString(output_w , output_h , framerate) ;
- DEBUG_TRACE_CONFIGURE_COMPOSITOR_BIN
- #ifdef NO_DYNAMIC_MEDIA_Z_ORDER
- image_z = 0 ; screen_z = 1 ; camera_z = 2 ;
- #endif // NO_DYNAMIC_MEDIA_Z_ORDER
- #ifndef GST_COMPOSITOR_BUG
- ConfigureCaps (CompositorCapsfilter , caps_str ) ;
- #endif // GST_COMPOSITOR_BUG
- ConfigureCompositorSink(CompositorScreenSinkpad , screen_w , screen_h ,
- screen_x , screen_y , screen_z) ;
- ConfigureCompositorSink(CompositorCameraSinkpad , camera_w , camera_h ,
- camera_x , camera_y , camera_z) ;
- ConfigureCompositorSink(CompositorImageSinkpad , image_w , image_h ,
- image_x , image_y , image_z ) ;
- return true ;
- }
- GstElement* Gstreamer::ConfigurePreviewBin()
- {
- GstElement *current_sink , *next_sink ;
- bool is_active = AvCaster::GetIsPreviewActive() ;
- current_sink = (IsInBin(PreviewBin , PreviewRealSink)) ? PreviewRealSink :
- (IsInBin(PreviewBin , PreviewFauxSink)) ? PreviewFauxSink : nullptr ;
- next_sink = (is_active) ? PreviewRealSink : PreviewFauxSink ;
- DEBUG_TRACE_CONFIGURE_PREVIEW_BIN
- // configure elements
- if (!ConfigureVideoSink(PreviewRealSink) && is_active)
- AvCaster::Error(GUI::GST_XWIN_ERROR_MSG) ;
- // swap sink elements
- if (IsInBin(PreviewBin , current_sink) && next_sink != current_sink)
- {
- if (!RemoveElement(PreviewBin , current_sink) ||
- !AddElement (PreviewBin , next_sink ) ||
- !LinkElements (PreviewQueue , next_sink ) )
- { AvCaster::Error(GUI::PREVIEW_LINK_ERROR_MSG) ; return nullptr ; }
- }
- return next_sink ;
- }
- GstElement* Gstreamer::ConfigureAudioBin()
- {
- GstElement *current_source , *next_source ;
- String caps_str ;
- // TODO: JACK init fails if samplerate mismatch (issue #37)
- bool is_enabled = bool(ConfigStore[CONFIG::AUDIO_ID ]) ;
- int audio_api_idx = int (ConfigStore[CONFIG::AUDIO_API_ID ]) ;
- int n_channels = int (ConfigStore[CONFIG::N_CHANNELS_ID]) ;
- int samplerate_idx = int (ConfigStore[CONFIG::SAMPLERATE_ID]) ;
- int samplerate = CONFIG::AudioSampleRates()[samplerate_idx].getIntValue() ;
- String audio16_caps_str = MakeAudioCapsString("S16LE" , samplerate , n_channels) ;
- String audio32_caps_str = MakeAudioCapsString("F32LE" , samplerate , n_channels) ;
- current_source = (IsInBin(AudioBin , AudioAlsaSource )) ? AudioAlsaSource :
- (IsInBin(AudioBin , AudioPulseSource)) ? AudioPulseSource :
- (IsInBin(AudioBin , AudioJackSource )) ? AudioJackSource :
- (IsInBin(AudioBin , AudioFauxSource )) ? AudioFauxSource : nullptr ;
- if (!is_enabled) audio_api_idx = CONFIG::INVALID_IDX ;
- switch ((CONFIG::AudioApi)audio_api_idx)
- {
- case CONFIG::ALSA_AUDIO_IDX: next_source = AudioAlsaSource ; caps_str = audio16_caps_str ; break ;
- case CONFIG::PULSE_AUDIO_IDX: next_source = AudioPulseSource ; caps_str = audio16_caps_str ; break ;
- case CONFIG::JACK_AUDIO_IDX: next_source = AudioJackSource ; caps_str = audio32_caps_str ; break ;
- default: next_source = AudioFauxSource ; caps_str = audio16_caps_str ; break ;
- }
- DEBUG_TRACE_CONFIGURE_AUDIO_BIN
- // configure elements
- ConfigureCaps(AudioCaps , caps_str) ;
- // swap source elements
- if (IsInBin(AudioBin , current_source) && current_source != next_source)
- {
- if (!RemoveElement(AudioBin , current_source) ||
- !AddElement (AudioBin , next_source ) ||
- !LinkElements (next_source , AudioCaps ) )
- { AvCaster::Error(GUI::AUDIO_LINK_ERROR_MSG) ; return nullptr ; }
- }
- return next_source ;
- }
- GstElement* Gstreamer::ConfigureOutputBin()
- {
- bool is_enabled = bool (ConfigStore[CONFIG::OUTPUT_ID ]) ;
- int muxer_idx = int (ConfigStore[CONFIG::OUTPUT_MUXER_ID]) ;
- int sink_idx = int (ConfigStore[CONFIG::OUTPUT_SINK_ID ]) ;
- String destination = STRING(ConfigStore[CONFIG::OUTPUT_DEST_ID ]) ;
- String file_ext = CONFIG::OutputMuxers()[muxer_idx] ;
- String file_url = MakeFileName(destination , file_ext) ;
- String rtmp_url = MakeRtmpUrl (destination) ;
- GstElement* current_sink = (IsInBin(OutputBin , OutputFileSink)) ? OutputFileSink :
- (IsInBin(OutputBin , OutputRtmpSink)) ? OutputRtmpSink :
- (IsInBin(OutputBin , OutputFauxSink)) ? OutputFauxSink :
- nullptr ;
- GstElement* next_sink ; String output_url ;
- #ifdef DISABLE_OUTPUT
- UNUSED(is_enabled) ; is_enabled = (false) ? (bool)0 : false ;
- #endif // DISABLE_OUTPUT
- if (!is_enabled) sink_idx = -1 ;
- switch ((CONFIG::OutputStream)sink_idx)
- {
- case CONFIG::FILE_OUTPUT_IDX: next_sink = OutputFileSink ; output_url = file_url ; break ;
- case CONFIG::RTMP_OUTPUT_IDX: next_sink = OutputRtmpSink ; output_url = rtmp_url ; break ;
- default: next_sink = OutputFauxSink ; is_enabled = false ; break ;
- }
- DEBUG_TRACE_CONFIGURE_OUTPUT_BIN
- // configure elements
- if (is_enabled) ConfigureFileSink(next_sink , output_url) ;
- // swap sink elements
- if (IsInBin(OutputBin , current_sink) && next_sink != current_sink)
- {
- if (!RemoveElement(OutputBin , current_sink) ||
- !AddElement (OutputBin , next_sink ) ||
- !LinkElements (OutputQueue , next_sink ) )
- { AvCaster::Error(GUI::OUTPUT_LINK_ERROR_MSG) ; return nullptr ; }
- }
- return next_sink ;
- }
- void Gstreamer::ConfigureCaps(GstElement* a_capsfilter , String caps_str)
- {
- DEBUG_TRACE_CONFIGURE_CAPS
- g_object_set(G_OBJECT(a_capsfilter) , "caps" , NewCaps(caps_str) , NULL) ;
- }
- void Gstreamer::ConfigureQueue(GstElement* a_queue , guint max_bytes ,
- guint64 max_time , guint max_buffers)
- {
- DEBUG_TRACE_CONFIGURE_QUEUE
- g_object_set(G_OBJECT(a_queue) , "max-size-bytes" , max_bytes , NULL) ;
- g_object_set(G_OBJECT(a_queue) , "max-size-time" , max_time , NULL) ;
- g_object_set(G_OBJECT(a_queue) , "max-size-buffers" , max_buffers , NULL) ;
- }
- void Gstreamer::ConfigureScreenSource(GstElement* a_screen_source , guint capture_w , guint capture_h)
- {
- DEBUG_TRACE_CONFIGURE_SCREEN
- g_object_set(G_OBJECT(a_screen_source) , "endx" , capture_w - 1 , NULL) ;
- g_object_set(G_OBJECT(a_screen_source) , "endy" , capture_h - 1 , NULL) ;
- g_object_set(G_OBJECT(a_screen_source) , "use-damage" , false , NULL) ;
- }
- void Gstreamer::ConfigureCameraSource(GstElement* a_camera_source , String device_path)
- {
- DEBUG_TRACE_CONFIGURE_CAMERA
- g_object_set(G_OBJECT(a_camera_source) , "device" , CHARSTAR(device_path) , NULL) ;
- }
- void Gstreamer::ConfigureTestVideo(GstElement* a_test_source , guint pattern_n)
- {
- DEBUG_TRACE_CONFIGURE_TEST_VIDEO
- g_object_set(G_OBJECT(a_test_source) , "is_live" , (gboolean)true , NULL) ;
- g_object_set(G_OBJECT(a_test_source) , "pattern" , (guint )pattern_n , NULL) ;
- }
- void Gstreamer::ConfigureTextSource(GstElement* a_text_source , String font_desc)
- {
- DEBUG_TRACE_CONFIGURE_TEXT
- g_object_set(G_OBJECT(a_text_source) , "font-desc" , CHARSTAR(font_desc) , NULL) ;
- }
- void Gstreamer::ConfigureFileSource(GstElement* a_file_source , String location)
- {
- DEBUG_TRACE_CONFIGURE_FILE_SOURCE
- g_object_set(G_OBJECT(a_file_source) , "location" , CHARSTAR(location) , NULL) ;
- }
- void Gstreamer::ConfigureFileSink(GstElement* a_file_sink , String location)
- {
- DEBUG_TRACE_CONFIGURE_FILE_SINK
- g_object_set(G_OBJECT(a_file_sink) , "location" , CHARSTAR(location) , NULL) ;
- }
- void Gstreamer::ConfigureCompositor(GstElement* a_compositor , guint background_n)
- {
- DEBUG_TRACE_CONFIGURE_COMPOSITOR
- g_object_set(G_OBJECT(a_compositor) , "background" , background_n , NULL) ;
- }
- void Gstreamer::ConfigureCompositorSink(GstPad* sinkpad , gint w , gint h ,
- gint x , gint y , gint z)
- {
- DEBUG_TRACE_CONFIGURE_COMPOSITOR_SINK
- g_object_set(G_OBJECT(sinkpad) , "width" , w , NULL) ;
- g_object_set(G_OBJECT(sinkpad) , "height" , h , NULL) ;
- g_object_set(G_OBJECT(sinkpad) , "xpos" , x , NULL) ;
- g_object_set(G_OBJECT(sinkpad) , "ypos" , y , NULL) ;
- g_object_set(G_OBJECT(sinkpad) , "zorder" , z , NULL) ;
- }
- bool Gstreamer::ConfigureVideoSink(GstElement* a_video_sink)
- {
- bool is_active = AvCaster::GetIsPreviewActive() ;
- Rectangle<int> preview_bounds = AvCaster::GetPreviewBounds() ;
- guintptr x_window_handle = (is_active) ? PreviewXwin : 0 ;
- gint preview_x = preview_bounds.getX() ;
- gint preview_y = preview_bounds.getY() ;
- gint preview_w = preview_bounds.getWidth() ;
- gint preview_h = preview_bounds.getHeight() ;
- DEBUG_TRACE_CONFIGURE_PREVIEW
- gst_video_overlay_set_window_handle(GST_VIDEO_OVERLAY(a_video_sink) , x_window_handle) ;
- // gst_video_overlay_expose(GST_VIDEO_OVERLAY(a_video_sink)) ;
- // g_object_set(a_video_sink , "async-handling" , TRUE , NULL) ;
- return gst_video_overlay_set_render_rectangle(GST_VIDEO_OVERLAY(a_video_sink) ,
- preview_x , preview_y ,
- preview_w , preview_h ) ;
- }
- void Gstreamer::ConfigureTestAudio(GstElement* a_test_source)
- {
- DEBUG_TRACE_CONFIGURE_TEST_AUDIO
- g_object_set(G_OBJECT(a_test_source) , "is_live" , true , NULL) ;
- g_object_set(G_OBJECT(a_test_source) , "volume" , 0.1 , NULL) ;
- }
- void Gstreamer::ConfigureX264Encoder(GstElement* an_x264_encoder , guint bitrate)
- {
- DEBUG_TRACE_CONFIGURE_X264ENC
- g_object_set(G_OBJECT(an_x264_encoder) , "bitrate" , bitrate , NULL) ;
- // g_object_set(G_OBJECT(video_encoder) , "tune" , 0x00000004 , NULL) ; // may lower quality in favor of latency
- }
- void Gstreamer::ConfigureLameEncoder(GstElement* a_lame_encoder , guint bitrate)
- {
- DEBUG_TRACE_CONFIGURE_LAMEENC
- g_object_set(G_OBJECT(a_lame_encoder) , "target" , 1 , NULL) ;
- g_object_set(G_OBJECT(a_lame_encoder) , "cbr" , true , NULL) ; // CBR
- g_object_set(G_OBJECT(a_lame_encoder) , "bitrate" , bitrate , NULL) ; // CBR
- // g_object_set(G_OBJECT(audio_encoder) , "quality" , 2 , NULL) ; // VBR (default is 4) // VBR
- }
- void Gstreamer::ConfigureFlvmux(GstElement* a_flvmuxer)
- {
- DEBUG_TRACE_CONFIGURE_FLVMUX
- g_object_set(G_OBJECT(a_flvmuxer) , "streamable" , true , NULL) ;
- }
- bool Gstreamer::SetState(GstElement* an_element , GstState next_state)
- {
- bool is_err = an_element != nullptr &&
- gst_element_set_state(an_element , next_state) == GST_STATE_CHANGE_FAILURE ;
- DEBUG_TRACE_SET_GST_STATE
- if (is_err) AvCaster::Error(GUI::GST_STATE_ERROR_MSG) ;
- return !is_err ;
- }
- bool Gstreamer::InitializeGst(int *argc , char **argv[]) { gst_init(nullptr , nullptr) ; }
- GstBusSyncReply Gstreamer::HandleMessage(GstBus* message_bus , GstMessage* message ,
- GstPipeline* pipeline )
- {
- switch (GST_MESSAGE_TYPE(message))
- {
- case GST_MESSAGE_ERROR: HandleErrorMessage(message) ; break ;
- case GST_MESSAGE_EOS: DEBUG_TRACE_MESSAGE_EOS break ;
- case GST_MESSAGE_STATE_CHANGED: DEBUG_TRACE_MESSAGE_STATE_CHANGED break ;
- case GST_MESSAGE_STREAM_STATUS: DEBUG_TRACE_DUMP_MESSAGE_STRUCT break ;
- default: DEBUG_TRACE_MESSAGE_UNHANDLED break ;
- /* GST_MESSAGE_TYPE types
- GST_MESSAGE_UNKNOWN = 0,
- GST_MESSAGE_EOS = (1 << 0),
- GST_MESSAGE_ERROR = (1 << 1),
- GST_MESSAGE_WARNING = (1 << 2),
- GST_MESSAGE_INFO = (1 << 3),
- GST_MESSAGE_TAG = (1 << 4),
- GST_MESSAGE_BUFFERING = (1 << 5),
- GST_MESSAGE_STATE_CHANGED = (1 << 6),
- GST_MESSAGE_STATE_DIRTY = (1 << 7),
- GST_MESSAGE_STEP_DONE = (1 << 8),
- GST_MESSAGE_CLOCK_PROVIDE = (1 << 9),
- GST_MESSAGE_CLOCK_LOST = (1 << 10),
- GST_MESSAGE_NEW_CLOCK = (1 << 11),
- GST_MESSAGE_STRUCTURE_CHANGE = (1 << 12),
- GST_MESSAGE_STREAM_STATUS = (1 << 13),
- GST_MESSAGE_APPLICATION = (1 << 14),
- GST_MESSAGE_ELEMENT = (1 << 15),
- GST_MESSAGE_SEGMENT_START = (1 << 16),
- GST_MESSAGE_SEGMENT_DONE = (1 << 17),
- GST_MESSAGE_DURATION = (1 << 18),
- GST_MESSAGE_LATENCY = (1 << 19),
- GST_MESSAGE_ASYNC_START = (1 << 20),
- GST_MESSAGE_ASYNC_DONE = (1 << 21),
- GST_MESSAGE_ANY = ~0
- */
- }
- /* The result values for a GstBusSyncHandler.
- GST_BUS_DROP drop the message
- GST_BUS_PASS pass the message to the async queue
- GST_BUS_ASYNC pass message to async queue, continue if message is handled
- */
- return GST_BUS_PASS ;
- }
- void Gstreamer::HandleErrorMessage(GstMessage* message)
- {
- GError *error ;
- gchar *debug ;
- gst_message_parse_error(message , &error , &debug) ;
- String error_message = String(error->message) ;
- String warning_msg = String::empty ;
- bool is_alsa_init_error = error_message == GST::ALSA_INIT_ERROR ;
- bool is_pulse_init_error = error_message == GST::PULSE_INIT_ERROR ;
- bool is_jack_init_error = error_message == GST::JACK_INIT_ERROR ;
- bool is_xv_init_error = error_message == GST::XV_INIT_ERROR ;
- bool is_file_sink_error = error_message == GST::FILE_SINK_ERROR ;
- DEBUG_TRACE_GST_ERROR_MESSAGE
- // disable control toggle and re-configure with null source or sink
- if (is_alsa_init_error || is_pulse_init_error || is_jack_init_error)
- {
- AvCaster::DeactivateControl(CONFIG::AUDIO_ID) ; ConfigureAudioBin() ;
- warning_msg = (is_alsa_init_error ) ? GUI::ALSA_INIT_ERROR_MSG :
- (is_pulse_init_error) ? GUI::PULSE_INIT_ERROR_MSG :
- (is_jack_init_error ) ? GUI::JACK_INIT_ERROR_MSG : String::empty ;
- }
- else if (is_xv_init_error)
- {
- AvCaster::DeactivateControl(CONFIG::PREVIEW_ID) ; ConfigurePreviewBin() ;
- warning_msg = GUI::XV_INIT_ERROR_MSG ;
- }
- else if (is_file_sink_error)
- {
- AvCaster::DeactivateControl(CONFIG::OUTPUT_ID) ; ConfigureOutputBin() ;
- warning_msg = GUI::FILE_SINK_ERROR_MSG ;
- }
- else { DEBUG_MAKE_GRAPHVIZ }
- // alert user
- if (warning_msg.isNotEmpty()) AvCaster::Warning(warning_msg + error_message) ;
- g_error_free(error) ; g_free(debug) ;
- }
- GstElement* Gstreamer::NewPipeline(String pipeline_id) { return gst_pipeline_new(CHARSTAR(pipeline_id)) ; }
- GstElement* Gstreamer::NewBin(String bin_id) { return gst_bin_new(CHARSTAR(bin_id)) ; }
- GstElement* Gstreamer::NewElement(String plugin_id , String element_id)
- {
- GstElement* new_element = gst_element_factory_make(CHARSTAR(plugin_id) , CHARSTAR(element_id)) ;
- DEBUG_TRACE_MAKE_ELEMENT
- return new_element ;
- }
- GstCaps* Gstreamer::NewCaps(String caps_str)
- {
- GstCaps* new_caps = gst_caps_from_string(CHARSTAR(caps_str)) ;
- DEBUG_TRACE_MAKE_CAPS
- return new_caps ;
- }
- void Gstreamer::SetMessageHandler(GstPipeline* pipeline , GstBusSyncHandler on_message_cb)
- {
- GstBus* message_bus ;
- if (!GST_IS_ELEMENT(pipeline) ||
- !GST_IS_BUS(message_bus = gst_pipeline_get_bus(pipeline)))
- { AvCaster::Error(GUI::GST_BUS_INST_ERROR_MSG) ; return ; }
- gst_bus_set_sync_handler(message_bus , on_message_cb , pipeline , NULL) ;
- gst_object_unref(message_bus) ;
- }
- bool Gstreamer::AddElement(GstElement* a_bin , GstElement* an_element)
- {
- bool is_err = !gst_bin_add(GST_BIN(a_bin) , an_element) ||
- !gst_element_sync_state_with_parent(an_element) ;
- DEBUG_TRACE_ADD_ELEMENT
- return !is_err ;
- }
- bool Gstreamer::RemoveElement(GstElement* a_bin , GstElement* an_element)
- {
- DEBUG_TRACE_REMOVE_ELEMENT_IN
- // bool is_err = !IsInBin(a_bin , an_element) || !SetState(an_element , GST_STATE_NULL) ||
- // !gst_bin_remove(GST_BIN(a_bin) , an_element) ;
- bool is_err = !IsInBin(a_bin , an_element) || !gst_bin_remove(GST_BIN(a_bin) , an_element) ;
- DEBUG_TRACE_REMOVE_ELEMENT_OUT
- return !is_err ;
- }
- void Gstreamer::DestroyElement(GstElement* an_element)
- {
- DEBUG_TRACE_DESTROY_ELEMENT
- // FIXME: on shutdown --> GStreamer-CRITICAL **: gst_object_unref: assertion '((GObject *) object)->ref_count > 0' failed
- gchar* element_name = gst_element_get_name(an_element) ;
- DBG("Gstreamer::DestroyElement(" + String(element_name) + ") refcount=" + String(GST_OBJECT_REFCOUNT_VALUE(an_element))) ;
- g_free(element_name) ;
- if (an_element != nullptr && SetState(an_element , GST_STATE_NULL))
- gst_object_unref(an_element) ;
- }
- bool Gstreamer::AddBin(GstElement* a_bin)
- {
- DEBUG_TRACE_ADD_BIN_IN
- bool is_err = a_bin == nullptr || IsInPipeline(a_bin) ||
- (!gst_bin_add(GST_BIN(Pipeline) , a_bin) ||
- !gst_element_sync_state_with_parent(a_bin) ) ;
- DEBUG_TRACE_ADD_BIN_OUT
- return !is_err ;
- }
- /*
- bool Gstreamer::RemoveBin(GstElement* a_bin)
- {
- DEBUG_TRACE_REMOVE_BIN_IN
- bool is_err = !IsInPipeline(a_bin) || !gst_bin_remove(GST_BIN(Pipeline) , a_bin) ;
- DEBUG_TRACE_REMOVE_BIN_OUT
- return !is_err ;
- }
- */
- bool Gstreamer::LinkElements(GstElement* source , GstElement* sink)
- {
- bool is_err = !gst_element_link(source , sink) ;
- DEBUG_TRACE_LINK_ELEMENTS
- return !is_err ;
- }
- bool Gstreamer::LinkPads(GstPad* srcpad , GstPad* sinkpad)
- {
- bool is_err = gst_pad_link(srcpad , sinkpad) != GST_PAD_LINK_OK ;
- DEBUG_TRACE_LINK_PADS
- return !is_err ;
- }
- GstPad* Gstreamer::NewGhostSrcPad(GstElement* a_bin , GstElement* an_element ,
- String public_pad_id )
- {
- return NewGhostPad(a_bin , an_element , "src" , public_pad_id) ;
- }
- GstPad* Gstreamer::NewGhostSinkPad(GstElement* a_bin , GstElement* an_element ,
- String public_pad_id )
- {
- return NewGhostPad(a_bin , an_element , "sink" , public_pad_id) ;
- }
- GstPad* Gstreamer::NewGhostPad(GstElement* a_bin , GstElement* an_element ,
- String template_id , String public_pad_id)
- {
- const gchar* private_id = UTF8(template_id ) ;
- const gchar* public_id = UTF8(public_pad_id) ;
- GstPad *private_pad , *public_pad ;
- bool is_err = !(private_pad = gst_element_get_static_pad(an_element , private_id )) ||
- !(public_pad = gst_ghost_pad_new (public_id , private_pad)) ||
- !gst_pad_set_active(public_pad , TRUE) ;
- gst_object_unref(private_pad) ;
- DEBUG_TRACE_MAKE_GHOST_PAD
- is_err = is_err || !AddGhostPad(a_bin , public_pad) ;
- if (is_err) gst_object_unref(public_pad) ;
- return (!is_err) ? public_pad : nullptr ;
- }
- bool Gstreamer::AddGhostPad(GstElement* a_bin , GstPad* public_pad)
- {
- bool is_err = a_bin == nullptr || !gst_element_add_pad(a_bin , public_pad) ;
- DEBUG_TRACE_ADD_GHOST_PAD ; UNUSED(is_err) ;
- return !is_err ;
- }
- GstPad* Gstreamer::NewStaticSinkPad(GstElement* an_element)
- {
- return NewStaticPad(an_element , "sink") ;
- }
- GstPad* Gstreamer::NewStaticSrcPad(GstElement* an_element)
- {
- return NewStaticPad(an_element , "src") ;
- }
- GstPad* Gstreamer::NewStaticPad(GstElement* an_element , String template_id)
- {
- const gchar* private_id = UTF8(template_id) ;
- GstPad* private_pad ;
- bool is_err = !(private_pad = gst_element_get_static_pad(an_element , private_id)) ;
- DEBUG_TRACE_GET_STATIC_PAD ; UNUSED(is_err) ;
- return private_pad ;
- }
- GstPad* Gstreamer::NewRequestSinkPad(GstElement* an_element)
- {
- return NewRequestPad(an_element , "sink_%u") ;
- }
- GstPad* Gstreamer::NewRequestSrcPad(GstElement* an_element)
- {
- return NewRequestPad(an_element , "src_%u") ;
- }
- GstPad* Gstreamer::NewRequestPad(GstElement* an_element , String template_id)
- {
- const gchar* private_id = UTF8(template_id) ;
- GstPad* private_pad ;
- bool is_err = !(private_pad = gst_element_get_request_pad(an_element , private_id)) ;
- DEBUG_TRACE_GET_REQUEST_PAD ; UNUSED(is_err) ;
- return private_pad ;
- }
- String Gstreamer::MakeVideoCapsString(int width , int height , int framerate)
- {
- return String("video/x-raw, ") +
- "width=(int)" + String(width ) + ", " +
- "height=(int)" + String(height ) + ", " +
- "framerate=(fraction)" + String(framerate) + "/1, " +
- // "format=ARGB, " +
- "format=I420, " +
- "pixel-aspect-ratio=(fraction)1/1, " +
- "interlace-mode=(string)progressive" ;
- }
- String Gstreamer::MakeScreenCapsString(int screencap_w , int screencap_h , int framerate)
- {
- return String("video/x-raw, ") +
- "width=(int)" + String(screencap_w) + ", " +
- "height=(int)" + String(screencap_h) + ", " +
- "framerate=(fraction)" + String(framerate ) + "/1, " +
- "pixel-aspect-ratio=(fraction)1/1" ;
- }
- String Gstreamer::MakeCameraCapsString(int camera_w , int camera_h , int framerate)
- {
- return String("video/x-raw, ") +
- #ifndef NATIVE_CAMERA_RESOLUTION_ONLY
- "width=(int)" + String(camera_w ) + ", " +
- "height=(int)" + String(camera_h ) + ", " +
- "framerate=(fraction)" + String(framerate) + "/1, " +
- "format=I420, " +
- #endif // NATIVE_CAMERA_RESOLUTION_ONLY
- "pixel-aspect-ratio=(fraction)1/1" ;
- }
- String Gstreamer::MakeAudioCapsString(String format , int samplerate , int n_channels)
- {
- return String("audio/x-raw, " ) +
- String("layout=(string)interleaved, ") +
- String("format=(string)" ) + format + ", " +
- String("rate=(int)" ) + String(samplerate) + ", " +
- String("channels=(int)") + String(n_channels) ;
- //"channel-mask=(bitmask)0x03"
- }
- String Gstreamer::MakeH264CapsString(int output_w , int output_h , int framerate)
- {
- return String("video/x-h264, ") +
- "width=(int)" + String(output_w ) + ", " +
- "height=(int)" + String(output_h ) + ", " +
- "framerate=(fraction)" + String(framerate) + "/1, " +
- "stream-format=avc, alignment=au, profile=main" ;
- // String h264_caps_str = "video/x-h264, level=(string)4.1, profile=main" ;
- }
- String Gstreamer::MakeMp3CapsString(int samplerate , int n_channels)
- {
- return String("audio/mpeg, mpegversion=1, layer=3, ") +
- String("rate=(int)" ) + String(samplerate) + ", " +
- String("channels=(int)") + String(n_channels) ;
- // String mp3_caps_str = String("audio/mpeg, mpegversion=1, layer=3, mpegaudioversion=3, ") +
- }
- String Gstreamer::MakeFileName(String destination , String file_ext)
- {
- String filename = (destination.isEmpty()) ? APP::APP_NAME :
- destination.upToLastOccurrenceOf(file_ext , false , true) ;
- File output_file = APP::videosDir().getNonexistentChildFile(filename , file_ext , false) ;
- return output_file.getFullPathName() ;
- }
- String Gstreamer::MakeRtmpUrl(String destination)
- {
- bool is_lctv = AvCaster::GetPresetIdx() == CONFIG::LCTV_PRESET_IDX ;
- String env_url = std::getenv("AVCASTER_RTMP_DEST") ;
- // String env_url = SystemStats::getEnvironmentVariable("AVCASTER_RTMP_DEST" , "") ;
- destination = destination.retainCharacters(APP::VALID_URI_CHARS) ;
- if (destination.isEmpty()) destination = env_url ;
- if (destination.isEmpty()) AvCaster::Error(GUI::OUTPUT_INIT_ERROR_MSG) ;
- if (is_lctv)
- {
- // trim input allowing either stream key or full url
- if (destination.contains(GST::LCTV_RTMP_URL))
- destination = destination.fromFirstOccurrenceOf(GST::LCTV_RTMP_URL , false , true) ;
- if (destination.contains(" live=1" ))
- destination = destination.upToLastOccurrenceOf (" live=1" , false , true) ;
- destination = GST::LCTV_RTMP_URL + destination + " live=1" ;
- }
- return destination ;
- }
- String Gstreamer::VersionMsg()
- {
- guint major_version , minor_version , micro_version , nano_version ;
- gst_version(&major_version , &minor_version , µ_version , &nano_version) ;
- return "gStreamer v" + String(major_version) + "." + String(minor_version) +
- "." + String(micro_version) + "." + String(nano_version ) ;
- }
- bool Gstreamer::IsSufficientVersion()
- {
- guint major_version , minor_version , micro_version , nano_version ;
- gst_version(&major_version , &minor_version , µ_version , &nano_version) ;
- return major_version >= GST::MIN_MAJOR_VERSION &&
- minor_version >= GST::MIN_MINOR_VERSION ;
- }
- String Gstreamer::GetElementId(GstElement* an_element)
- {
- if (!an_element) return "nil" ;
- gchar* id = gst_element_get_name(an_element) ; String element_id = id ; g_free(id) ;
- return element_id ;
- }
- String Gstreamer::GetPadId(GstPad* a_pad)
- {
- if (!a_pad) return "nil" ;
- gchar* id = gst_pad_get_name(a_pad) ; String pad_id = id ; g_free(id) ;
- return pad_id ;
- }
- bool Gstreamer::IsInitialized() { return gst_is_initialized() ; }
- // bool Gstreamer::IsPlaying() { return !!Pipeline && GST_STATE(Pipeline) == GST_STATE_PLAYING ; }
- bool Gstreamer::IsInPipeline(GstElement* an_element)
- {
- return IsInBin(Pipeline , an_element) ;
- }
- bool Gstreamer::IsInBin(GstElement* a_parent_element , GstElement* a_child_element)
- {
- return !!a_child_element && !!a_parent_element &&
- GST_ELEMENT_PARENT(a_child_element) == a_parent_element ;
- }
|