static void gst_vlc_video_sink_set_property( GObject *p_object, guint i_prop_id, const GValue *p_value, GParamSpec *p_pspec ) { GstVlcVideoSink *p_vsink = GST_VLC_VIDEO_SINK( p_object ); switch( i_prop_id ) { case PROP_ALLOCATOR: { GstAllocator *p_allocator = (GstAllocator*) g_value_get_pointer( p_value ); if( GST_IS_VLC_PICTURE_PLANE_ALLOCATOR( p_allocator )) { if( p_vsink->p_allocator ) gst_object_unref( p_vsink->p_allocator ); p_vsink->p_allocator = gst_object_ref( p_allocator ); } else msg_Warn( p_vsink->p_dec, "Invalid Allocator set"); } break; case PROP_ID: { p_vsink->p_dec = (decoder_t*) g_value_get_pointer( p_value ); } break; default: break; } }
static gboolean gst_vlc_video_sink_setcaps( GstBaseSink *p_basesink, GstCaps *p_caps ) { GstVlcVideoSink *p_vsink = GST_VLC_VIDEO_SINK( p_basesink ); GstVideoInfo info; gboolean b_ret = FALSE; //FIXME caps_signal #if 0 GValue ret = { 0 }; GValue args[2] = { {0}, {0} }; #endif if( !gst_video_info_from_caps( &info, p_caps )) return FALSE; p_vsink->vinfo = info; //FIXME caps_signal #if 0 g_value_init( &args[0], GST_TYPE_ELEMENT ); g_value_set_object( &args[0], p_vsink ); g_value_init( &args[1], GST_TYPE_CAPS ); g_value_set_boxed( &args[1], p_caps ); g_signal_emitv( args, gst_vlc_video_sink_signals[ SIGNAL_NEW_CAPS ], 0, &b_ret ); #else b_ret = p_vsink->new_caps( GST_ELEMENT_CAST( p_vsink ), p_caps, (gpointer) p_vsink->p_dec ); #endif return b_ret; }
static void gst_vlc_video_sink_finalize( GObject *p_obj ) { GstVlcVideoSink *p_vsink = GST_VLC_VIDEO_SINK( p_obj ); if( p_vsink->p_allocator ) gst_object_unref( p_vsink->p_allocator ); G_OBJECT_CLASS( parent_class)->finalize( p_obj ); }
static gboolean gst_vlc_video_sink_propose_allocation( GstBaseSink* p_bsink, GstQuery* p_query ) { GstVlcVideoSink *p_vsink = GST_VLC_VIDEO_SINK( p_bsink ); GstCaps *p_caps; gboolean b_need_pool; GstBufferPool* p_pool = NULL; gsize i_size; gst_query_parse_allocation (p_query, &p_caps, &b_need_pool); if( p_caps == NULL ) goto no_caps; if( b_need_pool ) { GstVideoInfo info; if( !gst_video_info_from_caps( &info, p_caps )) goto invalid_caps; p_pool = (GstBufferPool*) gst_vlc_video_sink_create_pool( p_vsink, p_caps, info.size, 2 ); if( p_pool == NULL ) goto no_pool; i_size = GST_VIDEO_INFO_SIZE( &GST_VLC_VIDEO_POOL_CAST( p_pool )->info); } if( p_pool ) { /* we need at least 2 buffer because we hold on to the last one */ gst_query_add_allocation_pool( p_query, p_pool, i_size, 2, 0); gst_object_unref (p_pool); } /* we support various metadata */ gst_query_add_allocation_meta( p_query, GST_VIDEO_META_API_TYPE, NULL ); return TRUE; /* ERRORS */ no_pool: { msg_Err( p_vsink->p_dec, "failed to create the pool" ); return FALSE; } no_caps: { msg_Err( p_vsink->p_dec, "no caps in allocation query" ); return FALSE; } invalid_caps: { msg_Err( p_vsink->p_dec, "invalid caps in allocation query" ); return FALSE; } }
static void gst_vlc_video_sink_get_property( GObject *p_object, guint i_prop_id, GValue *p_value, GParamSpec *p_pspec ) { GstVlcVideoSink *p_vsink = GST_VLC_VIDEO_SINK( p_object ); switch( i_prop_id ) { case PROP_ALLOCATOR: g_value_set_pointer( p_value, p_vsink->p_allocator ); break; default: break; } }
/***************************************************************************** * OpenDecoder: probe the decoder and return score *****************************************************************************/ static int OpenDecoder( vlc_object_t *p_this ) { decoder_t *p_dec = ( decoder_t* )p_this; decoder_sys_t *p_sys; GstStateChangeReturn i_ret; gboolean b_ret; sink_src_caps_t caps = { NULL, NULL }; GstStructure *p_str; GstAppSrcCallbacks cb; int i_rval = VLC_SUCCESS; GList *p_list; bool dbin; #define VLC_GST_CHECK( r, v, s, t ) \ { if( r == v ){ msg_Err( p_dec, s ); i_rval = t; goto fail; } } if( !vlc_gst_init( )) { msg_Err( p_dec, "failed to register vlcvideosink" ); return VLC_EGENERIC; } p_str = vlc_to_gst_fmt( &p_dec->fmt_in ); if( !p_str ) return VLC_EGENERIC; /* Allocate the memory needed to store the decoder's structure */ p_sys = p_dec->p_sys = calloc( 1, sizeof( *p_sys ) ); if( p_sys == NULL ) { gst_structure_free( p_str ); return VLC_ENOMEM; } dbin = var_CreateGetBool( p_dec, "use-decodebin" ); msg_Dbg( p_dec, "Using decodebin? %s", dbin ? "yes ":"no" ); caps.p_sinkcaps = gst_caps_new_empty( ); gst_caps_append_structure( caps.p_sinkcaps, p_str ); /* Currently supports only system memory raw output format */ caps.p_srccaps = gst_caps_new_empty_simple( "video/x-raw" ); /* Get the list of all the available gstreamer decoders */ p_list = gst_element_factory_list_get_elements( GST_ELEMENT_FACTORY_TYPE_DECODER, GST_RANK_MARGINAL ); VLC_GST_CHECK( p_list, NULL, "no decoder list found", VLC_ENOMOD ); if( !dbin ) { GList *p_l; /* Sort them as per ranks */ p_list = g_list_sort( p_list, gst_plugin_feature_rank_compare_func ); VLC_GST_CHECK( p_list, NULL, "failed to sort decoders list", VLC_ENOMOD ); p_l = g_list_find_custom( p_list, &caps, find_decoder_func ); VLC_GST_CHECK( p_l, NULL, "no suitable decoder found", VLC_ENOMOD ); /* create the decoder with highest rank */ p_sys->p_decode_in = gst_element_factory_create( ( GstElementFactory* )p_l->data, NULL ); VLC_GST_CHECK( p_sys->p_decode_in, NULL, "failed to create decoder", VLC_ENOMOD ); } else { GList *p_l; /* Just check if any suitable decoder exists, rest will be * handled by decodebin */ p_l = g_list_find_custom( p_list, &caps, find_decoder_func ); VLC_GST_CHECK( p_l, NULL, "no suitable decoder found", VLC_ENOMOD ); } gst_plugin_feature_list_free( p_list ); p_list = NULL; gst_caps_unref( caps.p_srccaps ); caps.p_srccaps = NULL; p_sys->b_prerolled = false; p_sys->b_running = false; /* Queue: GStreamer thread will dump buffers into this queue, * DecodeBlock() will pop out the buffers from the queue */ p_sys->p_que = gst_atomic_queue_new( 0 ); VLC_GST_CHECK( p_sys->p_que, NULL, "failed to create queue", VLC_ENOMEM ); p_sys->p_decode_src = gst_element_factory_make( "appsrc", NULL ); VLC_GST_CHECK( p_sys->p_decode_src, NULL, "appsrc not found", VLC_ENOMOD ); g_object_set( G_OBJECT( p_sys->p_decode_src ), "caps", caps.p_sinkcaps, "emit-signals", TRUE, "format", GST_FORMAT_BYTES, "stream-type", GST_APP_STREAM_TYPE_SEEKABLE, /* Making DecodeBlock() to block on appsrc with max queue size of 1 byte. * This will make the push_buffer() tightly coupled with the buffer * flow from appsrc -> decoder. push_buffer() will only return when * the same buffer it just fed to appsrc has also been fed to the * decoder element as well */ "block", TRUE, "max-bytes", ( guint64 )1, NULL ); gst_caps_unref( caps.p_sinkcaps ); caps.p_sinkcaps = NULL; cb.enough_data = NULL; cb.need_data = NULL; cb.seek_data = seek_data_cb; gst_app_src_set_callbacks( GST_APP_SRC( p_sys->p_decode_src ), &cb, p_dec, NULL ); if( dbin ) { p_sys->p_decode_in = gst_element_factory_make( "decodebin", NULL ); VLC_GST_CHECK( p_sys->p_decode_in, NULL, "decodebin not found", VLC_ENOMOD ); //g_object_set( G_OBJECT( p_sys->p_decode_in ), //"max-size-buffers", 2, NULL ); //g_signal_connect( G_OBJECT( p_sys->p_decode_in ), "no-more-pads", //G_CALLBACK( no_more_pads_cb ), p_dec ); g_signal_connect( G_OBJECT( p_sys->p_decode_in ), "pad-added", G_CALLBACK( pad_added_cb ), p_dec ); } /* videosink: will emit signal for every available buffer */ p_sys->p_decode_out = gst_element_factory_make( "vlcvideosink", NULL ); VLC_GST_CHECK( p_sys->p_decode_out, NULL, "vlcvideosink not found", VLC_ENOMOD ); p_sys->p_allocator = gst_vlc_picture_plane_allocator_new( (gpointer) p_dec ); g_object_set( G_OBJECT( p_sys->p_decode_out ), "sync", FALSE, "allocator", p_sys->p_allocator, "id", (gpointer) p_dec, NULL ); g_signal_connect( G_OBJECT( p_sys->p_decode_out ), "new-buffer", G_CALLBACK( frame_handoff_cb ), p_dec ); //FIXME: caps_signal #if 0 g_signal_connect( G_OBJECT( p_sys->p_decode_out ), "new-caps", G_CALLBACK( caps_handoff_cb ), p_dec ); #else GST_VLC_VIDEO_SINK( p_sys->p_decode_out )->new_caps = caps_handoff_cb; #endif p_sys->p_decoder = GST_ELEMENT( gst_bin_new( "decoder" ) ); VLC_GST_CHECK( p_sys->p_decoder, NULL, "bin not found", VLC_ENOMOD ); p_sys->p_bus = gst_bus_new( ); VLC_GST_CHECK( p_sys->p_bus, NULL, "failed to create bus", VLC_ENOMOD ); gst_element_set_bus( p_sys->p_decoder, p_sys->p_bus ); gst_bin_add_many( GST_BIN( p_sys->p_decoder ), p_sys->p_decode_src, p_sys->p_decode_in, p_sys->p_decode_out, NULL ); gst_object_ref( p_sys->p_decode_src ); gst_object_ref( p_sys->p_decode_in ); gst_object_ref( p_sys->p_decode_out ); b_ret = gst_element_link( p_sys->p_decode_src, p_sys->p_decode_in ); VLC_GST_CHECK( b_ret, FALSE, "failed to link src <-> in", VLC_EGENERIC ); if( !dbin ) { b_ret = gst_element_link( p_sys->p_decode_in, p_sys->p_decode_out ); VLC_GST_CHECK( b_ret, FALSE, "failed to link in <-> out", VLC_EGENERIC ); } p_dec->fmt_out.i_cat = p_dec->fmt_in.i_cat; /* set the pipeline to playing */ i_ret = gst_element_set_state( p_sys->p_decoder, GST_STATE_PLAYING ); VLC_GST_CHECK( i_ret, GST_STATE_CHANGE_FAILURE, "set state failure", VLC_EGENERIC ); p_sys->b_running = true; /* Set callbacks */ p_dec->pf_decode_video = DecodeBlock; p_dec->pf_flush = Flush; return VLC_SUCCESS; fail: if( caps.p_sinkcaps ) gst_caps_unref( caps.p_sinkcaps ); if( caps.p_srccaps ) gst_caps_unref( caps.p_srccaps ); if( p_list ) gst_plugin_feature_list_free( p_list ); CloseDecoder( ( vlc_object_t* )p_dec ); return i_rval; }