From 551ac4c5b34dccf1ba774a88f189d29caff2415e Mon Sep 17 00:00:00 2001 From: Sreerenj Balachandran Date: Thu, 8 Nov 2012 16:41:22 +0200 Subject: [PATCH] plugins: use new video buffer pools. Use new GstVaapiVideoBufferPool to maintain video buffers. Implement GstBaseSink::propose_allocation() to expose that pool to upstream elements; and also implement GstVideoDecoder::decide_allocation() to actually use that pool (from downstream), if any, or create one. Signed-off-by: Gwenole Beauchesne --- gst/vaapi/gstvaapidecode.c | 104 +++++++++++++++++++++++++++++++++++- gst/vaapi/gstvaapisink.c | 106 ++++++++++++++++++++++++++++++++++++- gst/vaapi/gstvaapisink.h | 2 + 3 files changed, 209 insertions(+), 3 deletions(-) diff --git a/gst/vaapi/gstvaapidecode.c b/gst/vaapi/gstvaapidecode.c index 77c437ba82..dd3327b9fb 100644 --- a/gst/vaapi/gstvaapidecode.c +++ b/gst/vaapi/gstvaapidecode.c @@ -35,6 +35,8 @@ #include "gstvaapidecode.h" #include "gstvaapipluginutil.h" #include "gstvaapivideobuffer.h" +#include "gstvaapivideobufferpool.h" +#include "gstvaapivideomemory.h" #include #include @@ -154,7 +156,7 @@ gst_vaapidecode_update_src_caps(GstVaapiDecode *decode, { GstVideoDecoder * const vdec = GST_VIDEO_DECODER(decode); GstVideoCodecState *state; - GstVideoInfo *vi; + GstVideoInfo *vi, vis; state = gst_video_decoder_set_output_state(vdec, GST_VIDEO_INFO_FORMAT(&ref_state->info), @@ -163,6 +165,12 @@ gst_vaapidecode_update_src_caps(GstVaapiDecode *decode, return FALSE; vi = &state->info; + if (GST_VIDEO_INFO_FORMAT(vi) == GST_VIDEO_FORMAT_ENCODED) { + gst_video_info_init(&vis); + gst_video_info_set_format(&vis, GST_VIDEO_FORMAT_NV12, + GST_VIDEO_INFO_WIDTH(vi), GST_VIDEO_INFO_HEIGHT(vi)); + vi->size = vis.size; + } gst_video_codec_state_unref(state); /* XXX: gst_video_info_to_caps() from GStreamer 0.10 does not @@ -263,6 +271,7 @@ gst_vaapidecode_push_decoded_frames(GstVideoDecoder *vdec) GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec); GstVaapiSurfaceProxy *proxy; GstVaapiDecoderStatus status; + GstVaapiVideoMeta *meta; GstVideoCodecFrame *out_frame; GstFlowReturn ret; @@ -278,10 +287,21 @@ gst_vaapidecode_push_decoded_frames(GstVideoDecoder *vdec) gst_vaapi_surface_proxy_set_user_data(proxy, decode, (GDestroyNotify)gst_vaapidecode_release); +#if GST_CHECK_VERSION(1,0,0) + ret = gst_video_decoder_allocate_output_frame(vdec, out_frame); + if (ret != GST_FLOW_OK) + goto error_create_buffer; + + meta = gst_buffer_get_vaapi_video_meta(out_frame->output_buffer); + if (!meta) + goto error_get_meta; + gst_vaapi_video_meta_set_surface_proxy(meta, proxy); +#else out_frame->output_buffer = gst_vaapi_video_buffer_new_with_surface_proxy(proxy); if (!out_frame->output_buffer) goto error_create_buffer; +#endif } ret = gst_video_decoder_finish_frame(vdec, out_frame); @@ -307,6 +327,13 @@ error_create_buffer: gst_video_codec_frame_unref(out_frame); return GST_FLOW_EOS; } +error_get_meta: + { + GST_ERROR("failed to get vaapi video meta attached to video buffer"); + gst_video_decoder_drop_frame(vdec, out_frame); + gst_video_codec_frame_unref(out_frame); + return GST_FLOW_EOS; + } error_commit_buffer: { GST_DEBUG("video sink rejected the video buffer (error %d)", ret); @@ -345,6 +372,78 @@ error_flush: } } +static gboolean +gst_vaapidecode_decide_allocation(GstVideoDecoder *vdec, GstQuery *query) +{ + GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec); + GstCaps *caps = NULL; + GstBufferPool *pool; + GstStructure *config; + GstVideoInfo vi; + guint size, min, max; + gboolean need_pool, update_pool; + + gst_query_parse_allocation(query, &caps, &need_pool); + + if (!caps) + goto error_no_caps; + + 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_NV12, + GST_VIDEO_INFO_WIDTH(&vi), GST_VIDEO_INFO_HEIGHT(&vi)); + + g_return_val_if_fail(decode->display != NULL, FALSE); + + if (gst_query_get_n_allocation_pools(query) > 0) { + gst_query_parse_nth_allocation_pool(query, 0, &pool, &size, &min, &max); + size = MAX(size, vi.size); + update_pool = TRUE; + } + else { + pool = NULL; + size = vi.size; + min = max = 0; + update_pool = FALSE; + } + + if (!pool || !gst_buffer_pool_has_option(pool, + GST_BUFFER_POOL_OPTION_VAAPI_VIDEO_META)) { + GST_INFO("no pool or doesn't support GstVaapiVideoMeta, " + "making new pool"); + pool = gst_vaapi_video_buffer_pool_new(decode->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); + gst_buffer_pool_set_config(pool, config); + } + + 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 (pool) + g_object_unref(pool); + return TRUE; + + /* ERRORS */ +error_no_caps: + { + GST_ERROR("no caps specified"); + return FALSE; + } +error_create_pool: + { + GST_ERROR("failed to create buffer pool"); + return FALSE; + } +} + static inline gboolean gst_vaapidecode_ensure_display(GstVaapiDecode *decode) { @@ -566,6 +665,9 @@ gst_vaapidecode_class_init(GstVaapiDecodeClass *klass) vdec_class->handle_frame = GST_DEBUG_FUNCPTR(gst_vaapidecode_handle_frame); vdec_class->finish = GST_DEBUG_FUNCPTR(gst_vaapidecode_finish); + vdec_class->decide_allocation = + GST_DEBUG_FUNCPTR(gst_vaapidecode_decide_allocation); + gst_element_class_set_static_metadata(element_class, "VA-API decoder", "Codec/Decoder/Video", diff --git a/gst/vaapi/gstvaapisink.c b/gst/vaapi/gstvaapisink.c index 28c61f1279..7393aab3ef 100644 --- a/gst/vaapi/gstvaapisink.c +++ b/gst/vaapi/gstvaapisink.c @@ -70,6 +70,8 @@ #include "gstvaapisink.h" #include "gstvaapipluginutil.h" #include "gstvaapivideometa.h" +#include "gstvaapivideobufferpool.h" +#include "gstvaapivideomemory.h" #define GST_PLUGIN_NAME "vaapisink" #define GST_PLUGIN_DESC "A VA-API based videosink" @@ -588,6 +590,66 @@ end: return success; } +static gboolean +gst_vaapisink_ensure_video_buffer_pool(GstVaapiSink *sink, GstCaps *caps) +{ + GstBufferPool *pool; + GstCaps *pool_caps; + GstStructure *config; + GstVideoInfo vi; + gboolean need_pool; + + if (!gst_vaapisink_ensure_display(sink)) + return FALSE; + + if (sink->video_buffer_pool) { + config = gst_buffer_pool_get_config(sink->video_buffer_pool); + gst_buffer_pool_config_get_params(config, &pool_caps, NULL, NULL, NULL); + need_pool = !gst_caps_is_equal(caps, pool_caps); + gst_structure_free(config); + if (!need_pool) + return TRUE; + g_clear_object(&sink->video_buffer_pool); + sink->video_buffer_size = 0; + } + + pool = gst_vaapi_video_buffer_pool_new(sink->display); + if (!pool) + goto error_create_pool; + + gst_video_info_init(&vi); + gst_video_info_from_caps(&vi, caps); + if (GST_VIDEO_INFO_FORMAT(&vi) == GST_VIDEO_FORMAT_ENCODED) { + GST_DEBUG("assume video buffer pool format is NV12"); + gst_video_info_set_format(&vi, GST_VIDEO_FORMAT_NV12, + GST_VIDEO_INFO_WIDTH(&vi), GST_VIDEO_INFO_HEIGHT(&vi)); + } + sink->video_buffer_size = vi.size; + + config = gst_buffer_pool_get_config(pool); + gst_buffer_pool_config_set_params(config, caps, sink->video_buffer_size, + 0, 0); + gst_buffer_pool_config_add_option(config, + GST_BUFFER_POOL_OPTION_VAAPI_VIDEO_META); + if (!gst_buffer_pool_set_config(pool, config)) + goto error_pool_config; + sink->video_buffer_pool = pool; + return TRUE; + + /* ERRORS */ +error_create_pool: + { + GST_ERROR("failed to create buffer pool"); + return FALSE; + } +error_pool_config: + { + GST_ERROR("failed to reset buffer pool config"); + g_object_unref(pool); + return FALSE; + } +} + static gboolean gst_vaapisink_start(GstBaseSink *base_sink) { @@ -608,6 +670,7 @@ gst_vaapisink_stop(GstBaseSink *base_sink) GstVaapiSink * const sink = GST_VAAPISINK(base_sink); gst_buffer_replace(&sink->video_buffer, NULL); + g_clear_object(&sink->video_buffer_pool); g_clear_object(&sink->window); g_clear_object(&sink->display); g_clear_object(&sink->uploader); @@ -645,6 +708,9 @@ gst_vaapisink_set_caps(GstBaseSink *base_sink, GstCaps *caps) return TRUE; #endif + if (!gst_vaapisink_ensure_video_buffer_pool(sink, caps)) + return FALSE; + if (!gst_video_info_from_caps(&vi, caps)) return FALSE; sink->use_video_raw = GST_VIDEO_INFO_IS_YUV(&vi); @@ -954,7 +1020,41 @@ error: return GST_FLOW_EOS; } -#if !GST_CHECK_VERSION(1,0,0) +#if GST_CHECK_VERSION(1,0,0) +static gboolean +gst_vaapisink_propose_allocation(GstBaseSink *base_sink, GstQuery *query) +{ + GstVaapiSink * const sink = GST_VAAPISINK(base_sink); + GstCaps *caps = NULL; + gboolean need_pool; + + gst_query_parse_allocation(query, &caps, &need_pool); + + if (need_pool) { + if (!caps) + goto error_no_caps; + if (!gst_vaapisink_ensure_video_buffer_pool(sink, caps)) + return FALSE; + gst_query_add_allocation_pool(query, sink->video_buffer_pool, + sink->video_buffer_size, 0, 0); + } + + gst_query_add_allocation_meta(query, + GST_VAAPI_VIDEO_META_API_TYPE, NULL); + gst_query_add_allocation_meta(query, + GST_VIDEO_META_API_TYPE, NULL); + gst_query_add_allocation_meta(query, + GST_VIDEO_OVERLAY_COMPOSITION_META_API_TYPE, NULL); + return TRUE; + + /* ERRORS */ +error_no_caps: + { + GST_ERROR("no caps specified"); + return FALSE; + } +} +#else static GstFlowReturn gst_vaapisink_buffer_alloc( GstBaseSink *base_sink, @@ -1104,7 +1204,9 @@ gst_vaapisink_class_init(GstVaapiSinkClass *klass) basesink_class->preroll = gst_vaapisink_show_frame; basesink_class->render = gst_vaapisink_show_frame; basesink_class->query = gst_vaapisink_query; -#if !GST_CHECK_VERSION(1,0,0) +#if GST_CHECK_VERSION(1,0,0) + basesink_class->propose_allocation = gst_vaapisink_propose_allocation; +#else basesink_class->buffer_alloc = gst_vaapisink_buffer_alloc; #endif diff --git a/gst/vaapi/gstvaapisink.h b/gst/vaapi/gstvaapisink.h index 8db8ac2387..c68efd634b 100644 --- a/gst/vaapi/gstvaapisink.h +++ b/gst/vaapi/gstvaapisink.h @@ -76,6 +76,8 @@ struct _GstVaapiSink { guint window_width; guint window_height; GstVaapiTexture *texture; + GstBufferPool *video_buffer_pool; + guint video_buffer_size; GstBuffer *video_buffer; guint video_width; guint video_height;