static void gst_decklink_video_sink_init (GstDecklinkVideoSink * self) { self->mode = GST_DECKLINK_MODE_NTSC; self->device_number = 0; gst_base_sink_set_max_lateness (GST_BASE_SINK_CAST (self), 20 * GST_MSECOND); gst_base_sink_set_qos_enabled (GST_BASE_SINK_CAST (self), TRUE); }
static void gst_video_sink_init (GstVideoSink * videosink) { videosink->width = 0; videosink->height = 0; /* 20ms is more than enough, 80-130ms is noticable */ gst_base_sink_set_max_lateness (GST_BASE_SINK (videosink), 20 * GST_MSECOND); gst_base_sink_set_qos_enabled (GST_BASE_SINK (videosink), TRUE); }
static void gst_decklink_audio_sink_init (GstDecklinkAudioSink * self) { self->device_number = DEFAULT_DEVICE_NUMBER; self->stream_align = gst_audio_stream_align_new (48000, DEFAULT_ALIGNMENT_THRESHOLD, DEFAULT_DISCONT_WAIT); self->buffer_time = DEFAULT_BUFFER_TIME * 1000; gst_base_sink_set_max_lateness (GST_BASE_SINK_CAST (self), 20 * GST_MSECOND); }
static void gst_decklink_video_sink_init (GstDecklinkVideoSink * self) { self->mode = GST_DECKLINK_MODE_NTSC; self->device_number = 0; self->video_format = GST_DECKLINK_VIDEO_FORMAT_8BIT_YUV; /* VITC is legacy, we should expect RP188 in modern use cases */ self->timecode_format = bmdTimecodeRP188Any; gst_base_sink_set_max_lateness (GST_BASE_SINK_CAST (self), 20 * GST_MSECOND); gst_base_sink_set_qos_enabled (GST_BASE_SINK_CAST (self), TRUE); }
static void gst_video_sink_init (GstVideoSink * videosink) { videosink->width = 0; videosink->height = 0; /* 20ms is more than enough, 80-130ms is noticable */ gst_base_sink_set_max_lateness (GST_BASE_SINK (videosink), 20 * GST_MSECOND); gst_base_sink_set_qos_enabled (GST_BASE_SINK (videosink), TRUE); videosink->priv = G_TYPE_INSTANCE_GET_PRIVATE (videosink, GST_TYPE_VIDEO_SINK, GstVideoSinkPrivate); }
static void cb_child_added(GstChildProxy *child_proxy, GObject *object, TSMFGstreamerDecoder* mdecoder) { DEBUG_TSMF("NAME: %s", G_OBJECT_TYPE_NAME(object)); if (!g_strcmp0(G_OBJECT_TYPE_NAME(object), "GstXvImageSink") || !g_strcmp0(G_OBJECT_TYPE_NAME(object), "GstXImageSink") || !g_strcmp0(G_OBJECT_TYPE_NAME(object), "GstFluVAAutoSink")) { gst_base_sink_set_max_lateness((GstBaseSink *) object, 10000000); /* nanoseconds */ g_object_set(G_OBJECT(object), "sync", TRUE, NULL); /* synchronize on the clock */ g_object_set(G_OBJECT(object), "async", TRUE, NULL); /* no async state changes */ } else if (!g_strcmp0(G_OBJECT_TYPE_NAME(object), "GstAlsaSink") || !g_strcmp0(G_OBJECT_TYPE_NAME(object), "GstPulseSink")) { gst_base_sink_set_max_lateness((GstBaseSink *) object, 10000000); /* nanoseconds */ g_object_set(G_OBJECT(object), "slave-method", 1, NULL); g_object_set(G_OBJECT(object), "buffer-time", (gint64) 20000, NULL); /* microseconds */ g_object_set(G_OBJECT(object), "drift-tolerance", (gint64) 20000, NULL); /* microseconds */ g_object_set(G_OBJECT(object), "latency-time", (gint64) 10000, NULL); /* microseconds */ g_object_set(G_OBJECT(object), "sync", TRUE, NULL); /* synchronize on the clock */ g_object_set(G_OBJECT(object), "async", TRUE, NULL); /* no async state changes */ } }
static void gst_gdk_pixbuf_sink_init (GstGdkPixbufSink * sink) { sink->par_n = 0; sink->par_d = 0; sink->has_alpha = FALSE; sink->last_pixbuf = NULL; sink->post_messages = DEFAULT_POST_MESSAGES; /* we're not a real video sink, we just derive from GstVideoSink in case * anything interesting is added to it in future */ gst_base_sink_set_max_lateness (GST_BASE_SINK (sink), -1); gst_base_sink_set_qos_enabled (GST_BASE_SINK (sink), FALSE); }
/****************************************************************************** * gst_tidmaivideosink_init ******************************************************************************/ static void gst_tidmaivideosink_init(GstTIDmaiVideoSink * dmaisink, GstTIDmaiVideoSinkClass * g_class) { GST_DEBUG("Initializing the class"); /* Set the default values to NULL or -1. If the user specifies a value * then the element will be non-null when the display is created. * Anything that has a NULL value will be initialized with DMAI defaults * in the gst_tidmaivideosink_init_display function. */ dmaisink->displayStd = NULL; dmaisink->displayDevice = NULL; dmaisink->videoStd = NULL; dmaisink->videoOutput = NULL; dmaisink->numBufs = -1; dmaisink->rotation = -1; dmaisink->tempDmaiBuf = NULL; dmaisink->accelFrameCopy = TRUE; dmaisink->autoselect = FALSE; dmaisink->prevVideoStd = 0; dmaisink->xPosition = -1; dmaisink->yPosition = -1; dmaisink->xCentering = FALSE; dmaisink->yCentering = FALSE; dmaisink->width = 0; dmaisink->height = 0; dmaisink->capsAreSet = FALSE; dmaisink->allocatedBuffers = NULL; dmaisink->numAllocatedBuffers = 0; dmaisink->unusedBuffers = NULL; dmaisink->numUnusedBuffers = 0; dmaisink->dmaiElementUpstream = FALSE; dmaisink->zeromemcpy = FALSE; dmaisink->lastAllocatedBuffer = NULL; gst_base_sink_set_max_lateness((GstBaseSink *)dmaisink,-1); }
bool ofGstVideoPlayer::loadMovie(string name){ close(); if( name.find( "file://",0 ) != string::npos){ bIsStream = false; }else if( name.find( "://",0 ) == string::npos){ name = "file://"+ofToDataPath(name,true); bIsStream = false; }else{ bIsStream = true; } ofLog(OF_LOG_VERBOSE,"loading "+name); ofGstUtils::startGstMainLoop(); GstElement * gstPipeline = gst_element_factory_make("playbin2","player"); g_object_set(G_OBJECT(gstPipeline), "uri", name.c_str(), (void*)NULL); // create the oF appsink for video rgb without sync to clock GstElement * gstSink = gst_element_factory_make("appsink", "app_sink"); gst_base_sink_set_sync(GST_BASE_SINK(gstSink), true); gst_app_sink_set_max_buffers(GST_APP_SINK(gstSink), 8); gst_app_sink_set_drop (GST_APP_SINK(gstSink),true); gst_base_sink_set_max_lateness (GST_BASE_SINK(gstSink), -1); int bpp; string mime; switch(internalPixelFormat){ case OF_PIXELS_MONO: mime = "video/x-raw-gray"; bpp = 8; break; case OF_PIXELS_RGB: mime = "video/x-raw-rgb"; bpp = 24; break; case OF_PIXELS_RGBA: case OF_PIXELS_BGRA: mime = "video/x-raw-rgb"; bpp = 32; break; default: mime = "video/x-raw-rgb"; bpp=24; break; } GstCaps *caps = gst_caps_new_simple(mime.c_str(), "bpp", G_TYPE_INT, bpp, "depth", G_TYPE_INT, 24, "endianness",G_TYPE_INT,4321, "red_mask",G_TYPE_INT,0xff0000, "green_mask",G_TYPE_INT,0x00ff00, "blue_mask",G_TYPE_INT,0x0000ff, "alpha_mask",G_TYPE_INT,0x000000ff, NULL); gst_app_sink_set_caps(GST_APP_SINK(gstSink), caps); gst_caps_unref(caps); if(threadAppSink){ GstElement * appQueue = gst_element_factory_make("queue","appsink_queue"); g_object_set(G_OBJECT(appQueue), "leaky", 0, "silent", 1, (void*)NULL); GstElement* appBin = gst_bin_new("app_bin"); gst_bin_add(GST_BIN(appBin), appQueue); GstPad* appQueuePad = gst_element_get_static_pad(appQueue, "sink"); GstPad* ghostPad = gst_ghost_pad_new("app_bin_sink", appQueuePad); gst_object_unref(appQueuePad); gst_element_add_pad(appBin, ghostPad); gst_bin_add_many(GST_BIN(appBin), gstSink, NULL); gst_element_link_many(appQueue, gstSink, NULL); g_object_set (G_OBJECT(gstPipeline),"video-sink",appBin,(void*)NULL); }else{ g_object_set (G_OBJECT(gstPipeline),"video-sink",gstSink,(void*)NULL); } #ifdef TARGET_WIN32 GstElement *audioSink = gst_element_factory_make("directsoundsink", NULL); g_object_set (G_OBJECT(gstPipeline),"audio-sink",audioSink,(void*)NULL); #endif videoUtils.setPipelineWithSink(gstPipeline,gstSink,bIsStream); if(!bIsStream) return allocate(bpp); else return true; }
bool GStreamerWrapper::open( std::string strFilename, bool bGenerateVideoBuffer, bool bGenerateAudioBuffer ) { if( m_bFileIsOpen ) { stop(); close(); } // init property variables m_iNumVideoStreams = 0; m_iNumAudioStreams = 0; m_iCurrentVideoStream = 0; m_iCurrentAudioStream = 0; m_iWidth = m_iHeight = 0; m_iCurrentFrameNumber = 0; // set to invalid, as it is not decoded yet m_dCurrentTimeInMs = 0; // set to invalid, as it is not decoded yet m_bIsAudioSigned = false; m_bIsNewVideoFrame = false; m_iNumAudioChannels = 0; m_iAudioSampleRate = 0; m_iAudioBufferSize = 0; m_iAudioWidth = 0; m_AudioEndianness = LITTLE_ENDIAN; m_fFps = 0; m_dDurationInMs = 0; m_iNumberOfFrames = 0; m_fVolume = 1.0f; m_fSpeed = 1.0f; m_PlayDirection = FORWARD; m_CurrentPlayState = NOT_INITIALIZED; m_LoopMode = LOOP; m_strFilename = strFilename; #ifdef THREADED_MESSAGE_HANDLER m_MsgHandlingThread = std::thread( std::bind( threadedMessageHandler, this ) ); #endif ////////////////////////////////////////////////////////////////////////// PIPELINE // Init main pipeline --> playbin2 m_GstPipeline = gst_element_factory_make( "playbin2", "pipeline" ); // Check and re-arrange filename string if ( strFilename.find( "file:/", 0 ) == std::string::npos && strFilename.find( "file:///", 0 ) == std::string::npos && strFilename.find( "http://", 0 ) == std::string::npos ) { strFilename = "file:/" + strFilename; } // Open Uri g_object_set( m_GstPipeline, "uri", strFilename.c_str(), NULL ); ////////////////////////////////////////////////////////////////////////// VIDEO SINK // Extract and Config Video Sink if ( bGenerateVideoBuffer ) { // Create the video appsink and configure it m_GstVideoSink = gst_element_factory_make( "appsink", "videosink" ); gst_base_sink_set_sync( GST_BASE_SINK( m_GstVideoSink ), true ); gst_app_sink_set_max_buffers( GST_APP_SINK( m_GstVideoSink ), 8 ); gst_app_sink_set_drop( GST_APP_SINK( m_GstVideoSink ),true ); gst_base_sink_set_max_lateness( GST_BASE_SINK( m_GstVideoSink ), -1); // Set some fix caps for the video sink // It would seem that GStreamer then tries to transform any incoming video stream according to these caps GstCaps* caps = gst_caps_new_simple( "video/x-raw-rgb", "bpp", G_TYPE_INT, 24, "depth", G_TYPE_INT, 24, "endianness",G_TYPE_INT,4321, "red_mask",G_TYPE_INT,0xff0000, "green_mask",G_TYPE_INT,0x00ff00, "blue_mask",G_TYPE_INT,0x0000ff, "alpha_mask",G_TYPE_INT,0x000000ff, NULL ); gst_app_sink_set_caps( GST_APP_SINK( m_GstVideoSink ), caps ); gst_caps_unref( caps ); // Set the configured video appsink to the main pipeline g_object_set( m_GstPipeline, "video-sink", m_GstVideoSink, (void*)NULL ); // Tell the video appsink that it should not emit signals as the buffer retrieving is handled via callback methods g_object_set( m_GstVideoSink, "emit-signals", false, "sync", true, (void*)NULL ); // Set Video Sink callback methods m_GstVideoSinkCallbacks.eos = &GStreamerWrapper::onEosFromVideoSource; m_GstVideoSinkCallbacks.new_preroll = &GStreamerWrapper::onNewPrerollFromVideoSource; m_GstVideoSinkCallbacks.new_buffer = &GStreamerWrapper::onNewBufferFromVideoSource; gst_app_sink_set_callbacks( GST_APP_SINK( m_GstVideoSink ), &m_GstVideoSinkCallbacks, this, NULL ); } else { #if defined _WIN32 // Use direct show as playback plugin if on Windows; Needed for features like play direction and playback speed to work correctly GstElement* videoSink = gst_element_factory_make( "directdrawsink", NULL ); g_object_set( m_GstPipeline, "video-sink", videoSink, NULL ); #elif defined LINUX GstElement* videoSink = gst_element_factory_make( "xvimagesink", NULL ); //possible alternatives: ximagesink (no (gpu) fancy stuff) or better: cluttersink g_object_set( m_GstPipeline, "video-sink", videoSink, NULL ); #else // Use Mac OSX plugin otherwise GstElement* videoSink = gst_element_factory_make( "osxvideosink", NULL ); g_object_set( m_GstPipeline, "video-sink", videoSink, NULL ); #endif } ////////////////////////////////////////////////////////////////////////// AUDIO SINK // Extract and config Audio Sink if ( bGenerateAudioBuffer ) { // Create and configure audio appsink m_GstAudioSink = gst_element_factory_make( "appsink", "audiosink" ); gst_base_sink_set_sync( GST_BASE_SINK( m_GstAudioSink ), true ); // Set the configured audio appsink to the main pipeline g_object_set( m_GstPipeline, "audio-sink", m_GstAudioSink, (void*)NULL ); // Tell the video appsink that it should not emit signals as the buffer retrieving is handled via callback methods g_object_set( m_GstAudioSink, "emit-signals", false, "sync", true, (void*)NULL ); // Set Audio Sink callback methods m_GstAudioSinkCallbacks.eos = &GStreamerWrapper::onEosFromAudioSource; m_GstAudioSinkCallbacks.new_preroll = &GStreamerWrapper::onNewPrerollFromAudioSource; m_GstAudioSinkCallbacks.new_buffer = &GStreamerWrapper::onNewBufferFromAudioSource; gst_app_sink_set_callbacks( GST_APP_SINK( m_GstAudioSink ), &m_GstAudioSinkCallbacks, this, NULL ); } else { #if defined _WIN32 // Use direct sound plugin if on Windows; Needed for features like play direction and playback speed to work correctly GstElement* audioSink = gst_element_factory_make( "directsoundsink", NULL ); g_object_set ( m_GstPipeline, "audio-sink", audioSink, NULL ); #elif defined LINUX GstElement* audioSink = gst_element_factory_make( "pulsesink", NULL ); //alternative: alsasink g_object_set ( m_GstPipeline, "audio-sink", audioSink, NULL ); #else // Use Mac OSC plugin otherwise GstElement* audioSink = gst_element_factory_make( "osxaudiosink", NULL ); g_object_set ( m_GstPipeline,"audio-sink", audioSink, NULL ); #endif } ////////////////////////////////////////////////////////////////////////// BUS // Set GstBus m_GstBus = gst_pipeline_get_bus( GST_PIPELINE( m_GstPipeline ) ); if ( m_GstPipeline != NULL ) { //just add this callback for threaded message handling #ifdef THREADED_MESSAGE_HANDLER gst_bus_add_watch (m_GstBus, onHandleGstMessages, this ); #endif // We need to stream the file a little bit in order to be able to retrieve information from it gst_element_set_state( m_GstPipeline, GST_STATE_READY ); gst_element_set_state( m_GstPipeline, GST_STATE_PAUSED ); // For some reason this is needed in order to gather video information such as size, framerate etc ... GstState state; gst_element_get_state( m_GstPipeline, &state, NULL, 2 * GST_SECOND ); m_CurrentPlayState = OPENED; } // Retrieve and store all relevant Media Information retrieveVideoInfo(); if( !hasVideo() && !hasAudio() ) // is a valid multimedia file? { close(); return false; } // Print Media Info printMediaFileInfo(); // TODO: Check if everything was initialized correctly // A file has been opened m_bFileIsOpen = true; return true; }
BOOL tsmf_gstreamer_pipeline_build(TSMFGstreamerDecoder* mdecoder) { #if GST_VERSION_MAJOR > 0 const char* video = "appsrc name=videosource ! queue2 name=videoqueue ! decodebin name=videodecoder !"; const char* audio = "appsrc name=audiosource ! queue2 name=audioqueue ! decodebin name=audiodecoder ! audioconvert ! audiorate ! audioresample ! volume name=audiovolume !"; #else const char* video = "appsrc name=videosource ! queue2 name=videoqueue ! decodebin2 name=videodecoder !"; const char* audio = "appsrc name=audiosource ! queue2 name=audioqueue ! decodebin2 name=audiodecoder ! audioconvert ! audiorate ! audioresample ! volume name=audiovolume !"; #endif char pipeline[1024]; if (!mdecoder) return FALSE; /* TODO: Construction of the pipeline from a string allows easy overwrite with arguments. * The only fixed elements necessary are appsrc and the volume element for audio streams. * The rest could easily be provided in gstreamer pipeline notation from command line. */ if (mdecoder->media_type == TSMF_MAJOR_TYPE_VIDEO) sprintf_s(pipeline, sizeof(pipeline), "%s %s name=videosink", video, tsmf_platform_get_video_sink()); else sprintf_s(pipeline, sizeof(pipeline), "%s %s name=audiosink", audio, tsmf_platform_get_audio_sink()); DEBUG_TSMF("pipeline=%s", pipeline); mdecoder->pipe = gst_parse_launch(pipeline, NULL); if (!mdecoder->pipe) { WLog_ERR(TAG, "Failed to create new pipe"); return FALSE; } if (mdecoder->media_type == TSMF_MAJOR_TYPE_VIDEO) mdecoder->src = gst_bin_get_by_name(GST_BIN(mdecoder->pipe), "videosource"); else mdecoder->src = gst_bin_get_by_name(GST_BIN(mdecoder->pipe), "audiosource"); if (!mdecoder->src) { WLog_ERR(TAG, "Failed to get appsrc"); return FALSE; } if (mdecoder->media_type == TSMF_MAJOR_TYPE_VIDEO) mdecoder->queue = gst_bin_get_by_name(GST_BIN(mdecoder->pipe), "videoqueue"); else mdecoder->queue = gst_bin_get_by_name(GST_BIN(mdecoder->pipe), "audioqueue"); if (!mdecoder->queue) { WLog_ERR(TAG, "Failed to get queue"); return FALSE; } if (mdecoder->media_type == TSMF_MAJOR_TYPE_VIDEO) mdecoder->outsink = gst_bin_get_by_name(GST_BIN(mdecoder->pipe), "videosink"); else mdecoder->outsink = gst_bin_get_by_name(GST_BIN(mdecoder->pipe), "audiosink"); if (!mdecoder->outsink) { WLog_ERR(TAG, "Failed to get sink"); return FALSE; } g_signal_connect(mdecoder->outsink, "child-added", G_CALLBACK(cb_child_added), mdecoder); if (mdecoder->media_type == TSMF_MAJOR_TYPE_AUDIO) { mdecoder->volume = gst_bin_get_by_name(GST_BIN(mdecoder->pipe), "audiovolume"); if (!mdecoder->volume) { WLog_ERR(TAG, "Failed to get volume"); return FALSE; } tsmf_gstreamer_change_volume((ITSMFDecoder*)mdecoder, mdecoder->gstVolume*((double) 10000), mdecoder->gstMuted); } tsmf_platform_register_handler(mdecoder); /* AppSrc settings */ GstAppSrcCallbacks callbacks = { tsmf_gstreamer_need_data, tsmf_gstreamer_enough_data, tsmf_gstreamer_seek_data }; g_object_set(mdecoder->src, "format", GST_FORMAT_TIME, NULL); g_object_set(mdecoder->src, "is-live", FALSE, NULL); g_object_set(mdecoder->src, "block", FALSE, NULL); g_object_set(mdecoder->src, "blocksize", 1024, NULL); gst_app_src_set_caps((GstAppSrc *) mdecoder->src, mdecoder->gst_caps); gst_app_src_set_callbacks((GstAppSrc *)mdecoder->src, &callbacks, mdecoder, NULL); gst_app_src_set_stream_type((GstAppSrc *) mdecoder->src, GST_APP_STREAM_TYPE_SEEKABLE); gst_app_src_set_latency((GstAppSrc *) mdecoder->src, 0, -1); gst_app_src_set_max_bytes((GstAppSrc *) mdecoder->src, (guint64) 0);//unlimited g_object_set(G_OBJECT(mdecoder->queue), "use-buffering", FALSE, NULL); g_object_set(G_OBJECT(mdecoder->queue), "use-rate-estimate", FALSE, NULL); g_object_set(G_OBJECT(mdecoder->queue), "max-size-buffers", 0, NULL); g_object_set(G_OBJECT(mdecoder->queue), "max-size-bytes", 0, NULL); g_object_set(G_OBJECT(mdecoder->queue), "max-size-time", (guint64) 0, NULL); /* Only set these properties if not an autosink, otherwise we will set properties when real sinks are added */ if (!g_strcmp0(G_OBJECT_TYPE_NAME(mdecoder->outsink), "GstAutoVideoSink") && !g_strcmp0(G_OBJECT_TYPE_NAME(mdecoder->outsink), "GstAutoAudioSink")) { if (mdecoder->media_type == TSMF_MAJOR_TYPE_VIDEO) { gst_base_sink_set_max_lateness((GstBaseSink *) mdecoder->outsink, 10000000); /* nanoseconds */ } else { gst_base_sink_set_max_lateness((GstBaseSink *) mdecoder->outsink, 10000000); /* nanoseconds */ g_object_set(G_OBJECT(mdecoder->outsink), "buffer-time", (gint64) 20000, NULL); /* microseconds */ g_object_set(G_OBJECT(mdecoder->outsink), "drift-tolerance", (gint64) 20000, NULL); /* microseconds */ g_object_set(G_OBJECT(mdecoder->outsink), "latency-time", (gint64) 10000, NULL); /* microseconds */ g_object_set(G_OBJECT(mdecoder->outsink), "slave-method", 1, NULL); } g_object_set(G_OBJECT(mdecoder->outsink), "sync", TRUE, NULL); /* synchronize on the clock */ g_object_set(G_OBJECT(mdecoder->outsink), "async", TRUE, NULL); /* no async state changes */ } tsmf_window_create(mdecoder); tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_READY); tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_PLAYING); mdecoder->pipeline_start_time_valid = 0; mdecoder->shutdown = 0; mdecoder->paused = FALSE; GST_DEBUG_BIN_TO_DOT_FILE(GST_BIN(mdecoder->pipe), GST_DEBUG_GRAPH_SHOW_ALL, get_type(mdecoder)); return TRUE; }