#include "gstvaapidecode.h"
#include "gstvaapipluginutil.h"
#include "gstvaapivideobuffer.h"
+#include "gstvaapivideobufferpool.h"
+#include "gstvaapivideomemory.h"
#include <gst/vaapi/gstvaapidecoder_h264.h>
#include <gst/vaapi/gstvaapidecoder_jpeg.h>
{
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),
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
GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
GstVaapiSurfaceProxy *proxy;
GstVaapiDecoderStatus status;
+ GstVaapiVideoMeta *meta;
GstVideoCodecFrame *out_frame;
GstFlowReturn ret;
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);
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);
}
}
+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)
{
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",
#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"
}
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)
{
GstVaapiSink * const sink = GST_VAAPISINK(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);
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);
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,
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