encoder: split another thread to do encoded buffer wrapper
authorWind Yuan <feng.yuan@intel.com>
Mon, 24 Dec 2012 02:19:01 +0000 (10:19 +0800)
committerWind Yuan <feng.yuan@intel.com>
Fri, 22 Mar 2013 01:59:17 +0000 (09:59 +0800)
mmap driver buffer and scanning may cost long time,
these actions better to be done in another thread

gst-libs/gst/vaapi/gstvaapibaseencoder.c
gst-libs/gst/vaapi/gstvaapibaseencoder.h
gst-libs/gst/vaapi/gstvaapiencoder.c
gst-libs/gst/vaapi/gstvaapiencoder.h
gst-libs/gst/vaapi/gstvaapiencoder_h263.c
gst-libs/gst/vaapi/gstvaapiencoder_h264.c
gst-libs/gst/vaapi/gstvaapiencoder_mpeg4.c
gst/vaapi/gstvaapiencode.c
gst/vaapi/gstvaapiencode.h

index b82cbb1..a35dbdd 100644 (file)
@@ -24,6 +24,8 @@
 #include <string.h>
 #include <stdlib.h>
 #include <glib.h>
+#include <glib-object.h>
+
 #include <X11/Xlib.h>
 
 #include <va/va.h>
@@ -47,6 +49,18 @@ GST_DEBUG_CATEGORY_STATIC (gst_vaapi_base_encoder_debug);
 #define VA_INVALID_PROFILE 0xffffffff
 #define DEFAULT_VA_CODEDBUF_NUM  4
 
+#define GST_VAAPI_BASE_ENCODER_LOCK(encoder)              \
+    G_STMT_START {                                        \
+      g_static_rec_mutex_lock(                            \
+        &((GstVaapiBaseEncoder*)(encoder))->priv->mutex); \
+    } G_STMT_END
+
+#define GST_VAAPI_BASE_ENCODER_UNLOCK(encoder)             \
+    G_STMT_START {                                         \
+      g_static_rec_mutex_unlock(                           \
+        &((GstVaapiBaseEncoder*)(encoder))->priv->mutex);  \
+    } G_STMT_END
+
 struct _GstVaapiBaseEncoderPrivate {
   guint32           format;   /*NV12, I420,*/
   VAProfile         profile;
@@ -54,26 +68,228 @@ struct _GstVaapiBaseEncoderPrivate {
   guint32           frame_count;
   VABufferID       *coded_bufs;
   guint32           coded_buf_num;
-  GMutex           *code_buffer_lock;
-  GCond            *code_buffer_cond;
-  GQueue           *available_code_buffers;
+  GStaticRecMutex   mutex;
+  GQueue           *idle_buf_queue;
+  GQueue           *busy_buf_queue;
 
-  GstVaapiSurfacePool *surfaces_pool;
+  GstVaapiSurfacePool            *surfaces_pool;
+  GstVaapiBaseEncoderNotifyStatus notify_status;
+  gpointer                        user_data;
 
-  guint             frame_notify_flag : 1;
+  guint             buffer_notify_flag : 1;
   guint             need_flush        : 1;
 };
 
 G_DEFINE_TYPE(GstVaapiBaseEncoder, gst_vaapi_base_encoder, GST_TYPE_VAAPI_ENCODER)
 
-static VABufferID *
-pop_available_coded_buffer(GstVaapiBaseEncoderPrivate *priv);
+typedef struct _GstVaapiEncoderBufferInfo      GstVaapiEncoderBufferInfo;
+typedef struct _GstVaapiEncoderBufferInfoClass GstVaapiEncoderBufferInfoClass;
+
+#define GST_TYPE_VAAPI_ENCODER_BUFFER_INFO  \
+    (gst_vaapi_encoder_buffer_info_get_type())
+
+#define GST_VAAPI_ENCODER_BUFFER_INFO(obj)                          \
+    (G_TYPE_CHECK_INSTANCE_CAST ((obj),                             \
+                                 GST_TYPE_VAAPI_ENCODER_BUFFER_INFO,\
+                                 GstVaapiEncoderBufferInfo))
+
+struct _GstVaapiEncoderBufferInfo {
+  GObject              base;
+  GstVaapiBaseEncoder *encoder;
+  VABufferID          *id;
+  GstClockTime         timestamp;
+  GstClockTime         duration;
+
+  void                *data;
+
+  guint32              is_key    : 1;
+  guint32              is_mapped : 1;
+};
+
+struct _GstVaapiEncoderBufferInfoClass {
+  GObjectClass   base_class;
+};
+
+G_DEFINE_TYPE(
+    GstVaapiEncoderBufferInfo,
+    gst_vaapi_encoder_buffer_info,
+    G_TYPE_OBJECT)
+
+static gboolean
+gst_vaapi_encoder_buffer_info_map(
+    GstVaapiEncoderBufferInfo *info,
+    void **buf
+)
+{
+  g_return_val_if_fail(info, FALSE);
+  g_return_val_if_fail(info->encoder && info->id && buf, FALSE);
+
+  GstVaapiDisplay *display = ENCODER_DISPLAY(info->encoder);
+  VADisplay va_dpy = ENCODER_VA_DISPLAY(info->encoder);
+  VAStatus va_status = VA_STATUS_SUCCESS;
+
+  if (info->is_mapped)
+    return TRUE;
+
+  GST_VAAPI_DISPLAY_LOCK(display);
+  va_status = vaMapBuffer(va_dpy, *info->id, &info->data);
+  GST_VAAPI_DISPLAY_UNLOCK(display);
+
+  g_return_val_if_fail(va_status == VA_STATUS_SUCCESS, FALSE);
+  info->is_mapped = TRUE;
+  *buf = info->data;
+  return TRUE;
+}
 
 static gboolean
-push_available_coded_buffer(
-    GstVaapiBaseEncoderPrivate *priv,
+gst_vaapi_encoder_buffer_info_unmap(
+    GstVaapiEncoderBufferInfo *info
+)
+{
+  g_return_val_if_fail(info, FALSE);
+  g_return_val_if_fail(info->encoder && info->id, FALSE);
+
+  GstVaapiDisplay *display = ENCODER_DISPLAY(info->encoder);
+  VADisplay va_dpy = ENCODER_VA_DISPLAY(info->encoder);
+  VAStatus va_status = VA_STATUS_SUCCESS;
+
+  if (!info->is_mapped)
+    return TRUE;
+
+  GST_VAAPI_DISPLAY_LOCK(display);
+  va_status = vaUnmapBuffer(va_dpy, *info->id);
+  GST_VAAPI_DISPLAY_UNLOCK(display);
+  info->data = NULL;
+  info->is_mapped = FALSE;
+
+  g_return_val_if_fail(va_status == VA_STATUS_SUCCESS, FALSE);
+  return TRUE;
+}
+
+static GstVaapiEncoderBufferInfo*
+pop_busy_buffer_info(GstVaapiBaseEncoder *encoder)
+{
+  GstVaapiBaseEncoderPrivate *priv = encoder->priv;
+  GstVaapiEncoderBufferInfo *info = NULL;
+
+  g_return_val_if_fail(priv->busy_buf_queue, NULL);
+
+  GST_VAAPI_BASE_ENCODER_LOCK(encoder);
+
+  if (g_queue_is_empty(priv->busy_buf_queue))
+    goto end;
+
+  info = (GstVaapiEncoderBufferInfo*)g_queue_pop_head(priv->busy_buf_queue);
+
+end:
+  GST_VAAPI_BASE_ENCODER_UNLOCK(encoder);
+  return info;
+}
+
+static void
+push_busy_buffer_info(
+    GstVaapiBaseEncoder *encoder,
+    GstVaapiEncoderBufferInfo *info)
+{
+  GstVaapiBaseEncoderPrivate *priv = encoder->priv;
+
+  GST_VAAPI_BASE_ENCODER_LOCK(encoder);
+  g_queue_push_tail(priv->busy_buf_queue, info);
+  GST_VAAPI_BASE_ENCODER_UNLOCK(encoder);
+}
+
+static VABufferID *
+pop_idle_buffer_id(GstVaapiBaseEncoder *encoder)
+{
+  GstVaapiBaseEncoderPrivate *priv = encoder->priv;
+  VABufferID *coded_buf = NULL;
+
+  g_return_val_if_fail(priv->idle_buf_queue, NULL);
+
+  GST_VAAPI_BASE_ENCODER_LOCK(encoder);
+
+  if (g_queue_is_empty(priv->idle_buf_queue))
+    goto end;
+
+  coded_buf = (VABufferID*)g_queue_pop_head(priv->idle_buf_queue);
+
+end:
+  GST_VAAPI_BASE_ENCODER_UNLOCK(encoder);
+  return coded_buf;
+}
+
+static void
+push_idle_buffer_id(
+    GstVaapiBaseEncoder *encoder,
     VABufferID *buf
-);
+)
+{
+  GstVaapiBaseEncoderPrivate *priv = encoder->priv;
+
+  GST_VAAPI_BASE_ENCODER_LOCK(encoder);
+  g_queue_push_tail(priv->idle_buf_queue, buf);
+  GST_VAAPI_BASE_ENCODER_UNLOCK(encoder);
+}
+
+static void
+gst_vaapi_encoder_buffer_info_init(
+    GstVaapiEncoderBufferInfo *info
+)
+{
+    info->encoder   = NULL;
+    info->id        = NULL;
+    info->timestamp = 0;
+    info->duration  = 0;
+    info->data      = NULL;
+    info->is_key    = FALSE;
+    info->is_mapped = FALSE;
+}
+
+static void
+gst_vaapi_encoder_buffer_info_finalize(GObject *object)
+{
+  GstVaapiEncoderBufferInfo *info = GST_VAAPI_ENCODER_BUFFER_INFO(object);
+
+  if (info->id && *info->id != VA_INVALID_ID && info->encoder) {
+    if (info->is_mapped)
+      gst_vaapi_encoder_buffer_info_unmap(info);
+    push_idle_buffer_id(info->encoder, info->id);
+  }
+
+  if (info->encoder) {
+    g_object_unref(info->encoder);
+    info->encoder = NULL;
+  }
+  info->id = NULL;
+}
+
+static GstVaapiEncoderBufferInfo*
+gst_vaapi_encoder_buffer_info_new(
+    GstVaapiBaseEncoder *encoder
+)
+{
+    GstVaapiEncoderBufferInfo *ret;
+
+    g_return_val_if_fail(encoder, NULL);
+
+    ret = GST_VAAPI_ENCODER_BUFFER_INFO(
+            g_object_new(GST_TYPE_VAAPI_ENCODER_BUFFER_INFO,
+                         NULL));
+    if (!ret)
+        return NULL;
+    ret->encoder = g_object_ref(encoder);
+    return ret;
+}
+
+static void
+gst_vaapi_encoder_buffer_info_class_init(
+    GstVaapiEncoderBufferInfoClass *klass
+)
+{
+  GObjectClass * const obj_class = G_OBJECT_CLASS(klass);
+
+  obj_class->finalize = gst_vaapi_encoder_buffer_info_finalize;
+}
 
 void
 gst_vaapi_base_encoder_set_frame_notify(
@@ -82,7 +298,7 @@ gst_vaapi_base_encoder_set_frame_notify(
 )
 {
   GstVaapiBaseEncoderPrivate *priv = encoder->priv;
-  priv->frame_notify_flag = flag;
+  priv->buffer_notify_flag = flag;
 }
 
 gboolean
@@ -106,6 +322,20 @@ gst_vaapi_base_encoder_set_input_format(
   priv->format = format;
 }
 
+gboolean
+gst_vaapi_base_encoder_set_notify_status(
+    GstVaapiBaseEncoder *encoder,
+    GstVaapiBaseEncoderNotifyStatus func,
+    gpointer             user_data
+)
+{
+  GstVaapiBaseEncoderPrivate *priv = encoder->priv;
+
+  priv->notify_status = func;
+  priv->user_data = user_data;
+  return TRUE;
+}
+
 static gboolean
 default_validate_encoder_parameters(
     GstVaapiBaseEncoder *encoder
@@ -136,7 +366,7 @@ base_encoder_alloc_coded_buffers(
       (16*16);
 
   ENCODER_ASSERT(context);
-  ENCODER_ASSERT(priv->available_code_buffers);
+  ENCODER_ASSERT(priv->idle_buf_queue);
   ENCODER_ASSERT(!priv->coded_bufs);
 
   va_dpy = ENCODER_VA_DISPLAY(base_encoder);
@@ -159,13 +389,12 @@ base_encoder_alloc_coded_buffers(
                        FALSE,
                        "create coded buffer failed.");
 
-  /* init queue available_code_buffers */
-  g_mutex_lock(priv->code_buffer_lock);
+  /* init queue idle_buf_queue */
+  GST_VAAPI_BASE_ENCODER_LOCK(base_encoder);
   for (i = 0; i < priv->coded_buf_num; i++) {
-    g_queue_push_head(priv->available_code_buffers, &priv->coded_bufs[i]);
+    g_queue_push_head(priv->idle_buf_queue, &priv->coded_bufs[i]);
   }
-  g_cond_signal(priv->code_buffer_cond);
-  g_mutex_unlock(priv->code_buffer_lock);
+  GST_VAAPI_BASE_ENCODER_UNLOCK(base_encoder);
 
 end:
   return ret;
@@ -179,23 +408,27 @@ release_coded_buffers(GstVaapiBaseEncoder *base_encoder)
   GstVaapiBaseEncoderPrivate *priv = base_encoder->priv;
   GstVaapiDisplay *display = ENCODER_DISPLAY(base_encoder);
   guint32 available_buf_count = priv->coded_buf_num;
+  GstVaapiEncoderBufferInfo *info;
   guint32 i;
 
   ENCODER_ASSERT(display);
   VAAPI_UNUSED_ARG(va_status);
   VADisplay va_dpy = gst_vaapi_display_get_display(display);
 
-  /* wait clear all available coded buffers*/
-  g_mutex_lock(priv->code_buffer_lock);
-  while (available_buf_count) {
-    if (g_queue_is_empty(priv->available_code_buffers)) {
-      g_cond_wait(priv->code_buffer_cond, priv->code_buffer_lock);
-    } else {
-      g_queue_pop_head(priv->available_code_buffers);
+  /* wait clear all available coded buffers */
+  GST_VAAPI_BASE_ENCODER_LOCK(base_encoder);
+  if (available_buf_count) {
+    while (!g_queue_is_empty(priv->busy_buf_queue)) {
+      info = (GstVaapiEncoderBufferInfo*)g_queue_pop_head(priv->busy_buf_queue);
+      g_object_unref(info);
+    }
+    while(!g_queue_is_empty(priv->idle_buf_queue)) {
+      g_queue_pop_head(priv->idle_buf_queue);
       available_buf_count--;
     }
   }
-  g_mutex_unlock(priv->code_buffer_lock);
+  GST_VAAPI_BASE_ENCODER_UNLOCK(base_encoder);
+  ENCODER_ASSERT(available_buf_count == 0);
 
   for (i = 0; i < priv->coded_buf_num; i++) {
     va_status = vaDestroyBuffer(va_dpy, priv->coded_bufs[i]);
@@ -315,153 +548,154 @@ end:
   return ret;
 }
 
-static GstBuffer *
-gst_vaapi_base_encoder_copy_buffer_default(
-    GstVaapiBaseEncoder *encoder,
-    guint8 *frame,
-    guint32 frame_size,
-    VABufferID *coded_buf
+static EncoderStatus
+query_encoding_status(
+    GstVaapiBaseEncoder *base_encoder,
+    GstVaapiSurface *buffer_surface
 )
 {
-  GstBuffer *ret_buffer = NULL;
-#if SHARE_CODED_BUF
-  ret_buffer = gst_base_encode_share_buffer_new(encoder, coded_buf);
-  ENCODER_ASSERT(ret_buffer);
-  GST_BUFFER_MALLOCDATA(ret_buffer) = NULL;
-  GST_BUFFER_DATA(ret_buffer) = frame;
-  GST_BUFFER_SIZE(ret_buffer) = frame_size;
-#else
-  ret_buffer = gst_buffer_new_and_alloc(frame_size);
-  memcpy(GST_BUFFER_DATA(ret_buffer),frame, frame_size);
-#endif
-  return ret_buffer;
+  EncoderStatus ret = ENCODER_NO_ERROR;
+  GstVaapiSurfaceStatus surface_status;
+
+  ENCODER_CHECK_STATUS(gst_vaapi_surface_sync(buffer_surface),
+                       ENCODER_SURFACE_ERR,
+                       "gst_vaapi_surface_sync failed.");
+
+  ENCODER_CHECK_STATUS(
+      gst_vaapi_surface_query_status(buffer_surface, &surface_status),
+      ENCODER_SURFACE_ERR,
+      "gst_vaapi_surface_query_status failed."
+      );
+  if (GST_VAAPI_SURFACE_STATUS_SKIPPED & surface_status) {
+    ENCODER_LOG_ERROR("frame skipped"); /* not sure continue or not */
+  }
+
+  return ENCODER_NO_ERROR;
+
+end:
+  return ret;
+}
+
+static inline guint
+get_buf_list_size(VACodedBufferSegment *buf_list)
+{
+  guint size = 0;
+  while(buf_list) {
+    size += buf_list->size;
+    buf_list = (VACodedBufferSegment*)buf_list->next;
+  }
+  return size;
+}
+
+static inline guint
+move_buf_list_to_buf(
+    VACodedBufferSegment *buf_list,
+    guint8 *data,
+    guint max_len
+)
+{
+    guint left_size = max_len;
+    guint cur_size;
+    while (buf_list && left_size) {
+      if (buf_list->size <= left_size)
+        cur_size = buf_list->size;
+      else
+        cur_size = left_size;
+      memcpy(data, buf_list->buf, cur_size);
+      data += cur_size;
+      buf_list = (VACodedBufferSegment*)buf_list->next;
+      left_size -= cur_size;
+    }
+    return max_len - left_size;
 }
 
 static EncoderStatus
-base_query_encoding_status(
-    GstVaapiBaseEncoder *base_encoder,
-    GstVaapiSurface *buffer_surface,
-    gboolean is_key,
-    GstVaapiVideoBuffer *surface_buffer,
-    VABufferID *coded_buf,
-    GList **coded_pics
+gst_vaapi_base_encoder_get_coded_buffer(
+    GstVaapiEncoder* base,
+    GstBuffer **out_buf
 )
 {
-  EncoderStatus ret = ENCODER_NO_ERROR;
-  VAStatus va_status = VA_STATUS_SUCCESS;
-  VASurfaceStatus surface_status = 0;
+  GstVaapiBaseEncoder *encoder = GST_VAAPI_BASE_ENCODER(base);
+  GstVaapiBaseEncoderPrivate *priv = encoder->priv;
+  GstVaapiBaseEncoderClass   *klass =
+      GST_VAAPI_BASE_ENCODER_GET_CLASS(encoder);
+  GstVaapiEncoderBufferInfo* info;
+  EncoderStatus ret;
   VACodedBufferSegment *buf_list = NULL;
-  GstBuffer* ret_buffer = NULL;
-  gboolean has_coded_data = FALSE;
-  gboolean is_locked = FALSE;
-  GstVaapiBaseEncoderClass   *base_class =
-      GST_VAAPI_BASE_ENCODER_GET_CLASS(base_encoder);
-  GstVaapiBaseEncoderPrivate *priv = base_encoder->priv;
-  GstVaapiDisplay *display = ENCODER_DISPLAY(base_encoder);
+  GstBuffer* buffer = NULL;
+  guint buf_size;
 
-  ENCODER_ASSERT(display);
-  VASurfaceID surface_id = (VASurfaceID)GST_VAAPI_OBJECT_ID(buffer_surface);
-  VADisplay va_dpy = ENCODER_VA_DISPLAY(base_encoder);
-
-  ENCODER_ASSERT(coded_pics);
-  VAAPI_UNUSED_ARG(has_coded_data);
-
-  /* lock display */
-  ENCODER_ACQUIRE_DISPLAY_LOCK(display);
-
-  va_status = vaSyncSurface(va_dpy, surface_id);
-  ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS ==va_status,
-                       ENCODER_QUERY_STATUS_ERR,
-                       "vaSyncSurface failed.");
-
-  va_status = vaQuerySurfaceStatus(va_dpy, surface_id, &surface_status);
-  ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS ==va_status,
-                       ENCODER_QUERY_STATUS_ERR,
-                       "vaQuerySurfaceStatus failed.");
-  if (VASurfaceSkipped & surface_status) {
-    ENCODER_LOG_ERROR("frame skipped, dts:%" GST_TIME_FORMAT,
-                      GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(surface_buffer)));
+  while((info = pop_busy_buffer_info(encoder)) == NULL){
+    ret = ENCODER_NO_BUSY_BUF;
+    if (!priv->notify_status ||
+        !priv->notify_status(encoder, ret, priv->user_data))
+      goto end;
   }
+  ret = ENCODER_NO_ERROR;
 
-  va_status = vaMapBuffer(va_dpy, *coded_buf, (void **)(&buf_list));
-  ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS ==va_status,
-                       ENCODER_QUERY_STATUS_ERR,
-                       "vaMapBuffer failed.");
-
-  /*unlock display*/
-  ENCODER_RELEASE_DISPLAY_LOCK(display);
-
-  while (buf_list != NULL) {
-      GstBuffer *new_data = NULL;
-      if (priv->frame_notify_flag && base_class->notify_frame) {
-        base_class->notify_frame(base_encoder,
-                                 buf_list->buf,
-                                 buf_list->size);
-      }
+  ENCODER_CHECK_STATUS(
+      info->id && *info->id != VA_INVALID_ID,
+      ENCODER_DATA_ERR,
+      "get invalid buffer info"
+      );
 
-      if (base_class->copy_coded_frame) {
-        new_data = base_class->copy_coded_frame(
-            base_encoder,
-            buf_list->buf,
-            buf_list->size,
-            coded_buf);
-      } else {
-        new_data = gst_vaapi_base_encoder_copy_buffer_default(
-            base_encoder,
-            buf_list->buf,
-            buf_list->size,
-            coded_buf);
-      }
+  ENCODER_CHECK_STATUS(
+      gst_vaapi_encoder_buffer_info_map(info, (void**)&buf_list),
+      ENCODER_DATA_ERR,
+      "vaMapBuffer failed");
 
-      if (!ret_buffer)
-        ret_buffer = new_data;
-      else if (new_data)
-        ret_buffer = gst_buffer_join(ret_buffer, new_data);
-      buf_list = (VACodedBufferSegment*)buf_list->next;
-      has_coded_data = TRUE;
+  buf_size = get_buf_list_size(buf_list);
+  ENCODER_CHECK_STATUS(
+      buf_size,
+      ENCODER_DATA_ERR,
+      "encoded size:0");
+  buffer = gst_buffer_new_and_alloc(buf_size);
+  GST_BUFFER_SIZE(buffer) = move_buf_list_to_buf(
+                                buf_list,
+                                GST_BUFFER_DATA(buffer),
+                                buf_size);
+
+  if (priv->buffer_notify_flag && klass->notify_buffer) {
+    klass->notify_buffer(
+        encoder,
+        GST_BUFFER_DATA(buffer),
+        GST_BUFFER_SIZE(buffer));
   }
 
-  if (ret_buffer) {
-      GST_BUFFER_TIMESTAMP(ret_buffer) = GST_BUFFER_TIMESTAMP(surface_buffer);
-      GST_BUFFER_DURATION(ret_buffer) = GST_BUFFER_DURATION(surface_buffer);
-      if (!is_key) {
-        GST_BUFFER_FLAG_SET(ret_buffer, GST_BUFFER_FLAG_DELTA_UNIT);
-      }
-      GST_BUFFER_OFFSET_END(ret_buffer) =
-          GST_BUFFER_OFFSET_END(surface_buffer);
-      *coded_pics = g_list_append(*coded_pics, ret_buffer);
+  if (klass->wrap_buffer) {
+    GstBuffer *new_buf = klass->wrap_buffer(encoder, buffer);
+    gst_buffer_unref(buffer);
+    buffer = new_buf;
   }
-  FPS_CALCULATION(vaapiencode);
 
-#if SHARE_CODED_BUF
-  if (!has_coded_data)
-#endif
-  { // if non-related, push back to available_code_buffers
-    ENCODER_ACQUIRE_DISPLAY_LOCK(display);
-    vaUnmapBuffer(va_dpy, *coded_buf);
-    ENCODER_RELEASE_DISPLAY_LOCK(display);
-    push_available_coded_buffer(priv, coded_buf);
+  if (buffer) {
+    GST_BUFFER_TIMESTAMP(buffer) = info->timestamp;
+    GST_BUFFER_DURATION(buffer) = info->duration;
+    if (!info->is_key)
+      GST_BUFFER_FLAG_SET(buffer, GST_BUFFER_FLAG_DELTA_UNIT);
   }
+  FPS_CALCULATION(vaapiencode);
 
-  return ENCODER_NO_ERROR;
+  *out_buf = buffer;
 
 end:
-  /*unlock display*/
-  ENCODER_RELEASE_DISPLAY_LOCK(display);
+  if (info) {
+    gst_vaapi_encoder_buffer_info_unmap(info);
+    g_object_unref(info);
+  }
   return ret;
 }
 
 static EncoderStatus
 gst_vaapi_base_encoder_encode_default(
-    GstVaapiEncoder* encoder,
-    GstBuffer *raw_pic,
-    GList **coded_pics
+    GstVaapiEncoder* base,
+    GstBuffer *raw_pic
 )
 {
-  GstVaapiBaseEncoder* base_encoder = GST_VAAPI_BASE_ENCODER(encoder);
+  GstVaapiBaseEncoder* encoder = GST_VAAPI_BASE_ENCODER(base);
   GstVaapiBaseEncoderClass *base_class =
       GST_VAAPI_BASE_ENCODER_GET_CLASS(encoder);
-  GstVaapiBaseEncoderPrivate *priv = base_encoder->priv;
+  GstVaapiBaseEncoderPrivate *priv = encoder->priv;
   GstVaapiDisplay *display = ENCODER_DISPLAY(encoder);
   GstVaapiContext *context = ENCODER_CONTEXT(encoder);
   EncoderStatus ret = ENCODER_NO_ERROR;
@@ -492,7 +726,7 @@ gst_vaapi_base_encoder_encode_default(
 again:
   if (base_class->prepare_next_input_buffer) {
     GstVaapiVideoBuffer* tmp_buf = NULL;
-    ret = base_class->prepare_next_input_buffer(base_encoder,
+    ret = base_class->prepare_next_input_buffer(encoder,
                                                 video_buffer,
                                                 priv->need_flush,
                                                 &tmp_buf);
@@ -508,37 +742,42 @@ again:
 
   buffer_surface = gst_vaapi_video_buffer_get_surface(video_buffer);
 
-  /*get valid coded buffer*/
-  coded_buf = pop_available_coded_buffer(priv);
-  ENCODER_CHECK_STATUS(coded_buf,
-                       ENCODER_ENC_RES_ERR,
-                       "dequeue_available_coded_buffer error");
+  while ((coded_buf = pop_idle_buffer_id(encoder)) == NULL) {
+    ret = ENCODER_NO_IDLE_BUF;
+    if (!priv->notify_status ||
+        !priv->notify_status(encoder, ret, priv->user_data))
+      goto end;
+  }
+  ret = ENCODER_NO_ERROR;
 
   /* prepare frame*/
-  ret = base_class->render_frame(base_encoder,
+  ret = base_class->render_frame(encoder,
                                  buffer_surface,
                                  priv->frame_count,
                                  *coded_buf,
                                  &is_key);
   /* prepare failed, push back */
   if (ENCODER_NO_ERROR != ret) {
-    push_available_coded_buffer(priv, coded_buf);
+    push_idle_buffer_id(encoder, coded_buf);
   }
   ENCODER_CHECK_STATUS(ENCODER_NO_ERROR == ret,
                        ENCODER_PICTURE_ERR,
                        "base_prepare_encoding failed");
 
   /*query surface result*/
-  ret = base_query_encoding_status(base_encoder,
-                                   buffer_surface,
-                                   is_key,
-                                   video_buffer,
-                                   coded_buf,
-                                   coded_pics);
+  ret = query_encoding_status(encoder, buffer_surface);
   if (ENCODER_NO_ERROR != ret) {
     goto end;
   }
 
+  /* Push coded buffer to another task */
+  GstVaapiEncoderBufferInfo* info = gst_vaapi_encoder_buffer_info_new(encoder);
+  info->id = coded_buf;
+  info->timestamp = GST_BUFFER_TIMESTAMP(video_buffer);
+  info->duration = GST_BUFFER_DURATION(video_buffer);
+  info->is_key = is_key;
+  push_busy_buffer_info(encoder, info);
+
   priv->frame_count++;
 
   if (base_class->prepare_next_input_buffer) {
@@ -547,15 +786,13 @@ again:
     }
     video_buffer = NULL;
     buffer_surface = NULL;
+    coded_buf = NULL;
     goto again;
   }
 
 end:
-  if (ret > ENCODER_NO_ERROR) {
-    ret = ENCODER_NO_ERROR;
-  }
-  if (ret < 0 && base_class->encode_frame_failed) {
-    base_class->encode_frame_failed(base_encoder, video_buffer);
+  if (ret < ENCODER_NO_ERROR && base_class->encode_frame_failed) {
+    base_class->encode_frame_failed(encoder, video_buffer);
   }
   if (video_buffer) {
     gst_buffer_unref(GST_BUFFER_CAST(video_buffer));
@@ -564,41 +801,6 @@ end:
   return ret;
 }
 
-static VABufferID *
-pop_available_coded_buffer(GstVaapiBaseEncoderPrivate *priv)
-{
-  VABufferID *coded_buf = NULL;
-  gboolean ret = TRUE;
-
-  g_mutex_lock(priv->code_buffer_lock);
-
-  ENCODER_CHECK_STATUS(priv->available_code_buffers,
-                       FALSE,
-                       "coded buffer not found");
-  while (g_queue_is_empty(priv->available_code_buffers)) {
-    g_cond_wait(priv->code_buffer_cond, priv->code_buffer_lock);
-  }
-  coded_buf = (VABufferID*)g_queue_pop_head (priv->available_code_buffers);
-
-end:
-  g_mutex_unlock(priv->code_buffer_lock);
-  VAAPI_UNUSED_ARG(ret);
-  return coded_buf;
-}
-
-static gboolean
-push_available_coded_buffer(
-    GstVaapiBaseEncoderPrivate *priv,
-    VABufferID *buf
-)
-{
-  g_mutex_lock(priv->code_buffer_lock);
-  g_queue_push_head(priv->available_code_buffers, buf);
-  g_cond_signal(priv->code_buffer_cond);
-  g_mutex_unlock(priv->code_buffer_lock);
-  return TRUE;
-}
-
 #if 0
 static EncoderStatus
 base_put_raw_buffer_to_surface(GstVaapiBaseEncoder *base_encoder,
@@ -693,8 +895,7 @@ base_put_raw_buffer_to_surface(GstVaapiBaseEncoder *base_encoder,
 
 static EncoderStatus
 gst_vaapi_base_encoder_flush_default(
-    GstVaapiEncoder* encoder,
-    GList **coded_pics
+    GstVaapiEncoder* encoder
 )
 {
   GstVaapiBaseEncoder* base_encoder = GST_VAAPI_BASE_ENCODER(encoder);
@@ -722,12 +923,12 @@ gst_vaapi_base_encoder_finalize(GObject *object)
     gst_vaapi_encoder_uninitialize(encoder);
   }
 
-  g_mutex_free(priv->code_buffer_lock);
-  g_cond_free(priv->code_buffer_cond);
-  if (priv->available_code_buffers) {
-    g_queue_free(priv->available_code_buffers);
-    priv->available_code_buffers = NULL;
-  }
+  g_static_rec_mutex_free(&priv->mutex);
+  if (priv->idle_buf_queue)
+    g_queue_free(priv->idle_buf_queue);
+
+  if (priv->busy_buf_queue)
+    g_queue_free(priv->busy_buf_queue);
 
   G_OBJECT_CLASS(gst_vaapi_base_encoder_parent_class)->finalize(object);
 }
@@ -744,13 +945,16 @@ gst_vaapi_base_encoder_init(GstVaapiBaseEncoder *encoder)
   priv->format = 0;
   priv->profile= VA_INVALID_PROFILE;
   priv->frame_count = 0;
-  priv->frame_notify_flag = FALSE;
+  priv->buffer_notify_flag = FALSE;
 
   priv->coded_bufs = NULL;
   priv->coded_buf_num = DEFAULT_VA_CODEDBUF_NUM;
-  priv->code_buffer_lock = g_mutex_new();
-  priv->code_buffer_cond = g_cond_new();
-  priv->available_code_buffers = g_queue_new();
+  priv->idle_buf_queue = g_queue_new();
+  priv->busy_buf_queue = g_queue_new();
+  g_static_rec_mutex_init(&priv->mutex);
+
+  priv->notify_status = NULL;
+  priv->user_data = NULL;
 
   priv->need_flush = FALSE;
 }
@@ -773,6 +977,7 @@ gst_vaapi_base_encoder_class_init(GstVaapiBaseEncoderClass *klass)
   encoder_class->close = gst_vaapi_base_encoder_close_default;
   encoder_class->encode = gst_vaapi_base_encoder_encode_default;
   encoder_class->flush = gst_vaapi_base_encoder_flush_default;
+  encoder_class->get_buf = gst_vaapi_base_encoder_get_coded_buffer;
   encoder_class->get_codec_data = NULL;
 
   /* user defined functions*/
@@ -781,8 +986,8 @@ gst_vaapi_base_encoder_class_init(GstVaapiBaseEncoderClass *klass)
   klass->release_resource = NULL;
   klass->prepare_next_input_buffer = NULL;
   klass->render_frame = NULL;
-  klass->notify_frame = NULL;
-  klass->copy_coded_frame = NULL;
+  klass->notify_buffer = NULL;
+  klass->wrap_buffer = NULL;
   klass->encode_frame_failed = NULL;
 
   /*
index b3e1df7..2b132ce 100644 (file)
@@ -60,6 +60,13 @@ typedef struct _GstVaapiBaseEncoderClass         GstVaapiBaseEncoderClass;
                                  GST_TYPE_VAAPI_BASE_ENCODER,  \
                                  GstVaapiBaseEncoderPrivate))
 
+/* return: if true, continue; else, stop*/
+typedef gboolean
+  (*GstVaapiBaseEncoderNotifyStatus)(
+       GstVaapiBaseEncoder* encoder,
+       EncoderStatus status,
+       void* userdata);
+
 struct _GstVaapiBaseEncoder {
   GstVaapiEncoder parent;
 
@@ -92,12 +99,11 @@ struct _GstVaapiBaseEncoderClass {
   void (*encode_frame_failed)       (GstVaapiBaseEncoder *encoder,
                                      GstVaapiVideoBuffer* buffer);
 
-  void (*notify_frame)              (GstVaapiBaseEncoder *encoder,
+  void (*notify_buffer)             (GstVaapiBaseEncoder *encoder,
                                      guint8 *buf, guint32 size);
 
-  GstBuffer *(*copy_coded_frame)    (GstVaapiBaseEncoder *encoder,
-                                     guint8 *buf, guint32 size,
-                                     VABufferID *coded_buf);
+  GstBuffer *(*wrap_buffer)         (GstVaapiBaseEncoder *encoder,
+                                     GstBuffer *buf);
 };
 
 GType
@@ -120,6 +126,13 @@ gst_vaapi_base_encoder_set_input_format(
     guint32 format
 );
 
+gboolean
+gst_vaapi_base_encoder_set_notify_status(
+    GstVaapiBaseEncoder *encoder,
+    GstVaapiBaseEncoderNotifyStatus func,
+    gpointer             user_data
+);
+
 G_END_DECLS
 
 #endif /* GST_VAAPI_BASE_ENCODER_H */
index 2b0c875..43fc19c 100644 (file)
@@ -156,8 +156,7 @@ end:
 EncoderStatus
 gst_vaapi_encoder_encode(
     GstVaapiEncoder* encoder,
-    GstBuffer *raw_pic,
-    GList **coded_pics
+    GstBuffer *pic
 )
 {
   EncoderStatus ret = ENCODER_NO_ERROR;
@@ -170,8 +169,8 @@ gst_vaapi_encoder_encode(
   ENCODER_CHECK_STATUS(encoder_class->encode,
                        ENCODER_FUNC_PTR_ERR,
                        "encoder <encode> function pointer empty.");
-  ret = encoder_class->encode(encoder, raw_pic, coded_pics);
-  ENCODER_CHECK_STATUS(ENCODER_NO_ERROR == ret,
+  ret = encoder_class->encode(encoder, pic);
+  ENCODER_CHECK_STATUS(ENCODER_NO_ERROR <= ret,
                        ret,
                        "encoder <encode> failed.");
   if (priv->state < VAAPI_ENC_ENCODING) {
@@ -182,6 +181,31 @@ end:
 }
 
 EncoderStatus
+gst_vaapi_encoder_get_encoded_buffer(
+    GstVaapiEncoder* encoder,
+    GstBuffer **buf
+)
+{
+  EncoderStatus ret = ENCODER_NO_ERROR;
+  GstVaapiEncoderClass *encoder_class = GST_VAAPI_ENCODER_GET_CLASS(encoder);
+  GstVaapiEncoderPrivate *priv = encoder->priv;
+
+  ENCODER_CHECK_STATUS(priv->state >= VAAPI_ENC_OPENED,
+                       ENCODER_STATE_ERR,
+                       "encoder was not encoding <encode>.");
+  ENCODER_CHECK_STATUS(encoder_class->get_buf,
+                       ENCODER_FUNC_PTR_ERR,
+                       "encoder <get_buf> function pointer empty.");
+  ret = encoder_class->get_buf(encoder, buf);
+  ENCODER_CHECK_STATUS(ENCODER_NO_ERROR <= ret,
+                       ret,
+                       "encoder <get_buf> failed.");
+end:
+  return ret;
+}
+
+
+EncoderStatus
 gst_vaapi_encoder_get_codec_data(
     GstVaapiEncoder* encoder,
     GstBuffer **codec_data
@@ -207,8 +231,7 @@ end:
 
 EncoderStatus
 gst_vaapi_encoder_flush(
-    GstVaapiEncoder* encoder,
-    GList **coded_pics
+    GstVaapiEncoder* encoder
 )
 {
   EncoderStatus ret = ENCODER_NO_ERROR;
@@ -221,13 +244,10 @@ gst_vaapi_encoder_flush(
   ENCODER_CHECK_STATUS(encoder_class->flush,
                        ENCODER_FUNC_PTR_ERR,
                        "encoder <flush> function pointer empty.");
-  ret = encoder_class->flush(encoder, coded_pics);
+  ret = encoder_class->flush(encoder);
   ENCODER_CHECK_STATUS(ENCODER_NO_ERROR == ret,
                        ret,
                        "encoder <flush> failed.");
-  if (priv->state > VAAPI_ENC_OPENED) {
-    priv->state = VAAPI_ENC_OPENED;
-  }
 end:
   return ret;
 }
index af0d2c3..7e890cc 100644 (file)
@@ -35,9 +35,9 @@ G_BEGIN_DECLS
 
 #define ENCODER_NO_ERROR       0
 #define ENCODER_NO_DATA        1
-#define ENCODER_BUFFER_WAITING 2
-#define ENCODER_BUFFER_EMPTY   3
-
+#define ENCODER_NO_BUSY_BUF    2
+#define ENCODER_NO_IDLE_BUF    3
+#define ENCODER_FRAME_IN_ORDER 4
 
 #define ENCODER_MEM_ERR       -1
 #define ENCODER_DISPLAY_ERR   -2
@@ -188,12 +188,12 @@ struct _GstVaapiEncoderClass {
                                   GstVaapiContext **context);
 
   EncoderStatus (*close)         (GstVaapiEncoder* encoder);
-  /* coded_pics [out] */
   EncoderStatus (*encode)        (GstVaapiEncoder* encoder,
-                                  GstBuffer *raw_pic,
-                                  GList **coded_pics);
-  /* coded_pics [out] */
-  EncoderStatus (*flush)         (GstVaapiEncoder* encoder, GList **coded_pics);
+                                  GstBuffer *pic);
+  /* buf [out] */
+  EncoderStatus (*get_buf)       (GstVaapiEncoder* encoder,
+                                  GstBuffer **buf);
+  EncoderStatus (*flush)         (GstVaapiEncoder* encoder);
 
   /* get_codec_data can be NULL */
   EncoderStatus (*get_codec_data)(GstVaapiEncoder* encoder, GstBuffer **codec_data);
@@ -239,8 +239,13 @@ gst_vaapi_encoder_open(GstVaapiEncoder* encoder);
 EncoderStatus
 gst_vaapi_encoder_encode(
     GstVaapiEncoder* encoder,
-    GstBuffer *raw_pic,
-    GList **coded_pics
+    GstBuffer *pic
+);
+
+EncoderStatus
+gst_vaapi_encoder_get_encoded_buffer(
+    GstVaapiEncoder* encoder,
+    GstBuffer **buf
 );
 
 EncoderStatus
@@ -251,7 +256,7 @@ gst_vaapi_encoder_get_codec_data(
 
 /* flush all frames */
 EncoderStatus
-gst_vaapi_encoder_flush(GstVaapiEncoder* encoder, GList **coded_pics);
+gst_vaapi_encoder_flush(GstVaapiEncoder* encoder);
 
 /* close context */
 EncoderStatus
index 70b0722..507a2fa 100644 (file)
@@ -315,8 +315,8 @@ gst_vaapi_encoder_h263_class_init(GstVaapiEncoderH263Class *klass)
   base_class->pre_alloc_resource  = NULL;
   base_class->release_resource    = gst_vaapi_encoder_h263_release_resource;
   base_class->render_frame = gst_vaapi_encoder_h263_rendering;
-  base_class->notify_frame = NULL;
-  base_class->copy_coded_frame = NULL;
+  base_class->notify_buffer = NULL;
+  base_class->wrap_buffer = NULL;
 
   /*
   encoder_class->flush = gst_vaapi_encoder_h263_flush;
index 1b82be8..a666aa4 100644 (file)
@@ -274,7 +274,7 @@ gst_vaapi_encoder_h264_validate_attributes(GstVaapiBaseEncoder *base)
   gst_vaapi_base_encoder_set_va_profile(base, h264_get_va_profile(encoder->profile));
   if (!encoder->level) {
     if (encoder->profile <= H264_PROFILE_BASELINE)
-      encoder->level = H264_LEVEL_30;
+      encoder->level = H264_LEVEL_31;
     else
       encoder->level = H264_LEVEL_41;
   }
@@ -522,7 +522,7 @@ gst_vaapi_encoder_h264_prepare_next_buffer(
   //guint64 pts = 0;
 
   if (NULL == display_buf && g_queue_is_empty(priv->queued_buffers)) {
-    ret = ENCODER_BUFFER_EMPTY;
+    ret = ENCODER_FRAME_IN_ORDER;
     if (priv->gop_count >= encoder->intra_period || need_flush)
       priv->gop_count = 0;
     goto end;
@@ -552,7 +552,7 @@ gst_vaapi_encoder_h264_prepare_next_buffer(
         )
     {
       g_queue_push_tail(priv->queued_buffers, display_buf);
-      ret = ENCODER_BUFFER_WAITING;
+      ret = ENCODER_FRAME_IN_ORDER;
       goto end;
     }
     priv->cur_slice_type = SLICE_TYPE_P;
@@ -1357,11 +1357,11 @@ h264_next_nal(const guint8 *buffer, guint32 len, guint32 *nal_size)
     /*find next nal start position*/
     while (cur < end) {
         flag = ((flag<<8) | ((*cur++)&0xFF));
-        if (flag == 0x00000001) {
-            *nal_size = cur - 4 - nal_start;
-            break;
-        } else if ((flag&0x00FFFFFF) == 0x00000001) {
-            *nal_size = cur - 3 - nal_start;
+        if ((flag&0x00FFFFFF) == 0x00000001) {
+            if (flag == 0x00000001)
+                *nal_size = cur - 4 - nal_start;
+            else
+                *nal_size = cur - 3 - nal_start;
             break;
         }
     }
@@ -1375,11 +1375,9 @@ h264_next_nal(const guint8 *buffer, guint32 len, guint32 *nal_size)
 }
 
 static GstBuffer *
-gst_vaapi_encoder_h264_copy_coded_buffer(
+gst_vaapi_encoder_h264_wrap_buffer(
     GstVaapiBaseEncoder *base,
-    guint8 *frame,
-    guint32 frame_size,
-    VABufferID *coded_buf
+    GstBuffer *buf
 )
 {
   GstVaapiEncoderH264 *encoder = GST_VAAPI_ENCODER_H264_CAST(base);
@@ -1388,33 +1386,34 @@ gst_vaapi_encoder_h264_copy_coded_buffer(
   guint32   nal_size;
   const guint8   *nal_start;
   guint8  *frame_end;
+  H264Bitstream bitstream;
+
+  if (!priv->avc_flag) {
+    gst_buffer_ref(buf);
+    return buf;
+  }
 
   ret_buffer = gst_buffer_new();
   ENCODER_ASSERT(ret_buffer);
-  H264Bitstream bitstream;
-  h264_bitstream_init(&bitstream, (frame_size+32)*8);
+  h264_bitstream_init(&bitstream, (GST_BUFFER_SIZE(buf)+32)*8);
   h264_bitstream_align(&bitstream, 0);
   ENCODER_ASSERT(bitstream.bit_size == 0);
 
-  if (!priv->avc_flag) { /*nal format*/
-    h264_bitstream_write_byte_array(&bitstream, frame, frame_size);
-    ENCODER_ASSERT(bitstream.bit_size == frame_size*8);
-  } else { /* elementary format */
-    frame_end = frame + frame_size;
-    nal_start = frame;
-    nal_size = 0;
-    while(NULL !=
-          (nal_start = h264_next_nal(nal_start, frame_end-nal_start, &nal_size))
-         ) {
-      ENCODER_ASSERT(nal_size);
-      if (!nal_size) {
-        nal_start += nal_size;
-        continue;
-      }
-      h264_bitstream_write_uint(&bitstream, nal_size, 32);
-      h264_bitstream_write_byte_array(&bitstream, nal_start, nal_size);
+
+  frame_end = GST_BUFFER_DATA(buf) + GST_BUFFER_SIZE(buf);
+  nal_start = GST_BUFFER_DATA(buf);
+  nal_size = 0;
+  while(NULL !=
+        (nal_start = h264_next_nal(nal_start, frame_end-nal_start, &nal_size))
+       ) {
+    ENCODER_ASSERT(nal_size);
+    if (!nal_size) {
       nal_start += nal_size;
+      continue;
     }
+    h264_bitstream_write_uint(&bitstream, nal_size, 32);
+    h264_bitstream_write_byte_array(&bitstream, nal_start, nal_size);
+    nal_start += nal_size;
   }
   h264_bitstream_align(&bitstream, 0);
 
@@ -1514,8 +1513,7 @@ read_sps_attributes(
 
 static EncoderStatus
 gst_vaapi_encoder_h264_flush(
-    GstVaapiEncoder* base,
-    GList **coded_pics
+    GstVaapiEncoder* base
 )
 {
   GstVaapiEncoderH264* encoder = GST_VAAPI_ENCODER_H264_CAST(base);
@@ -1715,8 +1713,8 @@ gst_vaapi_encoder_h264_class_init(GstVaapiEncoderH264Class *klass)
   base_class->prepare_next_input_buffer =
       gst_vaapi_encoder_h264_prepare_next_buffer;
   base_class->render_frame = gst_vaapi_encoder_h264_rendering;
-  base_class->notify_frame = gst_vaapi_encoder_h264_notify_frame;
-  base_class->copy_coded_frame = gst_vaapi_encoder_h264_copy_coded_buffer;
+  base_class->notify_buffer = gst_vaapi_encoder_h264_notify_frame;
+  base_class->wrap_buffer = gst_vaapi_encoder_h264_wrap_buffer;
   base_class->encode_frame_failed = gst_vaapi_encoder_h264_frame_failed;
 
   encoder_class->flush = gst_vaapi_encoder_h264_flush;
index df55421..70e08d7 100644 (file)
@@ -435,8 +435,7 @@ gst_vaapi_encoder_mpeg4_notify_frame(
 
 static EncoderStatus
 gst_vaapi_encoder_mpeg4_flush(
-    GstVaapiEncoder* base,
-    GList **coded_pics
+    GstVaapiEncoder* base
 )
 {
   GstVaapiEncoderMpeg4 *encoder = GST_VAAPI_ENCODER_MPEG4_CAST(base);
@@ -516,8 +515,8 @@ gst_vaapi_encoder_mpeg4_class_init(GstVaapiEncoderMpeg4Class *klass)
   base_class->pre_alloc_resource  = NULL;
   base_class->release_resource    = gst_vaapi_encoder_mpeg4_release_resource;
   base_class->render_frame = gst_vaapi_encoder_mpeg4_rendering;
-  base_class->notify_frame = gst_vaapi_encoder_mpeg4_notify_frame;
-  base_class->copy_coded_frame = NULL;
+  base_class->notify_buffer = gst_vaapi_encoder_mpeg4_notify_frame;
+  base_class->wrap_buffer = NULL;
 
   encoder_class->flush = gst_vaapi_encoder_mpeg4_flush;
   encoder_class->get_codec_data = gst_vaapi_encoder_mpeg4_get_codec_data;
index 4d53109..e6829e6 100644 (file)
@@ -52,6 +52,32 @@ typedef struct _GstVaapiEncodePrivate GstVaapiEncodePrivate;
 
 #define GstVideoContextClass GstVideoContextInterface
 
+#define GST_VAAPI_ENCODE_MUTEX_LOCK(encode)  \
+    G_STMT_START{ g_mutex_lock((encode)->mutex); }G_STMT_END
+
+#define GST_VAAPI_ENCODE_MUTEX_UNLOCK(encode) \
+    G_STMT_START{ g_mutex_unlock((encode)->mutex); }G_STMT_END
+
+#define GST_VAAPI_ENCODE_IDLE_BUF_WAIT(encode)                       \
+        G_STMT_START {                                               \
+            g_cond_wait((encode)->idle_buf_added, (encode)->mutex);  \
+        } G_STMT_END
+
+#define GST_VAAPI_ENCODE_IDLE_BUF_SIGNAL(encode)                     \
+        G_STMT_START {                                               \
+            g_cond_signal((encode)->idle_buf_added);                 \
+        } G_STMT_END
+
+#define GST_VAAPI_ENCODE_BUSY_BUF_WAIT(encode)                       \
+        G_STMT_START {                                               \
+            g_cond_wait((encode)->busy_buf_added, (encode)->mutex);  \
+        } G_STMT_END
+
+#define GST_VAAPI_ENCODE_BUSY_BUF_SIGNAL(encode)                     \
+        G_STMT_START {                                               \
+            g_cond_signal((encode)->busy_buf_added);                 \
+        } G_STMT_END
+
 GST_BOILERPLATE_WITH_INTERFACE(
     GstVaapiEncode,
     gst_vaapi_encode,
@@ -106,6 +132,7 @@ gst_vaapi_encode_set_video_context(
 {
     GstVaapiEncode *encode = GST_VAAPI_ENCODE (context);
     GstVaapiDisplay *display = NULL;
+
     gst_vaapi_set_display (type, value, &display);
     gst_vaapi_encoder_set_display(encode->encoder, display);
 }
@@ -146,6 +173,102 @@ gst_vaapi_encode_ensure_display(GstVaapiEncode *encode)
                                     &ENCODER_DISPLAY(encode->encoder));
 }
 
+static void
+gst_vaapi_encode_buffer_loop(GstVaapiEncode *encode)
+{
+  GstBuffer *buf = NULL;
+  EncoderStatus encoder_ret = ENCODER_NO_ERROR;
+  gboolean is_running;
+
+  GST_VAAPI_ENCODE_MUTEX_LOCK(encode);
+  is_running = encode->is_running;
+  GST_VAAPI_ENCODE_MUTEX_UNLOCK(encode);
+  if (!is_running)
+    return;
+
+  encoder_ret =
+      gst_vaapi_encoder_get_encoded_buffer(
+          encode->encoder,
+          &buf);
+  if (encoder_ret != ENCODER_NO_ERROR) {
+    ENCODER_LOG_ERROR("get encoded buffer failed");
+    return;
+  }
+  GST_VAAPI_ENCODE_IDLE_BUF_SIGNAL(encode);
+
+  ENCODER_ASSERT(buf);
+  if (!buf)
+    return;
+
+  GST_VAAPI_ENCODE_MUTEX_LOCK(encode);
+  if (encode->first_src_frame) { /* Set src pad caps and codec data */
+    GstBuffer *codec_data = NULL;
+    if ((ENCODER_NO_ERROR ==
+         gst_vaapi_encoder_get_codec_data(encode->encoder, &codec_data)) &&
+        codec_data) {
+      gst_caps_set_simple(encode->srcpad_caps,
+                          "codec_data",GST_TYPE_BUFFER, codec_data,
+                          NULL);
+    }
+    gst_pad_set_caps (encode->srcpad, encode->srcpad_caps);
+    GST_BUFFER_CAPS(buf) = gst_caps_ref(encode->srcpad_caps);
+    ENCODER_LOG_INFO("gst_vaapi_encode_chain 1st push-buffer caps,\n%s",
+                     _encode_dump_caps(encode->srcpad_caps));
+    encode->first_src_frame = FALSE;
+  }
+  GST_VAAPI_ENCODE_MUTEX_UNLOCK(encode);
+  ENCODER_LOG_DEBUG(
+      "output:%" GST_TIME_FORMAT ", 0x%s",
+      GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buf)),
+      gst_vaapi_encoder_dump_bytes(
+          GST_BUFFER_DATA(buf),
+          (GST_BUFFER_SIZE(buf) > 16 ? 16: GST_BUFFER_SIZE(buf))));
+
+  gst_pad_push(encode->srcpad, buf);
+}
+
+static gboolean
+_encoder_status_callback(
+    GstVaapiBaseEncoder* encoder,
+    EncoderStatus status,
+    void* user_data
+)
+{
+  GstVaapiEncode *encode = (GstVaapiEncode *)user_data;
+  gboolean ret = FALSE;
+
+  GST_VAAPI_ENCODE_MUTEX_LOCK(encode);
+
+  if (!encode->is_running) {
+    ret = FALSE;
+    goto end;
+  }
+
+  switch (status) {
+  case ENCODER_NO_IDLE_BUF:
+    GST_VAAPI_ENCODE_IDLE_BUF_WAIT(encode);
+    ret = TRUE;
+    break;
+
+  case ENCODER_NO_BUSY_BUF:
+    GST_VAAPI_ENCODE_BUSY_BUF_WAIT(encode);
+    ret = TRUE;
+    break;
+
+  default:
+    ret = FALSE;
+    goto end;
+  }
+
+  if (!encode->is_running)
+    ret = FALSE;
+
+end:
+  GST_VAAPI_ENCODE_MUTEX_UNLOCK(encode);
+
+  return ret;
+}
+
 static gboolean
 gst_vaapi_encode_set_caps(GstPad *sink_pad, GstCaps *caps)
 {
@@ -159,6 +282,8 @@ gst_vaapi_encode_set_caps(GstPad *sink_pad, GstCaps *caps)
   gboolean ret = TRUE;
   EncoderStatus encoder_ret = ENCODER_NO_ERROR;
 
+  GST_VAAPI_ENCODE_MUTEX_LOCK(encode);
+
   encode->sinkpad_caps = caps;
   gst_caps_ref(caps);
   ENCODER_LOG_INFO("gst_vaapi_encode_set_caps,\n%s",
@@ -212,6 +337,10 @@ gst_vaapi_encode_set_caps(GstPad *sink_pad, GstCaps *caps)
                        FALSE,
                        "encoder ensure display failed on setting caps.");
 
+  gst_vaapi_base_encoder_set_notify_status(
+      (GstVaapiBaseEncoder*)encode->encoder,
+      _encoder_status_callback,
+      encode);
   encoder_ret = gst_vaapi_encoder_initialize(encode->encoder);
   ENCODER_CHECK_STATUS (ENCODER_NO_ERROR == encoder_ret,
                         FALSE,
@@ -221,7 +350,15 @@ gst_vaapi_encode_set_caps(GstPad *sink_pad, GstCaps *caps)
   ENCODER_CHECK_STATUS (ENCODER_NO_ERROR == encoder_ret,
                         FALSE,
                         "gst_vaapi_encoder_open failed.");
+  encode->is_running = TRUE;
+
 end:
+  GST_VAAPI_ENCODE_MUTEX_UNLOCK(encode);
+  if (ret) {
+    ret = gst_pad_start_task(encode->srcpad, (GstTaskFunction)gst_vaapi_encode_buffer_loop, encode);
+       if (!ret)
+          ENCODER_LOG_INFO("gstvaapiencode start task failed.");
+  }
   return ret;
 }
 
@@ -232,13 +369,17 @@ gst_vaapi_encode_get_caps(GstPad *sink_pad)
   GstVaapiEncode * const encode =
       GST_VAAPI_ENCODE(GST_OBJECT_PARENT(sink_pad));
 
+  GST_VAAPI_ENCODE_MUTEX_LOCK(encode);
+
   if (encode->sinkpad_caps) {
     gst_caps_ref(encode->sinkpad_caps);
     ENCODER_LOG_INFO("get caps,\n%s",
                      _encode_dump_caps(encode->sinkpad_caps));
-    return encode->sinkpad_caps;
-  }
-  caps = gst_caps_copy(gst_pad_get_pad_template_caps(sink_pad));
+    caps = encode->sinkpad_caps;
+  } else
+    caps = gst_caps_copy(gst_pad_get_pad_template_caps(sink_pad));
+
+  GST_VAAPI_ENCODE_MUTEX_UNLOCK(encode);
   return caps;
 }
 
@@ -256,6 +397,17 @@ gst_vaapi_encode_change_state(
     break;
   case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
     break;
+  case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+    break;
+  case GST_STATE_CHANGE_PAUSED_TO_READY: {
+    GST_VAAPI_ENCODE_MUTEX_LOCK (encode);
+    encode->is_running = FALSE;
+    GST_VAAPI_ENCODE_BUSY_BUF_SIGNAL(encode);
+    GST_VAAPI_ENCODE_IDLE_BUF_SIGNAL(encode);
+    GST_VAAPI_ENCODE_MUTEX_UNLOCK(encode);
+    gst_pad_stop_task(encode->srcpad);
+    break;
+  }
   default:
     break;
   }
@@ -267,13 +419,13 @@ gst_vaapi_encode_change_state(
   switch (transition) {
   case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
     break;
-  case GST_STATE_CHANGE_PAUSED_TO_READY: {
+  case GST_STATE_CHANGE_PAUSED_TO_READY:
     gst_vaapi_encoder_close(encode->encoder);
-  }
     break;
   default:
     break;
   }
+
   return GST_STATE_CHANGE_SUCCESS;
 }
 
@@ -283,10 +435,11 @@ gst_vaapi_encode_chain(GstPad *sink_pad, GstBuffer *buf)
   GstFlowReturn ret = GST_FLOW_OK;
   GstVaapiEncode *encode = GST_VAAPI_ENCODE(GST_OBJECT_PARENT(sink_pad));
   EncoderStatus encoder_ret = ENCODER_NO_ERROR;
-  GList *out_buffers = NULL;
-  GstBuffer *tmp_buffer = NULL;
 
   ENCODER_ASSERT(encode && encode->encoder);
+
+  GST_VAAPI_ENCODE_MUTEX_LOCK(encode);
+
   if (encode->first_sink_frame) {
     /* get first buffer caps and set encoder values */
     if (GST_VAAPI_IS_VIDEO_BUFFER(buf)) {
@@ -297,46 +450,15 @@ gst_vaapi_encode_chain(GstPad *sink_pad, GstBuffer *buf)
     }
     encode->first_sink_frame = FALSE;
   }
+  GST_VAAPI_ENCODE_MUTEX_UNLOCK(encode);
 
   /*encoding frames*/
-  ENCODER_ASSERT(gst_vaapi_encoder_get_state(encode->encoder) >= VAAPI_ENC_OPENED);
-  encoder_ret = gst_vaapi_encoder_encode(encode->encoder, buf, &out_buffers);
-  ENCODER_CHECK_STATUS (ENCODER_NO_ERROR == encoder_ret,
+  encoder_ret = gst_vaapi_encoder_encode(encode->encoder, buf);
+  GST_VAAPI_ENCODE_BUSY_BUF_SIGNAL(encode);
+  ENCODER_CHECK_STATUS (ENCODER_NO_ERROR <= encoder_ret,
                         GST_FLOW_ERROR,
                         "gst_vaapi_encoder_encode failed.");
 
-  /*check results*/
-  while (out_buffers) {
-    tmp_buffer = out_buffers->data;
-    out_buffers = g_list_remove(out_buffers, tmp_buffer);
-    if (encode->first_src_frame) {
-      GstBuffer *codec_data = NULL;
-      ENCODER_ASSERT(encode->srcpad_caps);
-      /*replace codec data in src pad caps*/
-      if ((ENCODER_NO_ERROR ==
-           gst_vaapi_encoder_get_codec_data(encode->encoder, &codec_data)) &&
-          codec_data) {
-        gst_caps_set_simple(encode->srcpad_caps,
-                            "codec_data",GST_TYPE_BUFFER, codec_data,
-                            NULL);
-      }
-      gst_pad_set_caps (encode->srcpad, encode->srcpad_caps);
-
-      GST_BUFFER_CAPS(tmp_buffer) = gst_caps_ref(encode->srcpad_caps);
-      ENCODER_LOG_INFO("gst_vaapi_encode_chain 1st push-buffer caps,\n%s",
-                       _encode_dump_caps(encode->srcpad_caps));
-      encode->first_src_frame = FALSE;
-    }
-    ENCODER_LOG_DEBUG(
-        "output:%" GST_TIME_FORMAT ", 0x%s",
-        GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(tmp_buffer)),
-        gst_vaapi_encoder_dump_bytes(GST_BUFFER_DATA(tmp_buffer),
-                                 (GST_BUFFER_SIZE(tmp_buffer) > 16 ?
-                                  16: GST_BUFFER_SIZE(tmp_buffer)))
-                     );
-    gst_pad_push(encode->srcpad, tmp_buffer);
-  }
-
 end:
   gst_buffer_unref(buf);
   return ret;
@@ -412,6 +534,10 @@ gst_vaapi_encode_finalize(GObject *object)
       encode->encoder = NULL;
   }
 
+  g_mutex_free(encode->mutex);
+  g_cond_free(encode->idle_buf_added);
+  g_cond_free(encode->busy_buf_added);
+
   G_OBJECT_CLASS(parent_class)->finalize(object);
 }
 
@@ -427,9 +553,14 @@ gst_vaapi_encode_init(
   encode->srcpad_caps        = NULL;
   encode->first_sink_frame   = TRUE;
   encode->first_src_frame    = TRUE;
+  encode->is_running         = FALSE;
 
   encode->encoder = NULL;
 
+  encode->mutex = g_mutex_new();
+  encode->idle_buf_added = g_cond_new();
+  encode->busy_buf_added = g_cond_new();
+
   /*sink pad */
   encode->sinkpad = gst_pad_new_from_template(
       gst_element_class_get_pad_template(element_class, "sink"),
@@ -454,7 +585,7 @@ gst_vaapi_encode_init(
 
   gst_pad_use_fixed_caps(encode->srcpad);
   /*gst_pad_set_event_function(encode->srcpad, gst_vaapi_encode_src_event);*/
-  gst_pad_set_query_function(encode->sinkpad, gst_vaapi_encode_query);
+  gst_pad_set_query_function(encode->srcpad, gst_vaapi_encode_query);
   gst_element_add_pad(GST_ELEMENT(encode), encode->srcpad);
 }
 
index 2046369..538ee45 100644 (file)
@@ -73,6 +73,12 @@ struct _GstVaapiEncode {
     GstVaapiEncoder    *encoder;
     gboolean            first_sink_frame;
     gboolean            first_src_frame;
+
+    /*encode chain lock*/
+    GMutex             *mutex;
+    GCond              *idle_buf_added;
+    GCond              *busy_buf_added;
+    gboolean            is_running;
 };
 
 struct _GstVaapiEncodeClass {