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 gboolean ensure_srcpad_allocator (GstVaapiPluginBase * plugin, GstVideoInfo * vinfo, GstCaps * caps) { gboolean different_caps; const GstVideoInfo *image_info; GstVaapiImageUsageFlags usage_flag = GST_VAAPI_IMAGE_USAGE_FLAG_NATIVE_FORMATS; if (!reset_allocator (plugin->srcpad_allocator, vinfo)) goto valid_allocator; plugin->srcpad_allocator = NULL; if (caps && gst_caps_is_video_raw (caps)) { GstAllocator *allocator = create_dmabuf_srcpad_allocator (plugin, vinfo, !plugin->srcpad_can_dmabuf); if (!allocator && plugin->enable_direct_rendering) { usage_flag = GST_VAAPI_IMAGE_USAGE_FLAG_DIRECT_RENDER; GST_INFO_OBJECT (plugin, "enabling direct rendering in source allocator"); } plugin->srcpad_allocator = allocator; } else if (caps && gst_vaapi_caps_feature_contains (caps, GST_VAAPI_CAPS_FEATURE_DMABUF)) { plugin->srcpad_allocator = create_dmabuf_srcpad_allocator (plugin, vinfo, FALSE); if (!plugin->srcpad_allocator) goto error_create_allocator; } if (!plugin->srcpad_allocator) { plugin->srcpad_allocator = gst_vaapi_video_allocator_new (plugin->display, vinfo, 0, usage_flag); } if (!plugin->srcpad_allocator) goto error_create_allocator; valid_allocator: image_info = gst_allocator_get_vaapi_video_info (plugin->srcpad_allocator, NULL); g_assert (image_info); /* both allocators ought set its image * info */ /* update the size with the one generated by the allocator */ GST_VIDEO_INFO_SIZE (vinfo) = GST_VIDEO_INFO_SIZE (image_info); /* the received caps are the "allocation caps" which may be * different from the "negotiation caps". In this case, we should * indicate the allocator to store the negotiation caps since they * are the one should be used for frame mapping with GstVideoMeta */ different_caps = GST_IS_VIDEO_DECODER (plugin) && plugin->srcpad_caps && !gst_caps_is_strictly_equal (plugin->srcpad_caps, caps); if (different_caps) { guint i; GstVideoInfo vi = plugin->srcpad_info; /* update the planes and the size with the allocator image/surface * info, but not the resolution */ for (i = 0; i < GST_VIDEO_INFO_N_PLANES (image_info); i++) { GST_VIDEO_INFO_PLANE_OFFSET (&vi, i) = GST_VIDEO_INFO_PLANE_OFFSET (image_info, i); GST_VIDEO_INFO_PLANE_STRIDE (&vi, i) = GST_VIDEO_INFO_PLANE_STRIDE (image_info, i); } GST_VIDEO_INFO_SIZE (&vi) = GST_VIDEO_INFO_SIZE (image_info); gst_allocator_set_vaapi_negotiated_video_info (plugin->srcpad_allocator, &vi); } return TRUE; /* ERRORS */ error_create_allocator: { GST_ERROR_OBJECT (plugin, "failed to create src pad's allocator"); return FALSE; } }
/** * gst_vaapi_plugin_base_decide_allocation: * @plugin: a #GstVaapiPluginBase * @query: the allocation query to parse * @feature: the desired #GstVaapiCapsFeature, or zero to find the * preferred one * * Decides allocation parameters for the downstream elements. * * Returns: %TRUE if successful, %FALSE otherwise. */ gboolean gst_vaapi_plugin_base_decide_allocation (GstVaapiPluginBase * plugin, GstQuery * query) { GstCaps *caps = NULL; GstBufferPool *pool; GstVideoInfo vi; guint size, min, max, pool_options; gboolean update_pool = FALSE, update_allocator = FALSE; #if (USE_GLX || USE_EGL) guint idx; #endif gst_query_parse_allocation (query, &caps, NULL); if (!caps) goto error_no_caps; pool_options = 0; if (gst_query_find_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL)) pool_options |= GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_VIDEO_META; #if (USE_GLX || USE_EGL) if (gst_query_find_allocation_meta (query, GST_VIDEO_GL_TEXTURE_UPLOAD_META_API_TYPE, &idx) && gst_vaapi_caps_feature_contains (caps, GST_VAAPI_CAPS_FEATURE_GL_TEXTURE_UPLOAD_META)) pool_options |= GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_GL_TEXTURE_UPLOAD; #if USE_GST_GL_HELPERS if (!plugin->gl_context && (pool_options & GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_GL_TEXTURE_UPLOAD)) { const GstStructure *params; GstObject *gl_context; gst_query_parse_nth_allocation_meta (query, idx, ¶ms); if (params) { if (gst_structure_get (params, "gst.gl.GstGLContext", GST_TYPE_GL_CONTEXT, &gl_context, NULL) && gl_context) { gst_vaapi_plugin_base_set_gl_context (plugin, gl_context); gst_object_unref (gl_context); } } } #endif #endif /* Make sure the display we pass down to the buffer pool is actually the expected one, especially when the downstream element requires a GLX or EGL display */ if (!gst_vaapi_plugin_base_ensure_display (plugin)) goto error_ensure_display; if (!gst_video_info_from_caps (&vi, caps)) goto error_invalid_caps; gst_video_info_force_nv12_if_encoded (&vi); if (gst_query_get_n_allocation_params (query) > 0) update_allocator = TRUE; if (gst_query_get_n_allocation_pools (query) > 0) { gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max); update_pool = TRUE; size = MAX (size, GST_VIDEO_INFO_SIZE (&vi)); if (pool) { /* Check whether downstream element proposed a bufferpool but did not provide a correct propose_allocation() implementation */ if (gst_buffer_pool_has_option (pool, GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT)) pool_options |= GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT; /* GstVaapiVideoMeta is mandatory, and this implies VA surface memory */ if (!gst_buffer_pool_has_option (pool, GST_BUFFER_POOL_OPTION_VAAPI_VIDEO_META)) { GST_INFO_OBJECT (plugin, "ignoring non-VAAPI pool: %" GST_PTR_FORMAT, pool); g_clear_object (&pool); } } } else { pool = NULL; size = GST_VIDEO_INFO_SIZE (&vi); min = max = 0; } if (!pool) { if (!ensure_srcpad_allocator (plugin, &vi, caps)) goto error; pool = gst_vaapi_plugin_base_create_pool (plugin, caps, size, min, max, pool_options, plugin->srcpad_allocator); if (!pool) goto error; } if (update_pool) gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max); else gst_query_add_allocation_pool (query, pool, size, min, max); if (update_allocator) gst_query_set_nth_allocation_param (query, 0, plugin->srcpad_allocator, NULL); else gst_query_add_allocation_param (query, plugin->srcpad_allocator, NULL); g_clear_object (&plugin->srcpad_buffer_pool); plugin->srcpad_buffer_pool = pool; return TRUE; /* ERRORS */ error_no_caps: { GST_ERROR_OBJECT (plugin, "no caps specified"); return FALSE; } error_invalid_caps: { GST_ERROR_OBJECT (plugin, "invalid caps %" GST_PTR_FORMAT, caps); return FALSE; } error_ensure_display: { GST_ERROR_OBJECT (plugin, "failed to ensure display of type %d", plugin->display_type_req); return FALSE; } error: { /* error message already sent */ return FALSE; } }
GstVaapiCapsFeature gst_vaapi_find_preferred_caps_feature (GstPad * pad, GstCaps * allowed_caps, GstVideoFormat * out_format_ptr) { GstVaapiCapsFeature feature = GST_VAAPI_CAPS_FEATURE_NOT_NEGOTIATED; guint i, j, num_structures; GstCaps *peer_caps, *out_caps = NULL, *caps = NULL; static const guint feature_list[] = { GST_VAAPI_CAPS_FEATURE_VAAPI_SURFACE, GST_VAAPI_CAPS_FEATURE_DMABUF, GST_VAAPI_CAPS_FEATURE_GL_TEXTURE_UPLOAD_META, GST_VAAPI_CAPS_FEATURE_SYSTEM_MEMORY, }; /* query with no filter */ peer_caps = gst_pad_peer_query_caps (pad, NULL); if (!peer_caps) goto cleanup; if (gst_caps_is_empty (peer_caps)) goto cleanup; /* filter against our allowed caps */ out_caps = gst_caps_intersect_full (allowed_caps, peer_caps, GST_CAPS_INTERSECT_FIRST); /* default feature */ feature = GST_VAAPI_CAPS_FEATURE_SYSTEM_MEMORY; /* if downstream requests caps ANY, system memory is preferred */ if (gst_caps_is_any (peer_caps)) goto find_format; num_structures = gst_caps_get_size (out_caps); for (i = 0; i < num_structures; i++) { GstCapsFeatures *const features = gst_caps_get_features (out_caps, i); GstStructure *const structure = gst_caps_get_structure (out_caps, i); /* Skip ANY features, we need an exact match for correct evaluation */ if (gst_caps_features_is_any (features)) continue; gst_caps_replace (&caps, NULL); caps = gst_caps_new_full (gst_structure_copy (structure), NULL); if (!caps) continue; gst_caps_set_features (caps, 0, gst_caps_features_copy (features)); for (j = 0; j < G_N_ELEMENTS (feature_list); j++) { if (gst_vaapi_caps_feature_contains (caps, feature_list[j]) && feature < feature_list[j]) { feature = feature_list[j]; break; } } /* Stop at the first match, the caps should already be sorted out by preference order from downstream elements */ if (feature != GST_VAAPI_CAPS_FEATURE_SYSTEM_MEMORY) break; } if (!caps) goto cleanup; find_format: if (out_format_ptr) { GstVideoFormat out_format; GstStructure *structure = NULL; const GValue *format_list; GstCapsFeatures *features; /* if the best feature is SystemMemory, we should choose the * vidoe/x-raw caps in the filtered peer caps set. If not, use * the first caps, which is the preferred by downstream. */ if (feature == GST_VAAPI_CAPS_FEATURE_SYSTEM_MEMORY) { gst_caps_replace (&caps, out_caps); num_structures = gst_caps_get_size (caps); for (i = 0; i < num_structures; i++) { structure = gst_caps_get_structure (caps, i); features = gst_caps_get_features (caps, i); if (!gst_caps_features_is_any (features) && gst_caps_features_contains (features, gst_vaapi_caps_feature_to_string (GST_VAAPI_CAPS_FEATURE_SYSTEM_MEMORY))) break; } } else { structure = gst_caps_get_structure (caps, 0); } if (!structure) goto cleanup; format_list = gst_structure_get_value (structure, "format"); if (!format_list) goto cleanup; out_format = gst_vaapi_find_preferred_format (format_list, *out_format_ptr); if (out_format == GST_VIDEO_FORMAT_UNKNOWN) goto cleanup; *out_format_ptr = out_format; } cleanup: gst_caps_replace (&caps, NULL); gst_caps_replace (&out_caps, NULL); gst_caps_replace (&peer_caps, NULL); return feature; }