static GstElement * gst_auto_video_sink_find_best (GstAutoVideoSink * sink) { GList *list, *item; GstElement *choice = NULL; GstMessage *message = NULL; GSList *errors = NULL; GstBus *bus = gst_bus_new (); GstPad *el_pad = NULL; GstCaps *el_caps = NULL; gboolean no_match = TRUE; list = gst_registry_feature_filter (gst_registry_get_default (), (GstPluginFeatureFilter) gst_auto_video_sink_factory_filter, FALSE, sink); list = g_list_sort (list, (GCompareFunc) gst_auto_video_sink_compare_ranks); GST_LOG_OBJECT (sink, "Trying to find usable video devices ..."); for (item = list; item != NULL; item = item->next) { GstElementFactory *f = GST_ELEMENT_FACTORY (item->data); GstElement *el; if ((el = gst_auto_video_sink_create_element_with_pretty_name (sink, f))) { GstStateChangeReturn ret; GST_DEBUG_OBJECT (sink, "Testing %s", GST_PLUGIN_FEATURE (f)->name); /* If autovideosink has been provided with filter caps, * accept only sinks that match with the filter caps */ if (sink->filter_caps) { el_pad = gst_element_get_static_pad (GST_ELEMENT (el), "sink"); el_caps = gst_pad_get_caps (el_pad); gst_object_unref (el_pad); GST_DEBUG_OBJECT (sink, "Checking caps: %" GST_PTR_FORMAT " vs. %" GST_PTR_FORMAT, sink->filter_caps, el_caps); no_match = !gst_caps_can_intersect (sink->filter_caps, el_caps); gst_caps_unref (el_caps); if (no_match) { GST_DEBUG_OBJECT (sink, "Incompatible caps"); gst_object_unref (el); continue; } else { GST_DEBUG_OBJECT (sink, "Found compatible caps"); } } gst_element_set_bus (el, bus); ret = gst_element_set_state (el, GST_STATE_READY); if (ret == GST_STATE_CHANGE_SUCCESS) { GST_DEBUG_OBJECT (sink, "This worked!"); choice = el; break; } /* collect all error messages */ while ((message = gst_bus_pop_filtered (bus, GST_MESSAGE_ERROR))) { GST_DEBUG_OBJECT (sink, "error message %" GST_PTR_FORMAT, message); errors = g_slist_append (errors, message); } gst_element_set_state (el, GST_STATE_NULL); gst_object_unref (el); } } GST_DEBUG_OBJECT (sink, "done trying"); if (!choice) { if (errors) { /* FIXME: we forward the first error for now; but later on it might make * sense to actually analyse them */ gst_message_ref (GST_MESSAGE (errors->data)); GST_DEBUG_OBJECT (sink, "reposting message %p", errors->data); gst_element_post_message (GST_ELEMENT (sink), GST_MESSAGE (errors->data)); } else { /* send warning message to application and use a fakesink */ GST_ELEMENT_WARNING (sink, RESOURCE, NOT_FOUND, (NULL), ("Failed to find a usable video sink")); choice = gst_element_factory_make ("fakesink", "fake-video-sink"); if (g_object_class_find_property (G_OBJECT_GET_CLASS (choice), "sync")) g_object_set (choice, "sync", TRUE, NULL); gst_element_set_state (choice, GST_STATE_READY); } } gst_object_unref (bus); gst_plugin_feature_list_free (list); g_slist_foreach (errors, (GFunc) gst_mini_object_unref, NULL); g_slist_free (errors); return choice; }
static void helper (gboolean flush) { GstElement *filter; GstBus *bus; GstPad *mysrcpad; GstPad *mysinkpad; /* init */ filter = gst_check_setup_element ("omx_dummy"); mysrcpad = gst_check_setup_src_pad (filter, &srctemplate, NULL); mysinkpad = gst_check_setup_sink_pad (filter, &sinktemplate, NULL); gst_pad_set_active (mysrcpad, TRUE); gst_pad_set_active (mysinkpad, TRUE); /* need to know when we are eos */ gst_pad_set_event_function (mysinkpad, test_sink_event); /* and notify the test run */ eos_mutex = g_mutex_new (); eos_cond = g_cond_new (); eos_arrived = FALSE; g_object_set (G_OBJECT (filter), "library-name", "libomxil-foo.so", NULL); /* start */ fail_unless_equals_int (gst_element_set_state (filter, GST_STATE_PLAYING), GST_STATE_CHANGE_SUCCESS); bus = gst_bus_new (); gst_element_set_bus (filter, bus); /* send buffers in order*/ { guint i; for (i = 0; i < BUFFER_COUNT; i++) { GstBuffer *inbuffer; inbuffer = gst_buffer_new_and_alloc (BUFFER_SIZE); GST_BUFFER_DATA(inbuffer)[0] = i; ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK); if (flush && i % FLUSH_AT == 0) { gst_pad_push_event (mysrcpad, gst_event_new_flush_start ()); gst_pad_push_event (mysrcpad, gst_event_new_flush_stop ()); i += FLUSH_AT; } } } { GstMessage *message; fail_if ((message = gst_bus_pop (bus)) != NULL); /* make sure there's no error on the bus */ message = gst_bus_poll (bus, GST_MESSAGE_ERROR, 0); fail_if (message); } gst_pad_push_event (mysrcpad, gst_event_new_eos ()); /* need to wait a bit to make sure src pad task digested all and sent eos */ g_mutex_lock (eos_mutex); while (!eos_arrived) g_cond_wait (eos_cond, eos_mutex); g_mutex_unlock (eos_mutex); /* check the order of the buffers*/ if (!flush) { GList *cur; guint i; for (cur = buffers, i = 0; cur; cur = g_list_next (cur), i++) { GstBuffer *buffer; buffer = cur->data; fail_unless (GST_BUFFER_DATA(buffer)[0] == i); } fail_unless (i == BUFFER_COUNT); } /* cleanup */ gst_bus_set_flushing (bus, TRUE); gst_element_set_bus (filter, NULL); gst_object_unref (GST_OBJECT (bus)); gst_check_drop_buffers (); /* deinit */ gst_element_set_state (filter, GST_STATE_NULL); gst_pad_set_active (mysrcpad, FALSE); gst_pad_set_active (mysinkpad, FALSE); gst_check_teardown_src_pad (filter); gst_check_teardown_sink_pad (filter); gst_check_teardown_element (filter); g_mutex_free (eos_mutex); g_cond_free (eos_cond); }
/** * gst_uri_downloader_fetch_uri_with_range: * @downloader: the #GstUriDownloader * @uri: the uri * @range_start: the starting byte index * @range_end: the final byte index, use -1 for unspecified * * Returns the downloaded #GstFragment */ GstFragment * gst_uri_downloader_fetch_uri_with_range (GstUriDownloader * downloader, const gchar * uri, gint64 range_start, gint64 range_end) { GstStateChangeReturn ret; GstFragment *download = NULL; GST_DEBUG_OBJECT (downloader, "Fetching URI %s", uri); g_mutex_lock (&downloader->priv->download_lock); GST_OBJECT_LOCK (downloader); if (downloader->priv->cancelled) { GST_DEBUG_OBJECT (downloader, "Cancelled, aborting fetch"); goto quit; } if (!gst_uri_downloader_set_uri (downloader, uri)) { GST_WARNING_OBJECT (downloader, "Failed to set URI"); goto quit; } gst_bus_set_flushing (downloader->priv->bus, FALSE); downloader->priv->download = gst_fragment_new (); GST_OBJECT_UNLOCK (downloader); ret = gst_element_set_state (downloader->priv->urisrc, GST_STATE_READY); GST_OBJECT_LOCK (downloader); if (ret == GST_STATE_CHANGE_FAILURE || downloader->priv->download == NULL) { GST_WARNING_OBJECT (downloader, "Failed to set src to READY"); goto quit; } /* might have been cancelled because of failures in state change */ if (downloader->priv->cancelled) { goto quit; } if (!gst_uri_downloader_set_range (downloader, range_start, range_end)) { GST_WARNING_OBJECT (downloader, "Failed to set range"); goto quit; } GST_OBJECT_UNLOCK (downloader); ret = gst_element_set_state (downloader->priv->urisrc, GST_STATE_PLAYING); GST_OBJECT_LOCK (downloader); if (ret == GST_STATE_CHANGE_FAILURE) { if (downloader->priv->download) { g_object_unref (downloader->priv->download); downloader->priv->download = NULL; } goto quit; } /* might have been cancelled because of failures in state change */ if (downloader->priv->cancelled) { goto quit; } /* wait until: * - the download succeed (EOS in the src pad) * - the download failed (Error message on the fetcher bus) * - the download was canceled */ GST_DEBUG_OBJECT (downloader, "Waiting to fetch the URI %s", uri); while (!downloader->priv->cancelled && !downloader->priv->download->completed) g_cond_wait (&downloader->priv->cond, GST_OBJECT_GET_LOCK (downloader)); if (downloader->priv->cancelled) { if (downloader->priv->download) { g_object_unref (downloader->priv->download); downloader->priv->download = NULL; } goto quit; } download = downloader->priv->download; downloader->priv->download = NULL; if (download != NULL) GST_INFO_OBJECT (downloader, "URI fetched successfully"); else GST_INFO_OBJECT (downloader, "Error fetching URI"); quit: { if (downloader->priv->urisrc) { GstPad *pad; GstElement *urisrc; GST_DEBUG_OBJECT (downloader, "Stopping source element %s", GST_ELEMENT_NAME (downloader->priv->urisrc)); /* remove the bus' sync handler */ gst_bus_set_sync_handler (downloader->priv->bus, NULL, NULL, NULL); /* unlink the source element from the internal pad */ pad = gst_pad_get_peer (downloader->priv->pad); if (pad) { gst_pad_unlink (pad, downloader->priv->pad); gst_object_unref (pad); } urisrc = downloader->priv->urisrc; downloader->priv->urisrc = NULL; GST_OBJECT_UNLOCK (downloader); GST_DEBUG_OBJECT (downloader, "Stopping source element %s", GST_ELEMENT_NAME (urisrc)); /* set the element state to NULL */ gst_bus_set_flushing (downloader->priv->bus, TRUE); gst_element_set_state (urisrc, GST_STATE_NULL); gst_element_get_state (urisrc, NULL, NULL, GST_CLOCK_TIME_NONE); gst_element_set_bus (urisrc, NULL); gst_object_unref (urisrc); } else { GST_OBJECT_UNLOCK (downloader); } g_mutex_unlock (&downloader->priv->download_lock); return download; } }
static gboolean setup_recoder_pipeline (GstSmartEncoder * smart_encoder) { GstPad *tmppad; GstCaps *caps; /* Fast path */ if (G_UNLIKELY (smart_encoder->encoder)) return TRUE; GST_DEBUG ("Creating internal decoder and encoder"); /* Create decoder/encoder */ caps = gst_pad_get_current_caps (smart_encoder->sinkpad); smart_encoder->decoder = get_decoder (caps); if (G_UNLIKELY (smart_encoder->decoder == NULL)) goto no_decoder; gst_caps_unref (caps); gst_element_set_bus (smart_encoder->decoder, GST_ELEMENT_BUS (smart_encoder)); caps = gst_pad_get_current_caps (smart_encoder->sinkpad); smart_encoder->encoder = get_encoder (caps); if (G_UNLIKELY (smart_encoder->encoder == NULL)) goto no_encoder; gst_caps_unref (caps); gst_element_set_bus (smart_encoder->encoder, GST_ELEMENT_BUS (smart_encoder)); GST_DEBUG ("Creating internal pads"); /* Create internal pads */ /* Source pad which we'll use to feed data to decoders */ smart_encoder->internal_srcpad = gst_pad_new ("internal_src", GST_PAD_SRC); g_object_set_qdata ((GObject *) smart_encoder->internal_srcpad, INTERNAL_ELEMENT, smart_encoder); gst_pad_set_active (smart_encoder->internal_srcpad, TRUE); /* Sink pad which will get the buffers from the encoder. * Note: We don't need an event function since we'll be discarding all * of them. */ smart_encoder->internal_sinkpad = gst_pad_new ("internal_sink", GST_PAD_SINK); g_object_set_qdata ((GObject *) smart_encoder->internal_sinkpad, INTERNAL_ELEMENT, smart_encoder); gst_pad_set_chain_function (smart_encoder->internal_sinkpad, internal_chain); gst_pad_set_active (smart_encoder->internal_sinkpad, TRUE); GST_DEBUG ("Linking pads to elements"); /* Link everything */ tmppad = gst_element_get_static_pad (smart_encoder->encoder, "src"); if (GST_PAD_LINK_FAILED (gst_pad_link (tmppad, smart_encoder->internal_sinkpad))) goto sinkpad_link_fail; gst_object_unref (tmppad); if (!gst_element_link (smart_encoder->decoder, smart_encoder->encoder)) goto encoder_decoder_link_fail; tmppad = gst_element_get_static_pad (smart_encoder->decoder, "sink"); if (GST_PAD_LINK_FAILED (gst_pad_link (smart_encoder->internal_srcpad, tmppad))) goto srcpad_link_fail; gst_object_unref (tmppad); GST_DEBUG ("Done creating internal elements/pads"); return TRUE; no_decoder: { GST_WARNING ("Couldn't find a decoder for %" GST_PTR_FORMAT, caps); gst_caps_unref (caps); return FALSE; } no_encoder: { GST_WARNING ("Couldn't find an encoder for %" GST_PTR_FORMAT, caps); gst_caps_unref (caps); return FALSE; } srcpad_link_fail: { gst_object_unref (tmppad); GST_WARNING ("Couldn't link internal srcpad to decoder"); return FALSE; } sinkpad_link_fail: { gst_object_unref (tmppad); GST_WARNING ("Couldn't link encoder to internal sinkpad"); return FALSE; } encoder_decoder_link_fail: { GST_WARNING ("Couldn't link decoder to encoder"); return FALSE; } }
static void run_decoding_test (GstElement * mpg123audiodec, gchar const *filename) { GstBus *bus; unsigned int num_input_buffers, num_decoded_buffers; gint expected_size; GstCaps *out_caps, *caps; GstAudioInfo audioinfo; GstElement *input_pipeline, *input_appsink; int i; GstBuffer *outbuffer; /* 440 Hz = frequency of sine wave in audio data * 44100 Hz = sample rate * (44100 / 2) Hz = Nyquist frequency */ static double const expected_frequency_spot = 440.0 / (44100.0 / 2.0); fail_unless (gst_element_set_state (mpg123audiodec, GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, "could not set to playing"); bus = gst_bus_new (); gst_element_set_bus (mpg123audiodec, bus); setup_input_pipeline (filename, &input_pipeline, &input_appsink); num_input_buffers = 0; while (TRUE) { GstSample *sample; GstBuffer *input_buffer; sample = gst_app_sink_pull_sample (GST_APP_SINK (input_appsink)); if (sample == NULL) break; fail_unless (GST_IS_SAMPLE (sample)); input_buffer = gst_sample_get_buffer (sample); fail_if (input_buffer == NULL); /* This is done to be on the safe side - docs say lifetime of the input buffer * depends *solely* on the sample */ input_buffer = gst_buffer_copy (input_buffer); fail_unless_equals_int (gst_pad_push (mysrcpad, input_buffer), GST_FLOW_OK); ++num_input_buffers; gst_sample_unref (sample); } num_decoded_buffers = g_list_length (buffers); /* check number of decoded buffers */ fail_unless_equals_int (num_decoded_buffers, num_input_buffers - 2); caps = gst_pad_get_current_caps (mysinkpad); GST_LOG ("output caps %" GST_PTR_FORMAT, caps); fail_unless (gst_audio_info_from_caps (&audioinfo, caps), "Getting audio info from caps failed"); /* check caps */ out_caps = gst_caps_new_simple ("audio/x-raw", "format", G_TYPE_STRING, "S32LE", "layout", G_TYPE_STRING, "interleaved", "rate", G_TYPE_INT, 44100, "channels", G_TYPE_INT, 1, NULL); fail_unless (gst_caps_is_equal_fixed (caps, out_caps), "Incorrect out caps"); gst_caps_unref (out_caps); gst_caps_unref (caps); /* here, test if decoded data is a sine tone, and if the sine frequency is at the * right spot in the spectrum */ for (i = 0; i < num_decoded_buffers; ++i) { outbuffer = GST_BUFFER (buffers->data); fail_if (outbuffer == NULL, "Invalid buffer retrieved"); /* MPEG 1 layer 2 uses 1152 samples per frame */ expected_size = 1152 * GST_AUDIO_INFO_BPF (&audioinfo); fail_unless_equals_int (gst_buffer_get_size (outbuffer), expected_size); check_main_frequency_spot_S32 (outbuffer, expected_frequency_spot); buffers = g_list_remove (buffers, outbuffer); gst_buffer_unref (outbuffer); outbuffer = NULL; } g_list_free (buffers); buffers = NULL; cleanup_input_pipeline (input_pipeline); gst_bus_set_flushing (bus, TRUE); gst_element_set_bus (mpg123audiodec, NULL); gst_object_unref (GST_OBJECT (bus)); }
static gboolean gst_switch_commit_new_kid (GstSwitchSink * sink) { GstPad *targetpad; GstState kid_state; GstElement *new_kid, *old_kid; gboolean is_fakesink = FALSE; GstBus *bus; /* need locking around member accesses */ GST_OBJECT_LOCK (sink); /* If we're currently changing state, set the child to the next state * we're transitioning too, rather than our current state which is * about to change */ if (GST_STATE_NEXT (sink) != GST_STATE_VOID_PENDING) kid_state = GST_STATE_NEXT (sink); else kid_state = GST_STATE (sink); new_kid = sink->new_kid; sink->new_kid = NULL; GST_OBJECT_UNLOCK (sink); /* Fakesink by default if NULL is passed as the new child */ if (new_kid == NULL) { GST_DEBUG_OBJECT (sink, "Replacing kid with fakesink"); new_kid = gst_element_factory_make ("fakesink", "testsink"); if (new_kid == NULL) { GST_ERROR_OBJECT (sink, "Failed to create fakesink"); return FALSE; } /* Add a reference, as it would if the element came from sink->new_kid */ gst_object_ref (new_kid); g_object_set (new_kid, "sync", TRUE, NULL); is_fakesink = TRUE; } else { GST_DEBUG_OBJECT (sink, "Setting new kid"); } /* set temporary bus of our own to catch error messages from the child * (could we just set our own bus on it, or would the state change messages * from the not-yet-added element confuse the state change algorithm? Let's * play it safe for now) */ bus = gst_bus_new (); gst_element_set_bus (new_kid, bus); gst_object_unref (bus); if (gst_element_set_state (new_kid, kid_state) == GST_STATE_CHANGE_FAILURE) { GstMessage *msg; /* check if child posted an error message and if so re-post it on our bus * so that the application gets to see a decent error and not our generic * fallback error message which is completely indecipherable to the user */ msg = gst_bus_pop_filtered (GST_ELEMENT_BUS (new_kid), GST_MESSAGE_ERROR); if (msg) { GST_INFO_OBJECT (sink, "Forwarding kid error: %" GST_PTR_FORMAT, msg); gst_element_post_message (GST_ELEMENT (sink), msg); } /* FIXME: need a translated error message that tells the user to check * her GConf audio/video settings */ GST_ELEMENT_ERROR (sink, CORE, STATE_CHANGE, (NULL), ("Failed to set state on new child.")); gst_element_set_bus (new_kid, NULL); gst_object_unref (new_kid); return FALSE; } gst_element_set_bus (new_kid, NULL); gst_bin_add (GST_BIN (sink), new_kid); /* Now, replace the existing child */ GST_OBJECT_LOCK (sink); old_kid = sink->kid; sink->kid = new_kid; /* Mark whether a custom kid or fakesink has been installed */ sink->have_kid = !is_fakesink; GST_OBJECT_UNLOCK (sink); /* kill old element */ if (old_kid) { GST_DEBUG_OBJECT (sink, "Removing old kid %" GST_PTR_FORMAT, old_kid); gst_element_set_state (old_kid, GST_STATE_NULL); gst_bin_remove (GST_BIN (sink), old_kid); gst_object_unref (old_kid); } /* re-attach ghostpad */ GST_DEBUG_OBJECT (sink, "Creating new ghostpad"); targetpad = gst_element_get_static_pad (sink->kid, "sink"); gst_ghost_pad_set_target (GST_GHOST_PAD (sink->pad), targetpad); gst_object_unref (targetpad); GST_DEBUG_OBJECT (sink, "done changing child of switchsink"); /* FIXME: Push new-segment info and pre-roll buffer(s) into the kid */ /* Unblock the target pad if necessary */ if (sink->awaiting_block) { gst_pad_set_blocked (sink->pad, FALSE); sink->awaiting_block = FALSE; } return TRUE; }
static void _setup_test (gboolean link_h264, gboolean link_yuy2, gboolean link_nv12, gboolean link_jpg) { GstCaps *caps; GstPad *sinkpad, *h264pad, *yuy2pad, *nv12pad, *jpgpad; GstBus *bus; bus = gst_bus_new (); have_h264_eos = have_yuy2_eos = have_nv12_eos = have_jpg_eos = FALSE; buffer_h264 = buffer_yuy2 = buffer_nv12 = buffer_jpg = NULL; demux = gst_element_factory_make ("uvch264mjpgdemux", NULL); fail_unless (demux != NULL); gst_element_set_bus (demux, bus); gst_bus_set_sync_handler (bus, _bus_sync_handler, NULL, NULL); mjpg_pad = gst_pad_new_from_static_template (&mjpg_template, "src"); fail_unless (mjpg_pad != NULL); sinkpad = gst_element_get_static_pad (demux, "sink"); fail_unless (sinkpad != NULL); fail_unless (gst_pad_link (mjpg_pad, sinkpad) == GST_PAD_LINK_OK); gst_object_unref (sinkpad); gst_pad_set_active (mjpg_pad, TRUE); if (link_h264) { h264pad = gst_element_get_static_pad (demux, "h264"); fail_unless (h264pad != NULL); h264_pad = gst_pad_new_from_static_template (&sink_template, "h264"); fail_unless (h264_pad != NULL); gst_pad_set_chain_function (h264_pad, _sink_h264_chain); gst_pad_set_event_function (h264_pad, _sink_h264_event); fail_unless (gst_pad_link (h264pad, h264_pad) == GST_PAD_LINK_OK); gst_object_unref (h264pad); gst_pad_set_active (h264_pad, TRUE); } if (link_yuy2) { yuy2pad = gst_element_get_static_pad (demux, "yuy2"); fail_unless (yuy2pad != NULL); yuy2_pad = gst_pad_new_from_static_template (&sink_template, "yuy2"); fail_unless (yuy2_pad != NULL); gst_pad_set_chain_function (yuy2_pad, _sink_yuy2_chain); gst_pad_set_event_function (yuy2_pad, _sink_yuy2_event); fail_unless (gst_pad_link (yuy2pad, yuy2_pad) == GST_PAD_LINK_OK); gst_object_unref (yuy2pad); gst_pad_set_active (yuy2_pad, TRUE); } if (link_nv12) { nv12pad = gst_element_get_static_pad (demux, "nv12"); fail_unless (nv12pad != NULL); nv12_pad = gst_pad_new_from_static_template (&sink_template, "nv12"); fail_unless (nv12_pad != NULL); gst_pad_set_chain_function (nv12_pad, _sink_nv12_chain); gst_pad_set_event_function (nv12_pad, _sink_nv12_event); fail_unless (gst_pad_link (nv12pad, nv12_pad) == GST_PAD_LINK_OK); gst_object_unref (nv12pad); gst_pad_set_active (nv12_pad, TRUE); } if (link_jpg) { jpgpad = gst_element_get_static_pad (demux, "jpeg"); fail_unless (jpgpad != NULL); jpg_pad = gst_pad_new_from_static_template (&sink_template, "jpeg"); fail_unless (jpg_pad != NULL); gst_pad_set_chain_function (jpg_pad, _sink_jpg_chain); gst_pad_set_event_function (jpg_pad, _sink_jpg_event); fail_unless (gst_pad_link (jpgpad, jpg_pad) == GST_PAD_LINK_OK); gst_object_unref (jpgpad); gst_pad_set_active (jpg_pad, TRUE); } gst_element_set_state (demux, GST_STATE_PLAYING); caps = gst_static_pad_template_get_caps (&mjpg_template); gst_check_setup_events_with_stream_id (mjpg_pad, demux, caps, GST_FORMAT_TIME, "uvch264demux-test"); gst_caps_unref (caps); }
/***************************************************************************** * 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; }
static void test_videoframe_audiolevel_generic (void) { GstElement *alevel; GstPad *asink, *vsink, *asrc, *vsrc, *aoutput_sink, *voutput_sink; GThread *athread, *vthread; GstBus *bus; guint i; got_eos = FALSE; audio_buffer_count = 0; video_buffer_count = 0; num_msgs = 0; g_queue_init (&v_timestamp_q); g_queue_init (&msg_timestamp_q); alevel = gst_element_factory_make ("videoframe-audiolevel", NULL); fail_unless (alevel != NULL); bus = gst_bus_new (); gst_element_set_bus (alevel, bus); gst_bus_set_sync_handler (bus, on_message, NULL, NULL); asink = gst_element_get_static_pad (alevel, "asink"); fail_unless (asink != NULL); vsink = gst_element_get_static_pad (alevel, "vsink"); fail_unless (vsink != NULL); asrc = gst_element_get_static_pad (alevel, "asrc"); aoutput_sink = gst_pad_new ("sink", GST_PAD_SINK); fail_unless (aoutput_sink != NULL); fail_unless (gst_pad_link (asrc, aoutput_sink) == GST_PAD_LINK_OK); vsrc = gst_element_get_static_pad (alevel, "vsrc"); voutput_sink = gst_pad_new ("sink", GST_PAD_SINK); fail_unless (voutput_sink != NULL); fail_unless (gst_pad_link (vsrc, voutput_sink) == GST_PAD_LINK_OK); gst_pad_set_chain_function (aoutput_sink, output_achain); gst_pad_set_event_function (aoutput_sink, output_aevent); gst_pad_set_chain_function (voutput_sink, output_vchain); gst_pad_set_event_function (voutput_sink, output_vevent); gst_pad_set_active (aoutput_sink, TRUE); gst_pad_set_active (voutput_sink, TRUE); fail_unless (gst_element_set_state (alevel, GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS); athread = g_thread_new ("athread", (GThreadFunc) push_abuffers, asink); vthread = g_thread_new ("vthread", (GThreadFunc) push_vbuffers, vsink); g_thread_join (vthread); g_thread_join (athread); fail_unless (got_eos); fail_unless_equals_int (audio_buffer_count, n_abuffers); fail_unless_equals_int (video_buffer_count, n_vbuffers); if (!long_video) fail_unless_equals_int (num_msgs, n_vbuffers); fail_unless_equals_int (g_queue_get_length (&v_timestamp_q), n_vbuffers); /* num_msgs is equal to n_vbuffers except in the case of long_video */ fail_unless_equals_int (g_queue_get_length (&msg_timestamp_q), num_msgs); for (i = 0; i < g_queue_get_length (&msg_timestamp_q); i++) { GstClockTime *vt = g_queue_pop_head (&v_timestamp_q); GstClockTime *mt = g_queue_pop_head (&msg_timestamp_q); fail_unless (vt != NULL); fail_unless (mt != NULL); if (!video_gaps && !video_overlaps && !early_video) fail_unless_equals_uint64 (*vt, *mt); g_free (vt); g_free (mt); } /* teardown */ gst_element_set_state (alevel, GST_STATE_NULL); gst_bus_set_flushing (bus, TRUE); gst_object_unref (bus); g_queue_foreach (&v_timestamp_q, (GFunc) g_free, NULL); g_queue_foreach (&msg_timestamp_q, (GFunc) g_free, NULL); g_queue_clear (&v_timestamp_q); g_queue_clear (&msg_timestamp_q); gst_pad_unlink (asrc, aoutput_sink); gst_object_unref (asrc); gst_pad_unlink (vsrc, voutput_sink); gst_object_unref (vsrc); gst_object_unref (asink); gst_object_unref (vsink); gst_pad_set_active (aoutput_sink, FALSE); gst_object_unref (aoutput_sink); gst_pad_set_active (voutput_sink, FALSE); gst_object_unref (voutput_sink); gst_object_unref (alevel); }
gboolean check_missing_plugins(GstEncodingProfile *profile, char ***details, char ***descriptions) { GstElement *encodebin; GstBus *bus; GstPad *pad; gboolean ret; ret = FALSE; encodebin = gst_element_factory_make("encodebin", NULL); if (encodebin == NULL) { g_warning("Unable to create encodebin"); return TRUE; } bus = gst_bus_new(); gst_element_set_bus(encodebin, bus); gst_bus_set_flushing(bus, FALSE); /* necessary? */ g_object_set(encodebin, "profile", profile, NULL); pad = gst_element_get_static_pad(encodebin, "audio_0"); if (pad == NULL) { GstMessage *message; GList *messages = NULL; GList *m; message = gst_bus_pop(bus); while (message != NULL) { if (gst_is_missing_plugin_message(message)) messages = g_list_append(messages, message); else gst_message_unref(message); message = gst_bus_pop(bus); } if (messages != NULL) { int i; if (details != NULL) *details = g_new0(char *, g_list_length(messages)+1); if (descriptions != NULL) *descriptions = g_new0(char *, g_list_length(messages)+1); i = 0; for (m = messages; m != NULL; m = m->next) { char *str; if (details != NULL) { str = gst_missing_plugin_message_get_installer_detail(m->data); (*details)[i] = str; } if (descriptions != NULL) { str = gst_missing_plugin_message_get_description(m->data); (*descriptions)[i] = str; } i++; } ret = TRUE; g_list_foreach(messages,(GFunc)gst_message_unref, NULL); g_list_free(messages); }