#include <string.h>
#include <stdlib.h>
#include <glib.h>
+#include <glib-object.h>
+
#include <X11/Xlib.h>
#include <va/va.h>
#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;
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(
)
{
GstVaapiBaseEncoderPrivate *priv = encoder->priv;
- priv->frame_notify_flag = flag;
+ priv->buffer_notify_flag = flag;
}
gboolean
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
(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);
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;
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]);
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;
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);
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) {
}
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));
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,
static EncoderStatus
gst_vaapi_base_encoder_flush_default(
- GstVaapiEncoder* encoder,
- GList **coded_pics
+ GstVaapiEncoder* encoder
)
{
GstVaapiBaseEncoder* base_encoder = GST_VAAPI_BASE_ENCODER(encoder);
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);
}
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;
}
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*/
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;
/*
#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,
{
GstVaapiEncode *encode = GST_VAAPI_ENCODE (context);
GstVaapiDisplay *display = NULL;
+
gst_vaapi_set_display (type, value, &display);
gst_vaapi_encoder_set_display(encode->encoder, display);
}
&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)
{
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",
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,
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;
}
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;
}
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;
}
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;
}
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)) {
}
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;
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);
}
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"),
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);
}