static void gst_vaapiencode_init (GstVaapiEncode * encode) { GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (encode); gst_vaapi_plugin_base_init (GST_VAAPI_PLUGIN_BASE (encode), GST_CAT_DEFAULT); gst_pad_use_fixed_caps (plugin->srcpad); }
gboolean gst_vaapi_ensure_display (gpointer element, GstVaapiDisplayType type) { GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (element); GstVaapiDisplay *display; GstVideoContext *context; g_return_val_if_fail (GST_IS_VIDEO_CONTEXT (element), FALSE); context = GST_VIDEO_CONTEXT (element); g_return_val_if_fail (context != NULL, FALSE); gst_vaapi_video_context_prepare (context, display_types); /* Neighbour found and it updated the display */ if (gst_vaapi_plugin_base_has_display_type (plugin, type)) return TRUE; /* If no neighboor, or application not interested, use system default */ if (plugin->gl_context) display = gst_vaapi_create_display_from_gl_context (plugin->gl_context); else display = gst_vaapi_create_display (type, plugin->display_name); if (!display) return FALSE; gst_vaapi_video_context_propagate (context, display); GST_VAAPI_PLUGIN_BASE_DISPLAY_REPLACE (plugin, display); gst_vaapi_display_unref (display); return TRUE; }
static gboolean gst_vaapidecode_decide_allocation (GstVideoDecoder * vdec, GstQuery * query) { GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec); GstCaps *caps = NULL; gst_query_parse_allocation (query, &caps, NULL); if (!caps) goto error_no_caps; decode->has_texture_upload_meta = FALSE; #if (USE_GLX || USE_EGL) decode->has_texture_upload_meta = gst_query_find_allocation_meta (query, GST_VIDEO_GL_TEXTURE_UPLOAD_META_API_TYPE, NULL) && gst_vaapi_caps_feature_contains (caps, GST_VAAPI_CAPS_FEATURE_GL_TEXTURE_UPLOAD_META); #endif return gst_vaapi_plugin_base_decide_allocation (GST_VAAPI_PLUGIN_BASE (vdec), query); /* ERRORS */ error_no_caps: { GST_ERROR_OBJECT (decode, "no caps specified"); return FALSE; } }
static void gst_vaapidecode_init (GstVaapiDecode * decode) { GstVideoDecoder *const vdec = GST_VIDEO_DECODER (decode); gst_vaapi_plugin_base_init (GST_VAAPI_PLUGIN_BASE (decode), GST_CAT_DEFAULT); decode->decoder = NULL; decode->decoder_caps = NULL; decode->allowed_caps = NULL; g_mutex_init (&decode->surface_ready_mutex); g_cond_init (&decode->surface_ready); gst_video_decoder_set_packetized (vdec, FALSE); #if !GST_CHECK_VERSION(1,4,0) /* Pad through which data comes in to the element */ GstPad *pad = GST_VAAPI_PLUGIN_BASE_SINK_PAD (decode); gst_pad_set_query_function (pad, GST_DEBUG_FUNCPTR (gst_vaapidecode_query)); /* Pad through which data goes out of the element */ pad = GST_VAAPI_PLUGIN_BASE_SRC_PAD (decode); gst_pad_set_query_function (pad, GST_DEBUG_FUNCPTR (gst_vaapidecode_query)); #endif }
gboolean gst_vaapi_ensure_display (GstElement * element, GstVaapiDisplayType type) { GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (element); GstVaapiDisplay *display; g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE); if (gst_vaapi_video_context_prepare (element, &plugin->display)) { /* Neighbour found and it updated the display */ if (gst_vaapi_plugin_base_has_display_type (plugin, type)) return TRUE; } /* If no neighboor, or application not interested, use system default */ if (plugin->gl_context) display = gst_vaapi_create_display_from_gl_context (plugin->gl_context); else display = gst_vaapi_create_display (type, plugin->display_name); if (!display) return FALSE; gst_vaapi_video_context_propagate (element, display); gst_vaapi_display_unref (display); return TRUE; }
static void plugin_set_context (GstElement * element, GstContext * context) { GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (element); GstVaapiDisplay *display = NULL; if (gst_vaapi_video_context_get_display (context, &display)) plugin_set_display (plugin, display); }
static gboolean gst_vaapiencode_propose_allocation (GstVideoEncoder * venc, GstQuery * query) { GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (venc); if (!gst_vaapi_plugin_base_propose_allocation (plugin, query)) return FALSE; return TRUE; }
static gboolean is_src_allocator_dmabuf (GstVaapiDecode * decode) { GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (decode); if (!GST_VAAPI_PLUGIN_BASE_SRC_PAD_CAN_DMABUF (plugin)) return FALSE; return gst_vaapi_is_dmabuf_allocator (plugin->srcpad_allocator); }
static gboolean ensure_uploader (GstVaapiEncode * encode) { if (!ensure_display (encode)) return FALSE; if (!gst_vaapi_plugin_base_ensure_uploader (GST_VAAPI_PLUGIN_BASE (encode))) return FALSE; return TRUE; }
static gboolean gst_vaapiencode_close (GstVideoEncoder * venc) { GstVaapiEncode *const encode = GST_VAAPIENCODE_CAST (venc); gst_vaapiencode_destroy (encode); gst_vaapi_plugin_base_close (GST_VAAPI_PLUGIN_BASE (encode)); return TRUE; }
static gboolean gst_vaapidecode_close (GstVideoDecoder * vdec) { GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec); gst_vaapi_decode_input_state_replace (decode, NULL); gst_vaapidecode_destroy (decode); gst_vaapi_plugin_base_close (GST_VAAPI_PLUGIN_BASE (decode)); return TRUE; }
static gboolean gst_vaapidecode_close (GstVideoDecoder * vdec) { GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec); gst_vaapidecode_destroy (decode); gst_caps_replace (&decode->allowed_srcpad_caps, NULL); gst_caps_replace (&decode->allowed_sinkpad_caps, NULL); gst_vaapi_plugin_base_close (GST_VAAPI_PLUGIN_BASE (decode)); return TRUE; }
static gboolean gst_vaapiencode_set_format (GstVideoEncoder * venc, GstVideoCodecState * state) { GstVaapiEncode *const encode = GST_VAAPIENCODE_CAST (venc); gboolean ret; g_return_val_if_fail (state->caps != NULL, FALSE); if (!set_codec_state (encode, state)) return FALSE; if (!gst_vaapi_plugin_base_set_caps (GST_VAAPI_PLUGIN_BASE (encode), state->caps, NULL)) return FALSE; if (encode->input_state) gst_video_codec_state_unref (encode->input_state); encode->input_state = gst_video_codec_state_ref (state); encode->input_state_changed = TRUE; ret = gst_pad_start_task (GST_VAAPI_PLUGIN_BASE_SRC_PAD (encode), (GstTaskFunction) gst_vaapiencode_buffer_loop, encode, NULL); if (!ret) return FALSE; /* Store some tags */ { GstTagList *tags = gst_tag_list_new_empty (); const gchar *encoder, *codec; guint bitrate = 0; g_object_get (encode, "bitrate", &bitrate, NULL); gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_NOMINAL_BITRATE, bitrate, NULL); if ((encoder = gst_element_class_get_metadata (GST_ELEMENT_GET_CLASS (encode), GST_ELEMENT_METADATA_LONGNAME))) gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_ENCODER, encoder, NULL); if ((codec = gst_vaapi_codec_get_name (gst_vaapi_profile_get_codec (gst_vaapi_profile_from_caps (state->caps))))) gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CODEC, codec, NULL); gst_video_encoder_merge_tags (venc, tags, GST_TAG_MERGE_REPLACE); gst_tag_list_unref (tags); } return TRUE; }
static void gst_vaapidecode_finalize (GObject * object) { GstVaapiDecode *const decode = GST_VAAPIDECODE (object); g_cond_clear (&decode->surface_ready); g_mutex_clear (&decode->surface_ready_mutex); gst_vaapi_plugin_base_finalize (GST_VAAPI_PLUGIN_BASE (object)); G_OBJECT_CLASS (parent_class)->finalize (object); }
static void gst_vaapidecode_init (GstVaapiDecode * decode) { GstVideoDecoder *const vdec = GST_VIDEO_DECODER (decode); gst_vaapi_plugin_base_init (GST_VAAPI_PLUGIN_BASE (decode), GST_CAT_DEFAULT); g_mutex_init (&decode->surface_ready_mutex); g_cond_init (&decode->surface_ready); gst_video_decoder_set_packetized (vdec, FALSE); }
static GstCaps * gst_vaapiencode_get_caps_impl (GstVideoEncoder * venc) { GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (venc); GstCaps *caps; if (plugin->sinkpad_caps) caps = gst_caps_ref (plugin->sinkpad_caps); else { caps = gst_pad_get_pad_template_caps (plugin->sinkpad); } return caps; }
static gboolean gst_vaapidecode_open (GstVideoDecoder * vdec) { GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec); if (!gst_vaapi_plugin_base_open (GST_VAAPI_PLUGIN_BASE (decode))) return FALSE; decode->display_width = 0; decode->display_height = 0; gst_video_info_init (&decode->decoded_info); return TRUE; }
static void gst_vaapiencode_finalize (GObject * object) { GstVaapiEncode *const encode = GST_VAAPIENCODE_CAST (object); gst_vaapiencode_destroy (encode); if (encode->prop_values) { g_ptr_array_unref (encode->prop_values); encode->prop_values = NULL; } gst_vaapi_plugin_base_finalize (GST_VAAPI_PLUGIN_BASE (object)); G_OBJECT_CLASS (gst_vaapiencode_parent_class)->finalize (object); }
static gboolean gst_vaapiencode_open (GstVideoEncoder * venc) { GstVaapiEncode *const encode = GST_VAAPIENCODE_CAST (venc); GstVaapiDisplay *const old_display = GST_VAAPI_PLUGIN_BASE_DISPLAY (encode); gboolean success; if (!gst_vaapi_plugin_base_open (GST_VAAPI_PLUGIN_BASE (encode))) return FALSE; GST_VAAPI_PLUGIN_BASE_DISPLAY (encode) = NULL; success = ensure_display (encode); if (old_display) gst_vaapi_display_unref (old_display); return success; }
static gboolean gst_vaapidecode_set_format (GstVideoDecoder * vdec, GstVideoCodecState * state) { GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (vdec); GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec); if (!gst_vaapi_decode_input_state_replace (decode, state)) return TRUE; if (!gst_vaapidecode_update_sink_caps (decode, state->caps)) return FALSE; if (!gst_vaapi_plugin_base_set_caps (plugin, decode->sinkpad_caps, NULL)) return FALSE; if (!gst_vaapidecode_reset (decode, decode->sinkpad_caps, FALSE)) return FALSE; return TRUE; }
static gboolean gst_vaapidecode_ensure_allowed_srcpad_caps (GstVaapiDecode * decode) { GstCaps *out_caps, *raw_caps; if (decode->allowed_srcpad_caps) return TRUE; if (!GST_VAAPI_PLUGIN_BASE_DISPLAY (decode)) return FALSE; /* Create VA caps */ out_caps = gst_caps_from_string (GST_VAAPI_MAKE_SURFACE_CAPS); if (!out_caps) { GST_WARNING_OBJECT (decode, "failed to create VA/GL source caps"); return FALSE; } #if (USE_GLX || USE_EGL) if (!GST_VAAPI_PLUGIN_BASE_SRC_PAD_CAN_DMABUF (decode) && gst_vaapi_display_has_opengl (GST_VAAPI_PLUGIN_BASE_DISPLAY (decode))) { out_caps = gst_caps_make_writable (out_caps); gst_caps_append (out_caps, gst_caps_from_string (GST_VAAPI_MAKE_GLTEXUPLOAD_CAPS)); } #endif out_caps = gst_caps_make_writable (out_caps); gst_caps_append (out_caps, gst_caps_from_string (GST_VAAPI_MAKE_DMABUF_CAPS)); raw_caps = gst_vaapi_plugin_base_get_allowed_srcpad_raw_caps (GST_VAAPI_PLUGIN_BASE (decode), GST_VIDEO_INFO_FORMAT (&decode->decoded_info)); if (!raw_caps) { gst_caps_unref (out_caps); GST_WARNING_OBJECT (decode, "failed to create raw sink caps"); return FALSE; } out_caps = gst_caps_make_writable (out_caps); gst_caps_append (out_caps, gst_caps_copy (raw_caps)); decode->allowed_srcpad_caps = out_caps; GST_INFO_OBJECT (decode, "allowed srcpad caps: %" GST_PTR_FORMAT, decode->allowed_srcpad_caps); return TRUE; }
static gboolean gst_vaapidecode_src_query (GstVideoDecoder * vdec, GstQuery * query) { gboolean ret = TRUE; GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec); GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (decode); switch (GST_QUERY_TYPE (query)) { case GST_QUERY_CAPS:{ GstCaps *caps, *filter = NULL; GstPad *pad = GST_VIDEO_DECODER_SRC_PAD (vdec); gst_query_parse_caps (query, &filter); caps = gst_pad_get_pad_template_caps (pad); if (filter) { GstCaps *tmp = caps; caps = gst_caps_intersect_full (filter, tmp, GST_CAPS_INTERSECT_FIRST); gst_caps_unref (tmp); } gst_query_set_caps_result (query, caps); gst_caps_unref (caps); break; } case GST_QUERY_CONTEXT:{ ret = gst_vaapi_handle_context_query (query, plugin->display); break; } default:{ #if GST_CHECK_VERSION(1,4,0) ret = GST_VIDEO_DECODER_CLASS (gst_vaapidecode_parent_class)->src_query (vdec, query); #else GstPad *pad = GST_VIDEO_DECODER_SRC_PAD (vdec); GstObject *parent = gst_pad_get_parent (pad); ret = plugin->srcpad_query (pad, parent, query); if (parent) gst_object_unref (parent); #endif break; } } return ret; }
static gboolean gst_vaapiencode_query (GstPad * pad, GstObject * parent, GstQuery * query) { GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (gst_pad_get_parent_element (pad)); gboolean success; GST_INFO_OBJECT (plugin, "query type %s", GST_QUERY_TYPE_NAME (query)); if (gst_vaapi_reply_to_query (query, plugin->display)) success = TRUE; else if (GST_PAD_IS_SINK (pad)) success = plugin->sinkpad_query (plugin->sinkpad, parent, query); else success = plugin->srcpad_query (plugin->srcpad, parent, query); gst_object_unref (plugin); return success; }
static void gst_vaapi_find_gl_context (GstElement * element) { #if USE_GST_GL_HELPERS GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (element); /* if the element is vaapisink or any vaapi encoder it doesn't need * to know a GstGLContext in order to create an appropriate * GstVaapiDisplay. Let's them to choose their own * GstVaapiDisplay */ if (GST_IS_VIDEO_SINK (element) || GST_IS_VIDEO_ENCODER (element)) return; if (!gst_gl_ensure_element_data (plugin, (GstGLDisplay **) & plugin->gl_display, (GstGLContext **) & plugin->gl_other_context)) goto no_valid_gl_display; gst_vaapi_find_gl_local_context (element, &plugin->gl_context); if (plugin->gl_context) { gst_vaapi_plugin_base_set_srcpad_can_dmabuf (plugin, plugin->gl_context); } else { GstObject *gl_context; gl_context = gst_vaapi_plugin_base_create_gl_context (plugin); if (gl_context) { gst_vaapi_plugin_base_set_gl_context (plugin, gl_context); gst_object_unref (gl_context); } } /* ERRORS */ no_valid_gl_display: { GST_INFO_OBJECT (plugin, "No valid GL display found"); gst_object_replace (&plugin->gl_display, NULL); gst_object_replace (&plugin->gl_other_context, NULL); return; } #endif }
static gboolean gst_vaapidecode_start (GstVideoDecoder * vdec) { GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec); GstVaapiDisplay *const old_display = GST_VAAPI_PLUGIN_BASE_DISPLAY (decode); gboolean success; /* Let GstVideoContext ask for a proper display to its neighbours */ /* Note: steal old display that may be allocated from get_caps() so that to retain a reference to it, thus avoiding extra initialization steps if we turn out to simply re-use the existing (cached) VA display */ GST_VAAPI_PLUGIN_BASE_DISPLAY (decode) = NULL; success = gst_vaapi_plugin_base_ensure_display (GST_VAAPI_PLUGIN_BASE (decode)); if (old_display) gst_vaapi_display_unref (old_display); return success; }
gboolean gst_vaapi_handle_context_query (GstElement * element, GstQuery * query) { GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (element); const gchar *type = NULL; GstContext *context, *old_context; g_return_val_if_fail (query != NULL, FALSE); #if USE_GST_GL_HELPERS if (plugin->gl_display && plugin->gl_context && plugin->gl_other_context) { if (gst_gl_handle_context_query (element, query, (GstGLDisplay *) plugin->gl_display, (GstGLContext *) plugin->gl_context, (GstGLContext *) plugin->gl_other_context)) return TRUE; } #endif if (!plugin->display) return FALSE; if (!gst_query_parse_context_type (query, &type)) return FALSE; if (g_strcmp0 (type, GST_VAAPI_DISPLAY_CONTEXT_TYPE_NAME)) return FALSE; gst_query_parse_context (query, &old_context); if (old_context) { context = gst_context_copy (old_context); gst_vaapi_video_context_set_display (context, plugin->display); } else { context = gst_vaapi_video_context_new_with_display (plugin->display, FALSE); } gst_query_set_context (query, context); gst_context_unref (context); return TRUE; }
static gboolean gst_vaapidecode_negotiate (GstVaapiDecode * decode) { GstVideoDecoder *const vdec = GST_VIDEO_DECODER (decode); GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (vdec); GST_DEBUG_OBJECT (decode, "input codec state changed: renegotiating"); GST_VIDEO_DECODER_STREAM_LOCK (vdec); if (!gst_vaapi_plugin_base_set_caps (plugin, decode->sinkpad_caps, NULL)) return FALSE; if (!gst_vaapidecode_update_src_caps (decode)) return FALSE; if (!gst_vaapi_plugin_base_set_caps (plugin, NULL, decode->srcpad_caps)) return FALSE; GST_VIDEO_DECODER_STREAM_UNLOCK (vdec); if (!gst_video_decoder_negotiate (vdec)) return FALSE; return TRUE; }
gboolean gst_vaapi_ensure_display (GstElement * element, GstVaapiDisplayType type) { GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (element); GstVaapiDisplay *display = NULL; g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE); if (gst_vaapi_video_context_prepare (element, &plugin->display)) { /* Neighbour found and it updated the display */ if (gst_vaapi_plugin_base_has_display_type (plugin, type)) return TRUE; } /* Query for a local GstGL context. If it's found, it will be used * to create the VA display */ if (!plugin->gl_context) gst_vaapi_find_gl_context (element); /* If no neighboor, or application not interested, use system default */ if (plugin->gl_context) { display = gst_vaapi_create_display_from_gl_context (plugin->gl_context); /* Cannot instantiate VA display based on GL context. Reset the * requested display type to ANY to try again */ if (!display) gst_vaapi_plugin_base_set_display_type (plugin, GST_VAAPI_DISPLAY_TYPE_ANY); } if (!display) display = gst_vaapi_create_display (type, plugin->display_name); if (!display) return FALSE; gst_vaapi_video_context_propagate (element, display); gst_object_unref (display); return TRUE; }
static gboolean gst_vaapiencode_set_format (GstVideoEncoder * venc, GstVideoCodecState * state) { GstVaapiEncode *const encode = GST_VAAPIENCODE_CAST (venc); g_return_val_if_fail (state->caps != NULL, FALSE); if (!ensure_encoder (encode)) return FALSE; if (!set_codec_state (encode, state)) return FALSE; if (!gst_vaapi_plugin_base_set_caps (GST_VAAPI_PLUGIN_BASE (encode), state->caps, NULL)) return FALSE; if (encode->input_state) gst_video_codec_state_unref (encode->input_state); encode->input_state = gst_video_codec_state_ref (state); encode->input_state_changed = TRUE; return gst_pad_start_task (GST_VAAPI_PLUGIN_BASE_SRC_PAD (encode), (GstTaskFunction) gst_vaapiencode_buffer_loop, encode, NULL); }
static inline gboolean gst_vaapidecode_ensure_display (GstVaapiDecode * decode) { return gst_vaapi_plugin_base_ensure_display (GST_VAAPI_PLUGIN_BASE (decode)); }