[Pkg-gstreamer-commits] [gstreamer-vaapi] 08/176: plugins: add base encoder element.
Vincent Cheng
vcheng at moszumanska.debian.org
Tue Jun 3 08:09:23 UTC 2014
This is an automated email from the git hooks/post-receive script.
vcheng pushed a commit to branch upstream
in repository gstreamer-vaapi.
commit 06ea8ba92b1151a1e603d965dc0e78361cc576c0
Author: Wind Yuan <feng.yuan at intel.com>
Date: Mon Jul 29 13:44:48 2013 +0800
plugins: add base encoder element.
vaapiencode element is based on GstVideoEncoder APIs.
Signed-off-by: Gwenole Beauchesne <gwenole.beauchesne at intel.com>
---
gst/vaapi/Makefile.am | 13 +
gst/vaapi/gstvaapiencode.c | 764 +++++++++++++++++++++++++++++++++++++++++++++
gst/vaapi/gstvaapiencode.h | 100 ++++++
3 files changed, 877 insertions(+)
diff --git a/gst/vaapi/Makefile.am b/gst/vaapi/Makefile.am
index 99c2fac..5c040ec 100644
--- a/gst/vaapi/Makefile.am
+++ b/gst/vaapi/Makefile.am
@@ -56,6 +56,19 @@ libgstvaapi_source_h = \
gstvaapivideometa.h \
$(NULL)
+libgstvaapi_enc_source_c = \
+ gstvaapiencode.c \
+ $(NULL)
+
+libgstvaapi_enc_source_h = \
+ gstvaapiencode.h \
+ $(NULL)
+
+if USE_ENCODERS
+libgstvaapi_source_c += $(libgstvaapi_enc_source_c)
+libgstvaapi_source_h += $(libgstvaapi_enc_source_h)
+endif
+
libgstvaapi_x11_source_c = gstvaapivideoconverter_x11.c
libgstvaapi_x11_source_h = gstvaapivideoconverter_x11.h
diff --git a/gst/vaapi/gstvaapiencode.c b/gst/vaapi/gstvaapiencode.c
new file mode 100644
index 0000000..b484db4
--- /dev/null
+++ b/gst/vaapi/gstvaapiencode.c
@@ -0,0 +1,764 @@
+/*
+ * gstvaapiencode.c - VA-API video encoder
+ *
+ * Copyright (C) 2013 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#include "gst/vaapi/sysdeps.h"
+#include <gst/video/videocontext.h>
+#include <gst/vaapi/gstvaapidisplay.h>
+#include <gst/vaapi/gstvaapiencoder_priv.h>
+#include <gst/vaapi/gstvaapiencoder_objects.h>
+#include "gstvaapiencode.h"
+#include "gstvaapipluginutil.h"
+#include "gstvaapivideometa.h"
+#include "gstvaapivideomemory.h"
+#include "gstvaapivideobufferpool.h"
+
+#define GST_PLUGIN_NAME "vaapiencode"
+#define GST_PLUGIN_DESC "A VA-API based video encoder"
+
+#define GST_VAAPI_ENCODE_FLOW_TIMEOUT GST_FLOW_CUSTOM_SUCCESS
+#define GST_VAAPI_ENCODE_FLOW_MEM_ERROR GST_FLOW_CUSTOM_ERROR
+#define GST_VAAPI_ENCODE_FLOW_CONVERT_ERROR GST_FLOW_CUSTOM_ERROR_1
+#define GST_VAAPI_ENCODE_FLOW_CODEC_DATA_ERROR GST_FLOW_CUSTOM_ERROR_2
+
+typedef struct _GstVaapiEncodeFrameUserData
+{
+ GstVaapiEncObjUserDataHead head;
+ GstBuffer *vaapi_buf;
+} GstVaapiEncodeFrameUserData;
+
+GST_DEBUG_CATEGORY_STATIC (gst_vaapiencode_debug);
+
+#define GST_CAT_DEFAULT gst_vaapiencode_debug
+
+#define GstVideoContextClass GstVideoContextInterface
+
+/* GstImplementsInterface interface */
+#if !GST_CHECK_VERSION(1,0,0)
+static gboolean
+gst_vaapiencode_implements_interface_supported (GstImplementsInterface * iface,
+ GType type)
+{
+ return (type == GST_TYPE_VIDEO_CONTEXT);
+}
+
+static void
+gst_vaapiencode_implements_iface_init (GstImplementsInterfaceClass * iface)
+{
+ iface->supported = gst_vaapiencode_implements_interface_supported;
+}
+#endif
+
+/* context(display) interface */
+static void
+gst_vaapiencode_set_video_context (GstVideoContext * context,
+ const gchar * type, const GValue * value)
+{
+ GstVaapiEncode *const encode = GST_VAAPIENCODE (context);
+
+ gst_vaapi_set_display (type, value, &encode->display);
+}
+
+static void
+gst_video_context_interface_init (GstVideoContextInterface * iface)
+{
+ iface->set_context = gst_vaapiencode_set_video_context;
+}
+
+G_DEFINE_TYPE_WITH_CODE (GstVaapiEncode,
+ gst_vaapiencode, GST_TYPE_VIDEO_ENCODER,
+#if !GST_CHECK_VERSION(1,0,0)
+ G_IMPLEMENT_INTERFACE (GST_TYPE_IMPLEMENTS_INTERFACE,
+ gst_vaapiencode_implements_iface_init);
+#endif
+ G_IMPLEMENT_INTERFACE (GST_TYPE_VIDEO_CONTEXT,
+ gst_video_context_interface_init))
+
+static gboolean
+gst_vaapiencode_query (GstPad * pad, GstObject * parent,
+ GstQuery * query)
+{
+ GstVaapiEncode *const encode = GST_VAAPIENCODE (parent);
+ gboolean success;
+
+ GST_DEBUG ("vaapiencode query %s", GST_QUERY_TYPE_NAME (query));
+
+ if (gst_vaapi_reply_to_query (query, encode->display))
+ success = TRUE;
+ else if (GST_PAD_IS_SINK (pad))
+ success = encode->sinkpad_query (pad, parent, query);
+ else
+ success = encode->srcpad_query (pad, parent, query);;
+ return success;
+}
+
+static GstFlowReturn
+gst_vaapiencode_default_allocate_buffer (GstVaapiEncode * encode,
+ GstVaapiCodedBuffer * coded_buf, GstBuffer ** outbuf_ptr)
+{
+ GstBuffer *buf;
+ gint32 buf_size;
+
+ g_return_val_if_fail (coded_buf != NULL, GST_FLOW_ERROR);
+ g_return_val_if_fail (outbuf_ptr != NULL, GST_FLOW_ERROR);
+
+ if (!gst_vaapi_coded_buffer_map (coded_buf, NULL))
+ return GST_VAAPI_ENCODE_FLOW_MEM_ERROR;
+
+ buf_size = gst_vaapi_coded_buffer_get_size (coded_buf);
+ if (buf_size <= 0) {
+ GST_ERROR ("get GstVaapiCodedBuf buffer size:%d", buf_size);
+ return GST_VAAPI_ENCODE_FLOW_MEM_ERROR;
+ }
+
+ buf =
+ gst_video_encoder_allocate_output_buffer (GST_VIDEO_ENCODER_CAST (encode),
+ buf_size);
+ if (!buf) {
+ GST_ERROR ("failed to allocate output buffer of size %d", buf_size);
+ return GST_VAAPI_ENCODE_FLOW_MEM_ERROR;
+ }
+
+ if (!gst_vaapi_coded_buffer_get_buffer (coded_buf, buf)) {
+ GST_ERROR ("failed to get encoded buffer");
+ gst_buffer_replace (&buf, NULL);
+ return GST_VAAPI_ENCODE_FLOW_MEM_ERROR;
+ }
+ gst_vaapi_coded_buffer_unmap (coded_buf);
+ *outbuf_ptr = buf;
+ return GST_FLOW_OK;
+}
+
+static GstFlowReturn
+gst_vaapiencode_push_frame (GstVaapiEncode * encode, gint64 ms_timeout)
+{
+ GstVideoEncoder *const venc = GST_VIDEO_ENCODER_CAST (encode);
+ GstVaapiEncodeClass *klass = GST_VAAPIENCODE_GET_CLASS (encode);
+ GstVideoCodecFrame *out_frame = NULL;
+ GstVaapiCodedBufferProxy *coded_buf_proxy = NULL;
+ GstVaapiCodedBuffer *coded_buf;
+ GstVaapiEncoderStatus encode_status;
+ GstBuffer *output_buf;
+ GstFlowReturn ret;
+
+ g_return_val_if_fail (klass->allocate_buffer, GST_FLOW_ERROR);
+
+ encode_status = gst_vaapi_encoder_get_buffer (encode->encoder,
+ &out_frame, &coded_buf_proxy, ms_timeout);
+ if (encode_status == GST_VAAPI_ENCODER_STATUS_TIMEOUT)
+ return GST_VAAPI_ENCODE_FLOW_TIMEOUT;
+
+ if (encode_status != GST_VAAPI_ENCODER_STATUS_SUCCESS) {
+ GST_ERROR ("get encoded buffer failed, status:%d", encode_status);
+ ret = GST_FLOW_ERROR;
+ goto error;
+ }
+
+ g_assert (out_frame);
+ gst_video_codec_frame_set_user_data (out_frame, NULL, NULL);
+
+ coded_buf = coded_buf_proxy->buffer;
+ g_assert (coded_buf);
+
+ /* alloc buffer */
+ ret = klass->allocate_buffer (encode, coded_buf, &output_buf);
+ if (ret != GST_FLOW_OK)
+ goto error;
+
+ out_frame->output_buffer = output_buf;
+
+ gst_vaapi_coded_buffer_proxy_replace (&coded_buf_proxy, NULL);
+
+ /* check out_caps, need lock first */
+ GST_VIDEO_ENCODER_STREAM_LOCK (encode);
+ if (!encode->out_caps_done) {
+ GstVaapiEncoderStatus encoder_status;
+ GstVideoCodecState *old_state, *new_state;
+ GstBuffer *codec_data;
+
+ encoder_status =
+ gst_vaapi_encoder_get_codec_data (encode->encoder, &codec_data);
+ if (encoder_status != GST_VAAPI_ENCODER_STATUS_SUCCESS) {
+ ret = GST_VAAPI_ENCODE_FLOW_CODEC_DATA_ERROR;
+ goto error_unlock;
+ }
+ if (codec_data) {
+ encode->srcpad_caps = gst_caps_make_writable (encode->srcpad_caps);
+ gst_caps_set_simple (encode->srcpad_caps,
+ "codec_data", GST_TYPE_BUFFER, codec_data, NULL);
+ gst_buffer_replace (&codec_data, NULL);
+ old_state =
+ gst_video_encoder_get_output_state (GST_VIDEO_ENCODER_CAST (encode));
+ new_state =
+ gst_video_encoder_set_output_state (GST_VIDEO_ENCODER_CAST (encode),
+ gst_caps_ref (encode->srcpad_caps), old_state);
+ gst_video_codec_state_unref (old_state);
+ gst_video_codec_state_unref (new_state);
+ if (!gst_video_encoder_negotiate (GST_VIDEO_ENCODER_CAST (encode))) {
+ GST_ERROR ("failed to negotiate with caps %" GST_PTR_FORMAT,
+ encode->srcpad_caps);
+ ret = GST_FLOW_NOT_NEGOTIATED;
+ goto error_unlock;
+ }
+ GST_DEBUG ("updated srcpad caps to: %" GST_PTR_FORMAT,
+ encode->srcpad_caps);
+ }
+ encode->out_caps_done = TRUE;
+ }
+ GST_VIDEO_ENCODER_STREAM_UNLOCK (encode);
+
+ GST_DEBUG ("output:%" GST_TIME_FORMAT ", size:%d",
+ GST_TIME_ARGS (out_frame->pts), gst_buffer_get_size (output_buf));
+
+ ret = gst_video_encoder_finish_frame (venc, out_frame);
+ out_frame = NULL;
+ if (ret != GST_FLOW_OK)
+ goto error;
+
+ return GST_FLOW_OK;
+
+error_unlock:
+ GST_VIDEO_ENCODER_STREAM_UNLOCK (encode);
+error:
+ gst_vaapi_coded_buffer_proxy_replace (&coded_buf_proxy, NULL);
+ if (out_frame)
+ gst_video_codec_frame_unref (out_frame);
+
+ return ret;
+}
+
+static void
+gst_vaapiencode_buffer_loop (GstVaapiEncode * encode)
+{
+ GstFlowReturn ret;
+ const gint64 timeout = 50000; /* microseconds */
+
+ ret = gst_vaapiencode_push_frame (encode, timeout);
+ if (ret == GST_FLOW_OK || ret == GST_VAAPI_ENCODE_FLOW_TIMEOUT)
+ return;
+
+ gst_pad_pause_task (encode->srcpad);
+}
+
+static GstCaps *
+gst_vaapiencode_get_caps (GstPad * pad)
+{
+ GstVaapiEncode *const encode = GST_VAAPIENCODE (GST_OBJECT_PARENT (pad));
+ GstCaps *caps;
+
+ if (encode->sinkpad_caps)
+ caps = gst_caps_ref (encode->sinkpad_caps);
+ else
+ caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
+ return caps;
+}
+
+static gboolean
+gst_vaapiencode_destroy (GstVaapiEncode * encode)
+{
+ gst_vaapi_encoder_replace (&encode->encoder, NULL);
+ g_clear_object (&encode->video_buffer_pool);
+
+ if (encode->sinkpad_caps) {
+ gst_caps_unref (encode->sinkpad_caps);
+ encode->sinkpad_caps = NULL;
+ }
+
+ if (encode->srcpad_caps) {
+ gst_caps_unref (encode->srcpad_caps);
+ encode->srcpad_caps = NULL;
+ }
+
+ gst_vaapi_display_replace (&encode->display, NULL);
+ return TRUE;
+}
+
+static inline gboolean
+ensure_display (GstVaapiEncode * encode)
+{
+ return gst_vaapi_ensure_display (encode,
+ GST_VAAPI_DISPLAY_TYPE_ANY, &encode->display);
+}
+
+static gboolean
+ensure_encoder (GstVaapiEncode * encode)
+{
+ GstVaapiEncodeClass *klass = GST_VAAPIENCODE_GET_CLASS (encode);
+
+ g_return_val_if_fail (klass->create_encoder, FALSE);
+
+ if (!ensure_display (encode))
+ return FALSE;
+
+ encode->encoder = klass->create_encoder (encode, encode->display);
+ g_assert (encode->encoder);
+ return (encode->encoder ? TRUE : FALSE);
+}
+
+static gboolean
+gst_vaapiencode_open (GstVideoEncoder * venc)
+{
+ GstVaapiEncode *const encode = GST_VAAPIENCODE (venc);
+ GstVaapiDisplay *const old_display = encode->display;
+ gboolean success;
+
+ encode->display = NULL;
+ success = ensure_display (encode);
+ if (old_display)
+ gst_vaapi_display_unref (old_display);
+
+ GST_DEBUG ("ensure display %s, display:%p",
+ (success ? "okay" : "failed"), encode->display);
+ return success;
+}
+
+static gboolean
+gst_vaapiencode_close (GstVideoEncoder * venc)
+{
+ GstVaapiEncode *const encode = GST_VAAPIENCODE (venc);
+
+ GST_DEBUG ("vaapiencode starting close");
+
+ return gst_vaapiencode_destroy (encode);
+}
+
+static inline gboolean
+gst_vaapiencode_update_sink_caps (GstVaapiEncode * encode,
+ GstVideoCodecState * state)
+{
+ gst_caps_replace (&encode->sinkpad_caps, state->caps);
+ encode->sink_video_info = state->info;
+ return TRUE;
+}
+
+static gboolean
+gst_vaapiencode_update_src_caps (GstVaapiEncode * encode,
+ GstVideoCodecState * in_state)
+{
+ GstVideoCodecState *out_state;
+ GstStructure *structure;
+ GstCaps *outcaps, *allowed_caps, *template_caps, *intersect;
+ GstVaapiEncoderStatus encoder_status;
+ GstBuffer *codec_data = NULL;
+
+ g_return_val_if_fail (encode->encoder, FALSE);
+
+ encode->out_caps_done = FALSE;
+
+ /* get peer caps for stream-format avc/bytestream, codec_data */
+ template_caps = gst_pad_get_pad_template_caps (encode->srcpad);
+ allowed_caps = gst_pad_get_allowed_caps (encode->srcpad);
+ intersect = gst_caps_intersect (template_caps, allowed_caps);
+ gst_caps_unref (template_caps);
+ gst_caps_unref (allowed_caps);
+
+ /* codec data was not set */
+ outcaps = gst_vaapi_encoder_set_format (encode->encoder, in_state, intersect);
+ gst_caps_unref (intersect);
+ g_return_val_if_fail (outcaps, FALSE);
+
+ if (!gst_caps_is_fixed (outcaps)) {
+ GST_ERROR ("encoder output caps was not fixed");
+ gst_caps_unref (outcaps);
+ return FALSE;
+ }
+ structure = gst_caps_get_structure (outcaps, 0);
+ if (!gst_structure_has_field (structure, "codec_data")) {
+ encoder_status =
+ gst_vaapi_encoder_get_codec_data (encode->encoder, &codec_data);
+ if (encoder_status == GST_VAAPI_ENCODER_STATUS_SUCCESS) {
+ if (codec_data) {
+ outcaps = gst_caps_make_writable (outcaps);
+ gst_caps_set_simple (outcaps,
+ "codec_data", GST_TYPE_BUFFER, codec_data, NULL);
+ gst_buffer_replace (&codec_data, NULL);
+ }
+ encode->out_caps_done = TRUE;
+ }
+ } else
+ encode->out_caps_done = TRUE;
+
+ out_state =
+ gst_video_encoder_set_output_state (GST_VIDEO_ENCODER_CAST (encode),
+ outcaps, in_state);
+
+ gst_caps_replace (&encode->srcpad_caps, out_state->caps);
+ gst_video_codec_state_unref (out_state);
+
+ GST_DEBUG ("set srcpad caps to: %" GST_PTR_FORMAT, encode->srcpad_caps);
+ return TRUE;
+}
+
+static gboolean
+gst_vaapiencode_ensure_video_buffer_pool (GstVaapiEncode * encode,
+ GstCaps * caps)
+{
+ GstBufferPool *pool;
+ GstCaps *pool_caps;
+ GstStructure *config;
+ GstVideoInfo vi;
+ gboolean need_pool;
+
+ if (!ensure_display (encode))
+ return FALSE;
+
+ if (encode->video_buffer_pool) {
+ config = gst_buffer_pool_get_config (encode->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 (&encode->video_buffer_pool);
+ encode->video_buffer_size = 0;
+ }
+
+ pool = gst_vaapi_video_buffer_pool_new (encode->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));
+ }
+ encode->video_buffer_size = vi.size;
+
+ config = gst_buffer_pool_get_config (pool);
+ gst_buffer_pool_config_set_params (config, caps, encode->video_buffer_size,
+ 0, 0);
+ gst_buffer_pool_config_add_option (config,
+ GST_BUFFER_POOL_OPTION_VAAPI_VIDEO_META);
+ gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
+ if (!gst_buffer_pool_set_config (pool, config))
+ goto error_pool_config;
+ encode->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");
+ gst_object_unref (pool);
+ return FALSE;
+ }
+}
+
+static gboolean
+gst_vaapiencode_set_format (GstVideoEncoder * venc, GstVideoCodecState * state)
+{
+ GstVaapiEncode *const encode = GST_VAAPIENCODE (venc);
+
+ g_return_val_if_fail (state->caps != NULL, FALSE);
+
+ if (!gst_vaapiencode_ensure_video_buffer_pool (encode, state->caps))
+ return FALSE;
+
+ if (!ensure_encoder (encode))
+ return FALSE;
+ if (!gst_vaapiencode_update_sink_caps (encode, state))
+ return FALSE;
+ if (!gst_vaapiencode_update_src_caps (encode, state))
+ return FALSE;
+
+ if (encode->out_caps_done && !gst_video_encoder_negotiate (venc)) {
+ GST_ERROR ("failed to negotiate with caps %" GST_PTR_FORMAT,
+ encode->srcpad_caps);
+ return FALSE;
+ }
+
+ return gst_pad_start_task (encode->srcpad,
+ (GstTaskFunction) gst_vaapiencode_buffer_loop, encode, NULL);
+ return TRUE;
+}
+
+static gboolean
+gst_vaapiencode_reset (GstVideoEncoder * venc, gboolean hard)
+{
+ GstVaapiEncode *const encode = GST_VAAPIENCODE (venc);
+
+ GST_DEBUG ("vaapiencode starting reset");
+
+ /* FIXME: compare sink_caps with encoder */
+ encode->is_running = FALSE;
+ encode->out_caps_done = FALSE;
+ return TRUE;
+}
+
+static GstFlowReturn
+gst_vaapiencode_get_vaapi_buffer (GstVaapiEncode * encode,
+ GstBuffer * src_buffer, GstBuffer ** out_buffer_ptr)
+{
+ GstVaapiVideoMeta *meta;
+ GstBuffer *out_buffer;
+ GstVideoFrame src_frame, out_frame;
+ GstFlowReturn ret;
+
+ *out_buffer_ptr = NULL;
+ meta = gst_buffer_get_vaapi_video_meta (src_buffer);
+ if (meta) {
+ *out_buffer_ptr = gst_buffer_ref (src_buffer);
+ return GST_FLOW_OK;
+ }
+
+ if (!GST_VIDEO_INFO_IS_YUV (&encode->sink_video_info)) {
+ GST_ERROR ("unsupported video buffer");
+ return GST_FLOW_EOS;
+ }
+
+ GST_DEBUG ("buffer %p not from our pool, copying", src_buffer);
+
+ if (!encode->video_buffer_pool)
+ goto error_no_pool;
+
+ if (!gst_buffer_pool_set_active (encode->video_buffer_pool, TRUE))
+ goto error_activate_pool;
+
+ ret = gst_buffer_pool_acquire_buffer (encode->video_buffer_pool,
+ &out_buffer, NULL);
+ if (ret != GST_FLOW_OK)
+ goto error_create_buffer;
+
+ if (!gst_video_frame_map (&src_frame, &encode->sink_video_info, src_buffer,
+ GST_MAP_READ))
+ goto error_map_src_buffer;
+
+ if (!gst_video_frame_map (&out_frame, &encode->sink_video_info, out_buffer,
+ GST_MAP_WRITE))
+ goto error_map_dst_buffer;
+
+ gst_video_frame_copy (&out_frame, &src_frame);
+ gst_video_frame_unmap (&out_frame);
+ gst_video_frame_unmap (&src_frame);
+
+ *out_buffer_ptr = out_buffer;
+ return GST_FLOW_OK;
+
+ /* ERRORS */
+error_no_pool:
+ GST_ERROR ("no buffer pool was negotiated");
+ return GST_FLOW_ERROR;
+error_activate_pool:
+ GST_ERROR ("failed to activate buffer pool");
+ return GST_FLOW_ERROR;
+error_create_buffer:
+ GST_WARNING ("failed to create image. Skipping this frame");
+ return GST_FLOW_OK;
+error_map_dst_buffer:
+ gst_video_frame_unmap (&src_frame);
+ // fall-through
+error_map_src_buffer:
+ GST_WARNING ("failed to map buffer. Skipping this frame");
+ gst_buffer_unref (out_buffer);
+ return GST_FLOW_OK;
+}
+
+static inline gpointer
+_create_user_data (GstBuffer * buf)
+{
+ GstVaapiVideoMeta *meta;
+ GstVaapiSurface *surface;
+ GstVaapiEncodeFrameUserData *user_data;
+
+ meta = gst_buffer_get_vaapi_video_meta (buf);
+ if (!meta) {
+ GST_DEBUG ("convert to vaapi buffer failed");
+ return NULL;
+ }
+ surface = gst_vaapi_video_meta_get_surface (meta);
+ if (!surface) {
+ GST_DEBUG ("vaapi_meta of codec frame doesn't have vaapisurfaceproxy");
+ return NULL;
+ }
+
+ user_data = g_slice_new0 (GstVaapiEncodeFrameUserData);
+ user_data->head.surface = surface;
+ user_data->vaapi_buf = gst_buffer_ref (buf);
+ return user_data;
+}
+
+static void
+_destroy_user_data (gpointer data)
+{
+ GstVaapiEncodeFrameUserData *user_data = (GstVaapiEncodeFrameUserData *) data;
+
+ g_assert (data);
+ if (!user_data)
+ return;
+ gst_buffer_replace (&user_data->vaapi_buf, NULL);
+ g_slice_free (GstVaapiEncodeFrameUserData, user_data);
+}
+
+static GstFlowReturn
+gst_vaapiencode_handle_frame (GstVideoEncoder * venc,
+ GstVideoCodecFrame * frame)
+{
+ GstVaapiEncode *const encode = GST_VAAPIENCODE (venc);
+ GstFlowReturn ret = GST_FLOW_OK;
+ GstVaapiEncoderStatus encoder_ret = GST_VAAPI_ENCODER_STATUS_SUCCESS;
+ GstBuffer *vaapi_buf = NULL;
+ gpointer user_data;
+
+ g_assert (encode && encode->encoder);
+ g_assert (frame && frame->input_buffer);
+
+ ret =
+ gst_vaapiencode_get_vaapi_buffer (encode, frame->input_buffer,
+ &vaapi_buf);
+ GST_VAAPI_ENCODER_CHECK_STATUS (ret == GST_FLOW_OK, ret,
+ "convert to vaapi buffer failed");
+
+ user_data = _create_user_data (vaapi_buf);
+ GST_VAAPI_ENCODER_CHECK_STATUS (user_data,
+ ret, "create frame user data failed");
+
+ gst_video_codec_frame_set_user_data (frame, user_data, _destroy_user_data);
+
+ GST_VIDEO_ENCODER_STREAM_UNLOCK (encode);
+ /*encoding frames */
+ encoder_ret = gst_vaapi_encoder_put_frame (encode->encoder, frame);
+ GST_VIDEO_ENCODER_STREAM_LOCK (encode);
+
+ GST_VAAPI_ENCODER_CHECK_STATUS (GST_VAAPI_ENCODER_STATUS_SUCCESS <=
+ encoder_ret, GST_FLOW_ERROR, "gst_vaapiencoder_encode failed.");
+
+end:
+ gst_video_codec_frame_unref (frame);
+ gst_buffer_replace (&vaapi_buf, NULL);
+ return ret;
+}
+
+static GstFlowReturn
+gst_vaapiencode_finish (GstVideoEncoder * venc)
+{
+ GstVaapiEncode *const encode = GST_VAAPIENCODE (venc);
+ GstVaapiEncoderStatus status;
+ GstFlowReturn ret = GST_FLOW_OK;
+
+ GST_DEBUG ("vaapiencode starting finish");
+
+ status = gst_vaapi_encoder_flush (encode->encoder);
+
+ GST_VIDEO_ENCODER_STREAM_UNLOCK (encode);
+ gst_pad_stop_task (encode->srcpad);
+ GST_VIDEO_ENCODER_STREAM_LOCK (encode);
+
+ while (status == GST_VAAPI_ENCODER_STATUS_SUCCESS && ret == GST_FLOW_OK)
+ ret = gst_vaapiencode_push_frame (encode, 0);
+
+ if (ret == GST_VAAPI_ENCODE_FLOW_TIMEOUT);
+ ret = GST_FLOW_OK;
+ return ret;
+}
+
+static gboolean
+gst_vaapiencode_propose_allocation (GstVideoEncoder * venc, GstQuery * query)
+{
+ GstVaapiEncode *const encode = GST_VAAPIENCODE (venc);
+ 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_vaapiencode_ensure_video_buffer_pool (encode, caps))
+ return FALSE;
+ gst_query_add_allocation_pool (query, encode->video_buffer_pool,
+ encode->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);
+ return TRUE;
+
+ /* ERRORS */
+error_no_caps:
+ {
+ GST_ERROR ("no caps specified");
+ return FALSE;
+ }
+}
+
+static void
+gst_vaapiencode_finalize (GObject * object)
+{
+ GstVaapiEncode *const encode = GST_VAAPIENCODE (object);
+
+ gst_vaapiencode_destroy (encode);
+
+ encode->sinkpad = NULL;
+ encode->srcpad = NULL;
+
+ G_OBJECT_CLASS (gst_vaapiencode_parent_class)->finalize (object);
+}
+
+static void
+gst_vaapiencode_init (GstVaapiEncode * encode)
+{
+ /* sink pad */
+ encode->sinkpad = GST_VIDEO_ENCODER_SINK_PAD (encode);
+ encode->sinkpad_query = GST_PAD_QUERYFUNC (encode->sinkpad);
+ gst_pad_set_query_function (encode->sinkpad, gst_vaapiencode_query);
+ gst_video_info_init (&encode->sink_video_info);
+
+ /* src pad */
+ encode->srcpad = GST_VIDEO_ENCODER_SRC_PAD (encode);
+ encode->srcpad_query = GST_PAD_QUERYFUNC (encode->srcpad);
+ gst_pad_set_query_function (encode->srcpad, gst_vaapiencode_query);
+
+ gst_pad_use_fixed_caps (encode->srcpad);
+}
+
+static void
+gst_vaapiencode_class_init (GstVaapiEncodeClass * klass)
+{
+ GObjectClass *const object_class = G_OBJECT_CLASS (klass);
+ GstVideoEncoderClass *const venc_class = GST_VIDEO_ENCODER_CLASS (klass);
+
+ GST_DEBUG_CATEGORY_INIT (gst_vaapiencode_debug,
+ GST_PLUGIN_NAME, 0, GST_PLUGIN_DESC);
+
+ object_class->finalize = gst_vaapiencode_finalize;
+
+ venc_class->open = GST_DEBUG_FUNCPTR (gst_vaapiencode_open);
+ venc_class->close = GST_DEBUG_FUNCPTR (gst_vaapiencode_close);
+ venc_class->set_format = GST_DEBUG_FUNCPTR (gst_vaapiencode_set_format);
+ venc_class->reset = GST_DEBUG_FUNCPTR (gst_vaapiencode_reset);
+ venc_class->handle_frame = GST_DEBUG_FUNCPTR (gst_vaapiencode_handle_frame);
+ venc_class->finish = GST_DEBUG_FUNCPTR (gst_vaapiencode_finish);
+
+ venc_class->propose_allocation =
+ GST_DEBUG_FUNCPTR (gst_vaapiencode_propose_allocation);
+
+ klass->allocate_buffer = gst_vaapiencode_default_allocate_buffer;
+
+ /* Registering debug symbols for function pointers */
+ GST_DEBUG_REGISTER_FUNCPTR (gst_vaapiencode_get_caps);
+ GST_DEBUG_REGISTER_FUNCPTR (gst_vaapiencode_query);
+}
diff --git a/gst/vaapi/gstvaapiencode.h b/gst/vaapi/gstvaapiencode.h
new file mode 100644
index 0000000..87e1a8e
--- /dev/null
+++ b/gst/vaapi/gstvaapiencode.h
@@ -0,0 +1,100 @@
+/*
+ * gstvaapiencode.h - VA-API video encoder
+ *
+ * Copyright (C) 2013 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPIENCODE_H
+#define GST_VAAPIENCODE_H
+
+#include <gst/gst.h>
+#include <gst/video/gstvideoencoder.h>
+#include <gst/vaapi/gstvaapiencoder.h>
+#include "gst/vaapi/gstvaapiencoder_objects.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_VAAPIENCODE \
+ (gst_vaapiencode_get_type ())
+
+#define GST_IS_VAAPIENCODE(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPIENCODE))
+
+#define GST_IS_VAAPIENCODE_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VAAPIENCODE))
+
+#define GST_VAAPIENCODE_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+ GST_TYPE_VAAPIENCODE, \
+ GstVaapiEncodeClass))
+
+#define GST_VAAPIENCODE(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+ GST_TYPE_VAAPIENCODE, \
+ GstVaapiEncode))
+
+#define GST_VAAPIENCODE_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), \
+ GST_TYPE_VAAPIENCODE, \
+ GstVaapiEncodeClass))
+
+typedef struct _GstVaapiEncode GstVaapiEncode;
+typedef struct _GstVaapiEncodeClass GstVaapiEncodeClass;
+
+struct _GstVaapiEncode
+{
+ /*< private > */
+ GstVideoEncoder parent_instance;
+
+ GstPad *sinkpad;
+ GstCaps *sinkpad_caps;
+ GstPadQueryFunction sinkpad_query;
+ GstVideoInfo sink_video_info;
+
+ GstPad *srcpad;
+ GstCaps *srcpad_caps;
+ GstPadQueryFunction srcpad_query;
+
+ GstVaapiDisplay *display;
+ GstVaapiEncoder *encoder;
+
+ GstBufferPool *video_buffer_pool;
+ guint video_buffer_size;
+
+ guint32 is_running:1;
+ guint32 out_caps_done:1;
+};
+
+struct _GstVaapiEncodeClass
+{
+ /*< private > */
+ GstVideoEncoderClass parent_class;
+
+ GstVaapiEncoder * (*create_encoder) (GstVaapiEncode * encode,
+ GstVaapiDisplay * display);
+ GstFlowReturn (*allocate_buffer) (GstVaapiEncode * encode,
+ GstVaapiCodedBuffer * coded_buf,
+ GstBuffer ** outbuf_ptr);
+};
+
+GType
+gst_vaapiencode_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* GST_VAAPIENCODE_H */
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-gstreamer/gstreamer-vaapi.git
More information about the Pkg-gstreamer-commits
mailing list