static gboolean gst_mpeg2dec_decide_allocation (GstVideoDecoder * decoder, GstQuery * query) { GstMpeg2dec *dec = GST_MPEG2DEC (decoder); GstBufferPool *pool; guint size, min, max; GstStructure *config, *down_config = NULL; GstAllocator *allocator; GstAllocationParams params; gboolean update_allocator; gboolean has_videometa = FALSE; GstCaps *caps; /* Get rid of ancient pool */ if (dec->downstream_pool) { gst_buffer_pool_set_active (dec->downstream_pool, FALSE); gst_object_unref (dec->downstream_pool); dec->downstream_pool = NULL; } /* Get negotiated allocation caps */ gst_query_parse_allocation (query, &caps, NULL); /* Set allocation parameters to guarantee 16-byte aligned output buffers */ if (gst_query_get_n_allocation_params (query) > 0) { gst_query_parse_nth_allocation_param (query, 0, &allocator, ¶ms); update_allocator = TRUE; } else { allocator = NULL; gst_allocation_params_init (¶ms); update_allocator = FALSE; } params.align = MAX (params.align, 15); if (update_allocator) gst_query_set_nth_allocation_param (query, 0, allocator, ¶ms); else gst_query_add_allocation_param (query, allocator, ¶ms); /* Now chain up to the parent class to guarantee that we can * get a buffer pool from the query */ if (!GST_VIDEO_DECODER_CLASS (parent_class)->decide_allocation (decoder, query)) { if (allocator) gst_object_unref (allocator); return FALSE; } gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max); config = gst_buffer_pool_get_config (pool); if (gst_query_find_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL)) { gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META); has_videometa = TRUE; } if (dec->need_alignment) { /* If downstream does not support video meta, we will have to copy, keep * the downstream pool to avoid double copying */ if (!has_videometa) { dec->downstream_pool = pool; pool = NULL; down_config = config; config = NULL; min = 2; max = 0; } /* In case downstream support video meta, but the downstream pool does not * have alignment support, discard downstream pool and use video pool */ else if (!gst_buffer_pool_has_option (pool, GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT)) { gst_object_unref (pool); pool = NULL; gst_structure_free (config); config = NULL; } if (!pool) pool = gst_mpeg2dec_create_generic_pool (allocator, ¶ms, caps, size, min, max, &config); gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT); gst_buffer_pool_config_set_video_alignment (config, &dec->valign); } if (allocator) gst_object_unref (allocator); /* If we are copying out, we'll need to setup and activate the other pool */ if (dec->downstream_pool) { if (!gst_buffer_pool_set_config (dec->downstream_pool, down_config)) { down_config = gst_buffer_pool_get_config (dec->downstream_pool); if (!gst_buffer_pool_config_validate_params (down_config, caps, size, min, max)) { gst_structure_free (down_config); goto config_failed; } if (!gst_buffer_pool_set_config (dec->downstream_pool, down_config)) goto config_failed; } if (!gst_buffer_pool_set_active (dec->downstream_pool, TRUE)) goto activate_failed; } /* Now configure the pool, if the pool had made some changes, it will * return FALSE. Validate the changes ...*/ if (!gst_buffer_pool_set_config (pool, config)) { config = gst_buffer_pool_get_config (pool); /* Check basic params */ if (!gst_buffer_pool_config_validate_params (config, caps, size, min, max)) { gst_structure_free (config); goto config_failed; } /* If needed, check that resulting alignment is still valid */ if (dec->need_alignment) { GstVideoAlignment valign; if (!gst_buffer_pool_config_get_video_alignment (config, &valign)) { gst_structure_free (config); goto config_failed; } if (valign.padding_left != 0 || valign.padding_top != 0 || valign.padding_right < dec->valign.padding_right || valign.padding_bottom < dec->valign.padding_bottom) { gst_structure_free (config); goto config_failed; } } if (!gst_buffer_pool_set_config (pool, config)) goto config_failed; } /* For external pools, we need to check strides */ if (!GST_IS_VIDEO_BUFFER_POOL (pool) && has_videometa) { GstBuffer *buffer; const GstVideoFormatInfo *finfo; GstVideoMeta *vmeta; gint uv_stride; if (!gst_buffer_pool_set_active (pool, TRUE)) goto activate_failed; if (gst_buffer_pool_acquire_buffer (pool, &buffer, NULL) != GST_FLOW_OK) { gst_buffer_pool_set_active (pool, FALSE); goto acquire_failed; } vmeta = gst_buffer_get_video_meta (buffer); finfo = gst_video_format_get_info (vmeta->format); /* Check that strides are compatible. In this case, we can scale the * stride directly since all the pixel strides for the formats we support * is 1 */ uv_stride = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (finfo, 1, vmeta->stride[0]); if (uv_stride != vmeta->stride[1] || uv_stride != vmeta->stride[2]) { gst_buffer_pool_set_active (pool, FALSE); gst_object_unref (pool); pool = gst_mpeg2dec_create_generic_pool (allocator, ¶ms, caps, size, min, max, &config); if (dec->need_alignment) { gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT); gst_buffer_pool_config_set_video_alignment (config, &dec->valign); } /* Generic pool don't fail on _set_config() */ gst_buffer_pool_set_config (pool, config); } gst_buffer_unref (buffer); } gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max); gst_object_unref (pool); return TRUE; config_failed: gst_object_unref (pool); GST_ELEMENT_ERROR (dec, RESOURCE, SETTINGS, ("Failed to configure buffer pool"), ("Configuration is most likely invalid, please report this issue.")); return FALSE; activate_failed: gst_object_unref (pool); GST_ELEMENT_ERROR (dec, RESOURCE, SETTINGS, ("Failed to activate buffer pool"), (NULL)); return FALSE; acquire_failed: gst_object_unref (pool); GST_ELEMENT_ERROR (dec, RESOURCE, SETTINGS, ("Failed to acquire a buffer"), (NULL)); return FALSE; }
/** * gst_vaapi_plugin_base_create_pool: * @plugin: a #GstVaapiPluginBase * @caps: the initial #GstCaps for the resulting buffer pool * @size: the size of each buffer, not including prefix and padding * @options: a set of #GstVaapiVideoBufferPoolOption encoded as bit-wise * @allocator: (allow-none): the #GstAllocator to use or %NULL * * Create an instance of #GstVaapiVideoBufferPool * * Returns: (transfer full): a new allocated #GstBufferPool **/ static GstBufferPool * gst_vaapi_plugin_base_create_pool (GstVaapiPluginBase * plugin, GstCaps * caps, gsize size, guint min_buffers, guint max_buffers, guint options, GstAllocator * allocator) { GstBufferPool *pool; GstStructure *config; if (!(pool = gst_vaapi_video_buffer_pool_new (plugin->display))) goto error_create_pool; config = gst_buffer_pool_get_config (pool); gst_buffer_pool_config_set_params (config, caps, size, min_buffers, max_buffers); gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VAAPI_VIDEO_META); if (options & GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_VIDEO_META) { gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META); } if (options & GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT) { gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT); } #if (USE_GLX || USE_EGL) if (options & GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_GL_TEXTURE_UPLOAD) { gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_GL_TEXTURE_UPLOAD_META); } #endif if (allocator) gst_buffer_pool_config_set_allocator (config, allocator, NULL); if (!gst_buffer_pool_set_config (pool, config)) { config = gst_buffer_pool_get_config (pool); if (!gst_buffer_pool_config_validate_params (config, caps, size, min_buffers, max_buffers)) { gst_structure_free (config); goto error_pool_config; } if (!gst_buffer_pool_set_config (pool, config)) goto error_pool_config; } return pool; /* ERRORS */ error_create_pool: { GST_ERROR_OBJECT (plugin, "failed to create buffer pool"); return NULL; } error_pool_config: { gst_object_unref (pool); GST_ELEMENT_ERROR (plugin, RESOURCE, SETTINGS, ("Failed to configure the buffer pool"), ("Configuration is most likely invalid, please report this issue.")); return NULL; } }
/** * 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, guint feature) { GstCaps *caps = NULL; GstBufferPool *pool; GstStructure *config; GstVideoInfo vi; guint size, min, max; gboolean update_pool = FALSE; gboolean has_video_meta = FALSE; gboolean has_video_alignment = FALSE; #if (USE_GLX || USE_EGL) gboolean has_texture_upload_meta = FALSE; guint idx; #endif g_return_val_if_fail (plugin->display != NULL, FALSE); gst_query_parse_allocation (query, &caps, NULL); /* We don't need any GL context beyond this point if not requested so explicitly through GstVideoGLTextureUploadMeta */ gst_object_replace (&plugin->gl_context, NULL); if (!caps) goto error_no_caps; if (!feature) feature = gst_vaapi_find_preferred_caps_feature (plugin->srcpad, GST_VIDEO_FORMAT_ENCODED, NULL); has_video_meta = gst_query_find_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL); #if (USE_GLX || USE_EGL) has_texture_upload_meta = gst_query_find_allocation_meta (query, GST_VIDEO_GL_TEXTURE_UPLOAD_META_API_TYPE, &idx) && (feature == GST_VAAPI_CAPS_FEATURE_GL_TEXTURE_UPLOAD_META); #if USE_GST_GL_HELPERS if (has_texture_upload_meta) { 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_GL_TYPE_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; gst_video_info_init (&vi); gst_video_info_from_caps (&vi, caps); if (GST_VIDEO_INFO_FORMAT (&vi) == GST_VIDEO_FORMAT_ENCODED) gst_video_info_set_format (&vi, GST_VIDEO_FORMAT_I420, GST_VIDEO_INFO_WIDTH (&vi), GST_VIDEO_INFO_HEIGHT (&vi)); 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, vi.size); if (pool) { /* Check whether downstream element proposed a bufferpool but did not provide a correct propose_allocation() implementation */ has_video_alignment = gst_buffer_pool_has_option (pool, GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT); } } else { pool = NULL; size = vi.size; min = max = 0; } /* GstVaapiVideoMeta is mandatory, and this implies VA surface memory */ if (!pool || !gst_buffer_pool_has_option (pool, GST_BUFFER_POOL_OPTION_VAAPI_VIDEO_META)) { GST_INFO_OBJECT (plugin, "%s. Making a new pool", pool == NULL ? "No pool" : "Pool hasn't GstVaapiVideoMeta"); if (pool) gst_object_unref (pool); pool = gst_vaapi_video_buffer_pool_new (plugin->display); if (!pool) goto error_create_pool; config = gst_buffer_pool_get_config (pool); gst_buffer_pool_config_set_params (config, caps, size, min, max); gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VAAPI_VIDEO_META); if (!gst_buffer_pool_set_config (pool, config)) { config = gst_buffer_pool_get_config (pool); if (!gst_buffer_pool_config_validate_params (config, caps, size, min, max)) { gst_structure_free (config); goto config_failed; } if (!gst_buffer_pool_set_config (pool, config)) goto config_failed; } } /* Check whether GstVideoMeta, or GstVideoAlignment, is needed (raw video) */ if (has_video_meta) { if (!gst_vaapi_plugin_base_set_pool_config (pool, GST_BUFFER_POOL_OPTION_VIDEO_META)) goto config_failed; } else if (has_video_alignment) { if (!gst_vaapi_plugin_base_set_pool_config (pool, GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT)) goto config_failed; } /* GstVideoGLTextureUploadMeta (OpenGL) */ #if (USE_GLX || USE_EGL) if (has_texture_upload_meta) { if (!gst_vaapi_plugin_base_set_pool_config (pool, GST_BUFFER_POOL_OPTION_VIDEO_GL_TEXTURE_UPLOAD_META)) goto config_failed; } #endif 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); 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_ensure_display: { GST_ERROR_OBJECT (plugin, "failed to ensure display of type %d", plugin->display_type_req); return FALSE; } error_create_pool: { GST_ERROR_OBJECT (plugin, "failed to create buffer pool"); return FALSE; } config_failed: { if (pool) gst_object_unref (pool); GST_ELEMENT_ERROR (plugin, RESOURCE, SETTINGS, ("Failed to configure the buffer pool"), ("Configuration is most likely invalid, please report this issue.")); return FALSE; } }