va: Add a common encoder object.
authorHe Junyan <junyan.he@intel.com>
Mon, 4 Oct 2021 17:50:07 +0000 (01:50 +0800)
committerVíctor Manuel Jáquez Leal <vjaquez@igalia.com>
Tue, 1 Mar 2022 09:53:50 +0000 (10:53 +0100)
As the counterpart of the va decoder, this class handles all the
common logic for the encoding routine and miscellaneous queries about
encoding.

Co-authored-by: Victor Jaquez <vjaquez@igalia.com>
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1051>

subprojects/gst-plugins-bad/sys/va/gstvaencoder.c [new file with mode: 0644]
subprojects/gst-plugins-bad/sys/va/gstvaencoder.h [new file with mode: 0644]
subprojects/gst-plugins-bad/sys/va/meson.build

diff --git a/subprojects/gst-plugins-bad/sys/va/gstvaencoder.c b/subprojects/gst-plugins-bad/sys/va/gstvaencoder.c
new file mode 100644 (file)
index 0000000..d6f45e7
--- /dev/null
@@ -0,0 +1,1362 @@
+/* GStreamer
+ *  Copyright (C) 2021 Intel Corporation
+ *     Author: He Junyan <junyan.he@intel.com>
+ *     Author: Víctor Jáquez <vjaquez@igalia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstvaencoder.h"
+
+#include "vacompat.h"
+#include "gstvaallocator.h"
+#include "gstvapool.h"
+#include "gstvacaps.h"
+#include "gstvadisplay_priv.h"
+#include "gstvavideoformat.h"
+#include <gst/va/gstvadisplay_wrapped.h>
+
+#define VA_ENTRYPOINT_FLAG(entry) (1U << G_PASTE(VAEntrypoint, entry))
+
+typedef struct _GstVaProfileConfig GstVaProfileConfig;
+typedef struct _GstVaPackedHeader GstVaPackedHeader;
+typedef struct _GstVaEncSlice GstVaEncSlice;
+typedef struct _GstVaEncReconstruct GstVaEncReconstruct;
+
+struct _GstVaProfileConfig
+{
+  VAProfile profile;
+  guint32 entrypoints;          /* bits map of GstVaapiEntrypoint */
+};
+
+struct _GstVaEncoder
+{
+  GstObject parent;
+
+  GArray *available_profiles;
+  GstCaps *srcpad_caps;
+  GstCaps *sinkpad_caps;
+  GstVaDisplay *display;
+  VAConfigID config;
+  VAContextID context;
+  VAProfile profile;
+  VAEntrypoint entrypoint;
+  guint rt_format;
+  gint coded_width;
+  gint coded_height;
+  gint codedbuf_size;
+
+  GstBufferPool *recon_pool;
+  /* global parameters va buffers, such as sequence, hrd, etc */
+  GArray *params;
+};
+
+GST_DEBUG_CATEGORY_STATIC (gst_va_encoder_debug);
+#define GST_CAT_DEFAULT gst_va_encoder_debug
+
+#define gst_va_encoder_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstVaEncoder, gst_va_encoder, GST_TYPE_OBJECT,
+    GST_DEBUG_CATEGORY_INIT (gst_va_encoder_debug, "vaencoder", 0,
+        "VA Encoder"));
+
+enum
+{
+  PROP_DISPLAY = 1,
+  PROP_PROFILE,
+  PROP_ENTRYPOINT,
+  PROP_WIDTH,
+  PROP_HEIGHT,
+  PROP_CHROMA,
+  PROP_CODED_BUF_SIZE,
+  N_PROPERTIES
+};
+
+static GParamSpec *g_properties[N_PROPERTIES];
+
+static gboolean
+_destroy_buffer (GstVaDisplay * display, VABufferID buffer)
+{
+  VAStatus status;
+  gboolean ret = TRUE;
+  VADisplay dpy = gst_va_display_get_va_dpy (display);
+
+  status = vaDestroyBuffer (dpy, buffer);
+  if (status != VA_STATUS_SUCCESS) {
+    ret = FALSE;
+    GST_WARNING ("Failed to destroy the buffer: %s", vaErrorStr (status));
+  }
+
+  return ret;
+}
+
+static VABufferID
+_create_buffer (GstVaEncoder * self, gint type, gpointer data, gsize size)
+{
+  VAStatus status;
+  VADisplay dpy = gst_va_display_get_va_dpy (self->display);
+  VABufferID buffer;
+  VAContextID context;
+
+  GST_OBJECT_LOCK (self);
+  context = self->context;
+  GST_OBJECT_UNLOCK (self);
+
+  dpy = gst_va_display_get_va_dpy (self->display);
+  status = vaCreateBuffer (dpy, context, type, size, 1, data, &buffer);
+  if (status != VA_STATUS_SUCCESS) {
+    GST_ERROR_OBJECT (self, "vaCreateBuffer: %s", vaErrorStr (status));
+    return VA_INVALID_ID;
+  }
+
+  return buffer;
+}
+
+static void
+gst_va_encoder_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstVaEncoder *self = GST_VA_ENCODER (object);
+
+  GST_OBJECT_LOCK (self);
+
+  switch (prop_id) {
+    case PROP_DISPLAY:{
+      g_assert (!self->display);
+      self->display = g_value_dup_object (value);
+      break;
+    }
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+
+  GST_OBJECT_UNLOCK (self);
+}
+
+static void
+gst_va_encoder_get_property (GObject * object, guint prop_id, GValue * value,
+    GParamSpec * pspec)
+{
+  GstVaEncoder *self = GST_VA_ENCODER (object);
+
+  GST_OBJECT_LOCK (self);
+
+  switch (prop_id) {
+    case PROP_DISPLAY:
+      g_value_set_object (value, self->display);
+      break;
+    case PROP_PROFILE:
+      g_value_set_int (value, self->profile);
+      break;
+    case PROP_ENTRYPOINT:
+      g_value_set_int (value, self->entrypoint);
+      break;
+    case PROP_CHROMA:
+      g_value_set_uint (value, self->rt_format);
+      break;
+    case PROP_WIDTH:
+      g_value_set_int (value, self->coded_width);
+      break;
+    case PROP_HEIGHT:
+      g_value_set_int (value, self->coded_height);
+      break;
+    case PROP_CODED_BUF_SIZE:
+      g_value_set_int (value, self->codedbuf_size);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+
+  GST_OBJECT_UNLOCK (self);
+}
+
+static void
+gst_va_encoder_init (GstVaEncoder * self)
+{
+  self->profile = VAProfileNone;
+  self->entrypoint = 0;
+  self->config = VA_INVALID_ID;
+  self->context = VA_INVALID_ID;
+  self->rt_format = 0;
+  self->coded_width = 0;
+  self->coded_height = 0;
+  self->codedbuf_size = 0;
+  g_clear_pointer (&self->recon_pool, gst_object_unref);
+}
+
+static inline gboolean
+_is_open_unlocked (GstVaEncoder * self)
+{
+  return (self->config != VA_INVALID_ID && self->profile != VAProfileNone);
+}
+
+gboolean
+gst_va_encoder_is_open (GstVaEncoder * self)
+{
+  gboolean ret;
+
+  g_return_val_if_fail (GST_IS_VA_ENCODER (self), FALSE);
+
+  GST_OBJECT_LOCK (self);
+  ret = _is_open_unlocked (self);
+  GST_OBJECT_UNLOCK (self);
+  return ret;
+}
+
+gboolean
+gst_va_encoder_close (GstVaEncoder * self)
+{
+  VADisplay dpy;
+  VAStatus status;
+  VAConfigID config = VA_INVALID_ID;
+  VAContextID context = VA_INVALID_ID;
+  GstBufferPool *recon_pool = NULL;
+
+  g_return_val_if_fail (GST_IS_VA_ENCODER (self), FALSE);
+
+
+  if (!gst_va_encoder_is_open (self))
+    return TRUE;
+
+  gst_va_encoder_reset_global_params (self);
+
+  GST_OBJECT_LOCK (self);
+  config = self->config;
+  context = self->context;
+
+  recon_pool = self->recon_pool;
+  self->recon_pool = NULL;
+
+  g_clear_pointer (&self->params, g_array_unref);
+
+  gst_va_encoder_init (self);
+  GST_OBJECT_UNLOCK (self);
+
+  gst_buffer_pool_set_active (recon_pool, FALSE);
+  g_clear_pointer (&recon_pool, gst_object_unref);
+
+  dpy = gst_va_display_get_va_dpy (self->display);
+
+  if (context != VA_INVALID_ID) {
+    status = vaDestroyContext (dpy, context);
+    if (status != VA_STATUS_SUCCESS)
+      GST_ERROR_OBJECT (self, "vaDestroyContext: %s", vaErrorStr (status));
+  }
+
+  status = vaDestroyConfig (dpy, config);
+  if (status != VA_STATUS_SUCCESS)
+    GST_ERROR_OBJECT (self, "vaDestroyConfig: %s", vaErrorStr (status));
+
+  gst_caps_replace (&self->srcpad_caps, NULL);
+  gst_caps_replace (&self->sinkpad_caps, NULL);
+
+  return TRUE;
+}
+
+static GArray *
+_get_surface_formats (GstVaDisplay * display, VAConfigID config)
+{
+  GArray *formats;
+  GstVideoFormat format;
+  VASurfaceAttrib *attribs;
+  guint i, attrib_count;
+
+  attribs = gst_va_get_surface_attribs (display, config, &attrib_count);
+  if (!attribs)
+    return NULL;
+
+  formats = g_array_new (FALSE, FALSE, sizeof (GstVideoFormat));
+
+  for (i = 0; i < attrib_count; i++) {
+    if (attribs[i].value.type != VAGenericValueTypeInteger)
+      continue;
+    switch (attribs[i].type) {
+      case VASurfaceAttribPixelFormat:
+        format = gst_va_video_format_from_va_fourcc (attribs[i].value.value.i);
+        if (format != GST_VIDEO_FORMAT_UNKNOWN)
+          g_array_append_val (formats, format);
+        break;
+      default:
+        break;
+    }
+  }
+
+  g_free (attribs);
+
+  if (formats->len == 0) {
+    g_array_unref (formats);
+    return NULL;
+  }
+
+  return formats;
+}
+
+static GstBufferPool *
+_create_reconstruct_pool (GstVaDisplay * display, GArray * surface_formats,
+    GstVideoFormat format, gint coded_width, gint coded_height, guint max_num)
+{
+  GstAllocator *allocator = NULL;
+  guint usage_hint = VA_SURFACE_ATTRIB_USAGE_HINT_ENCODER;
+  GstVideoInfo info;
+  GstAllocationParams params = { 0, };
+  GstBufferPool *pool;
+  guint size;
+  GstCaps *caps = NULL;
+
+  gst_video_info_set_format (&info, format, coded_width, coded_height);
+
+  size = GST_VIDEO_INFO_SIZE (&info);
+
+  caps = gst_video_info_to_caps (&info);
+  gst_caps_set_features_simple (caps,
+      gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_VA));
+
+  allocator = gst_va_allocator_new (display, surface_formats);
+
+  if (!gst_va_allocator_set_format (allocator, &info, usage_hint)) {
+    gst_clear_object (&allocator);
+    gst_clear_caps (&caps);
+    return NULL;
+  }
+
+  gst_allocation_params_init (&params);
+
+  pool = gst_va_pool_new_with_config (caps, size, 1, max_num,
+      usage_hint, allocator, &params);
+
+  gst_clear_object (&allocator);
+  gst_clear_caps (&caps);
+
+  return pool;
+}
+
+gboolean
+gst_va_encoder_open (GstVaEncoder * self, VAProfile profile,
+    VAEntrypoint entrypoint, GstVideoFormat video_format, guint rt_format,
+    gint coded_width, gint coded_height, gint codedbuf_size,
+    guint reconstruct_buffer_num, guint rc_ctrl, guint32 packed_headers)
+{
+  /* *INDENT-OFF* */
+  VAConfigAttrib attribs[3] = {
+    { .type = VAConfigAttribRTFormat, .value = rt_format, },
+    { .type = VAConfigAttribRateControl, .value = rc_ctrl, },
+  };
+  /* *INDENT-ON* */
+  VAConfigID config = VA_INVALID_ID;
+  VAContextID context = VA_INVALID_ID;
+  VADisplay dpy;
+  GPtrArray *reconstruct_buffers = NULL;
+  GArray *surfaces = NULL;
+  GArray *surface_formats = NULL;
+  VAStatus status;
+  GstBufferPool *recon_pool = NULL;
+  guint i, attrib_idx = 2;
+
+  g_return_val_if_fail (GST_IS_VA_ENCODER (self), FALSE);
+  g_return_val_if_fail (reconstruct_buffer_num > 0, FALSE);
+  g_return_val_if_fail (codedbuf_size > 0, FALSE);
+
+  if (gst_va_encoder_is_open (self))
+    return TRUE;
+
+  if (!gst_va_encoder_has_profile_and_entrypoint (self, profile, entrypoint)) {
+    GST_ERROR_OBJECT (self, "Unsupported profile: %d, entrypoint: %d",
+        profile, entrypoint);
+    return FALSE;
+  }
+
+  if (packed_headers > 0) {
+    attribs[attrib_idx].type = VAConfigAttribEncPackedHeaders;
+    attribs[attrib_idx].value = packed_headers;
+    attrib_idx++;
+  }
+
+  dpy = gst_va_display_get_va_dpy (self->display);
+
+  status = vaCreateConfig (dpy, profile, entrypoint, attribs, attrib_idx,
+      &config);
+  if (status != VA_STATUS_SUCCESS) {
+    GST_ERROR_OBJECT (self, "vaCreateConfig: %s", vaErrorStr (status));
+    goto error;
+  }
+
+  surface_formats = _get_surface_formats (self->display, config);
+  if (!surface_formats) {
+    GST_ERROR_OBJECT (self, "Failed to get surface formats");
+    goto error;
+  }
+
+  recon_pool = _create_reconstruct_pool (self->display, surface_formats,
+      video_format, coded_width, coded_height, reconstruct_buffer_num);
+  if (!recon_pool) {
+    GST_ERROR_OBJECT (self, "Failed to create reconstruct pool");
+    goto error;
+  }
+  gst_buffer_pool_set_active (recon_pool, TRUE);
+
+  /* Create VA surfaces list for vaCreateContext() */
+  surfaces = g_array_sized_new (FALSE, FALSE, sizeof (VASurfaceID),
+      reconstruct_buffer_num);
+  if (!surfaces)
+    goto error;
+
+  reconstruct_buffers = g_ptr_array_sized_new (reconstruct_buffer_num);
+  if (!reconstruct_buffers)
+    goto error;
+
+  g_ptr_array_set_free_func (reconstruct_buffers,
+      (GDestroyNotify) gst_buffer_unref);
+
+  /* The encoder need to binding all reconstruct surface when create contex,
+     we have to allocate them all here. */
+  for (i = 0; i < reconstruct_buffer_num; i++) {
+    GstBuffer *buffer;
+    VASurfaceID surface_id;
+    GstFlowReturn ret;
+    GstBufferPoolAcquireParams buffer_pool_params = { 0, };
+
+    buffer_pool_params.flags = GST_BUFFER_POOL_ACQUIRE_FLAG_DONTWAIT;
+    ret = gst_buffer_pool_acquire_buffer (recon_pool, &buffer,
+        &buffer_pool_params);
+    if (ret != GST_FLOW_OK) {
+      GST_ERROR_OBJECT (self, "Failed to create the reconstruct picture.");
+      goto error;
+    }
+
+    surface_id = gst_va_buffer_get_surface (buffer);
+    g_assert (surface_id != VA_INVALID_ID);
+
+    g_ptr_array_add (reconstruct_buffers, buffer);
+    g_array_append_val (surfaces, surface_id);
+  }
+
+  g_assert (surfaces->len == reconstruct_buffer_num);
+
+  status = vaCreateContext (dpy, config, coded_width, coded_height,
+      VA_PROGRESSIVE, (VASurfaceID *) surfaces->data, reconstruct_buffer_num,
+      &context);
+  if (status != VA_STATUS_SUCCESS) {
+    GST_ERROR_OBJECT (self, "vaCreateConfig: %s", vaErrorStr (status));
+    goto error;
+  }
+
+  g_clear_pointer (&surfaces, g_array_unref);
+  g_clear_pointer (&reconstruct_buffers, g_ptr_array_unref);
+
+  GST_OBJECT_LOCK (self);
+
+  self->config = config;
+  self->context = context;
+  self->profile = profile;
+  self->entrypoint = entrypoint;
+  self->rt_format = rt_format;
+  self->coded_width = coded_width;
+  self->coded_height = coded_height;
+  self->codedbuf_size = codedbuf_size;
+  self->params = g_array_sized_new (FALSE, FALSE, sizeof (VABufferID), 8);
+  gst_object_replace ((GstObject **) & self->recon_pool,
+      (GstObject *) recon_pool);
+
+  GST_OBJECT_UNLOCK (self);
+
+  g_clear_pointer (&recon_pool, gst_object_unref);
+  /* now we should return now only this profile's caps */
+  gst_caps_replace (&self->srcpad_caps, NULL);
+
+  return TRUE;
+
+error:
+  g_clear_pointer (&surfaces, g_array_unref);
+  g_clear_pointer (&reconstruct_buffers, g_ptr_array_unref);
+  g_clear_pointer (&recon_pool, gst_object_unref);
+
+  if (config == VA_INVALID_ID)
+    vaDestroyConfig (dpy, config);
+
+  if (context == VA_INVALID_ID)
+    vaDestroyContext (dpy, context);
+
+  return FALSE;
+}
+
+static void
+gst_va_encoder_dispose (GObject * object)
+{
+  GstVaEncoder *self = GST_VA_ENCODER (object);
+
+  gst_va_encoder_close (self);
+
+  g_clear_pointer (&self->available_profiles, g_array_unref);
+  gst_clear_object (&self->display);
+
+  G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+gst_va_encoder_class_init (GstVaEncoderClass * klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  gobject_class->set_property = gst_va_encoder_set_property;
+  gobject_class->get_property = gst_va_encoder_get_property;
+  gobject_class->dispose = gst_va_encoder_dispose;
+
+  g_properties[PROP_DISPLAY] =
+      g_param_spec_object ("display", "GstVaDisplay", "GstVADisplay object",
+      GST_TYPE_VA_DISPLAY,
+      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+
+  g_properties[PROP_PROFILE] =
+      g_param_spec_int ("va-profile", "VAProfile", "VA Profile",
+      VAProfileNone, 50, VAProfileNone,
+      G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
+  g_properties[PROP_ENTRYPOINT] =
+      g_param_spec_int ("va-entrypoint", "VAEntrypoint", "VA Entrypoint",
+      0, 14, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
+  g_properties[PROP_CHROMA] =
+      g_param_spec_uint ("va-rt-format", "VARTFormat", "VA RT Fromat or chroma",
+      VA_RT_FORMAT_YUV420, VA_RT_FORMAT_PROTECTED, VA_RT_FORMAT_YUV420,
+      G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
+  g_properties[PROP_WIDTH] =
+      g_param_spec_int ("coded-width", "coded-picture-width",
+      "coded picture width", 0, G_MAXINT, 0,
+      G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
+  g_properties[PROP_HEIGHT] =
+      g_param_spec_int ("coded-height", "coded-picture-height",
+      "coded picture height", 0, G_MAXINT, 0,
+      G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
+  g_properties[PROP_CODED_BUF_SIZE] =
+      g_param_spec_int ("coded-buf-size", "coded-buffer-size",
+      "coded buffer size", 0, G_MAXINT, 0,
+      G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
+  g_object_class_install_properties (gobject_class, N_PROPERTIES, g_properties);
+}
+
+static gboolean
+gst_va_encoder_initialize (GstVaEncoder * self, guint32 codec)
+{
+  GArray *enc_profiles = NULL;
+  gint i;
+
+  if (self->available_profiles)
+    return FALSE;
+
+  enc_profiles = gst_va_display_get_profiles (self->display, codec,
+      VAEntrypointEncSlice);
+
+  if (!enc_profiles)
+    return FALSE;
+
+  self->available_profiles =
+      g_array_new (FALSE, FALSE, sizeof (GstVaProfileConfig));
+
+  if (enc_profiles) {
+    for (i = 0; i < enc_profiles->len; i++) {
+      GstVaProfileConfig config;
+
+      config.profile = g_array_index (enc_profiles, VAProfile, i);
+      config.entrypoints = VA_ENTRYPOINT_FLAG (EncSlice);
+      g_array_append_val (self->available_profiles, config);
+    }
+  }
+
+  g_clear_pointer (&enc_profiles, g_array_unref);
+
+  if (self->available_profiles->len == 0)
+    return FALSE;
+
+  return TRUE;
+}
+
+GstVaEncoder *
+gst_va_encoder_new (GstVaDisplay * display, guint32 codec)
+{
+  GstVaEncoder *self;
+
+  g_return_val_if_fail (GST_IS_VA_DISPLAY (display), NULL);
+
+  self = g_object_new (GST_TYPE_VA_ENCODER, "display", display, NULL);
+  if (!gst_va_encoder_initialize (self, codec))
+    gst_clear_object (&self);
+
+  return self;
+}
+
+gboolean
+gst_va_encoder_has_profile_and_entrypoint (GstVaEncoder * self,
+    VAProfile profile, VAEntrypoint entrypoint)
+{
+  GstVaProfileConfig *config;
+  gint i;
+
+  g_return_val_if_fail (GST_IS_VA_ENCODER (self), FALSE);
+
+  if (profile == VAProfileNone)
+    return FALSE;
+
+  for (i = 0; i < self->available_profiles->len; i++) {
+    config = &g_array_index (self->available_profiles, GstVaProfileConfig, i);
+    if (config->profile == profile) {
+      if (entrypoint == 0)
+        break;
+
+      if (config->entrypoints & (1U << entrypoint))
+        break;
+    }
+  }
+  if (i == self->available_profiles->len)
+    return FALSE;
+
+  return TRUE;
+}
+
+gint32
+gst_va_encoder_get_max_slice_num (GstVaEncoder * self,
+    VAProfile profile, VAEntrypoint entrypoint)
+{
+  VAStatus status;
+  VADisplay dpy;
+  VAConfigAttrib attrib = {.type = VAConfigAttribEncMaxSlices };
+
+  g_return_val_if_fail (GST_IS_VA_ENCODER (self), -1);
+
+  if (profile == VAProfileNone)
+    return -1;
+
+  if (entrypoint != VAEntrypointEncSlice)
+    return -1;
+
+  dpy = gst_va_display_get_va_dpy (self->display);
+  status = vaGetConfigAttributes (dpy, profile, entrypoint, &attrib, 1);
+  if (status != VA_STATUS_SUCCESS) {
+    GST_WARNING_OBJECT (self, "Failed to query encoding slices: %s",
+        vaErrorStr (status));
+    return -1;
+  }
+
+  if (attrib.value == VA_ATTRIB_NOT_SUPPORTED) {
+    GST_WARNING_OBJECT (self, "Driver does not support encoding picture as "
+        "multiple slices");
+    return -1;
+  }
+
+  return attrib.value;
+}
+
+gboolean
+gst_va_encoder_get_max_num_reference (GstVaEncoder * self,
+    VAProfile profile, VAEntrypoint entrypoint,
+    guint32 * list0, guint32 * list1)
+{
+  VAStatus status;
+  VADisplay dpy;
+  VAConfigAttrib attrib = {.type = VAConfigAttribEncMaxRefFrames };
+
+  g_return_val_if_fail (GST_IS_VA_ENCODER (self), FALSE);
+
+  if (profile == VAProfileNone)
+    return FALSE;
+
+  if (entrypoint != VAEntrypointEncSlice)
+    return FALSE;
+
+  dpy = gst_va_display_get_va_dpy (self->display);
+  status = vaGetConfigAttributes (dpy, profile, entrypoint, &attrib, 1);
+  if (status != VA_STATUS_SUCCESS) {
+    GST_WARNING_OBJECT (self, "Failed to query reference frames: %s",
+        vaErrorStr (status));
+    return FALSE;
+  }
+
+  if (attrib.value == VA_ATTRIB_NOT_SUPPORTED) {
+    if (list0)
+      *list0 = 0;
+    if (list1)
+      *list1 = 0;
+
+    return TRUE;
+  }
+
+  if (list0)
+    *list0 = attrib.value & 0xffff;
+  if (list1)
+    *list1 = (attrib.value >> 16) & 0xffff;
+
+  return TRUE;
+}
+
+guint32
+gst_va_encoder_get_rate_control_mode (GstVaEncoder * self,
+    VAProfile profile, VAEntrypoint entrypoint)
+{
+  VAStatus status;
+  VADisplay dpy;
+  VAConfigAttrib attrib = {.type = VAConfigAttribRateControl };
+
+  g_return_val_if_fail (GST_IS_VA_ENCODER (self), 0);
+
+  if (profile == VAProfileNone)
+    return 0;
+
+  if (entrypoint != VAEntrypointEncSlice)
+    return 0;
+
+  dpy = gst_va_display_get_va_dpy (self->display);
+  status = vaGetConfigAttributes (dpy, profile, entrypoint, &attrib, 1);
+  if (status != VA_STATUS_SUCCESS) {
+    GST_WARNING_OBJECT (self, "Failed to query rate control mode: %s",
+        vaErrorStr (status));
+    return 0;
+  }
+
+  if (attrib.value == VA_ATTRIB_NOT_SUPPORTED) {
+    GST_WARNING_OBJECT (self, "Driver does not support any rate control modes");
+    return 0;
+  }
+
+  return attrib.value;
+}
+
+guint32
+gst_va_encoder_get_quality_level (GstVaEncoder * self,
+    VAProfile profile, VAEntrypoint entrypoint)
+{
+  VAStatus status;
+  VADisplay dpy;
+  VAConfigAttrib attrib = {.type = VAConfigAttribEncQualityRange };
+
+  g_return_val_if_fail (GST_IS_VA_ENCODER (self), 0);
+
+  if (profile == VAProfileNone)
+    return 0;
+
+  if (entrypoint != VAEntrypointEncSlice)
+    return 0;
+
+  dpy = gst_va_display_get_va_dpy (self->display);
+  status = vaGetConfigAttributes (dpy, profile, entrypoint, &attrib, 1);
+  if (status != VA_STATUS_SUCCESS) {
+    GST_WARNING_OBJECT (self, "Failed to query the quality level: %s",
+        vaErrorStr (status));
+    return 0;
+  }
+
+  if (attrib.value == VA_ATTRIB_NOT_SUPPORTED) {
+    GST_WARNING_OBJECT (self, "Driver does not support quality attribute");
+    return 0;
+  }
+
+  return attrib.value;
+}
+
+gboolean
+gst_va_encoder_has_trellis (GstVaEncoder * self,
+    VAProfile profile, VAEntrypoint entrypoint)
+{
+  VAStatus status;
+  VADisplay dpy;
+  VAConfigAttrib attrib = {.type = VAConfigAttribEncQuantization };
+
+  g_return_val_if_fail (GST_IS_VA_ENCODER (self), FALSE);
+
+  if (profile == VAProfileNone)
+    return FALSE;
+
+  if (entrypoint != VAEntrypointEncSlice)
+    return FALSE;
+
+  dpy = gst_va_display_get_va_dpy (self->display);
+  status = vaGetConfigAttributes (dpy, profile, entrypoint, &attrib, 1);
+  if (status != VA_STATUS_SUCCESS) {
+    GST_WARNING_OBJECT (self, "Failed to query the trellis: %s",
+        vaErrorStr (status));
+    return FALSE;
+  }
+
+  if (attrib.value == VA_ATTRIB_NOT_SUPPORTED) {
+    GST_WARNING_OBJECT (self, "Driver does not support trellis");
+    return FALSE;
+  }
+
+  return attrib.value & VA_ENC_QUANTIZATION_TRELLIS_SUPPORTED;
+}
+
+guint32
+gst_va_encoder_get_rtformat (GstVaEncoder * self,
+    VAProfile profile, VAEntrypoint entrypoint)
+{
+  VAStatus status;
+  VADisplay dpy;
+  VAConfigAttrib attrib = {.type = VAConfigAttribRTFormat };
+
+  if (profile == VAProfileNone)
+    return 0;
+
+  if (entrypoint != VAEntrypointEncSlice)
+    return 0;
+
+  dpy = gst_va_display_get_va_dpy (self->display);
+  status = vaGetConfigAttributes (dpy, profile, entrypoint, &attrib, 1);
+  if (status != VA_STATUS_SUCCESS) {
+    GST_ERROR_OBJECT (self, "Failed to query rt format: %s",
+        vaErrorStr (status));
+    return 0;
+  }
+
+  if (attrib.value == VA_ATTRIB_NOT_SUPPORTED) {
+    GST_WARNING_OBJECT (self, "Driver does not support any rt format");
+    return 0;
+  }
+
+  return attrib.value;
+}
+
+guint32
+gst_va_encoder_get_packed_headers (GstVaEncoder * self, VAProfile profile,
+    VAEntrypoint entrypoint)
+{
+  VAStatus status;
+  VADisplay dpy;
+  VAConfigAttrib attrib = {.type = VAConfigAttribEncPackedHeaders };
+
+  if (profile == VAProfileNone)
+    return 0;
+
+  if (entrypoint != VAEntrypointEncSlice)
+    return 0;
+
+  dpy = gst_va_display_get_va_dpy (self->display);
+  status = vaGetConfigAttributes (dpy, profile, entrypoint, &attrib, 1);
+  if (status != VA_STATUS_SUCCESS) {
+    GST_ERROR_OBJECT (self, "Failed to query packed headers: %s",
+        vaErrorStr (status));
+    return 0;
+  }
+
+  if (attrib.value == VA_ATTRIB_NOT_SUPPORTED) {
+    GST_WARNING_OBJECT (self, "Driver does not support any packed headers");
+    return 0;
+  }
+
+  return attrib.value;
+}
+
+/* Add packed header such as SPS, PPS, SEI, etc. If adding slice header,
+   it is attached to the last slice parameter. */
+gboolean
+gst_va_encoder_add_packed_header (GstVaEncoder * self, GstVaEncodePicture * pic,
+    gint type, gpointer data, gsize size_in_bits, gboolean has_emulation_bytes)
+{
+  VABufferID buffer;
+  VAEncPackedHeaderParameterBuffer param = {
+    .type = type,
+    .bit_length = size_in_bits,
+    .has_emulation_bytes = has_emulation_bytes,
+  };
+
+  g_return_val_if_fail (GST_IS_VA_ENCODER (self), FALSE);
+  g_return_val_if_fail (self->context != VA_INVALID_ID, FALSE);
+  g_return_val_if_fail (pic && data && size_in_bits > 0, FALSE);
+  g_return_val_if_fail (type >= VAEncPackedHeaderSequence
+      && type <= VAEncPackedHeaderRawData, FALSE);
+
+  if (!gst_va_encoder_is_open (self)) {
+    GST_ERROR_OBJECT (self, "encoder has not been opened yet");
+    return FALSE;
+  }
+
+  buffer = _create_buffer (self, VAEncPackedHeaderParameterBufferType, &param,
+      sizeof (param));
+  if (buffer == VA_INVALID_ID)
+    return FALSE;
+
+  g_array_append_val (pic->params, buffer);
+
+  buffer = _create_buffer (self, VAEncPackedHeaderDataBufferType, data,
+      (size_in_bits + 7) / 8);
+  if (buffer == VA_INVALID_ID)
+    return FALSE;
+
+  g_array_append_val (pic->params, buffer);
+
+  return TRUE;
+}
+
+gboolean
+gst_va_encoder_add_param (GstVaEncoder * self, GstVaEncodePicture * pic,
+    VABufferType type, gpointer data, gsize size)
+{
+  VABufferID buffer;
+
+  g_return_val_if_fail (GST_IS_VA_ENCODER (self), FALSE);
+  g_return_val_if_fail (self->context != VA_INVALID_ID, FALSE);
+  g_return_val_if_fail (pic && data && size > 0, FALSE);
+
+  if (!gst_va_encoder_is_open (self)) {
+    GST_ERROR_OBJECT (self, "encoder has not been opened yet");
+    return FALSE;
+  }
+
+  buffer = _create_buffer (self, type, data, size);
+  if (buffer == VA_INVALID_ID)
+    return FALSE;
+
+  g_array_append_val (pic->params, buffer);
+
+  return TRUE;
+}
+
+gboolean
+gst_va_encoder_add_global_param (GstVaEncoder * self, VABufferType type,
+    gpointer data, gsize size)
+{
+  VABufferID buffer;
+
+  g_return_val_if_fail (GST_IS_VA_ENCODER (self), FALSE);
+  g_return_val_if_fail (self->context != VA_INVALID_ID, FALSE);
+  g_return_val_if_fail (data && size > 0, FALSE);
+
+  if (!gst_va_encoder_is_open (self)) {
+    GST_ERROR_OBJECT (self, "encoder has not been opened yet");
+    return FALSE;
+  }
+
+  buffer = _create_buffer (self, type, data, size);
+  if (buffer == VA_INVALID_ID)
+    return FALSE;
+
+  GST_OBJECT_LOCK (self);
+  self->params = g_array_append_val (self->params, buffer);
+  GST_OBJECT_UNLOCK (self);
+
+  return TRUE;
+}
+
+gboolean
+gst_va_encoder_reset_global_params (GstVaEncoder * self)
+{
+  guint i;
+  gboolean ret = TRUE;
+  GArray *params;
+
+  g_return_val_if_fail (GST_IS_VA_ENCODER (self), FALSE);
+  g_return_val_if_fail (self->context != VA_INVALID_ID, FALSE);
+
+  GST_OBJECT_LOCK (self);
+
+  if (!_is_open_unlocked (self)) {
+    GST_OBJECT_UNLOCK (self);
+    GST_ERROR_OBJECT (self, "encoder has not been opened yet");
+    return TRUE;
+  }
+
+  params = g_array_copy (self->params);
+  self->params = g_array_set_size (self->params, 0);
+
+  GST_OBJECT_UNLOCK (self);
+
+  for (i = 0; i < params->len; i++) {
+    VABufferID buffer;
+
+    buffer = g_array_index (params, VABufferID, i);
+    ret &= _destroy_buffer (self->display, buffer);
+  }
+
+  g_array_unref (params);
+
+  return ret;
+}
+
+GArray *
+gst_va_encoder_get_surface_formats (GstVaEncoder * self)
+{
+  g_return_val_if_fail (GST_IS_VA_ENCODER (self), NULL);
+
+  if (!gst_va_encoder_is_open (self))
+    return NULL;
+
+  return _get_surface_formats (self->display, self->config);
+}
+
+static gboolean
+_get_codec_caps (GstVaEncoder * self)
+{
+  GstCaps *sinkpad_caps = NULL, *srcpad_caps = NULL;
+
+  if (!gst_va_encoder_is_open (self)
+      && GST_IS_VA_DISPLAY_WRAPPED (self->display)) {
+    if (gst_va_caps_from_profiles (self->display, self->available_profiles,
+            VAEntrypointEncSlice, &sinkpad_caps, &srcpad_caps)) {
+      gst_caps_replace (&self->sinkpad_caps, sinkpad_caps);
+      gst_caps_replace (&self->srcpad_caps, srcpad_caps);
+      gst_caps_unref (srcpad_caps);
+      gst_caps_unref (sinkpad_caps);
+
+      return TRUE;
+    }
+  }
+
+  return FALSE;
+}
+
+GstCaps *
+gst_va_encoder_get_sinkpad_caps (GstVaEncoder * self)
+{
+  GstCaps *sinkpad_caps = NULL;
+
+  g_return_val_if_fail (GST_IS_VA_ENCODER (self), FALSE);
+
+  if (g_atomic_pointer_get (&self->sinkpad_caps))
+    return gst_caps_ref (self->sinkpad_caps);
+
+  if (_get_codec_caps (self))
+    return gst_caps_ref (self->sinkpad_caps);
+
+  if (gst_va_encoder_is_open (self)) {
+    sinkpad_caps = gst_va_create_raw_caps_from_config (self->display,
+        self->config);
+    gst_caps_replace (&self->sinkpad_caps, sinkpad_caps);
+    gst_caps_unref (sinkpad_caps);
+
+    return gst_caps_ref (self->sinkpad_caps);
+  }
+
+  return NULL;
+}
+
+GstCaps *
+gst_va_encoder_get_srcpad_caps (GstVaEncoder * self)
+{
+  g_return_val_if_fail (GST_IS_VA_ENCODER (self), FALSE);
+
+  if (g_atomic_pointer_get (&self->srcpad_caps))
+    return gst_caps_ref (self->srcpad_caps);
+
+  if (_get_codec_caps (self))
+    return gst_caps_ref (self->srcpad_caps);
+
+  if (gst_va_encoder_is_open (self)) {
+    VAProfile profile;
+    VAEntrypoint entrypoint;
+    GstCaps *caps;
+
+    GST_OBJECT_LOCK (self);
+    profile = self->profile;
+    entrypoint = self->entrypoint;
+    GST_OBJECT_UNLOCK (self);
+
+    caps = gst_va_create_coded_caps (self->display, profile, entrypoint, NULL);
+    if (caps) {
+      gst_caps_replace (&self->srcpad_caps, caps);
+      return gst_caps_ref (self->srcpad_caps);
+    }
+  }
+
+  return NULL;
+}
+
+static gboolean
+_destroy_all_buffers (GstVaEncodePicture * pic)
+{
+  VABufferID buffer;
+  guint i;
+  gboolean ret = TRUE;
+
+  g_return_val_if_fail (GST_IS_VA_DISPLAY (pic->display), FALSE);
+
+  for (i = 0; i < pic->params->len; i++) {
+    buffer = g_array_index (pic->params, VABufferID, i);
+    ret &= _destroy_buffer (pic->display, buffer);
+  }
+  pic->params = g_array_set_size (pic->params, 0);
+
+  return ret;
+}
+
+gboolean
+gst_va_encoder_encode (GstVaEncoder * self, GstVaEncodePicture * pic)
+{
+  VADisplay dpy;
+  VAStatus status;
+  VASurfaceID surface;
+  VAContextID context;
+  gboolean ret = FALSE;
+  guint orig_len;
+
+  g_return_val_if_fail (pic, FALSE);
+
+  GST_OBJECT_LOCK (self);
+
+  if (!_is_open_unlocked (self)) {
+    GST_OBJECT_UNLOCK (self);
+    GST_ERROR_OBJECT (self, "encoder has not been opened yet");
+    return FALSE;
+  }
+
+  context = self->context;
+  GST_OBJECT_UNLOCK (self);
+
+  surface = gst_va_encode_picture_get_raw_surface (pic);
+  if (surface == VA_INVALID_ID) {
+    GST_ERROR_OBJECT (self, "Encode picture without valid raw surface");
+    goto bail;
+  }
+
+  GST_TRACE_OBJECT (self, "Encode the surface %#x", surface);
+
+  dpy = gst_va_display_get_va_dpy (self->display);
+
+  status = vaBeginPicture (dpy, context, surface);
+  if (status != VA_STATUS_SUCCESS) {
+    GST_WARNING_OBJECT (self, "vaBeginPicture: %s", vaErrorStr (status));
+    goto bail;
+  }
+
+  GST_OBJECT_LOCK (self);
+  orig_len = self->params->len;
+  self->params = g_array_append_vals (self->params, pic->params->data,
+      pic->params->len);
+  GST_OBJECT_UNLOCK (self);
+
+  if (pic->params->len > 0) {
+    status = vaRenderPicture (dpy, context, (VABufferID *) self->params->data,
+        self->params->len);
+    if (status != VA_STATUS_SUCCESS) {
+      GST_WARNING_OBJECT (self, "vaRenderPicture: %s", vaErrorStr (status));
+      goto fail_end_pic;
+    }
+  }
+
+  status = vaEndPicture (dpy, context);
+  ret = (status == VA_STATUS_SUCCESS);
+  if (!ret)
+    GST_WARNING_OBJECT (self, "vaEndPicture: %s", vaErrorStr (status));
+
+  self->params = g_array_set_size (self->params, orig_len);
+
+bail:
+  _destroy_all_buffers (pic);
+
+  return ret;
+
+fail_end_pic:
+  {
+    self->params = g_array_set_size (self->params, orig_len);
+    status = vaEndPicture (dpy, context);
+    ret = FALSE;
+    goto bail;
+  }
+}
+
+VASurfaceID
+gst_va_encode_picture_get_reconstruct_surface (GstVaEncodePicture * pic)
+{
+  g_return_val_if_fail (pic, VA_INVALID_ID);
+  g_return_val_if_fail (pic->reconstruct_buffer, VA_INVALID_ID);
+
+  return gst_va_buffer_get_surface (pic->reconstruct_buffer);
+}
+
+VASurfaceID
+gst_va_encode_picture_get_raw_surface (GstVaEncodePicture * pic)
+{
+  g_return_val_if_fail (pic, VA_INVALID_ID);
+  g_return_val_if_fail (pic->raw_buffer, VA_INVALID_ID);
+
+  return gst_va_buffer_get_surface (pic->raw_buffer);
+}
+
+gint
+gst_va_encode_picture_get_coded_size (GstVaEncodePicture * pic)
+{
+  VADisplay dpy;
+  VACodedBufferSegment *segment_list;
+  VACodedBufferSegment *segment;
+  VAStatus status;
+  gint size;
+
+  g_return_val_if_fail (pic, -1);
+  g_return_val_if_fail (pic->coded_buffer != VA_INVALID_ID, -1);
+
+  dpy = gst_va_display_get_va_dpy (pic->display);
+
+  status = vaMapBuffer (dpy, pic->coded_buffer, (gpointer *) & segment_list);
+  if (status != VA_STATUS_SUCCESS) {
+    GST_WARNING ("coded buffer vaMapBuffer: %s", vaErrorStr (status));
+    return -1;
+  }
+
+  if (!segment_list) {
+    GST_WARNING ("coded buffer has no segment list");
+    return -1;
+  }
+
+  size = 0;
+  for (segment = segment_list; segment != NULL; segment = segment->next)
+    size += segment->size;
+
+  status = vaUnmapBuffer (dpy, pic->coded_buffer);
+  if (status != VA_STATUS_SUCCESS) {
+    GST_WARNING ("coded buffer vaUnmapBuffer: %s", vaErrorStr (status));
+    return -1;
+  }
+
+  return size;
+}
+
+gboolean
+gst_va_encode_picture_copy_coded_data (GstVaEncodePicture * pic,
+    GstBuffer * dest)
+{
+  VADisplay dpy;
+  VACodedBufferSegment *segment_list;
+  VACodedBufferSegment *segment;
+  VAStatus status;
+  goffset offset;
+  gsize size;
+
+  g_return_val_if_fail (pic, FALSE);
+  g_return_val_if_fail (dest && GST_IS_BUFFER (dest), FALSE);
+  g_return_val_if_fail (pic->coded_buffer != VA_INVALID_ID, FALSE);
+
+  dpy = gst_va_display_get_va_dpy (pic->display);
+
+  status = vaMapBuffer (dpy, pic->coded_buffer, (gpointer *) & segment_list);
+  if (status != VA_STATUS_SUCCESS) {
+    GST_WARNING ("coded buffer vaMapBuffer: %s", vaErrorStr (status));
+    return FALSE;
+  }
+
+  if (!segment_list) {
+    GST_WARNING ("coded buffer has no segment list");
+    return FALSE;
+  }
+
+  offset = 0;
+  for (segment = segment_list; segment != NULL; segment = segment->next) {
+    size = gst_buffer_fill (dest, offset, segment->buf, segment->size);
+    if (size != segment->size) {
+      GST_WARNING ("Segment size is %d, but copied %" G_GSIZE_FORMAT,
+          segment->size, size);
+      break;
+    }
+    offset += segment->size;
+  }
+
+  status = vaUnmapBuffer (dpy, pic->coded_buffer);
+  if (status != VA_STATUS_SUCCESS)
+    GST_WARNING ("coded buffer vaUnmapBuffer: %s", vaErrorStr (status));
+
+  return TRUE;
+}
+
+GstVaEncodePicture *
+gst_va_encode_picture_new (GstVaEncoder * self, GstBuffer * raw_buffer)
+{
+  GstVaEncodePicture *pic;
+  VABufferID coded_buffer;
+  VADisplay dpy;
+  VAStatus status;
+  gint codedbuf_size;
+  GstBufferPool *recon_pool = NULL;
+  GstBuffer *reconstruct_buffer = NULL;
+  GstFlowReturn ret;
+  GstBufferPoolAcquireParams buffer_pool_params = {
+    .flags = GST_BUFFER_POOL_ACQUIRE_FLAG_DONTWAIT,
+  };
+
+  g_return_val_if_fail (self && GST_IS_VA_ENCODER (self), NULL);
+  g_return_val_if_fail (raw_buffer && GST_IS_BUFFER (raw_buffer), NULL);
+
+  GST_OBJECT_LOCK (self);
+
+  if (!_is_open_unlocked (self)) {
+    GST_OBJECT_UNLOCK (self);
+    GST_ERROR_OBJECT (self, "encoder has not been opened yet");
+    return NULL;
+  }
+
+  if (self->codedbuf_size <= 0) {
+    GST_ERROR_OBJECT (self, "codedbuf_size: %d, is invalid",
+        self->codedbuf_size);
+    GST_OBJECT_UNLOCK (self);
+    return NULL;
+  }
+  codedbuf_size = self->codedbuf_size;
+
+  recon_pool = gst_object_ref (self->recon_pool);
+
+  GST_OBJECT_UNLOCK (self);
+
+  ret = gst_buffer_pool_acquire_buffer (self->recon_pool, &reconstruct_buffer,
+      &buffer_pool_params);
+  gst_clear_object (&recon_pool);
+
+  if (ret != GST_FLOW_OK) {
+    GST_ERROR_OBJECT (self, "Failed to create the reconstruct picture");
+    gst_clear_buffer (&reconstruct_buffer);
+    return NULL;
+  }
+
+  dpy = gst_va_display_get_va_dpy (self->display);
+  status = vaCreateBuffer (dpy, self->context, VAEncCodedBufferType,
+      codedbuf_size, 1, NULL, &coded_buffer);
+  if (status != VA_STATUS_SUCCESS) {
+    GST_ERROR_OBJECT (self, "vaCreateBuffer: %s", vaErrorStr (status));
+    gst_clear_buffer (&reconstruct_buffer);
+    return NULL;
+  }
+
+  pic = g_slice_new (GstVaEncodePicture);
+  pic->raw_buffer = gst_buffer_ref (raw_buffer);
+  pic->reconstruct_buffer = reconstruct_buffer;
+  pic->display = gst_object_ref (self->display);
+  pic->coded_buffer = coded_buffer;
+
+  pic->params = g_array_sized_new (FALSE, FALSE, sizeof (VABufferID), 8);
+
+  return pic;
+}
+
+void
+gst_va_encode_picture_free (GstVaEncodePicture * pic)
+{
+  g_return_if_fail (pic);
+
+  _destroy_all_buffers (pic);
+
+  if (pic->coded_buffer != VA_INVALID_ID)
+    _destroy_buffer (pic->display, pic->coded_buffer);
+
+  gst_buffer_unref (pic->raw_buffer);
+  gst_buffer_unref (pic->reconstruct_buffer);
+
+  g_clear_pointer (&pic->params, g_array_unref);
+  gst_clear_object (&pic->display);
+
+  g_slice_free (GstVaEncodePicture, pic);
+}
diff --git a/subprojects/gst-plugins-bad/sys/va/gstvaencoder.h b/subprojects/gst-plugins-bad/sys/va/gstvaencoder.h
new file mode 100644 (file)
index 0000000..07cb886
--- /dev/null
@@ -0,0 +1,119 @@
+/* GStreamer
+ *  Copyright (C) 2021 Intel Corporation
+ *     Author: He Junyan <junyan.he@intel.com>
+ *     Author: Víctor Jáquez <vjaquez@igalia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#pragma once
+
+#include <gst/video/video.h>
+#include <gst/va/gstvadisplay.h>
+#include <va/va.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_VA_ENCODER (gst_va_encoder_get_type())
+G_DECLARE_FINAL_TYPE (GstVaEncoder, gst_va_encoder, GST, VA_ENCODER, GstObject);
+
+typedef struct _GstVaEncodePicture GstVaEncodePicture;
+struct _GstVaEncodePicture
+{
+  GstVaDisplay *display;
+
+  /* picture parameters */
+  GArray *params;
+
+  GstBuffer *raw_buffer;
+  GstBuffer *reconstruct_buffer;
+
+  VABufferID coded_buffer;
+};
+
+gboolean              gst_va_encoder_is_open              (GstVaEncoder * self);
+gboolean              gst_va_encoder_open                 (GstVaEncoder * self,
+                                                           VAProfile profile,
+                                                           VAEntrypoint entrypoint,
+                                                           GstVideoFormat video_format,
+                                                           guint rt_format,
+                                                           gint coded_width,
+                                                           gint coded_height,
+                                                           gint codedbuf_size,
+                                                           guint reconstruct_buffer_num,
+                                                           guint rc_ctrl,
+                                                           guint32 packed_headers);
+gboolean              gst_va_encoder_close                (GstVaEncoder * self);
+gboolean              gst_va_encoder_has_profile_and_entrypoint (GstVaEncoder * self,
+                                                                 VAProfile profile,
+                                                                 VAEntrypoint entrypoint);
+gint                  gst_va_encoder_get_max_slice_num    (GstVaEncoder * self,
+                                                           VAProfile profile,
+                                                           VAEntrypoint entrypoint);
+gboolean              gst_va_encoder_get_max_num_reference (GstVaEncoder * self,
+                                                            VAProfile profile,
+                                                            VAEntrypoint entrypoint,
+                                                            guint32 * list0,
+                                                            guint32 * list1);
+guint32               gst_va_encoder_get_rate_control_mode (GstVaEncoder * self,
+                                                            VAProfile profile,
+                                                            VAEntrypoint entrypoint);
+guint32               gst_va_encoder_get_quality_level    (GstVaEncoder * self,
+                                                           VAProfile profile,
+                                                           VAEntrypoint entrypoint);
+gboolean              gst_va_encoder_has_trellis          (GstVaEncoder * self,
+                                                           VAProfile profile,
+                                                           VAEntrypoint entrypoint);
+guint32               gst_va_encoder_get_rtformat         (GstVaEncoder * self,
+                                                           VAProfile profile,
+                                                           VAEntrypoint entrypoint);
+guint32               gst_va_encoder_get_packed_headers   (GstVaEncoder * self,
+                                                           VAProfile profile,
+                                                           VAEntrypoint entrypoint);
+gboolean              gst_va_encoder_add_global_param     (GstVaEncoder * self,
+                                                           VABufferType type,
+                                                           gpointer data,
+                                                           gsize size);
+gboolean              gst_va_encoder_reset_global_params  (GstVaEncoder * self);
+gboolean              gst_va_encoder_add_param            (GstVaEncoder * self,
+                                                           GstVaEncodePicture * pic,
+                                                           VABufferType type,
+                                                           gpointer data,
+                                                           gsize size);
+gboolean              gst_va_encoder_add_packed_header    (GstVaEncoder * self,
+                                                           GstVaEncodePicture * pic,
+                                                           gint type,
+                                                           gpointer data,
+                                                           gsize size_in_bits,
+                                                           gboolean has_emulation_bytes);
+GstVaEncoder *        gst_va_encoder_new                  (GstVaDisplay * display,
+                                                           guint32 codec);
+GArray *              gst_va_encoder_get_surface_formats  (GstVaEncoder * self);
+GstCaps *             gst_va_encoder_get_sinkpad_caps     (GstVaEncoder * self);
+GstCaps *             gst_va_encoder_get_srcpad_caps      (GstVaEncoder * self);
+gboolean              gst_va_encoder_encode               (GstVaEncoder * self,
+                                                           GstVaEncodePicture * pic);
+
+GstVaEncodePicture *  gst_va_encode_picture_new           (GstVaEncoder * self,
+                                                           GstBuffer * raw_buffer);
+void                  gst_va_encode_picture_free          (GstVaEncodePicture * pic);
+VASurfaceID           gst_va_encode_picture_get_raw_surface (GstVaEncodePicture * pic);
+VASurfaceID           gst_va_encode_picture_get_reconstruct_surface (GstVaEncodePicture * pic);
+gint                  gst_va_encode_picture_get_coded_size (GstVaEncodePicture * pic);
+gboolean              gst_va_encode_picture_copy_coded_data (GstVaEncodePicture * pic,
+                                                             GstBuffer * dest);
+
+G_END_DECLS
index e240dfa..63d70c5 100644 (file)
@@ -6,6 +6,7 @@ va_sources = [
   'gstvacaps.c',
   'gstvadecoder.c',
   'gstvadeinterlace.c',
+  'gstvaencoder.c',
   'gstvadevice.c',
   'gstvadisplay_priv.c',
   'gstvafilter.c',