static gboolean activate_vpp (GstVaapiDecodeBin * vaapidecbin) { GstElement *src; if (vaapidecbin->ghost_pad_src || vaapidecbin->postproc) return TRUE; if (!vaapidecbin->has_vpp || vaapidecbin->disable_vpp) { src = vaapidecbin->queue; goto connect_src_ghost_pad; } /* create the postproc */ vaapidecbin->postproc = gst_element_factory_make ("vaapipostproc", "vaapipostproc"); if (!vaapidecbin->postproc) goto error_element_missing; g_object_set (G_OBJECT (vaapidecbin->postproc), "deinterlace-method", vaapidecbin->deinterlace_method, NULL); gst_bin_add (GST_BIN (vaapidecbin), vaapidecbin->postproc); if (!gst_element_link_pads_full (vaapidecbin->queue, "src", vaapidecbin->postproc, "sink", GST_PAD_LINK_CHECK_NOTHING)) goto error_link_pad; GST_DEBUG_OBJECT (vaapidecbin, "Enabling VPP"); src = vaapidecbin->postproc; goto connect_src_ghost_pad; error_element_missing: { post_missing_element_message (vaapidecbin, "vaapipostproc"); return FALSE; } error_link_pad: { GST_ERROR_OBJECT (vaapidecbin, "Failed to link the child elements"); return FALSE; } connect_src_ghost_pad: { GstPad *srcpad, *ghostpad; srcpad = gst_element_get_static_pad (src, "src"); ghostpad = gst_ghost_pad_new ("src", srcpad); vaapidecbin->ghost_pad_src = ghostpad; gst_object_unref (srcpad); gst_element_add_pad (GST_ELEMENT (vaapidecbin), ghostpad); return TRUE; } }
static void gst_vaapi_decode_bin_init (GstVaapiDecodeBin * vaapidecbin) { GstPad *pad, *ghostpad; vaapidecbin->deinterlace_method = DEFAULT_DEINTERLACE_METHOD; vaapidecbin->disable_vpp = (g_getenv ("GST_VAAPI_DISABLE_VPP") != NULL); /* create the decoder */ vaapidecbin->decoder = g_object_new (g_type_from_name ("GstVaapiDecode"), NULL); g_assert (vaapidecbin->decoder); /* create the queue */ vaapidecbin->queue = gst_element_factory_make ("queue", "vaapi-queue"); if (!vaapidecbin->queue) { g_clear_object (&vaapidecbin->decoder); post_missing_element_message (vaapidecbin, "queue"); return; } gst_bin_add_many (GST_BIN (vaapidecbin), vaapidecbin->decoder, vaapidecbin->queue, NULL); if (!gst_element_link (vaapidecbin->decoder, vaapidecbin->queue)) { g_clear_object (&vaapidecbin->decoder); g_clear_object (&vaapidecbin->queue); g_critical ("failed to link decoder and queue"); return; } /* create ghost pad sink */ pad = gst_element_get_static_pad (vaapidecbin->decoder, "sink"); ghostpad = gst_ghost_pad_new_from_template ("sink", pad, GST_PAD_PAD_TEMPLATE (pad)); gst_object_unref (pad); if (!gst_element_add_pad (GST_ELEMENT (vaapidecbin), ghostpad)) g_critical ("failed to add decoder sink pad to bin"); /* create ghost pad src */ pad = gst_element_get_static_pad (GST_ELEMENT (vaapidecbin->queue), "src"); ghostpad = gst_ghost_pad_new_from_template ("src", pad, GST_PAD_PAD_TEMPLATE (pad)); gst_object_unref (pad); if (!gst_element_add_pad (GST_ELEMENT (vaapidecbin), ghostpad)) g_critical ("failed to add queue source pad to bin"); }
static gboolean gst_vaapi_decode_bin_configure (GstVaapiDecodeBin * vaapidecbin) { gchar *missing_factory = NULL; /* create the decoder */ vaapidecbin->decoder = gst_element_factory_make ("vaapidecode", "vaapidecode"); if (!vaapidecbin->decoder) { missing_factory = "vaapidecode"; goto error_element_missing; } /* create the queue */ vaapidecbin->queue = gst_element_factory_make ("queue", "queue"); if (!vaapidecbin->queue) { missing_factory = "queue"; goto error_element_missing; } g_object_set (G_OBJECT (vaapidecbin->queue), "max-size-bytes", vaapidecbin->max_size_bytes, "max-size-buffers", vaapidecbin->max_size_buffers, "max-size-time", vaapidecbin->max_size_time, NULL); gst_bin_add_many (GST_BIN (vaapidecbin), vaapidecbin->decoder, vaapidecbin->queue, NULL); if (!gst_element_link_pads_full (vaapidecbin->decoder, "src", vaapidecbin->queue, "sink", GST_PAD_LINK_CHECK_NOTHING)) goto error_link_pad; return TRUE; error_element_missing: { post_missing_element_message (vaapidecbin, missing_factory); return FALSE; } error_link_pad: { GST_ERROR_OBJECT (vaapidecbin, "Failed to link the child elements"); return FALSE; } }
static void pad_blocked_cb (GstPad * pad, gboolean blocked, GstPlaySinkVideoConvert * self) { GstPad *peer; GstCaps *caps; gboolean raw; GST_PLAY_SINK_VIDEO_CONVERT_LOCK (self); self->sink_proxypad_blocked = blocked; GST_DEBUG_OBJECT (self, "Pad blocked: %d", blocked); if (!blocked) goto done; /* There must be a peer at this point */ peer = gst_pad_get_peer (self->sinkpad); caps = gst_pad_get_negotiated_caps (peer); if (!caps) caps = gst_pad_get_caps_reffed (peer); gst_object_unref (peer); raw = is_raw_caps (caps); GST_DEBUG_OBJECT (self, "Caps %" GST_PTR_FORMAT " are raw: %d", caps, raw); gst_caps_unref (caps); if (raw == self->raw) goto unblock; self->raw = raw; if (raw) { GstBin *bin = GST_BIN_CAST (self); GstElement *head = NULL, *prev = NULL; GstPad *pad; GST_DEBUG_OBJECT (self, "Creating raw conversion pipeline"); gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->sinkpad), NULL); gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad), NULL); self->conv = gst_element_factory_make ("ffmpegcolorspace", "conv"); if (self->conv == NULL) { post_missing_element_message (self, "ffmpegcolorspace"); GST_ELEMENT_WARNING (self, CORE, MISSING_PLUGIN, (_("Missing element '%s' - check your GStreamer installation."), "ffmpegcolorspace"), ("video rendering might fail")); } else { gst_bin_add (bin, self->conv); gst_element_sync_state_with_parent (self->conv); distribute_running_time (self->conv, &self->segment); prev = head = self->conv; } self->scale = gst_element_factory_make ("videoscale", "scale"); if (self->scale == NULL) { post_missing_element_message (self, "videoscale"); GST_ELEMENT_WARNING (self, CORE, MISSING_PLUGIN, (_("Missing element '%s' - check your GStreamer installation."), "videoscale"), ("possibly a liboil version mismatch?")); } else { /* Add black borders if necessary to keep the DAR */ g_object_set (self->scale, "add-borders", TRUE, NULL); gst_bin_add (bin, self->scale); gst_element_sync_state_with_parent (self->scale); distribute_running_time (self->scale, &self->segment); if (prev) { if (!gst_element_link_pads_full (prev, "src", self->scale, "sink", GST_PAD_LINK_CHECK_TEMPLATE_CAPS)) goto link_failed; } else { head = self->scale; } prev = self->scale; } if (head) { pad = gst_element_get_static_pad (head, "sink"); gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->sinkpad), pad); gst_object_unref (pad); } if (prev) { pad = gst_element_get_static_pad (prev, "src"); gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad), pad); gst_object_unref (pad); } if (!head && !prev) { gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad), self->sink_proxypad); } GST_DEBUG_OBJECT (self, "Raw conversion pipeline created"); } else { GstBin *bin = GST_BIN_CAST (self); GST_DEBUG_OBJECT (self, "Removing raw conversion pipeline"); gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->sinkpad), NULL); gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad), NULL); if (self->conv) { gst_element_set_state (self->conv, GST_STATE_NULL); gst_bin_remove (bin, self->conv); self->conv = NULL; } if (self->scale) { gst_element_set_state (self->scale, GST_STATE_NULL); gst_bin_remove (bin, self->scale); self->scale = NULL; } gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad), self->sink_proxypad); GST_DEBUG_OBJECT (self, "Raw conversion pipeline removed"); } unblock: gst_pad_set_blocked_async_full (self->sink_proxypad, FALSE, (GstPadBlockCallback) pad_blocked_cb, gst_object_ref (self), (GDestroyNotify) gst_object_unref); done: GST_PLAY_SINK_VIDEO_CONVERT_UNLOCK (self); return; link_failed: { GST_ELEMENT_ERROR (self, CORE, PAD, (NULL), ("Failed to configure the video converter.")); gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad), self->sink_proxypad); gst_pad_set_blocked_async_full (self->sink_proxypad, FALSE, (GstPadBlockCallback) pad_blocked_cb, gst_object_ref (self), (GDestroyNotify) gst_object_unref); return; } }
static gboolean gst_vaapi_decode_bin_configure (GstVaapiDecodeBin * vaapidecbin) { GstElement *capsfilter; GstCaps *caps; GstPad *queue_srcpad, *bin_srcpad, *capsfilter_sinkpad, *vpp_srcpad; gboolean res; gboolean has_vpp; g_object_set (G_OBJECT (vaapidecbin->queue), "max-size-bytes", vaapidecbin->max_size_bytes, "max-size-buffers", vaapidecbin->max_size_buffers, "max-size-time", vaapidecbin->max_size_time, NULL); if (vaapidecbin->disable_vpp || vaapidecbin->configured) return TRUE; has_vpp = _gst_vaapi_has_video_processing; if (!has_vpp && (vaapidecbin->deinterlace_method == GST_VAAPI_DEINTERLACE_METHOD_MOTION_ADAPTIVE || vaapidecbin->deinterlace_method == GST_VAAPI_DEINTERLACE_METHOD_MOTION_COMPENSATED)) { GST_ERROR_OBJECT (vaapidecbin, "Don't have VPP support but advanced deinterlacing selected"); return FALSE; } GST_INFO_OBJECT (vaapidecbin, "enabling VPP"); /* capsfilter to avoid negotiation with vaapidecode */ caps = gst_caps_from_string ("video/x-raw(memory:VASurface), format=(string)NV12"); if (!caps) goto error_cannot_set_caps; capsfilter = gst_element_factory_make ("capsfilter", NULL); g_object_set (capsfilter, "caps", caps, NULL); gst_caps_unref (caps); /* create the postproc */ vaapidecbin->postproc = gst_element_factory_make ("vaapipostproc", NULL); if (!vaapidecbin->postproc) goto error_vpp_missing; g_object_set (G_OBJECT (vaapidecbin->postproc), "deinterlace-method", vaapidecbin->deinterlace_method, NULL); gst_bin_add_many (GST_BIN (vaapidecbin), capsfilter, vaapidecbin->postproc, NULL); if (!gst_element_link (capsfilter, vaapidecbin->postproc)) goto error_sync_state; if (!gst_element_sync_state_with_parent (capsfilter)) goto error_sync_state; if (!gst_element_sync_state_with_parent (vaapidecbin->postproc)) goto error_sync_state; /* break source ghost pad target */ bin_srcpad = gst_element_get_static_pad (GST_ELEMENT_CAST (vaapidecbin), "src"); if (!gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (bin_srcpad), NULL)) goto error_link_pad; /* link decoder and queue */ queue_srcpad = gst_element_get_static_pad (vaapidecbin->queue, "src"); capsfilter_sinkpad = gst_element_get_static_pad (capsfilter, "sink"); res = (gst_pad_link (queue_srcpad, capsfilter_sinkpad) == GST_PAD_LINK_OK); gst_object_unref (capsfilter_sinkpad); gst_object_unref (queue_srcpad); if (!res) goto error_link_pad; /* set vpp source pad as source ghost pad target */ vpp_srcpad = gst_element_get_static_pad (vaapidecbin->postproc, "src"); res = gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (bin_srcpad), vpp_srcpad); gst_object_unref (vpp_srcpad); if (!res) goto error_link_pad; gst_object_unref (bin_srcpad); vaapidecbin->configured = TRUE; return TRUE; /* ERRORS */ error_cannot_set_caps: { GST_ELEMENT_ERROR (vaapidecbin, CORE, PAD, ("Failed to configure caps for VA Surfaces."), (NULL)); return FALSE; } error_vpp_missing: { post_missing_element_message (vaapidecbin, "vaapipostproc"); return FALSE; } error_sync_state: { GST_ELEMENT_ERROR (vaapidecbin, CORE, STATE_CHANGE, ("Failed to sync state of vaapipostproc"), (NULL)); return FALSE; } error_link_pad: { gst_object_unref (bin_srcpad); GST_ELEMENT_ERROR (vaapidecbin, CORE, PAD, ("Failed to configure the vaapidecodebin."), (NULL)); return FALSE; } }
static gboolean gst_vaapi_decode_bin_configure (GstVaapiDecodeBin * vaapidecbin) { gchar *missing_factory = NULL; GstPad *pad, *ghostpad; GstPadTemplate *tmpl; /* create the decoder */ vaapidecbin->decoder = gst_element_factory_make ("vaapidecode", "vaapidecode"); if (!vaapidecbin->decoder) { missing_factory = "vaapidecode"; goto error_element_missing; } /* create the queue */ vaapidecbin->queue = gst_element_factory_make ("queue", "queue"); if (!vaapidecbin->queue) { missing_factory = "queue"; goto error_element_missing; } g_object_set (G_OBJECT (vaapidecbin->queue), "max-size-bytes", vaapidecbin->max_size_bytes, "max-size-buffers", vaapidecbin->max_size_buffers, "max-size-time", vaapidecbin->max_size_time, NULL); gst_bin_add_many (GST_BIN (vaapidecbin), vaapidecbin->decoder, vaapidecbin->queue, NULL); if (!gst_element_link_many (vaapidecbin->decoder, vaapidecbin->queue, NULL)) goto error_link_pad; /* create ghost pad sink */ pad = gst_element_get_static_pad (GST_ELEMENT (vaapidecbin->decoder), "sink"); ghostpad = gst_ghost_pad_new_from_template ("sink", pad, GST_PAD_PAD_TEMPLATE (pad)); gst_object_unref (pad); if (!gst_element_add_pad (GST_ELEMENT (vaapidecbin), ghostpad)) goto error_adding_pad; /* create ghost pad src */ pad = gst_element_get_static_pad (GST_ELEMENT (vaapidecbin->queue), "src"); tmpl = gst_static_pad_template_get (&gst_vaapi_decode_bin_src_factory); ghostpad = gst_ghost_pad_new_from_template ("src", pad, tmpl); gst_object_unref (pad); gst_object_unref (tmpl); if (!gst_element_add_pad (GST_ELEMENT (vaapidecbin), ghostpad)) goto error_adding_pad; return TRUE; error_element_missing: { post_missing_element_message (vaapidecbin, missing_factory); return FALSE; } error_link_pad: { GST_ELEMENT_ERROR (vaapidecbin, CORE, PAD, (NULL), ("Failed to configure the vaapidecodebin.")); return FALSE; } error_adding_pad: { GST_ELEMENT_ERROR (vaapidecbin, CORE, PAD, (NULL), ("Failed to adding pads.")); return FALSE; } }
static gboolean activate_vpp (GstVaapiDecodeBin * vaapidecbin) { GstPad *queue_srcpad, *srcpad, *vpp_sinkpad, *vpp_srcpad; gboolean res; if (vaapidecbin->postproc) return TRUE; if (vaapidecbin->has_vpp != HAS_VPP_YES || vaapidecbin->disable_vpp) return TRUE; GST_DEBUG_OBJECT (vaapidecbin, "Enabling VPP"); /* create the postproc */ vaapidecbin->postproc = gst_element_factory_make ("vaapipostproc", "vaapipostproc"); if (!vaapidecbin->postproc) goto error_element_missing; g_object_set (G_OBJECT (vaapidecbin->postproc), "deinterlace-method", vaapidecbin->deinterlace_method, NULL); gst_bin_add (GST_BIN (vaapidecbin), vaapidecbin->postproc); if (!gst_element_sync_state_with_parent (vaapidecbin->postproc)) goto error_sync_state; srcpad = gst_element_get_static_pad (GST_ELEMENT_CAST (vaapidecbin), "src"); if (!gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (srcpad), NULL)) goto error_link_pad; queue_srcpad = gst_element_get_static_pad (vaapidecbin->queue, "src"); vpp_sinkpad = gst_element_get_static_pad (vaapidecbin->postproc, "sink"); res = (gst_pad_link (queue_srcpad, vpp_sinkpad) == GST_PAD_LINK_OK); gst_object_unref (vpp_sinkpad); gst_object_unref (queue_srcpad); if (!res) goto error_link_pad; vpp_srcpad = gst_element_get_static_pad (vaapidecbin->postproc, "src"); res = gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (srcpad), vpp_srcpad); gst_object_unref (vpp_srcpad); if (!res) goto error_link_pad; gst_object_unref (srcpad); return TRUE; error_element_missing: { post_missing_element_message (vaapidecbin, "vaapipostproc"); return FALSE; } error_sync_state: { GST_ERROR_OBJECT (vaapidecbin, "Failed to sync VPP state"); return FALSE; } error_link_pad: { gst_object_unref (srcpad); GST_ERROR_OBJECT (vaapidecbin, "Failed to link the child elements"); return FALSE; } }