static gboolean gst_app_src_query (GstBaseSrc * src, GstQuery * query) { GstAppSrc *appsrc = GST_APP_SRC_CAST (src); GstAppSrcPrivate *priv = appsrc->priv; gboolean res; switch (GST_QUERY_TYPE (query)) { case GST_QUERY_LATENCY: { GstClockTime min, max; gboolean live; /* Query the parent class for the defaults */ res = gst_base_src_query_latency (src, &live, &min, &max); /* overwrite with our values when we need to */ g_mutex_lock (priv->mutex); if (priv->min_latency != -1) min = priv->min_latency; if (priv->max_latency != -1) max = priv->max_latency; g_mutex_unlock (priv->mutex); gst_query_set_latency (query, live, min, max); break; } default: res = GST_BASE_SRC_CLASS (parent_class)->query (src, query); break; } return res; }
static void gst_app_src_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { GstAppSrc *appsrc = GST_APP_SRC_CAST (object); GstAppSrcPrivate *priv = appsrc->priv; switch (prop_id) { case PROP_CAPS: g_value_take_boxed (value, gst_app_src_get_caps (appsrc)); break; case PROP_SIZE: g_value_set_int64 (value, gst_app_src_get_size (appsrc)); break; case PROP_STREAM_TYPE: g_value_set_enum (value, gst_app_src_get_stream_type (appsrc)); break; case PROP_MAX_BYTES: g_value_set_uint64 (value, gst_app_src_get_max_bytes (appsrc)); break; case PROP_FORMAT: g_value_set_enum (value, priv->format); break; case PROP_BLOCK: g_value_set_boolean (value, priv->block); break; case PROP_IS_LIVE: g_value_set_boolean (value, gst_base_src_is_live (GST_BASE_SRC (appsrc))); break; case PROP_MIN_LATENCY: { guint64 min; gst_app_src_get_latency (appsrc, &min, NULL); g_value_set_int64 (value, min); break; } case PROP_MAX_LATENCY: { guint64 max; gst_app_src_get_latency (appsrc, NULL, &max); g_value_set_int64 (value, max); break; } case PROP_EMIT_SIGNALS: g_value_set_boolean (value, gst_app_src_get_emit_signals (appsrc)); break; case PROP_MIN_PERCENT: g_value_set_uint (value, priv->min_percent); break; case PROP_CURRENT_LEVEL_BYTES: g_value_set_uint64 (value, gst_app_src_get_current_level_bytes (appsrc)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
static gboolean gst_app_src_do_get_size (GstBaseSrc * src, guint64 * size) { GstAppSrc *appsrc = GST_APP_SRC_CAST (src); *size = gst_app_src_get_size (appsrc); return TRUE; }
static void gst_app_src_finalize (GObject * obj) { GstAppSrc *appsrc = GST_APP_SRC_CAST (obj); GstAppSrcPrivate *priv = appsrc->priv; g_mutex_free (priv->mutex); g_cond_free (priv->cond); g_queue_free (priv->queue); G_OBJECT_CLASS (parent_class)->finalize (obj); }
static gboolean gst_app_src_negotiate (GstBaseSrc * basesrc) { GstAppSrc *appsrc = GST_APP_SRC_CAST (basesrc); GstAppSrcPrivate *priv = appsrc->priv; gboolean result; g_mutex_lock (&priv->mutex); result = gst_app_src_do_negotiate (basesrc); priv->new_caps = FALSE; g_mutex_unlock (&priv->mutex); return result; }
static gboolean gst_app_src_query (GstBaseSrc * src, GstQuery * query) { GstAppSrc *appsrc = GST_APP_SRC_CAST (src); GstAppSrcPrivate *priv = appsrc->priv; gboolean res; switch (GST_QUERY_TYPE (query)) { case GST_QUERY_LATENCY: { GstClockTime min, max; gboolean live; /* Query the parent class for the defaults */ res = gst_base_src_query_latency (src, &live, &min, &max); /* overwrite with our values when we need to */ g_mutex_lock (&priv->mutex); if (priv->min_latency != -1) min = priv->min_latency; if (priv->max_latency != -1) max = priv->max_latency; g_mutex_unlock (&priv->mutex); gst_query_set_latency (query, live, min, max); break; } case GST_QUERY_SCHEDULING: { gst_query_set_scheduling (query, GST_SCHEDULING_FLAG_SEEKABLE, 1, -1, 0); gst_query_add_scheduling_mode (query, GST_PAD_MODE_PUSH); switch (priv->stream_type) { case GST_APP_STREAM_TYPE_STREAM: case GST_APP_STREAM_TYPE_SEEKABLE: break; case GST_APP_STREAM_TYPE_RANDOM_ACCESS: gst_query_add_scheduling_mode (query, GST_PAD_MODE_PULL); break; } res = TRUE; break; } default: res = GST_BASE_SRC_CLASS (parent_class)->query (src, query); break; } return res; }
static gboolean gst_app_src_unlock_stop (GstBaseSrc * bsrc) { GstAppSrc *appsrc = GST_APP_SRC_CAST (bsrc); GstAppSrcPrivate *priv = appsrc->priv; g_mutex_lock (&priv->mutex); GST_DEBUG_OBJECT (appsrc, "unlock stop"); priv->flushing = FALSE; g_cond_broadcast (&priv->cond); g_mutex_unlock (&priv->mutex); return TRUE; }
static void gst_app_src_dispose (GObject * obj) { GstAppSrc *appsrc = GST_APP_SRC_CAST (obj); GstAppSrcPrivate *priv = appsrc->priv; if (priv->caps) { gst_caps_unref (priv->caps); priv->caps = NULL; } gst_app_src_flush_queued (appsrc); G_OBJECT_CLASS (parent_class)->dispose (obj); }
static void gst_app_src_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { GstAppSrc *appsrc = GST_APP_SRC_CAST (object); GstAppSrcPrivate *priv = appsrc->priv; switch (prop_id) { case PROP_CAPS: gst_app_src_set_caps (appsrc, gst_value_get_caps (value)); break; case PROP_SIZE: gst_app_src_set_size (appsrc, g_value_get_int64 (value)); break; case PROP_STREAM_TYPE: gst_app_src_set_stream_type (appsrc, g_value_get_enum (value)); break; case PROP_MAX_BYTES: gst_app_src_set_max_bytes (appsrc, g_value_get_uint64 (value)); break; case PROP_FORMAT: priv->format = g_value_get_enum (value); break; case PROP_BLOCK: priv->block = g_value_get_boolean (value); break; case PROP_IS_LIVE: gst_base_src_set_live (GST_BASE_SRC (appsrc), g_value_get_boolean (value)); break; case PROP_MIN_LATENCY: gst_app_src_set_latencies (appsrc, TRUE, g_value_get_int64 (value), FALSE, -1); break; case PROP_MAX_LATENCY: gst_app_src_set_latencies (appsrc, FALSE, -1, TRUE, g_value_get_int64 (value)); break; case PROP_EMIT_SIGNALS: gst_app_src_set_emit_signals (appsrc, g_value_get_boolean (value)); break; case PROP_MIN_PERCENT: priv->min_percent = g_value_get_uint (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
static gboolean gst_app_src_stop (GstBaseSrc * bsrc) { GstAppSrc *appsrc = GST_APP_SRC_CAST (bsrc); GstAppSrcPrivate *priv = appsrc->priv; g_mutex_lock (priv->mutex); GST_DEBUG_OBJECT (appsrc, "stopping"); priv->is_eos = FALSE; priv->flushing = TRUE; priv->started = FALSE; gst_app_src_flush_queued (appsrc); g_mutex_unlock (priv->mutex); return TRUE; }
static gboolean gst_app_src_is_seekable (GstBaseSrc * src) { GstAppSrc *appsrc = GST_APP_SRC_CAST (src); GstAppSrcPrivate *priv = appsrc->priv; gboolean res = FALSE; switch (priv->stream_type) { case GST_APP_STREAM_TYPE_STREAM: break; case GST_APP_STREAM_TYPE_SEEKABLE: case GST_APP_STREAM_TYPE_RANDOM_ACCESS: res = TRUE; break; } return res; }
static gboolean gst_app_src_start (GstBaseSrc * bsrc) { GstAppSrc *appsrc = GST_APP_SRC_CAST (bsrc); GstAppSrcPrivate *priv = appsrc->priv; g_mutex_lock (priv->mutex); GST_DEBUG_OBJECT (appsrc, "starting"); priv->started = TRUE; /* set the offset to -1 so that we always do a first seek. This is only used * in random-access mode. */ priv->offset = -1; priv->flushing = FALSE; g_mutex_unlock (priv->mutex); gst_base_src_set_format (bsrc, priv->format); return TRUE; }
/* will be called in push mode */ static gboolean gst_app_src_do_seek (GstBaseSrc * src, GstSegment * segment) { GstAppSrc *appsrc = GST_APP_SRC_CAST (src); GstAppSrcPrivate *priv = appsrc->priv; gint64 desired_position; gboolean res = FALSE; desired_position = segment->position; GST_DEBUG_OBJECT (appsrc, "seeking to %" G_GINT64_FORMAT ", format %s", desired_position, gst_format_get_name (segment->format)); /* no need to try to seek in streaming mode */ if (priv->stream_type == GST_APP_STREAM_TYPE_STREAM) return TRUE; if (priv->callbacks.seek_data) res = priv->callbacks.seek_data (appsrc, desired_position, priv->user_data); else { gboolean emit; g_mutex_lock (&priv->mutex); emit = priv->emit_signals; g_mutex_unlock (&priv->mutex); if (emit) g_signal_emit (appsrc, gst_app_src_signals[SIGNAL_SEEK_DATA], 0, desired_position, &res); } if (res) { GST_DEBUG_OBJECT (appsrc, "flushing queue"); gst_app_src_flush_queued (appsrc); priv->is_eos = FALSE; } else { GST_WARNING_OBJECT (appsrc, "seek failed"); } return res; }
static gboolean gst_app_src_do_negotiate (GstBaseSrc * basesrc) { GstAppSrc *appsrc = GST_APP_SRC_CAST (basesrc); GstAppSrcPrivate *priv = appsrc->priv; gboolean result; GstCaps *caps; GST_OBJECT_LOCK (basesrc); caps = priv->caps ? gst_caps_ref (priv->caps) : NULL; GST_OBJECT_UNLOCK (basesrc); if (caps) { result = gst_base_src_set_caps (basesrc, caps); gst_caps_unref (caps); } else { result = GST_BASE_SRC_CLASS (parent_class)->negotiate (basesrc); } return result; }
/* Decode */ static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block ) { block_t *p_block; picture_t *p_pic = NULL; decoder_sys_t *p_sys = p_dec->p_sys; GstMessage *p_msg; GstBuffer *p_buf; if( !pp_block ) return NULL; p_block = *pp_block; if( !p_block ) goto check_messages; if( unlikely( p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY | BLOCK_FLAG_CORRUPTED ) ) ) { if( p_block->i_flags & BLOCK_FLAG_DISCONTINUITY ) Flush( p_dec ); if( p_block->i_flags & BLOCK_FLAG_CORRUPTED ) { block_Release( p_block ); goto done; } } if( likely( p_block->i_buffer ) ) { p_buf = gst_buffer_new_wrapped_full( GST_MEMORY_FLAG_READONLY, p_block->p_start, p_block->i_size, p_block->p_buffer - p_block->p_start, p_block->i_buffer, p_block, ( GDestroyNotify )block_Release ); if( unlikely( p_buf == NULL ) ) { msg_Err( p_dec, "failed to create input gstbuffer" ); p_dec->b_error = true; block_Release( p_block ); goto done; } if( p_block->i_dts > VLC_TS_INVALID ) GST_BUFFER_DTS( p_buf ) = gst_util_uint64_scale( p_block->i_dts, GST_SECOND, GST_MSECOND ); if( p_block->i_pts <= VLC_TS_INVALID ) GST_BUFFER_PTS( p_buf ) = GST_BUFFER_DTS( p_buf ); else GST_BUFFER_PTS( p_buf ) = gst_util_uint64_scale( p_block->i_pts, GST_SECOND, GST_MSECOND ); if( p_block->i_length > VLC_TS_INVALID ) GST_BUFFER_DURATION( p_buf ) = gst_util_uint64_scale( p_block->i_length, GST_SECOND, GST_MSECOND ); if( p_dec->fmt_in.video.i_frame_rate && p_dec->fmt_in.video.i_frame_rate_base ) GST_BUFFER_DURATION( p_buf ) = gst_util_uint64_scale( GST_SECOND, p_dec->fmt_in.video.i_frame_rate_base, p_dec->fmt_in.video.i_frame_rate ); /* Give the input buffer to GStreamer Bin. * * libvlc libvlc * \ (i/p) (o/p) ^ * \ / * ___v____GSTREAMER BIN_____/____ * | | * | appsrc-->decode-->vlcsink | * |_______________________________| * * * * * * * * * * * * * * * * * * * * * */ if( unlikely( gst_app_src_push_buffer( GST_APP_SRC_CAST( p_sys->p_decode_src ), p_buf ) != GST_FLOW_OK ) ) { /* block will be released internally, * when gst_buffer_unref() is called */ p_dec->b_error = true; msg_Err( p_dec, "failed to push buffer" ); goto done; } } else block_Release( p_block ); check_messages: /* Poll for any messages, errors */ p_msg = gst_bus_pop_filtered( p_sys->p_bus, GST_MESSAGE_ASYNC_DONE | GST_MESSAGE_ERROR | GST_MESSAGE_EOS | GST_MESSAGE_WARNING | GST_MESSAGE_INFO ); if( p_msg ) { switch( GST_MESSAGE_TYPE( p_msg ) ){ case GST_MESSAGE_EOS: /* for debugging purpose */ msg_Warn( p_dec, "got unexpected eos" ); break; /* First buffer received */ case GST_MESSAGE_ASYNC_DONE: /* for debugging purpose */ p_sys->b_prerolled = true; msg_Dbg( p_dec, "Pipeline is prerolled" ); break; default: p_dec->b_error = default_msg_handler( p_dec, p_msg ); if( p_dec->b_error ) { gst_message_unref( p_msg ); goto done; } break; } gst_message_unref( p_msg ); } /* Look for any output buffers in the queue */ if( gst_atomic_queue_peek( p_sys->p_que ) ) { GstBuffer *p_buf = GST_BUFFER_CAST( gst_atomic_queue_pop( p_sys->p_que )); GstMemory *p_mem; if(( p_mem = gst_buffer_peek_memory( p_buf, 0 )) && GST_IS_VLC_PICTURE_PLANE_ALLOCATOR( p_mem->allocator )) { p_pic = picture_Hold(( (GstVlcPicturePlane*) p_mem )->p_pic ); } else { GstVideoFrame frame; /* Get a new picture */ p_pic = decoder_NewPicture( p_dec ); if( !p_pic ) goto done; if( unlikely( !gst_video_frame_map( &frame, &p_sys->vinfo, p_buf, GST_MAP_READ ) ) ) { msg_Err( p_dec, "failed to map gst video frame" ); gst_buffer_unref( p_buf ); p_dec->b_error = true; goto done; } gst_CopyPicture( p_pic, &frame ); gst_video_frame_unmap( &frame ); } if( likely( GST_BUFFER_PTS_IS_VALID( p_buf ) ) ) p_pic->date = gst_util_uint64_scale( GST_BUFFER_PTS( p_buf ), GST_MSECOND, GST_SECOND ); else msg_Warn( p_dec, "Gst Buffer has no timestamp" ); gst_buffer_unref( p_buf ); } done: *pp_block = NULL; return p_pic; }
/* Close the decoder instance */ static void CloseDecoder( vlc_object_t *p_this ) { decoder_t *p_dec = ( decoder_t* )p_this; decoder_sys_t *p_sys = p_dec->p_sys; gboolean b_running = p_sys->b_running; if( b_running ) { GstMessage *p_msg; GstFlowReturn i_ret; p_sys->b_running = false; /* Send EOS to the pipeline */ i_ret = gst_app_src_end_of_stream( GST_APP_SRC_CAST( p_sys->p_decode_src )); msg_Dbg( p_dec, "app src eos: %s", gst_flow_get_name( i_ret ) ); /* and catch it on the bus with a timeout */ p_msg = gst_bus_timed_pop_filtered( p_sys->p_bus, 2000000000ULL, GST_MESSAGE_EOS | GST_MESSAGE_ERROR ); if( p_msg ) { switch( GST_MESSAGE_TYPE( p_msg ) ){ case GST_MESSAGE_EOS: msg_Dbg( p_dec, "got eos" ); break; default: p_dec->b_error = default_msg_handler( p_dec, p_msg ); if( p_dec->b_error ) msg_Err( p_dec, "pipeline may not close gracefully" ); break; } gst_message_unref( p_msg ); } else msg_Warn( p_dec, "no message, pipeline may not close gracefully" ); } /* Remove any left-over buffers from the queue */ if( p_sys->p_que ) { GstBuffer *p_buf; while( ( p_buf = gst_atomic_queue_pop( p_sys->p_que ) ) ) gst_buffer_unref( p_buf ); gst_atomic_queue_unref( p_sys->p_que ); } if( b_running && gst_element_set_state( p_sys->p_decoder, GST_STATE_NULL ) != GST_STATE_CHANGE_SUCCESS ) msg_Err( p_dec, "failed to change the state to NULL," \ "pipeline may not close gracefully" ); if( p_sys->p_allocator ) gst_object_unref( p_sys->p_allocator ); if( p_sys->p_bus ) gst_object_unref( p_sys->p_bus ); if( p_sys->p_decode_src ) gst_object_unref( p_sys->p_decode_src ); if( p_sys->p_decode_in ) gst_object_unref( p_sys->p_decode_in ); if( p_sys->p_decode_out ) gst_object_unref( p_sys->p_decode_out ); if( p_sys->p_decoder ) gst_object_unref( p_sys->p_decoder ); free( p_sys ); }
static GstFlowReturn gst_app_src_create (GstBaseSrc * bsrc, guint64 offset, guint size, GstBuffer ** buf) { GstAppSrc *appsrc = GST_APP_SRC_CAST (bsrc); GstAppSrcPrivate *priv = appsrc->priv; GstFlowReturn ret; GST_OBJECT_LOCK (appsrc); if (G_UNLIKELY (priv->size != bsrc->segment.duration && bsrc->segment.format == GST_FORMAT_BYTES)) { GST_DEBUG_OBJECT (appsrc, "Size changed from %" G_GINT64_FORMAT " to %" G_GINT64_FORMAT, bsrc->segment.duration, priv->size); bsrc->segment.duration = priv->size; GST_OBJECT_UNLOCK (appsrc); gst_element_post_message (GST_ELEMENT (appsrc), gst_message_new_duration_changed (GST_OBJECT (appsrc))); } else { GST_OBJECT_UNLOCK (appsrc); } g_mutex_lock (&priv->mutex); /* check flushing first */ if (G_UNLIKELY (priv->flushing)) goto flushing; if (priv->stream_type == GST_APP_STREAM_TYPE_RANDOM_ACCESS) { /* if we are dealing with a random-access stream, issue a seek if the offset * changed. */ if (G_UNLIKELY (priv->offset != offset)) { gboolean res; /* do the seek */ res = gst_app_src_emit_seek (appsrc, offset); if (G_UNLIKELY (!res)) /* failing to seek is fatal */ goto seek_error; priv->offset = offset; priv->is_eos = FALSE; } } while (TRUE) { /* return data as long as we have some */ if (!g_queue_is_empty (priv->queue)) { guint buf_size; if (priv->new_caps) { gst_app_src_do_negotiate (bsrc); priv->new_caps = FALSE; } *buf = g_queue_pop_head (priv->queue); buf_size = gst_buffer_get_size (*buf); GST_DEBUG_OBJECT (appsrc, "we have buffer %p of size %u", *buf, buf_size); priv->queued_bytes -= buf_size; /* only update the offset when in random_access mode */ if (priv->stream_type == GST_APP_STREAM_TYPE_RANDOM_ACCESS) priv->offset += buf_size; /* signal that we removed an item */ g_cond_broadcast (&priv->cond); /* see if we go lower than the empty-percent */ if (priv->min_percent && priv->max_bytes) { if (priv->queued_bytes * 100 / priv->max_bytes <= priv->min_percent) /* ignore flushing state, we got a buffer and we will return it now. * Errors will be handled in the next round */ gst_app_src_emit_need_data (appsrc, size); } ret = GST_FLOW_OK; break; } else { gst_app_src_emit_need_data (appsrc, size); /* we can be flushing now because we released the lock above */ if (G_UNLIKELY (priv->flushing)) goto flushing; /* if we have a buffer now, continue the loop and try to return it. In * random-access mode (where a buffer is normally pushed in the above * signal) we can still be empty because the pushed buffer got flushed or * when the application pushes the requested buffer later, we support both * possibilities. */ if (!g_queue_is_empty (priv->queue)) continue; /* no buffer yet, maybe we are EOS, if not, block for more data. */ } /* check EOS */ if (G_UNLIKELY (priv->is_eos)) goto eos; /* nothing to return, wait a while for new data or flushing. */ g_cond_wait (&priv->cond, &priv->mutex); } g_mutex_unlock (&priv->mutex); return ret; /* ERRORS */ flushing: { GST_DEBUG_OBJECT (appsrc, "we are flushing"); g_mutex_unlock (&priv->mutex); return GST_FLOW_FLUSHING; } eos: { GST_DEBUG_OBJECT (appsrc, "we are EOS"); g_mutex_unlock (&priv->mutex); return GST_FLOW_EOS; } seek_error: { g_mutex_unlock (&priv->mutex); GST_ELEMENT_ERROR (appsrc, RESOURCE, READ, ("failed to seek"), GST_ERROR_SYSTEM); return GST_FLOW_ERROR; } }
bool nvxio::GStreamerVideoRenderImpl::InitializeGStreamerPipeline() { std::ostringstream stream; pipeline = GST_PIPELINE(gst_pipeline_new(NULL)); if (pipeline == NULL) { NVXIO_PRINT("Cannot create Gstreamer pipeline"); return false; } bus = gst_pipeline_get_bus(GST_PIPELINE (pipeline)); // create appsrc GstElement * appsrcelem = gst_element_factory_make("appsrc", NULL); if (appsrcelem == NULL) { NVXIO_PRINT("Cannot create appsrc"); FinalizeGStreamerPipeline(); return false; } g_object_set(G_OBJECT(appsrcelem), "is-live", 0, NULL); g_object_set(G_OBJECT(appsrcelem), "num-buffers", -1, NULL); g_object_set(G_OBJECT(appsrcelem), "emit-signals", 0, NULL); g_object_set(G_OBJECT(appsrcelem), "block", 1, NULL); g_object_set(G_OBJECT(appsrcelem), "size", static_cast<guint64>(wndHeight_ * wndWidth_ * 4), NULL); g_object_set(G_OBJECT(appsrcelem), "format", GST_FORMAT_TIME, NULL); g_object_set(G_OBJECT(appsrcelem), "stream-type", GST_APP_STREAM_TYPE_STREAM, NULL); appsrc = GST_APP_SRC_CAST(appsrcelem); #if GST_VERSION_MAJOR == 0 GstCaps * caps = gst_caps_new_simple("video/x-raw-rgb", "bpp", G_TYPE_INT, 32, "endianness", G_TYPE_INT, 4321, "red_mask", G_TYPE_INT, -16777216, "green_mask", G_TYPE_INT, 16711680, "blue_mask", G_TYPE_INT, 65280, "alpha_mask", G_TYPE_INT, 255, "width", G_TYPE_INT, wndWidth_, "height", G_TYPE_INT, wndHeight_, "framerate", GST_TYPE_FRACTION, GSTREAMER_DEFAULT_FPS, 1, NULL); if (caps == NULL) { NVXIO_PRINT("Failed to create caps"); FinalizeGStreamerPipeline(); return false; } #else // support 4 channel 8 bit data stream << "video/x-raw" << ", width=" << wndWidth_ << ", height=" << wndHeight_ << ", format=(string){RGBA}" << ", framerate=" << GSTREAMER_DEFAULT_FPS << "/1;"; GstCaps * caps = gst_caps_from_string(stream.str().c_str()); if (caps == NULL) { NVXIO_PRINT("Failed to create caps"); FinalizeGStreamerPipeline(); return false; } caps = gst_caps_fixate(caps); #endif gst_app_src_set_caps(appsrc, caps); gst_caps_unref(caps); gst_bin_add(GST_BIN(pipeline), appsrcelem); // create color convert element GstElement * color = gst_element_factory_make(COLOR_ELEM, NULL); if (color == NULL) { NVXIO_PRINT("Cannot create " COLOR_ELEM " element"); FinalizeGStreamerPipeline(); return false; } gst_bin_add(GST_BIN(pipeline), color); // create videoflip element GstElement * videoflip = gst_element_factory_make("videoflip", NULL); if (videoflip == NULL) { NVXIO_PRINT("Cannot create videoflip element"); FinalizeGStreamerPipeline(); return false; } g_object_set(G_OBJECT(videoflip), "method", 5, NULL); gst_bin_add(GST_BIN(pipeline), videoflip); // create encodelem element GstElement * encodelem = gst_element_factory_make(ENCODE_ELEM, NULL); if (encodelem == NULL) { NVXIO_PRINT("Cannot create " ENCODE_ELEM " element"); FinalizeGStreamerPipeline(); return false; } gst_bin_add(GST_BIN(pipeline), encodelem); // create avimux element GstElement * avimux = gst_element_factory_make("avimux", NULL); if (avimux == NULL) { NVXIO_PRINT("Cannot create avimux element"); FinalizeGStreamerPipeline(); return false; } gst_bin_add(GST_BIN(pipeline), avimux); // create filesink element GstElement * filesink = gst_element_factory_make("filesink", NULL); if (filesink == NULL) { NVXIO_PRINT("Cannot create filesink element"); FinalizeGStreamerPipeline(); return false; } g_object_set(G_OBJECT(filesink), "location", windowTitle_.c_str(), NULL); g_object_set(G_OBJECT(filesink), "append", 0, NULL); gst_bin_add(GST_BIN(pipeline), filesink); // link elements if (!gst_element_link_many(appsrcelem, color, videoflip, encodelem, avimux, filesink, NULL)) { NVXIO_PRINT("GStreamer: cannot link appsrc -> " COLOR_ELEM " -> videoflip -> " ENCODE_ELEM " -> avimux -> filesink"); FinalizeGStreamerPipeline(); return false; } // Force pipeline to play video as fast as possible, ignoring system clock gst_pipeline_use_clock(pipeline, NULL); num_frames = 0; GstStateChangeReturn status = gst_element_set_state(GST_ELEMENT(pipeline), GST_STATE_PLAYING); if (status == GST_STATE_CHANGE_FAILURE) { NVXIO_PRINT("GStreamer: unable to start playback"); FinalizeGStreamerPipeline(); return false; } return true; }