2 * gstvaapibaseencoder.c - VA-API base encoder
4 * Copyright (C) 2011 Intel Corporation
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public License
8 * as published by the Free Software Foundation; either version 2.1
9 * of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free
18 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301 USA
22 #include "gstvaapibaseencoder.h"
30 #include "va/va_x11.h"
32 #include "gst/gstclock.h"
33 #include "gst/gstvalue.h"
35 #include "gst/vaapi/gstvaapiobject.h"
36 #include "gst/vaapi/gstvaapiobject_priv.h"
37 #include "gst/vaapi/gstvaapicontext.h"
38 #include "gst/vaapi/gstvaapisurface.h"
39 #include "gst/vaapi/gstvaapisurfacepool.h"
40 #include "gst/vaapi/gstvaapivideobuffer.h"
41 #include "gst/vaapi/gstvaapidisplay_priv.h"
42 #include "gst/vaapi/gstvaapidebug.h"
46 #include "gst/vaapi/gstvaapivideobuffer_glx.h"
47 #define gst_vaapi_video_buffer_new_from_pool(pool) \
48 gst_vaapi_video_buffer_glx_new_from_pool(pool)
52 GST_DEBUG_CATEGORY_STATIC (gst_vaapi_base_encoder_debug);
53 #define GST_CAT_DEFAULT gst_vaapi_base_encoder_debug
55 #define VA_INVALID_PROFILE 0xffffffff
56 #define DEFAULT_VA_CODEDBUF_NUM 4
58 #define GST_TYPE_ENCODER_SHARED_BUFFER (gst_base_encode_buffer_get_type())
60 static GstMiniObjectClass *gst_encoder_share_buffer_parent_class = NULL;
62 typedef struct _GstEncoderShareBuffer GstEncoderShareBuffer;
63 struct _GstEncoderShareBuffer {
66 GstVaapiBaseEncoder *encoder;
70 struct _GstVaapiBaseEncoderPrivate {
71 guint32 format; /*NV12, I420,*/
73 /*total encoded frames*/
75 gboolean frame_notify_flag;
77 VABufferID *coded_bufs;
78 guint32 coded_buf_num;
79 GMutex *code_buffer_lock;
80 GCond *code_buffer_cond;
81 GQueue *available_code_buffers;
83 GstVaapiSurfacePool *surfaces_pool;
88 G_DEFINE_TYPE(GstVaapiBaseEncoder, gst_vaapi_base_encoder, GST_TYPE_VAAPI_ENCODER);
90 static EncoderStatus gst_vaapi_base_encoder_initialize_default(
91 GstVaapiEncoder* encoder, GstVaapiDisplay *display);
92 static EncoderStatus gst_vaapi_base_encoder_uninitialize_default(
93 GstVaapiEncoder* encoder, GstVaapiDisplay *display);
94 static EncoderStatus gst_vaapi_base_encoder_open_default(GstVaapiEncoder* encoder,
95 GstVaapiDisplay *display, void* private_data,
96 GstVaapiContext **context);
97 static EncoderStatus gst_vaapi_base_encoder_close_default(GstVaapiEncoder* encoder,
98 GstVaapiDisplay *display, GstVaapiContext *context);
99 static EncoderStatus gst_vaapi_base_encoder_encode_default(GstVaapiEncoder* encoder,
100 GstVaapiDisplay *display, GstVaapiContext *context,
101 GstBuffer *raw_pic, GList **coded_pics);
102 static EncoderStatus gst_vaapi_base_encoder_flush_default(GstVaapiEncoder* encoder,
103 GstVaapiDisplay *display,
104 GstVaapiContext *context,
106 static GstBuffer *gst_vaapi_base_encoder_copy_buffer_default(GstVaapiBaseEncoder *encoder,
107 guint8 *frame, guint32 frame_size, VABufferID *coded_buf);
110 static gboolean base_encoder_alloc_coded_buffers(GstVaapiBaseEncoder *base_encoder,
111 GstVaapiDisplay *display, GstVaapiContext *context);
112 static EncoderStatus base_encoder_release_coded_buffers(GstVaapiBaseEncoder *base_encoder,
113 GstVaapiDisplay *display, GstVaapiContext *context);
114 static EncoderStatus base_put_raw_buffer_to_surface(GstVaapiBaseEncoder *base_encoder,
115 GstVaapiDisplay *display, GstBuffer *raw_pic, GstVaapiSurface *surface);
117 static EncoderStatus base_query_encoding_status(GstVaapiBaseEncoder *base_encoder,
118 GstVaapiDisplay *display, GstVaapiSurface *buffer_surface,
119 gboolean is_key, GstVaapiVideoBuffer *surface_buffer,
120 VABufferID *coded_buf, GList **coded_pics);
122 static VABufferID *pop_available_coded_buffer(GstVaapiBaseEncoderPrivate *base_prv);
123 static gboolean push_available_coded_buffer(
124 GstVaapiBaseEncoderPrivate *base_prv, VABufferID *buf);
127 gst_vaapi_base_encoder_finalize(GObject *object)
129 /*free private buffers*/
130 GstVaapiEncoder *encoder = GST_VAAPI_ENCODER(object);
131 GstVaapiBaseEncoderPrivate *base_prv = GST_VAAPI_BASE_ENCODER_GET_PRIVATE(object);
133 if (gst_vaapi_encoder_get_state(encoder) != VAAPI_ENC_NULL) {
134 gst_vaapi_encoder_uninitialize(encoder);
137 g_mutex_free(base_prv->code_buffer_lock);
138 g_cond_free(base_prv->code_buffer_cond);
139 if (base_prv->available_code_buffers) {
140 g_queue_free(base_prv->available_code_buffers);
141 base_prv->available_code_buffers = NULL;
144 G_OBJECT_CLASS(gst_vaapi_base_encoder_parent_class)->finalize(object);
149 gst_vaapi_base_encoder_class_init(GstVaapiBaseEncoderClass *klass)
151 GObjectClass * const object_class = G_OBJECT_CLASS(klass);
152 GstVaapiEncoderClass * const encoder_class = GST_VAAPI_ENCODER_CLASS(klass);
153 g_type_class_add_private(klass, sizeof(GstVaapiBaseEncoderPrivate));
155 GST_DEBUG_CATEGORY_INIT (gst_vaapi_base_encoder_debug, "gst_vaapi_base_encoder", 0,
156 "gst_vaapi_base_encoder element");
158 object_class->finalize = gst_vaapi_base_encoder_finalize;
160 encoder_class->initialize = gst_vaapi_base_encoder_initialize_default;
161 encoder_class->uninitialize = gst_vaapi_base_encoder_uninitialize_default;
162 encoder_class->open = gst_vaapi_base_encoder_open_default;
163 encoder_class->close = gst_vaapi_base_encoder_close_default;
164 encoder_class->encode = gst_vaapi_base_encoder_encode_default;
165 encoder_class->flush = gst_vaapi_base_encoder_flush_default;
166 encoder_class->get_codec_data = NULL;
168 /* user defined functions*/
169 klass->validate_attributes = NULL;
170 klass->pre_alloc_resource = NULL;
171 klass->release_resource = NULL;
172 klass->prepare_next_input_buffer = NULL;
173 klass->render_frame = NULL;
174 klass->notify_frame = NULL;
175 klass->copy_coded_frame = NULL;
176 klass->encode_frame_failed = NULL;
179 object_class->set_property = gst_vaapi_base_encoder_set_property;
180 object_class->get_property = gst_vaapi_base_encoder_get_property;
185 gst_encoder_share_buffer_finalize (GstEncoderShareBuffer *base_buffer)
187 GstVaapiBaseEncoder *encoder = NULL;
188 VABufferID* coded_id = NULL;
189 GstVaapiDisplay *display = NULL;
190 GstVaapiBaseEncoderPrivate *encoder_prv = NULL;
192 gboolean is_locked = FALSE;
194 encoder = base_buffer->encoder;
195 coded_id = base_buffer->coded_id;
196 display = ENCODER_DISPLAY(encoder);
197 encoder_prv = GST_VAAPI_BASE_ENCODER_GET_PRIVATE(encoder);
199 ENCODER_ASSERT(display);
200 VADisplay va_dpy = gst_vaapi_display_get_display(display);
202 ENCODER_ASSERT(encoder_prv);
203 ENCODER_ASSERT(coded_id && VA_INVALID_ID!= *coded_id);
205 /*if (--(*base_buffer->ref_coded_id) == 0) */
207 /*g_free(base_buffer->ref_coded_id);*/
208 ENCODER_ACQUIRE_DISPLAY_LOCK(display);
209 vaUnmapBuffer(va_dpy, *coded_id);
210 ENCODER_RELEASE_DISPLAY_LOCK(display);
211 push_available_coded_buffer(encoder_prv, coded_id);
214 if (GST_MINI_OBJECT_CLASS(gst_encoder_share_buffer_parent_class)->finalize) {
215 GST_MINI_OBJECT_CLASS(gst_encoder_share_buffer_parent_class)->finalize(GST_MINI_OBJECT(base_buffer));
220 gst_encode_share_buffer_class_init (gpointer g_class, gpointer class_data)
222 GstMiniObjectClass *mini_object_class = GST_MINI_OBJECT_CLASS(g_class);
224 gst_encoder_share_buffer_parent_class = g_type_class_peek_parent(g_class);
225 ENCODER_ASSERT(gst_encoder_share_buffer_parent_class);
227 mini_object_class->finalize = (GstMiniObjectFinalizeFunction)
228 gst_encoder_share_buffer_finalize;
233 gst_base_encode_buffer_get_type (void)
235 static GType s_base_encode_buffer_type = 0;
236 if (G_UNLIKELY (s_base_encode_buffer_type == 0)) {
237 static const GTypeInfo s_base_encode_buffer_info = {
238 sizeof(GstBufferClass),
241 gst_encode_share_buffer_class_init,
244 sizeof(GstEncoderShareBuffer),
249 s_base_encode_buffer_type = g_type_register_static (GST_TYPE_BUFFER,
250 "GstEncoderShareBuffer", &s_base_encode_buffer_info, 0);
252 return s_base_encode_buffer_type;
255 static GstEncoderShareBuffer *
256 gst_base_encode_share_buffer_new(GstVaapiBaseEncoder *encoder, VABufferID *coded_id)
258 GstEncoderShareBuffer *buf = (GstEncoderShareBuffer*)gst_mini_object_new(GST_TYPE_ENCODER_SHARED_BUFFER);
259 buf->coded_id = coded_id;
260 buf->encoder = encoder;
266 gst_vaapi_base_encoder_init(GstVaapiBaseEncoder *encoder)
268 GstVaapiBaseEncoderPrivate *base_prv = GST_VAAPI_BASE_ENCODER_GET_PRIVATE(encoder);
269 ENCODER_ASSERT(base_prv);
271 /* init private values*/
272 base_prv->format = 0;
273 base_prv->profile= VA_INVALID_PROFILE;
274 base_prv->frame_count = 0;
275 base_prv->frame_notify_flag = FALSE;
277 base_prv->coded_bufs = NULL;
278 base_prv->coded_buf_num = DEFAULT_VA_CODEDBUF_NUM;
279 base_prv->code_buffer_lock = g_mutex_new();
280 base_prv->code_buffer_cond = g_cond_new();
281 base_prv->available_code_buffers = g_queue_new();
283 base_prv->surfaces_pool = NULL;
284 base_prv->need_flush = FALSE;
288 gst_vaapi_base_encoder_set_frame_notify(GstVaapiBaseEncoder *encoder, gboolean flag)
290 GstVaapiBaseEncoderPrivate *base_prv = GST_VAAPI_BASE_ENCODER_GET_PRIVATE(encoder);
291 base_prv->frame_notify_flag = flag;
295 gst_vaapi_base_encoder_set_va_profile(GstVaapiBaseEncoder *encoder, guint profile)
297 GstVaapiBaseEncoderPrivate *base_prv = GST_VAAPI_BASE_ENCODER_GET_PRIVATE(encoder);
298 base_prv->profile = profile;
303 gst_vaapi_base_encoder_set_input_format(GstVaapiBaseEncoder* encoder, guint32 format)
305 GstVaapiBaseEncoderPrivate *base_prv = GST_VAAPI_BASE_ENCODER_GET_PRIVATE(encoder);
306 base_prv->format = format;
310 gst_vaapi_base_encoder_initialize_default(GstVaapiEncoder* encoder, GstVaapiDisplay *display)
312 return ENCODER_NO_ERROR;
316 gst_vaapi_base_encoder_uninitialize_default(GstVaapiEncoder* encoder, GstVaapiDisplay *display)
318 return ENCODER_NO_ERROR;
323 default_validate_encoder_parameters(GstVaapiBaseEncoder *encoder)
325 if (!ENCODER_WIDTH(encoder) || !ENCODER_HEIGHT(encoder) || !ENCODER_FPS(encoder)) {
332 gst_vaapi_base_encoder_open_default(GstVaapiEncoder* encoder, GstVaapiDisplay *display, void* private_data, GstVaapiContext **context)
334 GstVaapiBaseEncoder* base_encoder = GST_VAAPI_BASE_ENCODER(encoder);
335 GstVaapiBaseEncoderClass *base_class = GST_VAAPI_BASE_ENCODER_GET_CLASS(encoder);
336 GstVaapiBaseEncoderPrivate *base_prv = GST_VAAPI_BASE_ENCODER_GET_PRIVATE(encoder);
338 GstVaapiSurfacePool *surfaces_pool = private_data;
339 GstVaapiContext *out_context = NULL;
341 EncoderStatus ret = ENCODER_NO_ERROR;
342 gboolean check_attri_ret = TRUE;
343 /*check and set default values*/
344 if (base_class->validate_attributes) {
345 check_attri_ret = base_class->validate_attributes(base_encoder);
347 check_attri_ret = default_validate_encoder_parameters(base_encoder);
349 ENCODER_CHECK_STATUS(check_attri_ret, ENCODER_PARAMETER_ERR, "vaapi encoder paramerter error.");
350 ENCODER_CHECK_STATUS(VA_INVALID_PROFILE != base_prv->profile, ENCODER_PROFILE_ERR, "vaapi encoder profile not set.");
352 ENCODER_ASSERT(ENCODER_DISPLAY(encoder));
355 out_context = g_object_new(
356 GST_VAAPI_TYPE_CONTEXT,
358 "id", GST_VAAPI_ID(VA_INVALID_ID),
359 "entrypoint", gst_vaapi_entrypoint(VAEntrypointEncSlice),
360 "width", ENCODER_WIDTH(encoder),
361 "height", ENCODER_HEIGHT(encoder),
365 gst_vaapi_context_set_surface_pool(out_context, surfaces_pool);
367 g_object_set(out_context, "profile", gst_vaapi_profile(base_prv->profile), NULL);
370 VAAPI_UNUSED_ARG(surfaces_pool);
371 out_context = gst_vaapi_context_new(display,
372 gst_vaapi_profile(base_prv->profile),
373 gst_vaapi_entrypoint(VAEntrypointEncSlice),
374 ENCODER_WIDTH(encoder),
375 ENCODER_HEIGHT(encoder));
377 ENCODER_CHECK_STATUS(out_context, ENCODER_CONTEXT_ERR, "gst_vaapi_context_new failed.");
378 ENCODER_CHECK_STATUS(VA_INVALID_ID != GST_VAAPI_OBJECT_ID(out_context), ENCODER_CONTEXT_ERR, "gst_vaapi_context_new failed.");
380 if (base_class->pre_alloc_resource) {
381 ENCODER_CHECK_STATUS(base_class->pre_alloc_resource(base_encoder, display, out_context),
382 ENCODER_MEM_ERR, "encoder <pre_alloc_resource> failed.");
384 ENCODER_CHECK_STATUS(
385 base_encoder_alloc_coded_buffers(base_encoder, display, out_context),
387 "encoder <base_encoder_alloc_coded_buffers> failed."
389 *context = out_context;
391 base_prv->surfaces_pool = gst_vaapi_context_get_surface_pool(out_context);
392 ENCODER_ASSERT(base_prv->surfaces_pool);
393 return ENCODER_NO_ERROR;
397 if (ENCODER_NO_ERROR != ret) {
398 gst_vaapi_base_encoder_close_default(encoder, display, out_context);
400 g_object_unref(out_context);
407 gst_vaapi_base_encoder_close_default(GstVaapiEncoder* encoder, GstVaapiDisplay *display, GstVaapiContext *context)
409 GstVaapiBaseEncoder* base_encoder = GST_VAAPI_BASE_ENCODER(encoder);
410 GstVaapiBaseEncoderClass *base_class = GST_VAAPI_BASE_ENCODER_GET_CLASS(encoder);
411 GstVaapiBaseEncoderPrivate *base_prv = GST_VAAPI_BASE_ENCODER_GET_PRIVATE(encoder);
412 EncoderStatus ret = ENCODER_NO_ERROR;
414 /* release buffers first */
415 base_prv->need_flush = FALSE;
417 if (base_class->release_resource) {
418 base_class->release_resource(base_encoder, display, context);
420 base_encoder_release_coded_buffers(base_encoder, display, context);
421 base_prv->frame_count = 0;
423 if (base_prv->surfaces_pool) {
424 g_object_unref(base_prv->surfaces_pool);
425 base_prv->surfaces_pool = NULL;
432 base_encoder_alloc_coded_buffers(GstVaapiBaseEncoder *base_encoder, GstVaapiDisplay *display, GstVaapiContext *context)
434 GstVaapiBaseEncoderPrivate *base_prv = GST_VAAPI_BASE_ENCODER_GET_PRIVATE(base_encoder);
436 ENCODER_ASSERT(display && context);
437 VADisplay va_dpy = gst_vaapi_display_get_display(display);
438 VAContextID context_id = GST_VAAPI_OBJECT_ID(context);
439 VAStatus va_status = VA_STATUS_SUCCESS;
440 gboolean is_locked = FALSE;
443 guint32 buffer_size = (ENCODER_WIDTH(base_encoder) * ENCODER_HEIGHT(base_encoder) * 400) / (16*16);
445 ENCODER_ASSERT(base_prv->available_code_buffers);
446 ENCODER_ASSERT(!base_prv->coded_bufs);
448 base_prv->coded_bufs = (VABufferID*)g_malloc0(base_prv->coded_buf_num * sizeof(base_prv->coded_bufs[0]));
450 ENCODER_ACQUIRE_DISPLAY_LOCK(display);
451 for (i = 0; i < base_prv->coded_buf_num; i++) {
452 va_status = vaCreateBuffer(va_dpy, context_id,VAEncCodedBufferType,
453 buffer_size, 1, NULL, &base_prv->coded_bufs[i]);
454 if (VA_STATUS_SUCCESS != va_status)
457 ENCODER_RELEASE_DISPLAY_LOCK(display);
458 ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS == va_status, FALSE, "create coded buffer failed.");
460 /* init queue available_code_buffers */
461 g_mutex_lock(base_prv->code_buffer_lock);
462 for (i = 0; i < base_prv->coded_buf_num; i++) {
463 g_queue_push_head(base_prv->available_code_buffers, &base_prv->coded_bufs[i]);
465 g_cond_signal(base_prv->code_buffer_cond);
466 g_mutex_unlock(base_prv->code_buffer_lock);
474 base_encoder_release_coded_buffers(GstVaapiBaseEncoder *base_encoder, GstVaapiDisplay *display, GstVaapiContext *context)
476 VAStatus va_status = VA_STATUS_SUCCESS;
477 GstVaapiBaseEncoderPrivate *base_prv = GST_VAAPI_BASE_ENCODER_GET_PRIVATE(base_encoder);
478 guint32 available_buf_count = base_prv->coded_buf_num;
480 gboolean is_locked = FALSE;
482 ENCODER_ASSERT(display);
483 ENCODER_ASSERT(context);
484 VAAPI_UNUSED_ARG(va_status);
485 VADisplay va_dpy = gst_vaapi_display_get_display(display);
487 /* wait clear all available coded buffers*/
488 g_mutex_lock(base_prv->code_buffer_lock);
489 while (available_buf_count) {
490 if (g_queue_is_empty(base_prv->available_code_buffers)) {
491 g_cond_wait(base_prv->code_buffer_cond, base_prv->code_buffer_lock);
493 g_queue_pop_head(base_prv->available_code_buffers);
494 available_buf_count--;
497 g_mutex_unlock(base_prv->code_buffer_lock);
499 ENCODER_ACQUIRE_DISPLAY_LOCK(display);
500 for (i = 0; i < base_prv->coded_buf_num; i++) {
501 va_status = vaDestroyBuffer(va_dpy, base_prv->coded_bufs[i]);
503 ENCODER_RELEASE_DISPLAY_LOCK(display);
505 return ENCODER_NO_ERROR;
509 gst_vaapi_base_encoder_encode_default(GstVaapiEncoder* encoder, GstVaapiDisplay *display,
510 GstVaapiContext *context, GstBuffer *raw_pic, GList **coded_pics)
512 GstVaapiBaseEncoder* base_encoder = GST_VAAPI_BASE_ENCODER(encoder);
513 GstVaapiBaseEncoderClass *base_class = GST_VAAPI_BASE_ENCODER_GET_CLASS(encoder);
514 GstVaapiBaseEncoderPrivate *base_prv = GST_VAAPI_BASE_ENCODER_GET_PRIVATE(base_encoder);
516 EncoderStatus ret = ENCODER_NO_ERROR;
517 gboolean is_key = FALSE;
518 VABufferID* coded_buf = NULL;
519 VAStatus va_status = VA_STATUS_SUCCESS;
520 VASurfaceID buffer_surface_id = VA_INVALID_SURFACE;
521 GstVaapiSurface *buffer_surface = NULL;
523 gboolean is_locked = FALSE;
525 ENCODER_ASSERT(display && context);
526 VADisplay va_dpy = gst_vaapi_display_get_display(display);
527 VAContextID context_id = GST_VAAPI_OBJECT_ID(context);
528 GstVaapiSurface *new_surface = NULL;
531 GstVaapiVideoBuffer *video_buffer = NULL;
533 ENCODER_CHECK_STATUS(raw_pic || base_class->prepare_next_input_buffer,
534 ENCODER_DATA_ERR, "Need a picture to encode");
536 /* load picture to surface */
537 if (GST_VAAPI_IS_VIDEO_BUFFER(raw_pic)) {
538 video_buffer = GST_VAAPI_VIDEO_BUFFER(raw_pic);
539 gst_buffer_ref(GST_BUFFER_CAST(video_buffer));
541 ENCODER_CHECK_STATUS(base_prv->surfaces_pool, ENCODER_SURFACE_ERR, "surface pool could not be found in context");
542 video_buffer = (GstVaapiVideoBuffer*)gst_vaapi_video_buffer_new_from_pool((GstVaapiVideoPool*)base_prv->surfaces_pool);
543 new_surface = gst_vaapi_video_buffer_get_surface(video_buffer); //gst_vaapi_context_get_surface(context);
544 ENCODER_CHECK_STATUS(new_surface, ENCODER_SURFACE_ERR, "base_pop_free_surface failed.");
546 /* put picture to new surface */
547 va_status = base_put_raw_buffer_to_surface(base_encoder, display, raw_pic, new_surface);
548 ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS == va_status, ENCODER_PICTURE_ERR, "va put buffer to surface failed.");
550 GST_BUFFER_TIMESTAMP(video_buffer) = GST_BUFFER_TIMESTAMP(raw_pic);
551 GST_BUFFER_DURATION(video_buffer) = GST_BUFFER_DURATION(raw_pic);
554 base_prv->need_flush = TRUE;
558 if (base_class->prepare_next_input_buffer) {
559 GstVaapiVideoBuffer* tmp_buf = NULL;
560 ret = base_class->prepare_next_input_buffer(base_encoder, video_buffer, base_prv->need_flush, &tmp_buf);
561 base_prv->need_flush = FALSE;
563 gst_buffer_unref(GST_BUFFER_CAST(video_buffer));
566 if (ret != ENCODER_NO_ERROR || !tmp_buf)
568 video_buffer = tmp_buf;
571 buffer_surface = gst_vaapi_video_buffer_get_surface(video_buffer);
572 buffer_surface_id = (VASurfaceID)GST_VAAPI_OBJECT_ID(buffer_surface);
573 ENCODER_CHECK_STATUS(buffer_surface_id != VA_INVALID_SURFACE, ENCODER_SURFACE_ERR, "surface id == VA_INVALID_SURFACE.");
576 ENCODER_ACQUIRE_DISPLAY_LOCK(display);
577 va_status = vaBeginPicture(va_dpy, context_id, buffer_surface_id);
578 //ENCODER_RELEASE_DISPLAY_LOCK(display);
580 ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS == va_status, ENCODER_PICTURE_ERR, "vaBeginPicture error.");
582 /*get valid coded buffer*/
583 coded_buf = pop_available_coded_buffer(base_prv);
584 ENCODER_CHECK_STATUS(coded_buf, ENCODER_ENC_RES_ERR, "dequeue_available_coded_buffer error.");
587 ret = base_class->render_frame(base_encoder, display, context,
588 buffer_surface, base_prv->frame_count,
589 *coded_buf, &is_key);
590 /* prepare failed, push back */
591 if (ENCODER_NO_ERROR != ret) {
592 push_available_coded_buffer(base_prv, coded_buf);
594 ENCODER_CHECK_STATUS(ENCODER_NO_ERROR == ret, ENCODER_PICTURE_ERR, "base_prepare_encoding failed.");
597 //ENCODER_ACQUIRE_DISPLAY_LOCK(display);
598 va_status = vaEndPicture(va_dpy, context_id);
599 ENCODER_RELEASE_DISPLAY_LOCK(display);
600 ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS == va_status, ENCODER_PICTURE_ERR, "vaEndPicture error.");
602 /*query surface result*/
603 ret = base_query_encoding_status(base_encoder, display, buffer_surface,
604 is_key, video_buffer, coded_buf, coded_pics);
605 if (ENCODER_NO_ERROR != ret) {
609 base_prv->frame_count++;
611 if (base_class->prepare_next_input_buffer) {
613 gst_buffer_unref(GST_BUFFER_CAST(video_buffer));
616 buffer_surface = NULL;
621 ENCODER_RELEASE_DISPLAY_LOCK(display);
622 if (ret > ENCODER_NO_ERROR) {
623 ret = ENCODER_NO_ERROR;
625 if (ret < 0 && base_class->encode_frame_failed) {
626 base_class->encode_frame_failed(base_encoder, video_buffer);
629 gst_buffer_unref(GST_BUFFER_CAST(video_buffer));
636 pop_available_coded_buffer(GstVaapiBaseEncoderPrivate *base_prv)
638 VABufferID *coded_buf = NULL;
641 g_mutex_lock(base_prv->code_buffer_lock);
643 ENCODER_CHECK_STATUS(base_prv->available_code_buffers, FALSE, "coded buffer not found");
644 while (g_queue_is_empty(base_prv->available_code_buffers)) {
645 g_cond_wait(base_prv->code_buffer_cond, base_prv->code_buffer_lock);
647 coded_buf = (VABufferID*)g_queue_pop_head (base_prv->available_code_buffers);
650 g_mutex_unlock(base_prv->code_buffer_lock);
651 VAAPI_UNUSED_ARG(ret);
656 push_available_coded_buffer(GstVaapiBaseEncoderPrivate *base_prv, VABufferID *buf)
658 g_mutex_lock(base_prv->code_buffer_lock);
659 g_queue_push_head(base_prv->available_code_buffers, buf);
660 g_cond_signal(base_prv->code_buffer_cond);
661 g_mutex_unlock(base_prv->code_buffer_lock);
666 base_put_raw_buffer_to_surface(GstVaapiBaseEncoder *base_encoder,
667 GstVaapiDisplay *display,
669 GstVaapiSurface *surface)
671 EncoderStatus ret = ENCODER_NO_ERROR;
672 GstVaapiImage *image;
673 GstVaapiImageFormat image_format;
674 guint8 *y_src = NULL, *u_src = NULL, *v_src = NULL;
675 guint8 *y_dst = NULL, *u_dst = NULL, *v_dst = NULL;
676 int y_size = 0, u_size = 0;
677 int row = 0, col = 0;
678 guint32 plane_count = 0;
679 guint32 image_width = 0, image_height = 0;
680 guint32 pitchy = 0, pitchu = 0, pitchv = 0;
681 GstVaapiBaseEncoderPrivate *base_prv = GST_VAAPI_BASE_ENCODER_GET_PRIVATE(base_encoder);
683 ENCODER_ASSERT(display);
684 VAAPI_UNUSED_ARG(pitchv);
685 VAAPI_UNUSED_ARG(v_dst);
687 image = gst_vaapi_surface_derive_image(surface);
688 gst_vaapi_image_map(image);
690 image_format = gst_vaapi_image_get_format(image);
691 image_width = gst_vaapi_image_get_width(image);
692 image_height = gst_vaapi_image_get_height(image);
694 /* copy buffer to surface */
695 ENCODER_ASSERT(GST_BUFFER_SIZE(raw_pic) >= y_size + (y_size>>1));
697 y_size = ENCODER_WIDTH(base_encoder) * ENCODER_HEIGHT(base_encoder);
698 u_size = ((ENCODER_WIDTH(base_encoder)+1) >> 1) * ((ENCODER_HEIGHT(base_encoder)+1) >> 1);
700 y_src = GST_BUFFER_DATA(raw_pic);
701 u_src = y_src + y_size;
702 v_src = u_src + u_size;
704 plane_count = gst_vaapi_image_get_plane_count(image);
705 y_dst = gst_vaapi_image_get_plane(image, 0);
706 u_dst = gst_vaapi_image_get_plane(image, 1);
707 pitchy = gst_vaapi_image_get_pitch(image, 0);
708 pitchu = gst_vaapi_image_get_pitch(image, 1);
710 if (plane_count > 2) {
711 v_dst = gst_vaapi_image_get_plane(image, 2);
712 pitchv = gst_vaapi_image_get_pitch(image, 2);
715 /* copy from avcenc.c*/
717 for (row = 0; row < image_height; row++) {
718 memcpy(y_dst, y_src, image_width);
720 y_src += ENCODER_WIDTH(base_encoder);
723 if (GST_VAAPI_IMAGE_NV12 == image_format) { /* UV plane */
724 if (GST_VAAPI_IMAGE_I420 == base_prv->format) {
725 for (row = 0; row < image_height / 2; row++) {
726 for (col = 0; col < image_width / 2; col++) {
727 u_dst[col * 2] = u_src[col];
728 u_dst[col * 2 + 1] = v_src[col];
732 u_src += (ENCODER_WIDTH(base_encoder)>>1);
733 v_src += (ENCODER_WIDTH(base_encoder)>>1);
735 } else if (GST_VAAPI_IMAGE_NV12 == base_prv->format){
736 for (row = 0; row < image_height / 2; row++) {
737 memcpy(u_dst, u_src, image_width);
738 u_src += ENCODER_WIDTH(base_encoder);
745 /* FIXME: fix this later */
750 g_object_unref(image);
756 base_query_encoding_status(GstVaapiBaseEncoder *base_encoder,
757 GstVaapiDisplay *display,
758 GstVaapiSurface *buffer_surface,
760 GstVaapiVideoBuffer *surface_buffer,
761 VABufferID *coded_buf,
764 EncoderStatus ret = ENCODER_NO_ERROR;
765 VAStatus va_status = VA_STATUS_SUCCESS;
766 VASurfaceStatus surface_status = 0;
767 VACodedBufferSegment *buf_list = NULL;
768 GstBuffer* ret_buffer = NULL;
769 gboolean has_coded_data = FALSE;
770 gboolean is_locked = FALSE;
771 GstVaapiBaseEncoderClass *base_class = GST_VAAPI_BASE_ENCODER_GET_CLASS(base_encoder);
772 GstVaapiBaseEncoderPrivate *base_prv = GST_VAAPI_BASE_ENCODER_GET_PRIVATE(base_encoder);
774 ENCODER_ASSERT(display);
775 VASurfaceID surface_id = (VASurfaceID)GST_VAAPI_OBJECT_ID(buffer_surface);
776 VADisplay va_dpy = gst_vaapi_display_get_display(display);
778 ENCODER_ASSERT(coded_pics);
779 VAAPI_UNUSED_ARG(has_coded_data);
782 ENCODER_ACQUIRE_DISPLAY_LOCK(display);
784 va_status = vaSyncSurface(va_dpy, surface_id);
785 ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS ==va_status, ENCODER_QUERY_STATUS_ERR, "vaSyncSurface failed.");
787 va_status = vaQuerySurfaceStatus(va_dpy, surface_id, &surface_status);
788 ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS ==va_status, ENCODER_QUERY_STATUS_ERR, "vaQuerySurfaceStatus failed.");
789 if (VASurfaceSkipped&surface_status) {
790 ENCODER_LOG_ERROR("frame skipped, dts:%" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(surface_buffer)));
793 va_status = vaMapBuffer(va_dpy, *coded_buf, (void **)(&buf_list));
794 ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS ==va_status, ENCODER_QUERY_STATUS_ERR, "vaMapBuffer failed.");
797 ENCODER_RELEASE_DISPLAY_LOCK(display);
799 while (buf_list != NULL) {
800 if (base_prv->frame_notify_flag && base_class->notify_frame) {
801 base_class->notify_frame(base_encoder, buf_list->buf, buf_list->size);
804 if (base_class->copy_coded_frame) {
805 ret_buffer = base_class->copy_coded_frame(
806 base_encoder, buf_list->buf,
807 buf_list->size, coded_buf);
809 ret_buffer = gst_vaapi_base_encoder_copy_buffer_default(
810 base_encoder, buf_list->buf,
811 buf_list->size, coded_buf);
813 GST_BUFFER_TIMESTAMP(ret_buffer) = GST_BUFFER_TIMESTAMP(surface_buffer);
814 GST_BUFFER_DURATION(ret_buffer) = GST_BUFFER_DURATION(surface_buffer);
816 GST_BUFFER_FLAG_SET(ret_buffer, GST_BUFFER_FLAG_DELTA_UNIT);
818 GST_BUFFER_OFFSET_END(ret_buffer) = GST_BUFFER_OFFSET_END(surface_buffer);
819 *coded_pics = g_list_append(*coded_pics, ret_buffer);
820 buf_list = (VACodedBufferSegment*)buf_list->next;
821 ENCODER_ASSERT(NULL == buf_list);
822 has_coded_data = TRUE;
823 FPS_CALCULATION(vaapiencode);
829 { // if non-related, push back to available_code_buffers
830 ENCODER_ACQUIRE_DISPLAY_LOCK(display);
831 vaUnmapBuffer(va_dpy, *coded_buf);
832 ENCODER_RELEASE_DISPLAY_LOCK(display);
833 push_available_coded_buffer(base_prv, coded_buf);
836 return ENCODER_NO_ERROR;
840 ENCODER_RELEASE_DISPLAY_LOCK(display);
845 gst_vaapi_base_encoder_copy_buffer_default(GstVaapiBaseEncoder *encoder,
848 VABufferID *coded_buf)
850 GstBuffer *ret_buffer = NULL;
852 ret_buffer = gst_base_encode_share_buffer_new(encoder, coded_buf);
853 ENCODER_ASSERT(ret_buffer);
854 GST_BUFFER_MALLOCDATA(ret_buffer) = NULL;
855 GST_BUFFER_DATA(ret_buffer) = frame;
856 GST_BUFFER_SIZE(ret_buffer) = frame_size;
858 ret_buffer = gst_buffer_new_and_alloc(frame_size);
859 memcpy(GST_BUFFER_DATA(ret_buffer),frame, frame_size);
865 gst_vaapi_base_encoder_flush_default(GstVaapiEncoder* encoder, GstVaapiDisplay *display,
866 GstVaapiContext *context, GList **coded_pics)
868 GstVaapiBaseEncoder* base_encoder = GST_VAAPI_BASE_ENCODER(encoder);
869 EncoderStatus ret = ENCODER_NO_ERROR;
870 GstVaapiBaseEncoderPrivate *base_prv = GST_VAAPI_BASE_ENCODER_GET_PRIVATE(base_encoder);
872 base_prv->frame_count = 0;
873 base_prv->need_flush = TRUE;
874 /*do we need destroy base_prv->seq_parameter? */