/** * 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; } }
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; }
static gboolean gst_mpeg2dec_decide_allocation (GstVideoDecoder * decoder, GstQuery * query) { GstMpeg2dec *dec = GST_MPEG2DEC (decoder); GstVideoCodecState *state; GstBufferPool *pool; guint size, min, max; GstStructure *config; GstAllocator *allocator; GstAllocationParams params; gboolean update_allocator; /* 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); if (allocator) gst_object_unref (allocator); /* 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)) return FALSE; state = gst_video_decoder_get_output_state (decoder); gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max); dec->has_cropping = FALSE; 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); dec->has_cropping = gst_query_find_allocation_meta (query, GST_VIDEO_CROP_META_API_TYPE, NULL); } if (dec->has_cropping) { GstCaps *caps; /* Calculate uncropped size */ size = MAX (size, dec->decoded_info.size); caps = gst_video_info_to_caps (&dec->decoded_info); gst_buffer_pool_config_set_params (config, caps, size, min, max); gst_caps_unref (caps); } gst_buffer_pool_set_config (pool, config); gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max); gst_object_unref (pool); gst_video_codec_state_unref (state); return TRUE; }
static gboolean gst_msdkdec_decide_allocation (GstVideoDecoder * decoder, GstQuery * query) { GstMsdkDec *thiz = GST_MSDKDEC (decoder); GstBufferPool *pool = NULL; GstStructure *pool_config = NULL; GstCaps *pool_caps /*, *negotiated_caps */ ; guint size, min_buffers, max_buffers; if (!GST_VIDEO_DECODER_CLASS (parent_class)->decide_allocation (decoder, query)) return FALSE; /* Get the buffer pool config decided by the base class. The base class ensures that there will always be at least a 0th pool in the query. */ gst_query_parse_nth_allocation_pool (query, 0, &pool, NULL, NULL, NULL); pool_config = gst_buffer_pool_get_config (pool); /* Get the caps of pool and increase the min and max buffers by async_depth, * we will always have that number of decode operations in-flight */ gst_buffer_pool_config_get_params (pool_config, &pool_caps, &size, &min_buffers, &max_buffers); min_buffers += thiz->async_depth; if (max_buffers) max_buffers += thiz->async_depth; /* increase the min_buffers by 1 for smooth display in render pipeline */ min_buffers += 1; /* this will get updated with msdk requirement */ thiz->min_prealloc_buffers = min_buffers; if (_gst_caps_has_feature (pool_caps, GST_CAPS_FEATURE_MEMORY_DMABUF)) { GST_INFO_OBJECT (decoder, "This MSDK decoder uses DMABuf memory"); thiz->use_video_memory = thiz->use_dmabuf = TRUE; } /* Initialize MSDK decoder before new bufferpool tries to alloc each buffer, * which requires information of frame allocation. * No effect if already initialized. */ if (!gst_msdkdec_init_decoder (thiz)) return FALSE; /* get the updated min_buffers which account the msdk requirement too */ min_buffers = thiz->min_prealloc_buffers; /* Decoder always use its own pool. So we create a pool if msdk apis * previously requested for allocation (do_realloc = TRUE) */ if (thiz->do_realloc || !thiz->pool) { if (thiz->pool) gst_object_replace ((GstObject **) & thiz->pool, NULL); GST_INFO_OBJECT (decoder, "create new MSDK bufferpool"); thiz->pool = gst_msdkdec_create_buffer_pool (thiz, &thiz->output_info, min_buffers); if (!thiz->pool) goto failed_to_create_pool; } if (gst_query_find_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL) && gst_buffer_pool_has_option (pool, GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT)) { GstStructure *config; GstAllocator *allocator; /* If downstream supports video meta and video alignment, * we can replace our own msdk bufferpool and use it */ /* Remove downstream's pool */ gst_structure_free (pool_config); gst_object_unref (pool); pool = gst_object_ref (thiz->pool); /* Set the allocator of new msdk bufferpool */ config = gst_buffer_pool_get_config (GST_BUFFER_POOL_CAST (pool)); if (gst_buffer_pool_config_get_allocator (config, &allocator, NULL)) gst_query_set_nth_allocation_param (query, 0, allocator, NULL); gst_structure_free (config); } else { /* Unfortunately, dowstream doesn't have videometa or alignment support, * we keep msdk pool as a side-pool that will be decoded into and * then copied from. */ GST_INFO_OBJECT (decoder, "Keep MSDK bufferpool as a side-pool"); /* Update params to downstream's pool */ gst_buffer_pool_config_set_params (pool_config, pool_caps, size, min_buffers, max_buffers); if (!gst_buffer_pool_set_config (pool, pool_config)) goto error_set_config; gst_video_info_from_caps (&thiz->non_msdk_pool_info, pool_caps); /* update width and height with actual negotiated values */ GST_VIDEO_INFO_WIDTH (&thiz->non_msdk_pool_info) = GST_VIDEO_INFO_WIDTH (&thiz->output_info); GST_VIDEO_INFO_HEIGHT (&thiz->non_msdk_pool_info) = GST_VIDEO_INFO_HEIGHT (&thiz->output_info); } gst_query_set_nth_allocation_pool (query, 0, pool, size, min_buffers, max_buffers); if (pool) gst_object_unref (pool); return TRUE; failed_to_create_pool: GST_ERROR_OBJECT (decoder, "failed to set buffer pool config"); if (pool) gst_object_unref (pool); return FALSE; error_set_config: GST_ERROR_OBJECT (decoder, "failed to set buffer pool config"); if (pool) gst_object_unref (pool); return FALSE; }