From 8174a3573771f8110b27892335ecee7bf8299f49 Mon Sep 17 00:00:00 2001 From: Wind Yuan Date: Mon, 29 Jul 2013 13:34:06 +0800 Subject: [PATCH] Add initial infrastructure for video encoding. Add initial API for video encoding: only basic interfaces and small encoder objects are implemented so far. Signed-off-by: Gwenole Beauchesne --- configure.ac | 29 + gst-libs/gst/vaapi/Makefile.am | 20 + gst-libs/gst/vaapi/gstvaapiencoder.c | 688 +++++++++++++++++++ gst-libs/gst/vaapi/gstvaapiencoder.h | 91 +++ gst-libs/gst/vaapi/gstvaapiencoder_objects.c | 598 ++++++++++++++++ gst-libs/gst/vaapi/gstvaapiencoder_objects.h | 379 ++++++++++ gst-libs/gst/vaapi/gstvaapiencoder_priv.h | 188 +++++ 7 files changed, 1993 insertions(+) create mode 100644 gst-libs/gst/vaapi/gstvaapiencoder.c create mode 100644 gst-libs/gst/vaapi/gstvaapiencoder.h create mode 100644 gst-libs/gst/vaapi/gstvaapiencoder_objects.c create mode 100644 gst-libs/gst/vaapi/gstvaapiencoder_objects.h create mode 100644 gst-libs/gst/vaapi/gstvaapiencoder_priv.h diff --git a/configure.ac b/configure.ac index 20162a3483..e8fcb85886 100644 --- a/configure.ac +++ b/configure.ac @@ -37,12 +37,14 @@ m4_define([wayland_api_version], [1.0.0]) # VA-API minimum version number m4_define([va_api_version], [0.30.4]) +m4_define([va_api_enc_version], [0.34.0]) m4_define([va_api_drm_version], [0.33.0]) m4_define([va_api_x11_version], [0.31.0]) m4_define([va_api_glx_version], [0.32.0]) m4_define([va_api_wld_version], [0.33.0]) # libva package version number +m4_define([libva_enc_package_version], [1.2.0]) m4_define([libva_drm_package_version], [1.1.0]) m4_define([libva_x11_package_version], [1.0.3]) m4_define([libva_glx_package_version], [1.0.9]) @@ -98,6 +100,11 @@ AC_ARG_ENABLE(builtin_codecparsers, [enable built-in codecparsers @<:@default=yes@:>@]), [], [enable_builtin_codecparsers="yes"]) +AC_ARG_ENABLE([encoders], + AS_HELP_STRING([--enable-encoders], + [enable video encoders @<:@default=yes@:>@]), + [], [enable_encoders="yes"]) + AC_ARG_ENABLE(drm, AS_HELP_STRING([--enable-drm], [enable DRM backend @<:@default=yes@:>@]), @@ -700,6 +707,23 @@ AC_CACHE_CHECK([for video post-postprocessing API], LIBS="$saved_LIBS" ]) +dnl Check for encoding support +USE_ENCODERS=0 +if test "$enable_encoders" = "yes"; then + PKG_CHECK_MODULES([LIBVA], [libva >= va_api_enc_version], + [HAVE_VA_ENC=1], [HAVE_VA_ENC=0]) + + if test $HAVE_VA_ENC -eq 1; then + saved_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$LIBVA_CFLAGS" + AC_CHECK_HEADERS([va/va_enc_mpeg2.h va/va_enc_h264.h], + [USE_ENCODERS=1], [HAVE_VA_ENC=0 USE_ENCODERS=0], + [#include + ]) + CPPFLAGS="$saved_CPPFLAGS" + fi +fi + dnl VA/Wayland API if test "$enable_wayland" = "yes"; then PKG_CHECK_MODULES([LIBVA_WAYLAND], [libva-wayland >= va_api_wld_version], @@ -718,6 +742,10 @@ case ":$USE_X11:$USE_GLX:$USE_WAYLAND:$USE_DRM:" in ;; esac +AC_DEFINE_UNQUOTED([USE_ENCODERS], $USE_ENCODERS, + [Defined to 1 if video encoders are used]) +AM_CONDITIONAL([USE_ENCODERS], [test $USE_ENCODERS -eq 1]) + AC_DEFINE_UNQUOTED(USE_VA_VPP, $USE_VA_VPP, [Defined to 1 if video post-processing is used]) AM_CONDITIONAL(USE_VA_VPP, test $USE_VA_VPP -eq 1) @@ -812,5 +840,6 @@ echo $PACKAGE configuration summary: echo echo GStreamer API version ............ : $GST_API_VERSION echo VA-API version ................... : $VA_VERSION_STR +echo Video encoding ................... : $(yesno $USE_ENCODERS) echo Video outputs .................... : $VIDEO_OUTPUTS echo diff --git a/gst-libs/gst/vaapi/Makefile.am b/gst-libs/gst/vaapi/Makefile.am index 208daece62..52b4bf9aa0 100644 --- a/gst-libs/gst/vaapi/Makefile.am +++ b/gst-libs/gst/vaapi/Makefile.am @@ -134,6 +134,26 @@ libgstvaapi_source_c += $(libgstvaapi_jpegdec_source_c) libgstvaapi_source_h += $(libgstvaapi_jpegdec_source_h) endif +libgstvaapi_enc_source_c = \ + gstvaapiencoder.c \ + gstvaapiencoder_objects.c \ + $(NULL) + +libgstvaapi_enc_source_h = \ + gstvaapiencoder.h \ + $(NULL) + +libgstvaapi_enc_source_priv_h = \ + gstvaapiencoder_objects.h \ + gstvaapiencoder_priv.h \ + $(NULL) + +if USE_ENCODERS +libgstvaapi_source_c += $(libgstvaapi_enc_source_c) +libgstvaapi_source_h += $(libgstvaapi_enc_source_h) +libgstvaapi_source_priv_h += $(libgstvaapi_enc_source_priv_h) +endif + libgstvaapi_drm_source_c = \ gstvaapidisplay_drm.c \ gstvaapiwindow_drm.c \ diff --git a/gst-libs/gst/vaapi/gstvaapiencoder.c b/gst-libs/gst/vaapi/gstvaapiencoder.c new file mode 100644 index 0000000000..519e8f7f18 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiencoder.c @@ -0,0 +1,688 @@ +/* + * gstvaapiencoder.c - VA encoder abstraction + * + * 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 "sysdeps.h" +#include "gstvaapicompat.h" +#include "gstvaapiencoder.h" +#include "gstvaapiencoder_priv.h" +#include "gstvaapicontext.h" +#include "gstvaapidisplay_priv.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +typedef struct _GstVaapiCodedBufferProxyClass GstVaapiCodedBufferProxyClass; + +#define GST_VAAPI_ENCODER_LOCK(encoder) \ + G_STMT_START { \ + g_mutex_lock (&(GST_VAAPI_ENCODER_CAST(encoder))->lock); \ + } G_STMT_END + +#define GST_VAAPI_ENCODER_UNLOCK(encoder) \ + G_STMT_START { \ + g_mutex_unlock (&(GST_VAAPI_ENCODER_CAST(encoder))->lock); \ + } G_STMT_END + +#define GST_VAAPI_ENCODER_BUF_FREE_WAIT(encoder) \ + G_STMT_START { \ + g_cond_wait (&(GST_VAAPI_ENCODER_CAST(encoder))->codedbuf_free, \ + &(GST_VAAPI_ENCODER_CAST(encoder))->lock); \ + } G_STMT_END + +#define GST_VAAPI_ENCODER_BUF_FREE_SIGNAL(encoder) \ + G_STMT_START { \ + g_cond_signal (&(GST_VAAPI_ENCODER_CAST(encoder))->codedbuf_free); \ + } G_STMT_END + +#define GST_VAAPI_ENCODER_FREE_SURFACE_WAIT(encoder) \ + G_STMT_START { \ + g_cond_wait (&(GST_VAAPI_ENCODER_CAST(encoder))->surface_free, \ + &(GST_VAAPI_ENCODER_CAST(encoder))->lock); \ + } G_STMT_END + +#define GST_VAAPI_ENCODER_FREE_SURFACE_SIGNAL(encoder) \ + G_STMT_START { \ + g_cond_signal (&(GST_VAAPI_ENCODER_CAST(encoder))->surface_free); \ + } G_STMT_END + +#define GST_VAAPI_ENCODER_SYNC_SIGNAL(encoder) \ + G_STMT_START { \ + g_cond_signal (&(GST_VAAPI_ENCODER_CAST(encoder))->sync_ready); \ + } G_STMT_END + +static inline gboolean +GST_VAAPI_ENCODER_SYNC_WAIT_TIMEOUT (GstVaapiEncoder * encoder, gint64 timeout) +{ + gint64 end_time = g_get_monotonic_time () + timeout; + return g_cond_wait_until (&encoder->sync_ready, &encoder->lock, end_time); +} + +static GstVaapiCodedBuffer * +gst_vaapi_encoder_dequeue_coded_buffer (GstVaapiEncoder * encoder); + +static void +gst_vaapi_encoder_queue_coded_buffer (GstVaapiEncoder * encoder, + GstVaapiCodedBuffer * buf); + +typedef struct +{ + GstVaapiEncPicture *picture; + GstVaapiCodedBufferProxy *buf; +} GstVaapiEncoderSyncPic; + +static void +gst_vaapi_coded_buffer_proxy_finalize (GstVaapiCodedBufferProxy * proxy) +{ + if (proxy->buffer) { + gst_vaapi_coded_buffer_unmap (proxy->buffer); + if (proxy->encoder) + gst_vaapi_encoder_queue_coded_buffer (proxy->encoder, proxy->buffer); + else { + g_assert (FALSE); + gst_vaapi_mini_object_unref (GST_VAAPI_MINI_OBJECT (proxy->buffer)); + } + proxy->buffer = NULL; + } + gst_vaapi_encoder_replace (&proxy->encoder, NULL); +} + +static void +gst_vaapi_coded_buffer_proxy_class_init (GstVaapiCodedBufferProxyClass * klass) +{ + GstVaapiMiniObjectClass *const object_class = + GST_VAAPI_MINI_OBJECT_CLASS (klass); + + object_class->size = sizeof (GstVaapiCodedBufferProxy); + object_class->finalize = + (GDestroyNotify) gst_vaapi_coded_buffer_proxy_finalize; +} + +static inline const GstVaapiCodedBufferProxyClass * +gst_vaapi_coded_buffer_proxy_class (void) +{ + static GstVaapiCodedBufferProxyClass g_class; + static gsize g_class_init = FALSE; + + if (g_once_init_enter (&g_class_init)) { + gst_vaapi_coded_buffer_proxy_class_init (&g_class); + g_once_init_leave (&g_class_init, TRUE); + } + return (&g_class); +} + +GstVaapiCodedBufferProxy * +gst_vaapi_coded_buffer_proxy_new (GstVaapiEncoder * encoder) +{ + GstVaapiCodedBuffer *buf; + GstVaapiCodedBufferProxy *ret; + + g_assert (encoder); + buf = gst_vaapi_encoder_dequeue_coded_buffer (encoder); + if (!buf) + return NULL; + + ret = (GstVaapiCodedBufferProxy *) + gst_vaapi_mini_object_new0 (GST_VAAPI_MINI_OBJECT_CLASS + (gst_vaapi_coded_buffer_proxy_class ())); + g_assert (ret); + ret->encoder = gst_vaapi_encoder_ref (encoder); + ret->buffer = buf; + return ret; +} + +GstVaapiCodedBufferProxy * +gst_vaapi_coded_buffer_proxy_ref (GstVaapiCodedBufferProxy * proxy) +{ + return (GstVaapiCodedBufferProxy *) + gst_vaapi_mini_object_ref (GST_VAAPI_MINI_OBJECT (proxy)); +} + +void +gst_vaapi_coded_buffer_proxy_unref (GstVaapiCodedBufferProxy * proxy) +{ + gst_vaapi_mini_object_unref (GST_VAAPI_MINI_OBJECT (proxy)); +} + +void +gst_vaapi_coded_buffer_proxy_replace (GstVaapiCodedBufferProxy ** old_proxy_ptr, + GstVaapiCodedBufferProxy * new_proxy) +{ + gst_vaapi_mini_object_replace ((GstVaapiMiniObject **) old_proxy_ptr, + GST_VAAPI_MINI_OBJECT (new_proxy)); +} + +GstVaapiEncoder * +gst_vaapi_encoder_ref (GstVaapiEncoder * encoder) +{ + return gst_vaapi_object_ref (encoder); +} + +void +gst_vaapi_encoder_unref (GstVaapiEncoder * encoder) +{ + gst_vaapi_object_unref (encoder); +} + +void +gst_vaapi_encoder_replace (GstVaapiEncoder ** old_encoder_ptr, + GstVaapiEncoder * new_encoder) +{ + gst_vaapi_object_replace (old_encoder_ptr, new_encoder); +} + +static gboolean +gst_vaapi_encoder_init_coded_buffer_queue (GstVaapiEncoder * encoder, + guint count) +{ + GstVaapiCodedBuffer *buf; + guint i = 0; + + GST_VAAPI_ENCODER_LOCK (encoder); + if (count > encoder->max_buf_num) + count = encoder->max_buf_num; + + g_assert (encoder->buf_size); + for (i = 0; i < count; ++i) { + buf = GST_VAAPI_CODED_BUFFER_NEW (encoder, encoder->buf_size); + g_queue_push_tail (&encoder->coded_buffers, buf); + ++encoder->buf_count; + } + g_assert (encoder->buf_count <= encoder->max_buf_num); + + GST_VAAPI_ENCODER_UNLOCK (encoder); + return TRUE; +} + +static GstVaapiCodedBuffer * +gst_vaapi_encoder_dequeue_coded_buffer (GstVaapiEncoder * encoder) +{ + GstVaapiCodedBuffer *ret = NULL; + + GST_VAAPI_ENCODER_LOCK (encoder); + while (encoder->buf_count >= encoder->max_buf_num && + g_queue_is_empty (&encoder->coded_buffers)) { + GST_VAAPI_ENCODER_BUF_FREE_WAIT (encoder); + } + if (!g_queue_is_empty (&encoder->coded_buffers)) { + ret = (GstVaapiCodedBuffer *) g_queue_pop_head (&encoder->coded_buffers); + goto end; + } + + g_assert (encoder->buf_size); + ret = GST_VAAPI_CODED_BUFFER_NEW (encoder, encoder->buf_size); + if (ret) + ++encoder->buf_count; + +end: + GST_VAAPI_ENCODER_UNLOCK (encoder); + return ret; +} + +static void +gst_vaapi_encoder_queue_coded_buffer (GstVaapiEncoder * encoder, + GstVaapiCodedBuffer * buf) +{ + g_assert (buf); + g_return_if_fail (buf); + + GST_VAAPI_ENCODER_LOCK (encoder); + g_queue_push_tail (&encoder->coded_buffers, buf); + GST_VAAPI_ENCODER_BUF_FREE_SIGNAL (encoder); + GST_VAAPI_ENCODER_UNLOCK (encoder); +} + +static gboolean +gst_vaapi_encoder_free_coded_buffers (GstVaapiEncoder * encoder) +{ + GstVaapiCodedBuffer *buf; + guint count = 0; + gboolean ret; + + GST_VAAPI_ENCODER_LOCK (encoder); + while (!g_queue_is_empty (&encoder->coded_buffers)) { + buf = (GstVaapiCodedBuffer *) g_queue_pop_head (&encoder->coded_buffers); + g_assert (buf); + gst_vaapi_mini_object_unref (GST_VAAPI_MINI_OBJECT (buf)); + ++count; + } + ret = (count == encoder->buf_count); + GST_VAAPI_ENCODER_UNLOCK (encoder); + + if (!ret) { + GST_ERROR ("coded buffer leak, freed count:%d, total buf:%d", + count, encoder->buf_count); + } + + return ret; +} + +static void +_surface_proxy_released_notify (GstVaapiEncoder * encoder) +{ + GST_VAAPI_ENCODER_FREE_SURFACE_SIGNAL (encoder); +} + +GstVaapiSurfaceProxy * +gst_vaapi_encoder_create_surface (GstVaapiEncoder * encoder) +{ + GstVaapiSurfaceProxy *proxy; + + g_assert (encoder && encoder->context); + g_return_val_if_fail (encoder->context, NULL); + + GST_VAAPI_ENCODER_LOCK (encoder); + while (!gst_vaapi_context_get_surface_count (encoder->context)) { + GST_VAAPI_ENCODER_FREE_SURFACE_WAIT (encoder); + } + proxy = gst_vaapi_context_get_surface_proxy (encoder->context); + GST_VAAPI_ENCODER_UNLOCK (encoder); + + gst_vaapi_surface_proxy_set_destroy_notify (proxy, + (GDestroyNotify) _surface_proxy_released_notify, encoder); + + return proxy; +} + +void +gst_vaapi_encoder_release_surface (GstVaapiEncoder * encoder, + GstVaapiSurfaceProxy * surface) +{ + GST_VAAPI_ENCODER_LOCK (encoder); + gst_vaapi_surface_proxy_unref (surface); + GST_VAAPI_ENCODER_UNLOCK (encoder); +} + +static GstVaapiEncoderSyncPic * +_create_sync_picture (GstVaapiEncPicture * picture, + GstVaapiCodedBufferProxy * coded_buf) +{ + GstVaapiEncoderSyncPic *sync = g_slice_new0 (GstVaapiEncoderSyncPic); + + g_assert (picture && coded_buf); + sync->picture = gst_vaapi_enc_picture_ref (picture); + sync->buf = gst_vaapi_coded_buffer_proxy_ref (coded_buf); + return sync; +} + +static void +_free_sync_picture (GstVaapiEncoder * encoder, + GstVaapiEncoderSyncPic * sync_pic) +{ + g_assert (sync_pic); + + if (sync_pic->picture) + gst_vaapi_enc_picture_unref (sync_pic->picture); + if (sync_pic->buf) + gst_vaapi_coded_buffer_proxy_unref (sync_pic->buf); + g_slice_free (GstVaapiEncoderSyncPic, sync_pic); +} + +static void +gst_vaapi_encoder_free_sync_pictures (GstVaapiEncoder * encoder) +{ + GstVaapiEncoderSyncPic *sync; + + GST_VAAPI_ENCODER_LOCK (encoder); + while (!g_queue_is_empty (&encoder->sync_pictures)) { + sync = + (GstVaapiEncoderSyncPic *) g_queue_pop_head (&encoder->sync_pictures); + _free_sync_picture (encoder, sync); + } + GST_VAAPI_ENCODER_UNLOCK (encoder); +} + +static gboolean +gst_vaapi_encoder_push_sync_picture (GstVaapiEncoder * encoder, + GstVaapiEncoderSyncPic * sync_pic) +{ + GST_VAAPI_ENCODER_LOCK (encoder); + g_queue_push_tail (&encoder->sync_pictures, sync_pic); + GST_VAAPI_ENCODER_SYNC_SIGNAL (encoder); + GST_VAAPI_ENCODER_UNLOCK (encoder); + return TRUE; +} + +static GstVaapiEncoderStatus +gst_vaapi_encoder_pop_sync_picture (GstVaapiEncoder * encoder, + GstVaapiEncoderSyncPic ** sync_pic, guint64 timeout) +{ + GstVaapiEncoderStatus ret = GST_VAAPI_ENCODER_STATUS_SUCCESS; + + *sync_pic = NULL; + + GST_VAAPI_ENCODER_LOCK (encoder); + if (g_queue_is_empty (&encoder->sync_pictures) && + !GST_VAAPI_ENCODER_SYNC_WAIT_TIMEOUT (encoder, timeout)) + goto timeout; + + if (g_queue_is_empty (&encoder->sync_pictures)) { + ret = GST_VAAPI_ENCODER_STATUS_UNKNOWN_ERR; + goto end; + } + + *sync_pic = + (GstVaapiEncoderSyncPic *) g_queue_pop_head (&encoder->sync_pictures); + g_assert (*sync_pic); + ret = GST_VAAPI_ENCODER_STATUS_SUCCESS; + goto end; + +timeout: + ret = GST_VAAPI_ENCODER_STATUS_TIMEOUT; + +end: + GST_VAAPI_ENCODER_UNLOCK (encoder); + return ret; +} + +GstVaapiEncoderStatus +gst_vaapi_encoder_put_frame (GstVaapiEncoder * encoder, + GstVideoCodecFrame * frame) +{ + GstVaapiEncoderStatus ret = GST_VAAPI_ENCODER_STATUS_SUCCESS; + GstVaapiEncoderClass *klass = GST_VAAPI_ENCODER_GET_CLASS (encoder); + GstVaapiEncPicture *picture = NULL; + GstVaapiCodedBufferProxy *coded_buf = NULL; + GstVaapiEncoderSyncPic *sync_pic = NULL; + + if (!klass->reordering || !klass->encode) + goto error; + +again: + picture = NULL; + sync_pic = NULL; + ret = klass->reordering (encoder, frame, FALSE, &picture); + + if (ret == GST_VAAPI_ENCODER_STATUS_FRAME_NOT_READY) + return GST_VAAPI_ENCODER_STATUS_SUCCESS; + + g_assert (picture); + if (ret != GST_VAAPI_ENCODER_STATUS_SUCCESS) + goto error; + if (!picture) { + ret = GST_VAAPI_ENCODER_STATUS_PICTURE_ERR; + goto error; + } + + coded_buf = gst_vaapi_coded_buffer_proxy_new (encoder); + if (!coded_buf) { + ret = GST_VAAPI_ENCODER_STATUS_OBJECT_ERR; + goto error; + } + + ret = klass->encode (encoder, picture, coded_buf); + if (ret != GST_VAAPI_ENCODER_STATUS_SUCCESS) + goto error; + + /* another thread would sync and get coded buffer */ + sync_pic = _create_sync_picture (picture, coded_buf); + gst_vaapi_coded_buffer_proxy_replace (&coded_buf, NULL); + gst_vaapi_enc_picture_replace (&picture, NULL); + + if (!gst_vaapi_encoder_push_sync_picture (encoder, sync_pic)) { + ret = GST_VAAPI_ENCODER_STATUS_THREAD_ERR; + goto error; + } + + frame = NULL; + goto again; + +error: + gst_vaapi_enc_picture_replace (&picture, NULL); + gst_vaapi_coded_buffer_proxy_replace (&coded_buf, NULL); + if (sync_pic) + _free_sync_picture (encoder, sync_pic); + GST_ERROR ("encoding failed, error:%d", ret); + return ret; +} + +GstVaapiEncoderStatus +gst_vaapi_encoder_get_buffer (GstVaapiEncoder * encoder, + GstVideoCodecFrame ** frame, + GstVaapiCodedBufferProxy ** codedbuf, gint64 us_of_timeout) +{ + GstVaapiEncoderStatus ret = GST_VAAPI_ENCODER_STATUS_SUCCESS; + GstVaapiEncoderSyncPic *sync_pic = NULL; + GstVaapiSurfaceStatus surface_status; + GstVaapiEncPicture *picture; + + ret = gst_vaapi_encoder_pop_sync_picture (encoder, &sync_pic, us_of_timeout); + if (ret != GST_VAAPI_ENCODER_STATUS_SUCCESS) + goto end; + + picture = sync_pic->picture; + + if (!picture->surface || !gst_vaapi_surface_sync (picture->surface)) { + ret = GST_VAAPI_ENCODER_STATUS_PARAM_ERR; + goto end; + } + if (!gst_vaapi_surface_query_status (picture->surface, &surface_status)) { + ret = GST_VAAPI_ENCODER_STATUS_PICTURE_ERR; + goto end; + } + if (frame) + *frame = gst_video_codec_frame_ref (picture->frame); + if (codedbuf) + *codedbuf = gst_vaapi_coded_buffer_proxy_ref (sync_pic->buf); + +end: + if (sync_pic) + _free_sync_picture (encoder, sync_pic); + return ret; +} + +GstVaapiEncoderStatus +gst_vaapi_encoder_flush (GstVaapiEncoder * encoder) +{ + GstVaapiEncoderStatus ret = GST_VAAPI_ENCODER_STATUS_SUCCESS; + GstVaapiEncoderClass *const klass = GST_VAAPI_ENCODER_GET_CLASS (encoder); + + if (!klass->flush) + goto error; + + ret = klass->flush (encoder); + return ret; + +error: + GST_ERROR ("flush failed"); + return GST_VAAPI_ENCODER_STATUS_FUNC_PTR_ERR; +} + +GstVaapiEncoderStatus +gst_vaapi_encoder_get_codec_data (GstVaapiEncoder * encoder, + GstBuffer ** codec_data) +{ + GstVaapiEncoderStatus ret = GST_VAAPI_ENCODER_STATUS_SUCCESS; + GstVaapiEncoderClass *const klass = GST_VAAPI_ENCODER_GET_CLASS (encoder); + + *codec_data = NULL; + if (!klass->get_codec_data) + return GST_VAAPI_ENCODER_STATUS_SUCCESS; + + ret = klass->get_codec_data (encoder, codec_data); + return ret; +} + +static gboolean +gst_vaapi_encoder_ensure_context (GstVaapiEncoder * encoder) +{ + GstVaapiEncoderClass *const klass = GST_VAAPI_ENCODER_GET_CLASS (encoder); + GstVaapiContextInfo info; + GstVaapiContext *context; + + if (GST_VAAPI_ENCODER_CONTEXT (encoder)) + return TRUE; + + memset (&info, 0, sizeof (info)); + if (!klass->get_context_info || !klass->get_context_info (encoder, &info)) { + return FALSE; + } + + context = gst_vaapi_context_new_full (GST_VAAPI_ENCODER_DISPLAY (encoder), + &info); + if (!context) + return FALSE; + + GST_VAAPI_ENCODER_CONTEXT (encoder) = context; + GST_VAAPI_ENCODER_VA_CONTEXT (encoder) = gst_vaapi_context_get_id (context); + return TRUE; +} + +GstCaps * +gst_vaapi_encoder_set_format (GstVaapiEncoder * encoder, + GstVideoCodecState * in_state, GstCaps * ref_caps) +{ + GstVaapiEncoderClass *const klass = GST_VAAPI_ENCODER_GET_CLASS (encoder); + GstCaps *out_caps = NULL; + + if (!GST_VIDEO_INFO_WIDTH (&in_state->info) || + !GST_VIDEO_INFO_HEIGHT (&in_state->info)) { + GST_WARNING ("encoder set format failed, width or height equal to 0."); + return NULL; + } + GST_VAAPI_ENCODER_VIDEO_INFO (encoder) = in_state->info; + + if (!klass->set_format) + goto error; + + out_caps = klass->set_format (encoder, in_state, ref_caps); + if (!out_caps) + goto error; + + if (GST_VAAPI_ENCODER_CAPS (encoder) && + gst_caps_is_equal (out_caps, GST_VAAPI_ENCODER_CAPS (encoder))) { + gst_caps_unref (out_caps); + return GST_VAAPI_ENCODER_CAPS (encoder); + } + gst_caps_replace (&GST_VAAPI_ENCODER_CAPS (encoder), out_caps); + g_assert (GST_VAAPI_ENCODER_CONTEXT (encoder) == NULL); + gst_vaapi_object_replace (&GST_VAAPI_ENCODER_CONTEXT (encoder), NULL); + + if (!gst_vaapi_encoder_ensure_context (encoder)) + goto error; + + encoder->buf_size = (GST_VAAPI_ENCODER_WIDTH (encoder) * + GST_VAAPI_ENCODER_HEIGHT (encoder) * 400) / (16 * 16); + + if (!gst_vaapi_encoder_init_coded_buffer_queue (encoder, 5)) { + GST_ERROR ("encoder init coded buffer failed"); + goto error; + } + + return out_caps; + +error: + gst_caps_replace (&GST_VAAPI_ENCODER_CAPS (encoder), NULL); + gst_caps_replace (&out_caps, NULL); + GST_ERROR ("encoder set format failed"); + return NULL; +} + +static gboolean +gst_vaapi_encoder_init (GstVaapiEncoder * encoder, GstVaapiDisplay * display) +{ + GstVaapiEncoderClass *kclass = GST_VAAPI_ENCODER_GET_CLASS (encoder); + + g_assert (kclass); + g_assert (display); + + g_return_val_if_fail (display, FALSE); + g_return_val_if_fail (encoder->display == NULL, FALSE); + + encoder->display = gst_vaapi_display_ref (display); + encoder->va_display = gst_vaapi_display_get_display (display); + encoder->context = NULL; + encoder->va_context = VA_INVALID_ID; + encoder->caps = NULL; + + gst_video_info_init (&encoder->video_info); + + encoder->buf_count = 0; + encoder->max_buf_num = 10; + encoder->buf_size = 0; + + g_mutex_init (&encoder->lock); + g_cond_init (&encoder->codedbuf_free); + g_cond_init (&encoder->surface_free); + g_queue_init (&encoder->coded_buffers); + g_queue_init (&encoder->sync_pictures); + g_cond_init (&encoder->sync_ready); + + if (kclass->init) + return kclass->init (encoder); + return TRUE; +} + +static void +gst_vaapi_encoder_destroy (GstVaapiEncoder * encoder) +{ + GstVaapiEncoderClass *const klass = GST_VAAPI_ENCODER_GET_CLASS (encoder); + + if (klass->destroy) + klass->destroy (encoder); + + gst_vaapi_encoder_free_coded_buffers (encoder); + gst_vaapi_encoder_free_sync_pictures (encoder); + + gst_vaapi_object_replace (&encoder->context, NULL); + gst_vaapi_display_replace (&encoder->display, NULL); + encoder->va_display = NULL; + g_mutex_clear (&encoder->lock); + g_cond_clear (&encoder->codedbuf_free); + g_cond_clear (&encoder->surface_free); + g_queue_clear (&encoder->coded_buffers); + g_queue_clear (&encoder->sync_pictures); + g_cond_clear (&encoder->sync_ready); +} + +void +gst_vaapi_encoder_finalize (GstVaapiEncoder * encoder) +{ + gst_vaapi_encoder_destroy (encoder); +} + +void +gst_vaapi_encoder_class_init (GstVaapiEncoderClass * klass) +{ + GstVaapiMiniObjectClass *const object_class = + GST_VAAPI_MINI_OBJECT_CLASS (klass); + + object_class->size = sizeof (GstVaapiEncoder); + object_class->finalize = (GDestroyNotify) gst_vaapi_encoder_finalize; +} + +GstVaapiEncoder * +gst_vaapi_encoder_new (const GstVaapiEncoderClass * klass, + GstVaapiDisplay * display) +{ + GstVaapiEncoder *encoder; + + encoder = (GstVaapiEncoder *) + gst_vaapi_mini_object_new0 (GST_VAAPI_MINI_OBJECT_CLASS (klass)); + if (!encoder) + return NULL; + + if (!gst_vaapi_encoder_init (encoder, display)) + goto error; + return encoder; + +error: + gst_vaapi_encoder_unref (encoder); + return NULL; +} diff --git a/gst-libs/gst/vaapi/gstvaapiencoder.h b/gst-libs/gst/vaapi/gstvaapiencoder.h new file mode 100644 index 0000000000..1779b59a13 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiencoder.h @@ -0,0 +1,91 @@ +/* + * gstvaapiencoder.h - VA encoder abstraction + * + * 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_VAAPI_ENCODER_H +#define GST_VAAPI_ENCODER_H + +#include +#include +#include +#include + +G_BEGIN_DECLS + +typedef enum +{ + GST_VAAPI_ENCODER_STATUS_SUCCESS = 0, + GST_VAAPI_ENCODER_STATUS_FRAME_NOT_READY = 1, + GST_VAAPI_ENCODER_STATUS_NO_DATA = 2, + GST_VAAPI_ENCODER_STATUS_TIMEOUT = 3, + GST_VAAPI_ENCODER_STATUS_NOT_READY = 4, + GST_VAAPI_ENCODER_STATUS_FRAME_IN_ORDER = 5, + + GST_VAAPI_ENCODER_STATUS_PARAM_ERR = -1, + GST_VAAPI_ENCODER_STATUS_OBJECT_ERR = -2, + GST_VAAPI_ENCODER_STATUS_PICTURE_ERR = -3, + GST_VAAPI_ENCODER_STATUS_THREAD_ERR = -4, + GST_VAAPI_ENCODER_STATUS_PROFILE_ERR = -5, + GST_VAAPI_ENCODER_STATUS_FUNC_PTR_ERR = -6, + GST_VAAPI_ENCODER_STATUS_MEM_ERROR = -7, + GST_VAAPI_ENCODER_STATUS_UNKNOWN_ERR = -8, +} GstVaapiEncoderStatus; + +typedef struct _GstVaapiEncoder GstVaapiEncoder; +typedef struct _GstVaapiCodedBufferProxy GstVaapiCodedBufferProxy; + +#define GST_VAAPI_ENCODER(encoder) \ + ((GstVaapiEncoder *)(encoder)) + +#define GST_VAAPI_ENCODER_CAST(encoder) \ + ((GstVaapiEncoder *)(encoder)) + +GstVaapiEncoder * +gst_vaapi_encoder_ref (GstVaapiEncoder * encoder); + +void +gst_vaapi_encoder_unref (GstVaapiEncoder * encoder); + +void +gst_vaapi_encoder_replace (GstVaapiEncoder ** old_encoder_ptr, + GstVaapiEncoder * new_encoder); + +GstCaps *gst_vaapi_encoder_set_format (GstVaapiEncoder * encoder, + GstVideoCodecState * state, GstCaps * ref_caps); + +GstVaapiEncoderStatus +gst_vaapi_encoder_get_codec_data (GstVaapiEncoder * encoder, + GstBuffer ** codec_data_ptr); + +GstVaapiEncoderStatus +gst_vaapi_encoder_put_frame (GstVaapiEncoder * encoder, + GstVideoCodecFrame * frame); + +GstVaapiEncoderStatus +gst_vaapi_encoder_get_buffer (GstVaapiEncoder * encoder, + GstVideoCodecFrame ** out_frame_ptr, + GstVaapiCodedBufferProxy ** out_codedbuf_ptr, gint64 timeout); + +GstVaapiEncoderStatus +gst_vaapi_encoder_flush (GstVaapiEncoder * encoder); + +G_END_DECLS + +#endif /* GST_VAAPI_ENCODER_H */ diff --git a/gst-libs/gst/vaapi/gstvaapiencoder_objects.c b/gst-libs/gst/vaapi/gstvaapiencoder_objects.c new file mode 100644 index 0000000000..e87538ce17 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiencoder_objects.c @@ -0,0 +1,598 @@ +/* + * gstvaapiencoder_objects.c - VA encoder objects abstraction + * + * 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 "sysdeps.h" +#include "glibcompat.h" + +#include "gstvaapiencoder_objects.h" +#include "gstvaapiencoder.h" +#include "gstvaapiencoder_priv.h" +#include "gstvaapiutils.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +#define GET_ENCODER(obj) GST_VAAPI_ENCODER_CAST((obj)->parent_instance.codec) +#define GET_VA_DISPLAY(obj) GST_VAAPI_ENCODER_VA_DISPLAY(GET_ENCODER(obj)) +#define GET_VA_CONTEXT(obj) GST_VAAPI_ENCODER_VA_CONTEXT(GET_ENCODER(obj)) + +/* ------------------------------------------------------------------------- */ +/* --- Encoder Coded Data --- */ +/* ------------------------------------------------------------------------- */ + +GST_VAAPI_CODEC_DEFINE_TYPE (GstVaapiCodedBuffer, gst_vaapi_coded_buffer); + +void +gst_vaapi_coded_buffer_destroy (GstVaapiCodedBuffer * buffer) +{ + gst_vaapi_coded_buffer_unmap (buffer); + vaapi_destroy_buffer (GET_VA_DISPLAY (buffer), &buffer->buf_id); + buffer->segment_list = NULL; +} + +gboolean +gst_vaapi_coded_buffer_create (GstVaapiCodedBuffer * codec_buffer, + const GstVaapiCodecObjectConstructorArgs * args) +{ + codec_buffer->buf_id = VA_INVALID_ID; + codec_buffer->segment_list = NULL; + return vaapi_create_buffer (GET_VA_DISPLAY (codec_buffer), + GET_VA_CONTEXT (codec_buffer), + VAEncCodedBufferType, + args->param_size, args->param, &codec_buffer->buf_id, NULL); +} + +GstVaapiCodedBuffer * +gst_vaapi_coded_buffer_new (GstVaapiEncoder * encoder, + gconstpointer param, guint param_size) +{ + GstVaapiCodecObject *object; + + object = gst_vaapi_codec_object_new (&GstVaapiCodedBufferClass, + GST_VAAPI_CODEC_BASE (encoder), param, param_size, NULL, 0, 0); + if (!object) + return NULL; + return GST_VAAPI_CODED_BUFFER_CAST (object); +} + +gboolean +gst_vaapi_coded_buffer_map (GstVaapiCodedBuffer * buf, void **data) +{ + g_return_val_if_fail (buf->buf_id != VA_INVALID_ID, FALSE); + + if (buf->segment_list) + goto end; + buf->segment_list = vaapi_map_buffer (GET_VA_DISPLAY (buf), buf->buf_id); + if (!buf->segment_list) + return FALSE; +end: + if (data) + *data = buf->segment_list; + return TRUE; +} + +void +gst_vaapi_coded_buffer_unmap (GstVaapiCodedBuffer * buf) +{ + if (buf->buf_id != VA_INVALID_ID && buf->segment_list) + vaapi_unmap_buffer (GET_VA_DISPLAY (buf), + buf->buf_id, (void **) (&buf->segment_list)); +} + +gint32 +gst_vaapi_coded_buffer_get_size (GstVaapiCodedBuffer * buf) +{ + gint32 size; + VACodedBufferSegment *segment; + if (!gst_vaapi_coded_buffer_map (buf, NULL)) + return -1; + + size = 0; + segment = buf->segment_list; + while (segment) { + size += segment->size; + segment = (VACodedBufferSegment *) segment->next; + } + return size; +} + +gboolean +gst_vaapi_coded_buffer_get_buffer (GstVaapiCodedBuffer * buf, + GstBuffer * output) +{ + gint32 offset; + VACodedBufferSegment *segment; + + g_assert (output); + g_return_val_if_fail (output, FALSE); + + offset = 0; + segment = buf->segment_list; + while (segment) { + if (gst_buffer_fill (output, offset, segment->buf, segment->size) + != segment->size) + return FALSE; + offset += segment->size; + segment = (VACodedBufferSegment *) segment->next; + } + return TRUE; +} + +/* ------------------------------------------------------------------------- */ +/* --- Encoder Packed Header --- */ +/* ------------------------------------------------------------------------- */ + +GST_VAAPI_CODEC_DEFINE_TYPE (GstVaapiEncPackedHeader, + gst_vaapi_enc_packed_header); + +void +gst_vaapi_enc_packed_header_destroy (GstVaapiEncPackedHeader * packed_header) +{ + vaapi_destroy_buffer (GET_VA_DISPLAY (packed_header), + &packed_header->param_id); + vaapi_destroy_buffer (GET_VA_DISPLAY (packed_header), + &packed_header->data_id); + packed_header->param = NULL; + packed_header->data = NULL; +} + +gboolean +gst_vaapi_enc_packed_header_create (GstVaapiEncPackedHeader * packed_header, + const GstVaapiCodecObjectConstructorArgs * args) +{ + gboolean success; + + packed_header->param_id = VA_INVALID_ID; + packed_header->param = NULL; + packed_header->data_id = VA_INVALID_ID; + packed_header->data = NULL; + success = vaapi_create_buffer (GET_VA_DISPLAY (packed_header), + GET_VA_CONTEXT (packed_header), + VAEncPackedHeaderParameterBufferType, + args->param_size, + args->param, &packed_header->param_id, &packed_header->param); + if (!success) + return FALSE; + + if (!args->data_size) + return TRUE; + + success = vaapi_create_buffer (GET_VA_DISPLAY (packed_header), + GET_VA_CONTEXT (packed_header), + VAEncPackedHeaderDataBufferType, + args->data_size, + args->data, &packed_header->data_id, &packed_header->data); + if (!success) + return FALSE; + + return TRUE; +} + +GstVaapiEncPackedHeader * +gst_vaapi_enc_packed_header_new (GstVaapiEncoder * encoder, + gconstpointer param, guint param_size, gconstpointer data, guint data_size) +{ + GstVaapiCodecObject *object; + + object = gst_vaapi_codec_object_new (&GstVaapiEncPackedHeaderClass, + GST_VAAPI_CODEC_BASE (encoder), param, param_size, data, data_size, 0); + return GST_VAAPI_ENC_PACKED_HEADER (object); +} + +gboolean +gst_vaapi_enc_packed_header_set_data (GstVaapiEncPackedHeader * packed_header, + gconstpointer data, guint data_size) +{ + gboolean success; + + g_assert (packed_header->data_id == VA_INVALID_ID); + if (packed_header->data_id != VA_INVALID_ID) { + vaapi_destroy_buffer (GET_VA_DISPLAY (packed_header), + &packed_header->data_id); + packed_header->data = NULL; + } + success = vaapi_create_buffer (GET_VA_DISPLAY (packed_header), + GET_VA_CONTEXT (packed_header), + VAEncPackedHeaderDataBufferType, + data_size, data, &packed_header->data_id, &packed_header->data); + if (!success) + return FALSE; + return TRUE; +} + +/* ------------------------------------------------------------------------- */ +/* --- Encoder Sequence --- */ +/* ------------------------------------------------------------------------- */ + +GST_VAAPI_CODEC_DEFINE_TYPE (GstVaapiEncSequence, gst_vaapi_enc_sequence); + +void +gst_vaapi_enc_sequence_destroy (GstVaapiEncSequence * sequence) +{ + vaapi_destroy_buffer (GET_VA_DISPLAY (sequence), &sequence->param_id); + sequence->param = NULL; +} + +gboolean +gst_vaapi_enc_sequence_create (GstVaapiEncSequence * sequence, + const GstVaapiCodecObjectConstructorArgs * args) +{ + gboolean success; + + sequence->param_id = VA_INVALID_ID; + success = vaapi_create_buffer (GET_VA_DISPLAY (sequence), + GET_VA_CONTEXT (sequence), + VAEncSequenceParameterBufferType, + args->param_size, args->param, &sequence->param_id, &sequence->param); + if (!success) + return FALSE; + + return TRUE; +} + +GstVaapiEncSequence * +gst_vaapi_enc_sequence_new (GstVaapiEncoder * encoder, + gconstpointer param, guint param_size) +{ + GstVaapiCodecObject *object; + + object = gst_vaapi_codec_object_new (&GstVaapiEncSequenceClass, + GST_VAAPI_CODEC_BASE (encoder), param, param_size, NULL, 0, 0); + return GST_VAAPI_ENC_SEQUENCE_CAST (object); +} + +/* ------------------------------------------------------------------------- */ +/* --- Encoder Slice --- */ +/* ------------------------------------------------------------------------- */ + +GST_VAAPI_CODEC_DEFINE_TYPE (GstVaapiEncSlice, gst_vaapi_enc_slice); + +void +gst_vaapi_enc_slice_destroy (GstVaapiEncSlice * slice) +{ + vaapi_destroy_buffer (GET_VA_DISPLAY (slice), &slice->param_id); + slice->param = NULL; +} + +gboolean +gst_vaapi_enc_slice_create (GstVaapiEncSlice * slice, + const GstVaapiCodecObjectConstructorArgs * args) +{ + gboolean success; + + slice->param_id = VA_INVALID_ID; + success = vaapi_create_buffer (GET_VA_DISPLAY (slice), + GET_VA_CONTEXT (slice), + VAEncSliceParameterBufferType, + args->param_size, args->param, &slice->param_id, &slice->param); + if (!success) + return FALSE; + + return TRUE; +} + +GstVaapiEncSlice * +gst_vaapi_enc_slice_new (GstVaapiEncoder * encoder, + gconstpointer param, guint param_size) +{ + GstVaapiCodecObject *object; + + object = gst_vaapi_codec_object_new (&GstVaapiEncSliceClass, + GST_VAAPI_CODEC_BASE (encoder), param, param_size, NULL, 0, 0); + return GST_VAAPI_ENC_SLICE_CAST (object); +} + +/* ------------------------------------------------------------------------- */ +/* --- Encoder Misc Parameter Buffer --- */ +/* ------------------------------------------------------------------------- */ + +GST_VAAPI_CODEC_DEFINE_TYPE (GstVaapiEncMiscParam, gst_vaapi_enc_misc_param); + +void +gst_vaapi_enc_misc_param_destroy (GstVaapiEncMiscParam * misc) +{ + vaapi_destroy_buffer (GET_VA_DISPLAY (misc), &misc->param_id); + misc->param = NULL; + misc->impl = NULL; +} + +gboolean +gst_vaapi_enc_misc_param_create (GstVaapiEncMiscParam * misc, + const GstVaapiCodecObjectConstructorArgs * args) +{ + gboolean success; + + misc->param_id = VA_INVALID_ID; + success = vaapi_create_buffer (GET_VA_DISPLAY (misc), + GET_VA_CONTEXT (misc), + VAEncMiscParameterBufferType, + args->param_size, args->param, &misc->param_id, &misc->param); + if (!success) + return FALSE; + + return TRUE; +} + +GstVaapiEncMiscParam * +gst_vaapi_enc_misc_param_new (GstVaapiEncoder * encoder, + VAEncMiscParameterType type, guint total_size) +{ + GstVaapiCodecObject *object; + GstVaapiEncMiscParam *misc_obj; + VAEncMiscParameterBuffer *misc; + + object = gst_vaapi_codec_object_new (&GstVaapiEncMiscParamClass, + GST_VAAPI_CODEC_BASE (encoder), NULL, total_size, NULL, 0, 0); + if (!object) + return NULL; + + misc_obj = GST_VAAPI_ENC_MISC_PARAM_CAST (object); + misc = misc_obj->param; + misc->type = type; + misc_obj->impl = misc->data; + g_assert (misc_obj->impl); + return misc_obj; +} + +/* ------------------------------------------------------------------------- */ +/* --- Encoder Picture --- */ +/* ------------------------------------------------------------------------- */ + +GST_VAAPI_CODEC_DEFINE_TYPE (GstVaapiEncPicture, gst_vaapi_enc_picture); + +static void +destroy_vaapi_obj_cb (gpointer data, gpointer user_data) +{ + GstVaapiMiniObject *const object = data; + + gst_vaapi_mini_object_unref (object); +} + +void +gst_vaapi_enc_picture_destroy (GstVaapiEncPicture * picture) +{ + if (picture->packed_headers) { + g_ptr_array_foreach (picture->packed_headers, destroy_vaapi_obj_cb, NULL); + g_ptr_array_free (picture->packed_headers, TRUE); + picture->packed_headers = NULL; + } + if (picture->misc_buffers) { + g_ptr_array_foreach (picture->misc_buffers, destroy_vaapi_obj_cb, NULL); + g_ptr_array_free (picture->misc_buffers, TRUE); + picture->misc_buffers = NULL; + } + if (picture->slices) { + g_ptr_array_foreach (picture->slices, destroy_vaapi_obj_cb, NULL); + g_ptr_array_free (picture->slices, TRUE); + picture->slices = NULL; + } + gst_vaapi_mini_object_replace ( + (GstVaapiMiniObject **) (&picture->sequence), NULL); + + g_assert (picture->surface); + picture->surface_id = VA_INVALID_ID; + picture->surface = NULL; + + vaapi_destroy_buffer (GET_VA_DISPLAY (picture), &picture->param_id); + picture->param = NULL; + picture->param = NULL; + + if (picture->frame) { + gst_video_codec_frame_unref (picture->frame); + picture->frame = NULL; + } +} + +gboolean +gst_vaapi_enc_picture_create (GstVaapiEncPicture * picture, + const GstVaapiCodecObjectConstructorArgs * args) +{ + GstVideoCodecFrame *frame; + GstVaapiSurface *surface; + GstVaapiEncObjUserDataHead *user_data; + gboolean success; + + g_assert (args->data); + g_return_val_if_fail (args->data, FALSE); + + frame = (GstVideoCodecFrame *) args->data; + user_data = gst_video_codec_frame_get_user_data (frame); + g_assert (user_data); + surface = user_data->surface; + g_return_val_if_fail (surface, FALSE); + + picture->sequence = NULL; + picture->type = GST_VAAPI_PICTURE_TYPE_NONE; + picture->pts = GST_CLOCK_TIME_NONE; + picture->frame_num = 0; + picture->poc = 0; + + picture->param_id = VA_INVALID_ID; + picture->param_size = args->param_size; + picture->param = NULL; + success = vaapi_create_buffer (GET_VA_DISPLAY (picture), + GET_VA_CONTEXT (picture), + VAEncPictureParameterBufferType, + args->param_size, args->param, &picture->param_id, &picture->param); + if (!success) + return FALSE; + picture->param_size = args->param_size; + + picture->packed_headers = g_ptr_array_new (); + picture->misc_buffers = g_ptr_array_new (); + picture->slices = g_ptr_array_new (); + + g_assert (picture->packed_headers && picture->misc_buffers + && picture->slices); + if (!picture->packed_headers || !picture->misc_buffers || !picture->slices) + return FALSE; + + picture->frame = gst_video_codec_frame_ref (frame); + picture->surface = surface; + g_assert (picture->surface); + picture->surface_id = gst_vaapi_surface_get_id (picture->surface); + g_assert (picture->surface_id != VA_INVALID_SURFACE); + + return TRUE; +} + +GstVaapiEncPicture * +gst_vaapi_enc_picture_new (GstVaapiEncoder * encoder, + gconstpointer param, guint param_size, GstVideoCodecFrame * frame) +{ + GstVaapiCodecObject *object; + + object = gst_vaapi_codec_object_new (&GstVaapiEncPictureClass, + GST_VAAPI_CODEC_BASE (encoder), param, param_size, frame, 0, 0); + if (!object) + return NULL; + return GST_VAAPI_ENC_PICTURE_CAST (object); +} + +void +gst_vaapi_enc_picture_set_sequence (GstVaapiEncPicture * picture, + GstVaapiEncSequence * sequence) +{ + g_return_if_fail (GST_VAAPI_IS_ENC_PICTURE (picture)); + g_return_if_fail (GST_VAAPI_IS_ENC_SEQUENCE (sequence)); + + g_assert (sequence); + gst_vaapi_mini_object_replace ( + (GstVaapiMiniObject **) (&picture->sequence), + GST_VAAPI_MINI_OBJECT (sequence)); +} + +void +gst_vaapi_enc_picture_add_packed_header (GstVaapiEncPicture * picture, + GstVaapiEncPackedHeader * header) +{ + g_return_if_fail (GST_VAAPI_IS_ENC_PICTURE (picture)); + g_return_if_fail (GST_VAAPI_IS_ENC_PACKED_HEADER (header)); + + g_assert (picture->packed_headers); + g_ptr_array_add (picture->packed_headers, + gst_vaapi_mini_object_ref (GST_VAAPI_MINI_OBJECT (header))); +} + +void +gst_vaapi_enc_picture_add_misc_buffer (GstVaapiEncPicture * picture, + GstVaapiEncMiscParam * misc) +{ + g_return_if_fail (GST_VAAPI_IS_ENC_PICTURE (picture)); + g_return_if_fail (GST_VAAPI_IS_ENC_MISC_PARAM (misc)); + + g_assert (picture->misc_buffers); + g_ptr_array_add (picture->misc_buffers, + gst_vaapi_mini_object_ref (GST_VAAPI_MINI_OBJECT (misc))); +} + +void +gst_vaapi_enc_picture_add_slice (GstVaapiEncPicture * picture, + GstVaapiEncSlice * slice) +{ + g_return_if_fail (GST_VAAPI_IS_ENC_PICTURE (picture)); + g_return_if_fail (GST_VAAPI_IS_ENC_SLICE (slice)); + + g_ptr_array_add (picture->slices, + gst_vaapi_mini_object_ref (GST_VAAPI_MINI_OBJECT (slice))); +} + +static gboolean +do_encode (VADisplay dpy, VAContextID ctx, VABufferID * buf_id, void **buf_ptr) +{ + VAStatus status; + + vaapi_unmap_buffer (dpy, *buf_id, buf_ptr); + + status = vaRenderPicture (dpy, ctx, buf_id, 1); + if (!vaapi_check_status (status, "vaRenderPicture()")) + return FALSE; + + /* XXX: vaRenderPicture() is meant to destroy the VA buffer implicitly */ + vaapi_destroy_buffer (dpy, buf_id); + return TRUE; +} + +gboolean +gst_vaapi_enc_picture_encode (GstVaapiEncPicture * picture) +{ + GstVaapiEncSequence *sequence; + GstVaapiEncPackedHeader *packed_header; + GstVaapiEncMiscParam *misc; + GstVaapiEncSlice *slice; + VADisplay va_display; + VAContextID va_context; + VAStatus status; + guint i; + + g_return_val_if_fail (GST_VAAPI_IS_ENC_PICTURE (picture), FALSE); + g_return_val_if_fail (picture->surface_id != VA_INVALID_SURFACE, FALSE); + + va_display = GET_VA_DISPLAY (picture); + va_context = GET_VA_CONTEXT (picture); + + GST_DEBUG ("encode picture 0x%08x", picture->surface_id); + + status = vaBeginPicture (va_display, va_context, picture->surface_id); + if (!vaapi_check_status (status, "vaBeginPicture()")) + return FALSE; + + /* encode sequence parameter */ + sequence = picture->sequence; + if (sequence) { + if (!do_encode (va_display, va_context, + &sequence->param_id, &sequence->param)) + return FALSE; + } + + /* encode picture parameter */ + if (!do_encode (va_display, va_context, &picture->param_id, &picture->param)) + return FALSE; + + /* encode packed headers */ + for (i = 0; i < picture->packed_headers->len; i++) { + packed_header = g_ptr_array_index (picture->packed_headers, i); + if (!do_encode (va_display, va_context, + &packed_header->param_id, &packed_header->param) || + !do_encode (va_display, va_context, + &packed_header->data_id, &packed_header->data)) + return FALSE; + } + + /* encode misc buffers */ + for (i = 0; i < picture->misc_buffers->len; i++) { + misc = g_ptr_array_index (picture->misc_buffers, i); + if (!do_encode (va_display, va_context, &misc->param_id, &misc->param)) + return FALSE; + } + + /* encode slice parameters */ + for (i = 0; i < picture->slices->len; i++) { + slice = g_ptr_array_index (picture->slices, i); + if (!do_encode (va_display, va_context, &slice->param_id, &slice->param)) + return FALSE; + } + + status = vaEndPicture (va_display, va_context); + if (!vaapi_check_status (status, "vaEndPicture()")) + return FALSE; + return TRUE; +} diff --git a/gst-libs/gst/vaapi/gstvaapiencoder_objects.h b/gst-libs/gst/vaapi/gstvaapiencoder_objects.h new file mode 100644 index 0000000000..240d55b521 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiencoder_objects.h @@ -0,0 +1,379 @@ +/* + * gstvaapiencoder_objects.h - VA encoder objects abstraction + * + * 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_VAAPI_ENCODER_OBJECTS_H +#define GST_VAAPI_ENCODER_OBJECTS_H + +#include +#include +#include + +G_BEGIN_DECLS + +typedef struct _GstVaapiEncPicture GstVaapiEncPicture; +typedef struct _GstVaapiEncSequence GstVaapiEncSequence; +typedef struct _GstVaapiEncMiscParam GstVaapiEncMiscParam; +typedef struct _GstVaapiEncSlice GstVaapiEncSlice; +typedef struct _GstVaapiCodedBuffer GstVaapiCodedBuffer; +typedef struct _GstVaapiEncPackedHeader GstVaapiEncPackedHeader; + +/* ------------------------------------------------------------------------- */ +/* --- Encoder Coded Buffer --- */ +/* ------------------------------------------------------------------------- */ + +#define GST_VAAPI_CODED_BUFFER_CAST(obj) \ + ((GstVaapiCodedBuffer *)(obj)) + +#define GST_VAAPI_CODED_BUFFER(obj) \ + GST_VAAPI_CODED_BUFFER_CAST(obj) + +#define GST_VAAPI_IS_CODED_BUFFER(obj) \ + (GST_VAAPI_CODED_BUFFER(obj) != NULL) + +/** + * GstVaapiCodedBuffer: + * + * A #GstVaapiCodecObject holding an encoded buffer. + */ +struct _GstVaapiCodedBuffer +{ + /*< private > */ + GstVaapiCodecObject parent_instance; + VABufferID buf_id; + + /*< public > */ + VACodedBufferSegment *segment_list; +}; + +G_GNUC_INTERNAL +GstVaapiCodedBuffer * +gst_vaapi_coded_buffer_new (GstVaapiEncoder * encoder, + gconstpointer param, guint param_size); + +gboolean +gst_vaapi_coded_buffer_map (GstVaapiCodedBuffer * buf, void **data); + +void +gst_vaapi_coded_buffer_unmap (GstVaapiCodedBuffer * buf); + +gint32 +gst_vaapi_coded_buffer_get_size (GstVaapiCodedBuffer * buf); + +gboolean +gst_vaapi_coded_buffer_get_buffer (GstVaapiCodedBuffer * buf, + GstBuffer * output); + +/* ------------------------------------------------------------------------- */ +/* --- Encoder Packed Header --- */ +/* ------------------------------------------------------------------------- */ + +#define GST_VAAPI_ENC_PACKED_HEADER_CAST(obj) \ + ((GstVaapiEncPackedHeader *)(obj)) + +#define GST_VAAPI_ENC_PACKED_HEADER(obj) \ + GST_VAAPI_ENC_PACKED_HEADER_CAST(obj) + +#define GST_VAAPI_IS_ENC_PACKED_HEADER(obj) \ + (GST_VAAPI_ENC_PACKED_HEADER(obj) != NULL) + +/** + * GstVaapiEncPackedHeader: + * + * A #GstVaapiCodecObject holding a encoder packed header + * parameter/data parameter. + */ +struct _GstVaapiEncPackedHeader +{ + /*< private > */ + GstVaapiCodecObject parent_instance; + + /*< public > */ + VABufferID param_id; + gpointer param; + VABufferID data_id; + gpointer data; +}; + +G_GNUC_INTERNAL +GstVaapiEncPackedHeader * +gst_vaapi_enc_packed_header_new (GstVaapiEncoder * encoder, + gconstpointer param, guint param_size, gconstpointer data, guint data_size); + +G_GNUC_INTERNAL +gboolean +gst_vaapi_enc_packed_header_set_data (GstVaapiEncPackedHeader * packed_header, + gconstpointer data, guint data_size); + +/* ------------------------------------------------------------------------- */ +/* --- Encoder Sequence --- */ +/* ------------------------------------------------------------------------- */ + +#define GST_VAAPI_ENC_SEQUENCE_CAST(obj) \ + ((GstVaapiEncSequence *)(obj)) + +#define GST_VAAPI_ENC_SEQUENCE(obj) \ + GST_VAAPI_ENC_SEQUENCE_CAST(obj) + +#define GST_VAAPI_IS_ENC_SEQUENCE(obj) \ + (GST_VAAPI_ENC_SEQUENCE(obj) != NULL) + +/** + * GstVaapiEncSequence: + * + * A #GstVaapiCodecObject holding a encoder sequence parameter. + */ +struct _GstVaapiEncSequence +{ + /*< private > */ + GstVaapiCodecObject parent_instance; + + /*< public > */ + VABufferID param_id; + gpointer param; +}; + +G_GNUC_INTERNAL +GstVaapiEncSequence * +gst_vaapi_enc_sequence_new (GstVaapiEncoder * encoder, + gconstpointer param, guint param_size); + +/* ------------------------------------------------------------------------- */ +/* --- Encoder Slice --- */ +/* ------------------------------------------------------------------------- */ + +#define GST_VAAPI_ENC_SLICE_CAST(obj) \ + ((GstVaapiEncSlice *)(obj)) + +#define GST_VAAPI_ENC_SLICE(obj) \ + GST_VAAPI_ENC_SLICE_CAST(obj) + +#define GST_VAAPI_IS_ENC_SLICE(obj) \ + (GST_VAAPI_ENC_SLICE(obj) != NULL) + +/** + * GstVaapiEncSlice: + * + * A #GstVaapiCodecObject holding a encoder slice parameter. + */ +struct _GstVaapiEncSlice +{ + /*< private > */ + GstVaapiCodecObject parent_instance; + + /*< public > */ + VABufferID param_id; + gpointer param; +}; + +G_GNUC_INTERNAL +void +gst_vaapi_enc_slice_destroy (GstVaapiEncSlice * slice); + +G_GNUC_INTERNAL +gboolean +gst_vaapi_enc_slice_create (GstVaapiEncSlice * slice, + const GstVaapiCodecObjectConstructorArgs * args); + +G_GNUC_INTERNAL +GstVaapiEncSlice * +gst_vaapi_enc_slice_new (GstVaapiEncoder * encoder, + gconstpointer param, guint param_size); + +/* ------------------------------------------------------------------------- */ +/* --- Encoder Misc Parameter Buffer --- */ +/* ------------------------------------------------------------------------- */ + +#define GST_VAAPI_ENC_MISC_PARAM_CAST(obj) \ + ((GstVaapiEncMiscParam *)(obj)) + +#define GST_VAAPI_ENC_MISC_PARAM(obj) \ + GST_VAAPI_ENC_MISC_PARAM_CAST(obj) + +#define GST_VAAPI_IS_ENC_MISC_PARAM(obj) \ + (GST_VAAPI_ENC_MISC_PARAM(obj) != NULL) + +/** + * GstVaapiEncMiscParam: + * + * A #GstVaapiCodecObject holding a encoder misc parameter. + */ +struct _GstVaapiEncMiscParam +{ + /*< private > */ + GstVaapiCodecObject parent_instance; + gpointer param; + + /*< public > */ + VABufferID param_id; + gpointer impl; +}; + +G_GNUC_INTERNAL +GstVaapiEncMiscParam * +gst_vaapi_enc_misc_param_new (GstVaapiEncoder * encoder, + VAEncMiscParameterType type, guint total_size); + +/* ------------------------------------------------------------------------- */ +/* --- Encoder Picture --- */ +/* ------------------------------------------------------------------------- */ + +#define GST_VAAPI_ENC_PICTURE_CAST(obj) \ + ((GstVaapiEncPicture *)(obj)) + +#define GST_VAAPI_ENC_PICTURE(obj) \ + GST_VAAPI_ENC_PICTURE_CAST(obj) + +#define GST_VAAPI_IS_ENC_PICTURE(obj) \ + (GST_VAAPI_ENC_PICTURE(obj) != NULL) + +typedef enum +{ + GST_VAAPI_ENC_PICTURE_FLAG_IDR = (GST_VAAPI_CODEC_OBJECT_FLAG_LAST << 0), + GST_VAAPI_ENC_PICTURE_FLAG_LAST = (GST_VAAPI_CODEC_OBJECT_FLAG_LAST << 1), +} GstVaapiEncPictureFlags; + +#define GST_VAAPI_ENC_PICTURE_FLAGS GST_VAAPI_MINI_OBJECT_FLAGS +#define GST_VAAPI_ENC_PICTURE_FLAG_IS_SET GST_VAAPI_MINI_OBJECT_FLAG_IS_SET +#define GST_VAAPI_ENC_PICTURE_FLAG_SET GST_VAAPI_MINI_OBJECT_FLAG_SET +#define GST_VAAPI_ENC_PICTURE_FLAG_UNSET GST_VAAPI_MINI_OBJECT_FLAG_UNSET + +#define GST_VAAPI_ENC_PICTURE_IS_IDR(picture) \ + GST_VAAPI_ENC_PICTURE_FLAG_IS_SET(picture, GST_VAAPI_ENC_PICTURE_FLAG_IDR) + +#define GST_VAAPI_ENC_PICTURE_GET_FRAME(picture) \ + (picture)->frame + +typedef struct +{ + GstVaapiSurface *surface; +} GstVaapiEncObjUserDataHead; + +/** + * GstVaapiEncPicture: + * + * A #GstVaapiCodecObject holding a picture parameter. + */ +struct _GstVaapiEncPicture +{ + /*< private > */ + GstVaapiCodecObject parent_instance; + GstVideoCodecFrame *frame; + GstVaapiSurface *surface; + GstVaapiEncSequence *sequence; + /*< private >, picture packed header */ + GPtrArray *packed_headers; + GPtrArray *misc_buffers; + GPtrArray *slices; + VABufferID param_id; + guint param_size; + + /*< public > */ + GstVaapiPictureType type; + VASurfaceID surface_id; + gpointer param; + GstClockTime pts; + guint frame_num; + guint poc; +}; + +G_GNUC_INTERNAL +void +gst_vaapi_enc_picture_destroy (GstVaapiEncPicture * picture); + +G_GNUC_INTERNAL +gboolean +gst_vaapi_enc_picture_create (GstVaapiEncPicture * picture, + const GstVaapiCodecObjectConstructorArgs * args); + +G_GNUC_INTERNAL +GstVaapiEncPicture * +gst_vaapi_enc_picture_new (GstVaapiEncoder * encoder, + gconstpointer param, guint param_size, GstVideoCodecFrame * frame); + +G_GNUC_INTERNAL +void +gst_vaapi_enc_picture_set_sequence (GstVaapiEncPicture * picture, + GstVaapiEncSequence * sequence); + +G_GNUC_INTERNAL +void +gst_vaapi_enc_picture_add_packed_header (GstVaapiEncPicture * picture, + GstVaapiEncPackedHeader * header); + +G_GNUC_INTERNAL +void +gst_vaapi_enc_picture_add_misc_buffer (GstVaapiEncPicture * picture, + GstVaapiEncMiscParam * misc); + +G_GNUC_INTERNAL +void +gst_vaapi_enc_picture_add_slice (GstVaapiEncPicture * picture, + GstVaapiEncSlice * slice); + +G_GNUC_INTERNAL +gboolean +gst_vaapi_enc_picture_encode (GstVaapiEncPicture * picture); + +static inline gpointer +gst_vaapi_enc_picture_ref (gpointer ptr) +{ + return gst_vaapi_mini_object_ref (GST_VAAPI_MINI_OBJECT (ptr)); +} + +static inline void +gst_vaapi_enc_picture_unref (gpointer ptr) +{ + gst_vaapi_mini_object_unref (GST_VAAPI_MINI_OBJECT (ptr)); +} + +#define gst_vaapi_enc_picture_replace(old_picture_p, new_picture) \ + gst_vaapi_mini_object_replace((GstVaapiMiniObject **)(old_picture_p), \ + (GstVaapiMiniObject *)(new_picture)) + +/* GST_VAAPI_CODED_BUFFER_NEW */ +#define GST_VAAPI_CODED_BUFFER_NEW(encoder, size) \ + gst_vaapi_coded_buffer_new(GST_VAAPI_ENCODER_CAST(encoder), \ + NULL, size) + +/* GST_VAAPI_ENC_SEQUENCE_NEW */ +#define GST_VAAPI_ENC_SEQUENCE_NEW(codec, encoder) \ + gst_vaapi_enc_sequence_new(GST_VAAPI_ENCODER_CAST(encoder), \ + NULL, sizeof(VAEncSequenceParameterBuffer##codec)) + +/* GST_VAAPI_ENC_SLICE_NEW */ +#define GST_VAAPI_ENC_SLICE_NEW(codec, encoder) \ + gst_vaapi_enc_slice_new(GST_VAAPI_ENCODER_CAST(encoder), \ + NULL, sizeof(VAEncSliceParameterBuffer##codec)) + +/* GST_VAAPI_ENC_MISC_PARAM_NEW */ +#define GST_VAAPI_ENC_MISC_PARAM_NEW(type, encoder) \ + gst_vaapi_enc_misc_param_new(GST_VAAPI_ENCODER_CAST(encoder), \ + VAEncMiscParameterType##type, \ + (sizeof(VAEncMiscParameterBuffer) + sizeof(VAEncMiscParameter##type))) + +/* GST_VAAPI_ENC_PICTURE_NEW */ +#define GST_VAAPI_ENC_PICTURE_NEW(codec, encoder, frame) \ + gst_vaapi_enc_picture_new(GST_VAAPI_ENCODER_CAST(encoder), \ + NULL, sizeof(VAEncPictureParameterBuffer##codec), frame) + +G_END_DECLS + +#endif /* GST_VAAPI_ENCODER_OBJECTS_H */ diff --git a/gst-libs/gst/vaapi/gstvaapiencoder_priv.h b/gst-libs/gst/vaapi/gstvaapiencoder_priv.h new file mode 100644 index 0000000000..71fff0cd92 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiencoder_priv.h @@ -0,0 +1,188 @@ +/* + * gstvaapiencoder_priv.h - VA encoder abstraction (private definitions) + * + * 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_VAAPI_ENCODER_PRIV_H +#define GST_VAAPI_ENCODER_PRIV_H + +#include +#include +#include +#include + +G_BEGIN_DECLS + +#define GST_VAAPI_ENCODER_CLASS(klass) \ + ((GstVaapiEncoderClass *)(klass)) + +#define GST_IS_VAAPI_ENCODER_CLASS(klass) \ + ((klass) != NULL) + +#define GST_VAAPI_ENCODER_GET_CLASS(obj) \ + GST_VAAPI_ENCODER_CLASS(GST_VAAPI_MINI_OBJECT_GET_CLASS(obj)) + +/* Get GstVaapiDisplay* */ +#define GST_VAAPI_ENCODER_DISPLAY(encoder) \ + (GST_VAAPI_ENCODER_CAST(encoder)->display) + +/* Get VADisplay */ +#define GST_VAAPI_ENCODER_VA_DISPLAY(encoder) \ + (GST_VAAPI_ENCODER_CAST(encoder)->va_display) + +/* Get GstVaapiContext* */ +#define GST_VAAPI_ENCODER_CONTEXT(encoder) \ + (GST_VAAPI_ENCODER_CAST(encoder)->context) + +/* Get VAContext */ +#define GST_VAAPI_ENCODER_VA_CONTEXT(encoder) \ + (GST_VAAPI_ENCODER_CAST(encoder)->va_context) + +#define GST_VAAPI_ENCODER_VIDEO_INFO(encoder) (GST_VAAPI_ENCODER_CAST(encoder)->video_info) +#define GST_VAAPI_ENCODER_CAPS(encoder) (GST_VAAPI_ENCODER_CAST(encoder)->caps) +#define GST_VAAPI_ENCODER_WIDTH(encoder) (GST_VAAPI_ENCODER_CAST(encoder)->video_info.width) +#define GST_VAAPI_ENCODER_HEIGHT(encoder) (GST_VAAPI_ENCODER_CAST(encoder)->video_info.height) +#define GST_VAAPI_ENCODER_FPS_N(encoder) (GST_VAAPI_ENCODER_CAST(encoder)->video_info.fps_n) +#define GST_VAAPI_ENCODER_FPS_D(encoder) (GST_VAAPI_ENCODER_CAST(encoder)->video_info.fps_d) +#define GST_VAAPI_ENCODER_RATE_CONTROL(encoder) \ + (GST_VAAPI_ENCODER_CAST(encoder)->rate_control) + +#define GST_VAAPI_ENCODER_LOG_ERROR(...) GST_ERROR( __VA_ARGS__) +#define GST_VAAPI_ENCODER_LOG_WARNING(...) GST_WARNING( __VA_ARGS__) +#define GST_VAAPI_ENCODER_LOG_DEBUG(...) GST_DEBUG( __VA_ARGS__) +#define GST_VAAPI_ENCODER_LOG_INFO(...) GST_INFO( __VA_ARGS__) + +#define GST_VAAPI_ENCODER_CHECK_STATUS(exp, err_num, err_reason, ...) \ + if (!(exp)) { \ + ret = err_num; \ + GST_VAAPI_ENCODER_LOG_ERROR(err_reason, ## __VA_ARGS__); \ + goto end; \ + } + +typedef struct _GstVaapiCodedBufferProxyClass GstVaapiCodedBufferProxyClass; +typedef struct _GstVaapiEncoderClass GstVaapiEncoderClass; + +struct _GstVaapiEncoder +{ + /*< private > */ + GstVaapiMiniObject parent_instance; + + GstVaapiDisplay *display; + GstVaapiContext *context; + GstCaps *caps; + + VADisplay va_display; + VAContextID va_context; + GstVideoInfo video_info; + GstVaapiRateControl rate_control; + + guint buf_count; + guint max_buf_num; + guint buf_size; + GMutex lock; + GCond codedbuf_free; + GCond surface_free; + GQueue coded_buffers; + + /* queue for sync */ + GQueue sync_pictures; + GCond sync_ready; +}; + +struct _GstVaapiEncoderClass +{ + GObjectClass parent_class; + + gboolean (*init) (GstVaapiEncoder * encoder); + void (*destroy) (GstVaapiEncoder * encoder); + + GstCaps * (*set_format) (GstVaapiEncoder * encoder, + GstVideoCodecState * in_state, + GstCaps * ref_caps); + + gboolean (*get_context_info) (GstVaapiEncoder * encoder, + GstVaapiContextInfo * info); + + GstVaapiEncoderStatus (*reordering) (GstVaapiEncoder * encoder, + GstVideoCodecFrame * in, + gboolean flush, + GstVaapiEncPicture ** out); + GstVaapiEncoderStatus (*encode) (GstVaapiEncoder * encoder, + GstVaapiEncPicture * picture, + GstVaapiCodedBufferProxy * codedbuf); + + GstVaapiEncoderStatus (*flush) (GstVaapiEncoder * encoder); + + /* get_codec_data can be NULL */ + GstVaapiEncoderStatus (*get_codec_data) (GstVaapiEncoder * encoder, + GstBuffer ** codec_data); +}; + +struct _GstVaapiCodedBufferProxy +{ + /*< private >*/ + GstVaapiMiniObject parent_instance; + GstVaapiEncoder *encoder; + + /*< public >*/ + GstVaapiCodedBuffer *buffer; +}; + +struct _GstVaapiCodedBufferProxyClass +{ + GstVaapiMiniObjectClass parent_class; +}; + +void +gst_vaapi_encoder_class_init (GstVaapiEncoderClass * klass); + +GstVaapiEncoder * +gst_vaapi_encoder_new (const GstVaapiEncoderClass * klass, + GstVaapiDisplay * display); + +void +gst_vaapi_encoder_finalize (GstVaapiEncoder * encoder); + +GstVaapiSurfaceProxy * +gst_vaapi_encoder_create_surface (GstVaapiEncoder * + encoder); + +void +gst_vaapi_encoder_release_surface (GstVaapiEncoder * encoder, + GstVaapiSurfaceProxy * surface); + +/* ------------------ GstVaapiCodedBufferProxy ---------------------------- */ + +GstVaapiCodedBufferProxy * +gst_vaapi_coded_buffer_proxy_new (GstVaapiEncoder * + encoder); + +GstVaapiCodedBufferProxy * +gst_vaapi_coded_buffer_proxy_ref (GstVaapiCodedBufferProxy * proxy); + +void +gst_vaapi_coded_buffer_proxy_unref (GstVaapiCodedBufferProxy * proxy); + +void +gst_vaapi_coded_buffer_proxy_replace (GstVaapiCodedBufferProxy ** old_proxy_ptr, + GstVaapiCodedBufferProxy * new_proxy); + +G_END_DECLS + +#endif /* GST_VAAPI_ENCODER_PRIV_H */