static GstPadProbeReturn cb_latency (GstPad * pad, GstPadProbeInfo * info, gpointer data) { if (GST_QUERY_TYPE (GST_PAD_PROBE_INFO_QUERY (info)) != GST_QUERY_LATENCY) { return GST_PAD_PROBE_OK; } GST_LOG_OBJECT (pad, "Modifing latency query. New latency %" G_GUINT64_FORMAT, (guint64) (LATENCY * GST_MSECOND)); gst_query_set_latency (GST_PAD_PROBE_INFO_QUERY (info), TRUE, 0, LATENCY * GST_MSECOND); return GST_PAD_PROBE_HANDLED; }
static GstPadProbeReturn query_cb (GstPad * pad, GstPadProbeInfo * info, gpointer user_data) { APP_STATE_T *state = (APP_STATE_T *) user_data; GstQuery *query = GST_PAD_PROBE_INFO_QUERY (info); GstStructure *external_gl_context_desc = NULL; gchar *platform = NULL; gchar *gl_apis = NULL; switch (GST_QUERY_TYPE (query)) { case GST_QUERY_ALLOCATION: { platform = gst_gl_platform_to_string (GST_GL_PLATFORM_EGL); gl_apis = gst_gl_api_to_string (GST_GL_API_GLES2); external_gl_context_desc = gst_structure_new ("GstVideoGLTextureUploadMeta", "gst.gl.context.handle", G_TYPE_POINTER, state->context, "gst.gl.context.type", G_TYPE_STRING, platform, "gst.gl.context.apis", G_TYPE_STRING, gl_apis, NULL); gst_query_add_allocation_meta (query, GST_VIDEO_GL_TEXTURE_UPLOAD_META_API_TYPE, external_gl_context_desc); gst_structure_free (external_gl_context_desc); g_free (gl_apis); g_free (platform); GST_DEBUG ("done alocation"); return GST_PAD_PROBE_OK; break; } case GST_QUERY_CONTEXT: { return gst_gl_handle_context_query (state->pipeline, query, (GstGLDisplay **) & state->gst_display); break; } case GST_QUERY_DRAIN: { flush_internal (state); break; } default: break; } return GST_PAD_PROBE_OK; }
static GstPadProbeReturn block_agnostic_sink (GstPad * pad, GstPadProbeInfo * info, gpointer data) { static gboolean configuring = FALSE; /* HACK: Ignore caps event and stream start event that causes negotiation * failures.This is a workaround that should be removed */ if (GST_PAD_PROBE_INFO_TYPE (info) & GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM) { GstEvent *event = GST_PAD_PROBE_INFO_EVENT (info); if (GST_EVENT_TYPE (event) == GST_EVENT_STREAM_START || GST_EVENT_TYPE (event) == GST_EVENT_CAPS) { return GST_PAD_PROBE_PASS; } } /* HACK: Ignore query accept caps that causes negotiation errors. * This is a workaround that should be removed */ if (GST_PAD_PROBE_INFO_TYPE (info) & GST_PAD_PROBE_TYPE_QUERY_DOWNSTREAM) { GstQuery *query = GST_PAD_PROBE_INFO_QUERY (info); if (GST_QUERY_TYPE (query) == GST_QUERY_ACCEPT_CAPS) { return GST_PAD_PROBE_PASS; } } if (!g_atomic_int_get (&configuring)) { g_atomic_int_set (&configuring, TRUE); change_input (data); g_atomic_int_set (&configuring, FALSE); return GST_PAD_PROBE_REMOVE; } return GST_PAD_PROBE_PASS; }
static GstPadProbeReturn query_cb (GstPad * pad, GstPadProbeInfo * info, gpointer user_data) { APP_STATE_T *state = (APP_STATE_T *) user_data; GstQuery *query = GST_PAD_PROBE_INFO_QUERY (info); switch (GST_QUERY_TYPE (query)) { case GST_QUERY_ALLOCATION:{ GstBufferPool *pool; GstStructure *config; GstCaps *caps; GstVideoInfo info; gboolean need_pool; guint size; GstAllocator *allocator; GstAllocationParams params; gst_allocation_params_init (¶ms); gst_query_parse_allocation (query, &caps, &need_pool); if (!caps) { GST_ERROR ("allocation query without caps"); return GST_PAD_PROBE_OK; } if (!gst_video_info_from_caps (&info, caps)) { GST_ERROR ("allocation query with invalid caps"); return GST_PAD_PROBE_OK; } g_mutex_lock (state->queue_lock); pool = state->pool ? gst_object_ref (state->pool) : NULL; g_mutex_unlock (state->queue_lock); if (pool) { GstCaps *pcaps; /* we had a pool, check caps */ config = gst_buffer_pool_get_config (pool); gst_buffer_pool_config_get_params (config, &pcaps, &size, NULL, NULL); GST_DEBUG ("check existing pool caps %" GST_PTR_FORMAT " with new caps %" GST_PTR_FORMAT, pcaps, caps); if (!gst_caps_is_equal (caps, pcaps)) { GST_DEBUG ("pool has different caps"); /* different caps, we can't use this pool */ gst_object_unref (pool); pool = NULL; } gst_structure_free (config); } GST_DEBUG ("pool %p", pool); if (pool == NULL && need_pool) { GstVideoInfo info; if (!gst_video_info_from_caps (&info, caps)) { GST_ERROR ("allocation query has invalid caps %" GST_PTR_FORMAT, caps); return GST_PAD_PROBE_OK; } GST_DEBUG ("create new pool"); state->pool = pool = gst_egl_image_buffer_pool_new (state, state->display); GST_DEBUG ("done create new pool %p", pool); /* the normal size of a frame */ size = info.size; config = gst_buffer_pool_get_config (pool); /* we need at least 2 buffer because we hold on to the last one */ gst_buffer_pool_config_set_params (config, caps, size, 2, 0); gst_buffer_pool_config_set_allocator (config, NULL, ¶ms); if (!gst_buffer_pool_set_config (pool, config)) { gst_object_unref (pool); GST_ERROR ("failed to set pool configuration"); return GST_PAD_PROBE_OK; } } if (pool) { /* we need at least 2 buffer because we hold on to the last one */ gst_query_add_allocation_pool (query, pool, size, 2, 0); gst_object_unref (pool); } /* First the default allocator */ if (!gst_egl_image_memory_is_mappable ()) { allocator = gst_allocator_find (NULL); gst_query_add_allocation_param (query, allocator, ¶ms); gst_object_unref (allocator); } allocator = gst_egl_image_allocator_obtain (); GST_WARNING ("Allocator obtained %p", allocator); if (!gst_egl_image_memory_is_mappable ()) params.flags |= GST_MEMORY_FLAG_NOT_MAPPABLE; gst_query_add_allocation_param (query, allocator, ¶ms); gst_object_unref (allocator); gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL); gst_query_add_allocation_meta (query, GST_VIDEO_CROP_META_API_TYPE, NULL); gst_query_add_allocation_meta (query, GST_VIDEO_GL_TEXTURE_UPLOAD_META_API_TYPE, NULL); GST_DEBUG ("done alocation"); return GST_PAD_PROBE_OK; } break; default: break; } return GST_PAD_PROBE_OK; }
/* Probe on the output of a parser chain (the last * src pad) */ static GstPadProbeReturn parse_chain_output_probe (GstPad * pad, GstPadProbeInfo * info, DecodebinInputStream * input) { GstPadProbeReturn ret = GST_PAD_PROBE_OK; if (GST_IS_EVENT (GST_PAD_PROBE_INFO_DATA (info))) { GstEvent *ev = GST_PAD_PROBE_INFO_EVENT (info); GST_DEBUG_OBJECT (pad, "Got event %s", GST_EVENT_TYPE_NAME (ev)); switch (GST_EVENT_TYPE (ev)) { case GST_EVENT_STREAM_START: { GstStream *stream = NULL; guint group_id = G_MAXUINT32; gst_event_parse_group_id (ev, &group_id); GST_DEBUG_OBJECT (pad, "Got stream-start, group_id:%d, input %p", group_id, input->input); if (set_input_group_id (input->input, &group_id)) { ev = gst_event_make_writable (ev); gst_event_set_group_id (ev, group_id); GST_PAD_PROBE_INFO_DATA (info) = ev; } input->saw_eos = FALSE; gst_event_parse_stream (ev, &stream); /* FIXME : Would we ever end up with a stream already set on the input ?? */ if (stream) { if (input->active_stream != stream) { MultiQueueSlot *slot; if (input->active_stream) gst_object_unref (input->active_stream); input->active_stream = stream; /* We have the beginning of a stream, get a multiqueue slot and link to it */ g_mutex_lock (&input->dbin->selection_lock); slot = get_slot_for_input (input->dbin, input); link_input_to_slot (input, slot); g_mutex_unlock (&input->dbin->selection_lock); } else gst_object_unref (stream); } } break; case GST_EVENT_CAPS: { GstCaps *caps = NULL; gst_event_parse_caps (ev, &caps); GST_DEBUG_OBJECT (pad, "caps %" GST_PTR_FORMAT, caps); if (caps && input->active_stream) gst_stream_set_caps (input->active_stream, caps); } break; case GST_EVENT_EOS: input->saw_eos = TRUE; if (all_inputs_are_eos (input->dbin)) { GST_DEBUG_OBJECT (pad, "real input pad, marking as EOS"); check_all_streams_for_eos (input->dbin); } else { GstPad *peer = gst_pad_get_peer (input->srcpad); if (peer) { /* Send custom-eos event to multiqueue slot */ GstStructure *s; GstEvent *event; GST_DEBUG_OBJECT (pad, "Got EOS end of input stream, post custom-eos"); s = gst_structure_new_empty ("decodebin3-custom-eos"); event = gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s); gst_pad_send_event (peer, event); gst_object_unref (peer); } else { GST_FIXME_OBJECT (pad, "No peer, what should we do ?"); } } ret = GST_PAD_PROBE_DROP; break; case GST_EVENT_FLUSH_STOP: GST_DEBUG_OBJECT (pad, "Clear saw_eos flag"); input->saw_eos = FALSE; default: break; } } else if (GST_IS_QUERY (GST_PAD_PROBE_INFO_DATA (info))) { GstQuery *q = GST_PAD_PROBE_INFO_QUERY (info); GST_DEBUG_OBJECT (pad, "Seeing query %s", GST_QUERY_TYPE_NAME (q)); /* If we have a parser, we want to reply to the caps query */ /* FIXME: Set a flag when the input stream is created for * streams where we shouldn't reply to these queries */ if (GST_QUERY_TYPE (q) == GST_QUERY_CAPS && (info->type & GST_PAD_PROBE_TYPE_PULL)) { GstCaps *filter = NULL; GstCaps *allowed; gst_query_parse_caps (q, &filter); allowed = get_parser_caps_filter (input->dbin, filter); GST_DEBUG_OBJECT (pad, "Intercepting caps query, setting %" GST_PTR_FORMAT, allowed); gst_query_set_caps_result (q, allowed); gst_caps_unref (allowed); ret = GST_PAD_PROBE_HANDLED; } else if (GST_QUERY_TYPE (q) == GST_QUERY_ACCEPT_CAPS) { GstCaps *prop = NULL; gst_query_parse_accept_caps (q, &prop); /* Fast check against target caps */ if (gst_caps_can_intersect (prop, input->dbin->caps)) gst_query_set_accept_caps_result (q, TRUE); else { gboolean accepted = check_parser_caps_filter (input->dbin, prop); /* check against caps filter */ gst_query_set_accept_caps_result (q, accepted); GST_DEBUG_OBJECT (pad, "ACCEPT_CAPS query, returning %d", accepted); } ret = GST_PAD_PROBE_HANDLED; } } return ret; }