a15f74aabffe4f3ec62250f9d570dd898074229e
[profile/ivi/gstreamer-vaapi.git] / gst / vaapiencode / gstvaapibaseencoder.c
1
2 #include "gstvaapibaseencoder.h"
3
4 #include <string.h>
5 #include <stdlib.h>
6 #include <glib.h>
7 #include <X11/Xlib.h>
8
9 #include <va/va.h>
10 #include "va/va_x11.h"
11
12 #include "gst/gstclock.h"
13 #include "gst/gstvalue.h"
14
15 #include "gst/vaapi/gstvaapiobject.h"
16 #include "gst/vaapi/gstvaapiobject_priv.h"
17 #include "gst/vaapi/gstvaapicontext.h"
18 #include "gst/vaapi/gstvaapisurface.h"
19 #include "gst/vaapi/gstvaapisurfacepool.h"
20 #include "gst/vaapi/gstvaapivideobuffer.h"
21 #include "gst/vaapi/gstvaapidisplay_priv.h"
22 #include "gst/vaapi/gstvaapidebug.h"
23
24
25 #if USE_VAAPI_GLX
26 #include "gst/vaapi/gstvaapivideobuffer_glx.h"
27 #define gst_vaapi_video_buffer_new_from_pool(pool) \
28     gst_vaapi_video_buffer_glx_new_from_pool(pool)
29 #endif
30
31
32 GST_DEBUG_CATEGORY_STATIC (gst_vaapi_base_encoder_debug);
33 #define GST_CAT_DEFAULT gst_vaapi_base_encoder_debug
34
35 #define VA_INVALID_PROFILE 0xffffffff
36 #define DEFAULT_VA_CODEDBUF_NUM  4
37
38 #define GST_TYPE_ENCODER_SHARED_BUFFER (gst_base_encode_buffer_get_type())
39
40 static GstMiniObjectClass *gst_encoder_share_buffer_parent_class = NULL;
41
42 typedef struct _GstEncoderShareBuffer  GstEncoderShareBuffer;
43 struct _GstEncoderShareBuffer {
44   GstBuffer            buffer;
45   VABufferID          *coded_id;
46   GstVaapiBaseEncoder *encoder;
47 };
48
49
50 struct _GstVaapiBaseEncoderPrivate {
51   guint32           format;   /*NV12, I420,*/
52   VAProfile         profile;
53   /*total encoded frames*/
54   guint32           frame_count;
55   gboolean          frame_notify_flag;
56
57   VABufferID       *coded_bufs;
58   guint32           coded_buf_num;
59   GMutex           *code_buffer_lock;
60   GCond            *code_buffer_cond;
61   GQueue           *available_code_buffers;
62
63   GstVaapiSurfacePool *surfaces_pool;
64
65   gboolean          need_flush;
66 };
67
68 G_DEFINE_TYPE(GstVaapiBaseEncoder, gst_vaapi_base_encoder, GST_TYPE_VAAPI_ENCODER);
69
70 static EncoderStatus gst_vaapi_base_encoder_initialize_default(
71                          GstVaapiEncoder* encoder, GstVaapiDisplay *display);
72 static EncoderStatus gst_vaapi_base_encoder_uninitialize_default(
73                          GstVaapiEncoder* encoder, GstVaapiDisplay *display);
74 static EncoderStatus gst_vaapi_base_encoder_open_default(GstVaapiEncoder* encoder,
75                          GstVaapiDisplay *display, void* private_data,
76                          GstVaapiContext **context);
77 static EncoderStatus gst_vaapi_base_encoder_close_default(GstVaapiEncoder* encoder,
78                          GstVaapiDisplay *display, GstVaapiContext *context);
79 static EncoderStatus gst_vaapi_base_encoder_encode_default(GstVaapiEncoder* encoder,
80                          GstVaapiDisplay *display, GstVaapiContext *context,
81                          GstBuffer *raw_pic, GList **coded_pics);
82 static EncoderStatus gst_vaapi_base_encoder_flush_default(GstVaapiEncoder* encoder,
83                          GstVaapiDisplay *display,
84                          GstVaapiContext *context,
85                          GList **coded_pics);
86 static GstBuffer    *gst_vaapi_base_encoder_copy_buffer_default(GstVaapiBaseEncoder *encoder,
87                          guint8 *frame, guint32 frame_size, VABufferID *coded_buf);
88
89
90 static gboolean      base_encoder_alloc_coded_buffers(GstVaapiBaseEncoder *base_encoder,
91                          GstVaapiDisplay *display, GstVaapiContext *context);
92 static EncoderStatus base_encoder_release_coded_buffers(GstVaapiBaseEncoder *base_encoder,
93                          GstVaapiDisplay *display, GstVaapiContext *context);
94 static EncoderStatus base_put_raw_buffer_to_surface(GstVaapiBaseEncoder *base_encoder,
95                          GstVaapiDisplay *display, GstBuffer *raw_pic, GstVaapiSurface *surface);
96
97 static EncoderStatus base_query_encoding_status(GstVaapiBaseEncoder *base_encoder,
98                          GstVaapiDisplay *display, GstVaapiSurface *buffer_surface,
99                          gboolean is_key, GstVaapiVideoBuffer *surface_buffer,
100                          VABufferID *coded_buf, GList **coded_pics);
101
102 static VABufferID   *pop_available_coded_buffer(GstVaapiBaseEncoderPrivate *base_prv);
103 static gboolean      push_available_coded_buffer(
104                          GstVaapiBaseEncoderPrivate *base_prv, VABufferID *buf);
105
106 static void
107 gst_vaapi_base_encoder_finalize(GObject *object)
108 {
109   /*free private buffers*/
110   GstVaapiEncoder *encoder = GST_VAAPI_ENCODER(object);
111   GstVaapiBaseEncoderPrivate *base_prv = GST_VAAPI_BASE_ENCODER_GET_PRIVATE(object);
112
113   if (gst_vaapi_encoder_get_state(encoder) != VAAPI_ENC_NULL) {
114     gst_vaapi_encoder_uninitialize(encoder);
115   }
116
117   g_mutex_free(base_prv->code_buffer_lock);
118   g_cond_free(base_prv->code_buffer_cond);
119   if (base_prv->available_code_buffers) {
120     g_queue_free(base_prv->available_code_buffers);
121     base_prv->available_code_buffers = NULL;
122   }
123
124   G_OBJECT_CLASS(gst_vaapi_base_encoder_parent_class)->finalize(object);
125 }
126
127
128 static void
129 gst_vaapi_base_encoder_class_init(GstVaapiBaseEncoderClass *klass)
130 {
131   GObjectClass * const object_class = G_OBJECT_CLASS(klass);
132   GstVaapiEncoderClass * const encoder_class = GST_VAAPI_ENCODER_CLASS(klass);
133   g_type_class_add_private(klass, sizeof(GstVaapiBaseEncoderPrivate));
134
135   GST_DEBUG_CATEGORY_INIT (gst_vaapi_base_encoder_debug, "gst_vaapi_base_encoder", 0,
136       "gst_vaapi_base_encoder element");
137
138   object_class->finalize = gst_vaapi_base_encoder_finalize;
139
140   encoder_class->initialize = gst_vaapi_base_encoder_initialize_default;
141   encoder_class->uninitialize = gst_vaapi_base_encoder_uninitialize_default;
142   encoder_class->open = gst_vaapi_base_encoder_open_default;
143   encoder_class->close = gst_vaapi_base_encoder_close_default;
144   encoder_class->encode = gst_vaapi_base_encoder_encode_default;
145   encoder_class->flush = gst_vaapi_base_encoder_flush_default;
146   encoder_class->get_codec_data = NULL;
147
148   /* user defined functions*/
149   klass->validate_attributes = NULL;
150   klass->pre_alloc_resource = NULL;
151   klass->release_resource = NULL;
152   klass->prepare_next_input_buffer = NULL;
153   klass->render_frame = NULL;
154   klass->notify_frame = NULL;
155   klass->copy_coded_frame = NULL;
156   klass->encode_frame_failed = NULL;
157
158   /*
159   object_class->set_property = gst_vaapi_base_encoder_set_property;
160   object_class->get_property = gst_vaapi_base_encoder_get_property;
161   */
162 }
163
164 static void
165 gst_encoder_share_buffer_finalize (GstEncoderShareBuffer *base_buffer)
166 {
167   GstVaapiBaseEncoder *encoder = NULL;
168   VABufferID* coded_id = NULL;
169   GstVaapiDisplay *display = NULL;
170   GstVaapiBaseEncoderPrivate *encoder_prv = NULL;
171
172   gboolean is_locked = FALSE;
173
174   encoder = base_buffer->encoder;
175   coded_id = base_buffer->coded_id;
176   display = ENCODER_DISPLAY(encoder);
177   encoder_prv = GST_VAAPI_BASE_ENCODER_GET_PRIVATE(encoder);
178
179   ENCODER_ASSERT(display);
180   VADisplay va_dpy = gst_vaapi_display_get_display(display);
181
182   ENCODER_ASSERT(encoder_prv);
183   ENCODER_ASSERT(coded_id && VA_INVALID_ID!= *coded_id);
184
185   /*if (--(*base_buffer->ref_coded_id) == 0) */
186   {
187     /*g_free(base_buffer->ref_coded_id);*/
188     ENCODER_ACQUIRE_DISPLAY_LOCK(display);
189     vaUnmapBuffer(va_dpy, *coded_id);
190     ENCODER_RELEASE_DISPLAY_LOCK(display);
191     push_available_coded_buffer(encoder_prv, coded_id);
192   }
193
194   if (GST_MINI_OBJECT_CLASS(gst_encoder_share_buffer_parent_class)->finalize) {
195     GST_MINI_OBJECT_CLASS(gst_encoder_share_buffer_parent_class)->finalize(GST_MINI_OBJECT(base_buffer));
196   }
197 }
198
199 static void
200 gst_encode_share_buffer_class_init (gpointer g_class, gpointer class_data)
201 {
202   GstMiniObjectClass *mini_object_class = GST_MINI_OBJECT_CLASS(g_class);
203
204   gst_encoder_share_buffer_parent_class = g_type_class_peek_parent(g_class);
205   ENCODER_ASSERT(gst_encoder_share_buffer_parent_class);
206
207   mini_object_class->finalize = (GstMiniObjectFinalizeFunction)
208       gst_encoder_share_buffer_finalize;
209 }
210
211
212 static GType
213 gst_base_encode_buffer_get_type (void)
214 {
215   static GType s_base_encode_buffer_type = 0;
216   if (G_UNLIKELY (s_base_encode_buffer_type == 0)) {
217     static const GTypeInfo s_base_encode_buffer_info = {
218       sizeof(GstBufferClass),
219       NULL,
220       NULL,
221       gst_encode_share_buffer_class_init,
222       NULL,
223       NULL,
224       sizeof(GstEncoderShareBuffer),
225       0,
226       NULL,
227       NULL
228     };
229     s_base_encode_buffer_type = g_type_register_static (GST_TYPE_BUFFER,
230         "GstEncoderShareBuffer", &s_base_encode_buffer_info, 0);
231   }
232   return s_base_encode_buffer_type;
233 }
234
235 static GstEncoderShareBuffer *
236 gst_base_encode_share_buffer_new(GstVaapiBaseEncoder *encoder, VABufferID *coded_id)
237 {
238   GstEncoderShareBuffer *buf = (GstEncoderShareBuffer*)gst_mini_object_new(GST_TYPE_ENCODER_SHARED_BUFFER);
239   buf->coded_id = coded_id;
240   buf->encoder = encoder;
241   return buf;
242 }
243
244
245 static void
246 gst_vaapi_base_encoder_init(GstVaapiBaseEncoder *encoder)
247 {
248   GstVaapiBaseEncoderPrivate *base_prv = GST_VAAPI_BASE_ENCODER_GET_PRIVATE(encoder);
249   ENCODER_ASSERT(base_prv);
250
251   /* init private values*/
252   base_prv->format = 0;
253   base_prv->profile= VA_INVALID_PROFILE;
254   base_prv->frame_count = 0;
255   base_prv->frame_notify_flag = FALSE;
256
257   base_prv->coded_bufs = NULL;
258   base_prv->coded_buf_num = DEFAULT_VA_CODEDBUF_NUM;
259   base_prv->code_buffer_lock = g_mutex_new();
260   base_prv->code_buffer_cond = g_cond_new();
261   base_prv->available_code_buffers = g_queue_new();
262
263   base_prv->surfaces_pool = NULL;
264   base_prv->need_flush = FALSE;
265 }
266
267 void
268 gst_vaapi_base_encoder_set_frame_notify(GstVaapiBaseEncoder *encoder, gboolean flag)
269 {
270   GstVaapiBaseEncoderPrivate *base_prv = GST_VAAPI_BASE_ENCODER_GET_PRIVATE(encoder);
271   base_prv->frame_notify_flag = flag;
272 }
273
274 gboolean
275 gst_vaapi_base_encoder_set_va_profile(GstVaapiBaseEncoder *encoder, guint profile)
276 {
277   GstVaapiBaseEncoderPrivate *base_prv = GST_VAAPI_BASE_ENCODER_GET_PRIVATE(encoder);
278   base_prv->profile = profile;
279   return TRUE;
280 }
281
282 void
283 gst_vaapi_base_encoder_set_input_format(GstVaapiBaseEncoder* encoder, guint32 format)
284 {
285   GstVaapiBaseEncoderPrivate *base_prv = GST_VAAPI_BASE_ENCODER_GET_PRIVATE(encoder);
286   base_prv->format = format;
287 }
288
289 EncoderStatus
290 gst_vaapi_base_encoder_initialize_default(GstVaapiEncoder* encoder, GstVaapiDisplay *display)
291 {
292   return ENCODER_NO_ERROR;
293 }
294
295 EncoderStatus
296 gst_vaapi_base_encoder_uninitialize_default(GstVaapiEncoder* encoder, GstVaapiDisplay *display)
297 {
298   return ENCODER_NO_ERROR;
299
300 }
301
302 gboolean
303 default_validate_encoder_parameters(GstVaapiBaseEncoder *encoder)
304 {
305   if (!ENCODER_WIDTH(encoder) || !ENCODER_HEIGHT(encoder) || !ENCODER_FPS(encoder)) {
306     return FALSE;
307   }
308   return TRUE;
309 }
310
311 EncoderStatus
312 gst_vaapi_base_encoder_open_default(GstVaapiEncoder* encoder, GstVaapiDisplay *display, void* private_data, GstVaapiContext **context)
313 {
314   GstVaapiBaseEncoder* base_encoder = GST_VAAPI_BASE_ENCODER(encoder);
315   GstVaapiBaseEncoderClass *base_class = GST_VAAPI_BASE_ENCODER_GET_CLASS(encoder);
316   GstVaapiBaseEncoderPrivate *base_prv = GST_VAAPI_BASE_ENCODER_GET_PRIVATE(encoder);
317
318   GstVaapiSurfacePool *surfaces_pool = private_data;
319   GstVaapiContext *out_context = NULL;
320
321   EncoderStatus ret = ENCODER_NO_ERROR;
322   gboolean check_attri_ret = TRUE;
323   /*check and set default values*/
324   if (base_class->validate_attributes) {
325     check_attri_ret = base_class->validate_attributes(base_encoder);
326   } else {
327     check_attri_ret = default_validate_encoder_parameters(base_encoder);
328   }
329   ENCODER_CHECK_STATUS(check_attri_ret, ENCODER_PARAMETER_ERR, "vaapi encoder paramerter error.");
330   ENCODER_CHECK_STATUS(VA_INVALID_PROFILE != base_prv->profile, ENCODER_PROFILE_ERR, "vaapi encoder profile not set.");
331
332   ENCODER_ASSERT(ENCODER_DISPLAY(encoder));
333
334 #ifdef _MRST_
335   out_context = g_object_new(
336         GST_VAAPI_TYPE_CONTEXT,
337         "display",      display,
338         "id",           GST_VAAPI_ID(VA_INVALID_ID),
339         "entrypoint",   gst_vaapi_entrypoint(VAEntrypointEncSlice),
340         "width",        ENCODER_WIDTH(encoder),
341         "height",       ENCODER_HEIGHT(encoder),
342         NULL
343     );
344   if (surfaces_pool) {
345     gst_vaapi_context_set_surface_pool(out_context, surfaces_pool);
346   }
347   g_object_set(out_context, "profile",  gst_vaapi_profile(base_prv->profile), NULL);
348
349 #else
350   VAAPI_UNUSED_ARG(surfaces_pool);
351   out_context = gst_vaapi_context_new(display,
352                         gst_vaapi_profile(base_prv->profile),
353                         gst_vaapi_entrypoint(VAEntrypointEncSlice),
354                         ENCODER_WIDTH(encoder),
355                         ENCODER_HEIGHT(encoder));
356 #endif
357   ENCODER_CHECK_STATUS(out_context, ENCODER_CONTEXT_ERR, "gst_vaapi_context_new failed.");
358   ENCODER_CHECK_STATUS(VA_INVALID_ID != GST_VAAPI_OBJECT_ID(out_context), ENCODER_CONTEXT_ERR, "gst_vaapi_context_new failed.");
359
360   if (base_class->pre_alloc_resource) {
361     ENCODER_CHECK_STATUS(base_class->pre_alloc_resource(base_encoder, display, out_context),
362                          ENCODER_MEM_ERR, "encoder <pre_alloc_resource> failed.");
363   }
364   ENCODER_CHECK_STATUS(
365     base_encoder_alloc_coded_buffers(base_encoder, display, out_context),
366     ENCODER_MEM_ERR,
367     "encoder <base_encoder_alloc_coded_buffers> failed."
368   );
369   *context = out_context;
370
371   base_prv->surfaces_pool = gst_vaapi_context_get_surface_pool(out_context);
372   ENCODER_ASSERT(base_prv->surfaces_pool);
373   return ENCODER_NO_ERROR;
374
375 end:
376   // clear resources
377   if (ENCODER_NO_ERROR != ret) {
378     gst_vaapi_base_encoder_close_default(encoder, display, out_context);
379     if (out_context) {
380       g_object_unref(out_context);
381     }
382   }
383   return ret;
384 }
385
386 EncoderStatus
387 gst_vaapi_base_encoder_close_default(GstVaapiEncoder* encoder, GstVaapiDisplay *display, GstVaapiContext *context)
388 {
389   GstVaapiBaseEncoder* base_encoder = GST_VAAPI_BASE_ENCODER(encoder);
390   GstVaapiBaseEncoderClass *base_class = GST_VAAPI_BASE_ENCODER_GET_CLASS(encoder);
391   GstVaapiBaseEncoderPrivate *base_prv = GST_VAAPI_BASE_ENCODER_GET_PRIVATE(encoder);
392   EncoderStatus ret = ENCODER_NO_ERROR;
393
394   /* release buffers first */
395   base_prv->need_flush = FALSE;
396
397   if (base_class->release_resource) {
398     base_class->release_resource(base_encoder, display, context);
399   }
400   base_encoder_release_coded_buffers(base_encoder, display, context);
401   base_prv->frame_count = 0;
402
403   if (base_prv->surfaces_pool) {
404     g_object_unref(base_prv->surfaces_pool);
405     base_prv->surfaces_pool = NULL;
406   }
407
408   return ret;
409 }
410
411 static gboolean
412 base_encoder_alloc_coded_buffers(GstVaapiBaseEncoder *base_encoder, GstVaapiDisplay *display, GstVaapiContext *context)
413 {
414   GstVaapiBaseEncoderPrivate *base_prv = GST_VAAPI_BASE_ENCODER_GET_PRIVATE(base_encoder);
415
416   ENCODER_ASSERT(display && context);
417   VADisplay va_dpy = gst_vaapi_display_get_display(display);
418   VAContextID context_id = GST_VAAPI_OBJECT_ID(context);
419   VAStatus va_status = VA_STATUS_SUCCESS;
420   gboolean is_locked = FALSE;
421   guint i = 0;
422   gboolean ret = TRUE;
423   guint32 buffer_size = (ENCODER_WIDTH(base_encoder) * ENCODER_HEIGHT(base_encoder) * 400) / (16*16);
424
425   ENCODER_ASSERT(base_prv->available_code_buffers);
426   ENCODER_ASSERT(!base_prv->coded_bufs);
427
428   base_prv->coded_bufs = (VABufferID*)g_malloc0(base_prv->coded_buf_num * sizeof(base_prv->coded_bufs[0]));
429
430   ENCODER_ACQUIRE_DISPLAY_LOCK(display);
431   for (i = 0; i < base_prv->coded_buf_num; i++) {
432     va_status = vaCreateBuffer(va_dpy, context_id,VAEncCodedBufferType,
433                                buffer_size, 1, NULL, &base_prv->coded_bufs[i]);
434     if (VA_STATUS_SUCCESS != va_status)
435       break;
436   }
437   ENCODER_RELEASE_DISPLAY_LOCK(display);
438   ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS == va_status, FALSE, "create coded buffer failed.");
439
440   /* init queue available_code_buffers */
441   g_mutex_lock(base_prv->code_buffer_lock);
442   for (i = 0; i < base_prv->coded_buf_num; i++) {
443     g_queue_push_head(base_prv->available_code_buffers, &base_prv->coded_bufs[i]);
444   }
445   g_cond_signal(base_prv->code_buffer_cond);
446   g_mutex_unlock(base_prv->code_buffer_lock);
447
448 end:
449   return ret;
450
451 }
452
453 static EncoderStatus
454 base_encoder_release_coded_buffers(GstVaapiBaseEncoder *base_encoder, GstVaapiDisplay *display, GstVaapiContext *context)
455 {
456   VAStatus va_status = VA_STATUS_SUCCESS;
457   GstVaapiBaseEncoderPrivate *base_prv = GST_VAAPI_BASE_ENCODER_GET_PRIVATE(base_encoder);
458   guint32 available_buf_count = base_prv->coded_buf_num;
459   guint32 i;
460   gboolean is_locked = FALSE;
461
462   ENCODER_ASSERT(display);
463   ENCODER_ASSERT(context);
464   VAAPI_UNUSED_ARG(va_status);
465   VADisplay va_dpy = gst_vaapi_display_get_display(display);
466
467   /* wait clear all available coded buffers*/
468   g_mutex_lock(base_prv->code_buffer_lock);
469   while (available_buf_count) {
470     if (g_queue_is_empty(base_prv->available_code_buffers)) {
471       g_cond_wait(base_prv->code_buffer_cond, base_prv->code_buffer_lock);
472     } else {
473       g_queue_pop_head(base_prv->available_code_buffers);
474       available_buf_count--;
475     }
476   }
477   g_mutex_unlock(base_prv->code_buffer_lock);
478
479   ENCODER_ACQUIRE_DISPLAY_LOCK(display);
480   for (i = 0; i < base_prv->coded_buf_num; i++) {
481     va_status = vaDestroyBuffer(va_dpy, base_prv->coded_bufs[i]);
482   }
483   ENCODER_RELEASE_DISPLAY_LOCK(display);
484
485   return ENCODER_NO_ERROR;
486 }
487
488 EncoderStatus
489 gst_vaapi_base_encoder_encode_default(GstVaapiEncoder* encoder, GstVaapiDisplay *display,
490                         GstVaapiContext *context, GstBuffer *raw_pic, GList **coded_pics)
491 {
492   GstVaapiBaseEncoder* base_encoder = GST_VAAPI_BASE_ENCODER(encoder);
493   GstVaapiBaseEncoderClass *base_class = GST_VAAPI_BASE_ENCODER_GET_CLASS(encoder);
494   GstVaapiBaseEncoderPrivate *base_prv = GST_VAAPI_BASE_ENCODER_GET_PRIVATE(base_encoder);
495
496   EncoderStatus ret = ENCODER_NO_ERROR;
497   gboolean is_key = FALSE;
498   VABufferID* coded_buf = NULL;
499   VAStatus va_status = VA_STATUS_SUCCESS;
500   VASurfaceID  buffer_surface_id = VA_INVALID_SURFACE;
501   GstVaapiSurface *buffer_surface = NULL;
502
503   gboolean is_locked = FALSE;
504
505   ENCODER_ASSERT(display && context);
506   VADisplay va_dpy = gst_vaapi_display_get_display(display);
507   VAContextID context_id = GST_VAAPI_OBJECT_ID(context);
508   GstVaapiSurface *new_surface = NULL;
509
510   /* Video Buffer */
511   GstVaapiVideoBuffer *video_buffer = NULL;
512
513   ENCODER_CHECK_STATUS(raw_pic || base_class->prepare_next_input_buffer,
514                        ENCODER_DATA_ERR, "Need a picture to encode");
515   if (raw_pic) {
516     /* load picture to surface */
517     if (GST_VAAPI_IS_VIDEO_BUFFER(raw_pic)) {
518       video_buffer = GST_VAAPI_VIDEO_BUFFER(raw_pic);
519       gst_buffer_ref(GST_BUFFER_CAST(video_buffer));
520     } else {
521       ENCODER_CHECK_STATUS(base_prv->surfaces_pool, ENCODER_SURFACE_ERR, "surface pool could not be found in context");
522       video_buffer = (GstVaapiVideoBuffer*)gst_vaapi_video_buffer_new_from_pool((GstVaapiVideoPool*)base_prv->surfaces_pool);
523       new_surface = gst_vaapi_video_buffer_get_surface(video_buffer); //gst_vaapi_context_get_surface(context);
524       ENCODER_CHECK_STATUS(new_surface, ENCODER_SURFACE_ERR, "base_pop_free_surface failed.");
525
526       /* put picture to new surface */
527       va_status = base_put_raw_buffer_to_surface(base_encoder, display, raw_pic, new_surface);
528       ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS == va_status, ENCODER_PICTURE_ERR, "va put buffer to surface failed.");
529
530       GST_BUFFER_TIMESTAMP(video_buffer) = GST_BUFFER_TIMESTAMP(raw_pic);
531       GST_BUFFER_DURATION(video_buffer) = GST_BUFFER_DURATION(raw_pic);
532     }
533   } else {
534     base_prv->need_flush = TRUE;
535   }
536
537 again:
538   if (base_class->prepare_next_input_buffer) {
539     GstVaapiVideoBuffer* tmp_buf = NULL;
540     ret = base_class->prepare_next_input_buffer(base_encoder, video_buffer, base_prv->need_flush, &tmp_buf);
541     base_prv->need_flush = FALSE;
542     if (video_buffer) {
543       gst_buffer_unref(GST_BUFFER_CAST(video_buffer));
544       video_buffer = NULL;
545     }
546     if (ret != ENCODER_NO_ERROR || !tmp_buf)
547       goto end;
548     video_buffer = tmp_buf;
549   }
550
551   buffer_surface = gst_vaapi_video_buffer_get_surface(video_buffer);
552   buffer_surface_id = (VASurfaceID)GST_VAAPI_OBJECT_ID(buffer_surface);
553   ENCODER_CHECK_STATUS(buffer_surface_id != VA_INVALID_SURFACE, ENCODER_SURFACE_ERR, "surface id == VA_INVALID_SURFACE.");
554
555   /* begin surface*/
556   ENCODER_ACQUIRE_DISPLAY_LOCK(display);
557   va_status = vaBeginPicture(va_dpy, context_id, buffer_surface_id);
558   //ENCODER_RELEASE_DISPLAY_LOCK(display);
559
560   ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS == va_status, ENCODER_PICTURE_ERR, "vaBeginPicture error.");
561
562   /*get valid coded buffer*/
563   coded_buf = pop_available_coded_buffer(base_prv);
564   ENCODER_CHECK_STATUS(coded_buf, ENCODER_ENC_RES_ERR, "dequeue_available_coded_buffer error.");
565
566   /* prepare frame*/
567   ret = base_class->render_frame(base_encoder, display, context,
568                                   buffer_surface, base_prv->frame_count,
569                                   *coded_buf, &is_key);
570   /* prepare failed, push back */
571   if (ENCODER_NO_ERROR != ret) {
572     push_available_coded_buffer(base_prv, coded_buf);
573   }
574   ENCODER_CHECK_STATUS(ENCODER_NO_ERROR == ret, ENCODER_PICTURE_ERR, "base_prepare_encoding failed.");
575
576   /* end picture */
577   //ENCODER_ACQUIRE_DISPLAY_LOCK(display);
578   va_status = vaEndPicture(va_dpy, context_id);
579   ENCODER_RELEASE_DISPLAY_LOCK(display);
580   ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS == va_status, ENCODER_PICTURE_ERR, "vaEndPicture error.");
581
582   /*query surface result*/
583   ret = base_query_encoding_status(base_encoder, display, buffer_surface,
584                                    is_key, video_buffer, coded_buf, coded_pics);
585   if (ENCODER_NO_ERROR != ret) {
586     goto end;
587   }
588
589   base_prv->frame_count++;
590
591   if (base_class->prepare_next_input_buffer) {
592     if (video_buffer) {
593       gst_buffer_unref(GST_BUFFER_CAST(video_buffer));
594     }
595     video_buffer = NULL;
596     buffer_surface = NULL;
597     goto again;
598   }
599
600 end:
601   ENCODER_RELEASE_DISPLAY_LOCK(display);
602   if (ret > ENCODER_NO_ERROR) {
603     ret = ENCODER_NO_ERROR;
604   }
605   if (ret < 0 && base_class->encode_frame_failed) {
606     base_class->encode_frame_failed(base_encoder, video_buffer);
607   }
608   if (video_buffer) {
609     gst_buffer_unref(GST_BUFFER_CAST(video_buffer));
610     video_buffer = NULL;
611   }
612   return ret;
613 }
614
615 static VABufferID *
616 pop_available_coded_buffer(GstVaapiBaseEncoderPrivate *base_prv)
617 {
618   VABufferID *coded_buf = NULL;
619   gboolean ret = TRUE;
620
621   g_mutex_lock(base_prv->code_buffer_lock);
622
623   ENCODER_CHECK_STATUS(base_prv->available_code_buffers, FALSE, "coded buffer not found");
624   while (g_queue_is_empty(base_prv->available_code_buffers)) {
625     g_cond_wait(base_prv->code_buffer_cond, base_prv->code_buffer_lock);
626   }
627   coded_buf = (VABufferID*)g_queue_pop_head (base_prv->available_code_buffers);
628
629 end:
630   g_mutex_unlock(base_prv->code_buffer_lock);
631   VAAPI_UNUSED_ARG(ret);
632   return coded_buf;
633 }
634
635 static gboolean
636 push_available_coded_buffer(GstVaapiBaseEncoderPrivate *base_prv, VABufferID *buf)
637 {
638   g_mutex_lock(base_prv->code_buffer_lock);
639   g_queue_push_head(base_prv->available_code_buffers, buf);
640   g_cond_signal(base_prv->code_buffer_cond);
641   g_mutex_unlock(base_prv->code_buffer_lock);
642   return TRUE;
643 }
644
645 static EncoderStatus
646 base_put_raw_buffer_to_surface(GstVaapiBaseEncoder *base_encoder,
647                                GstVaapiDisplay *display,
648                                GstBuffer *raw_pic,
649                                GstVaapiSurface *surface)
650 {
651   EncoderStatus ret = ENCODER_NO_ERROR;
652   GstVaapiImage *image;
653   GstVaapiImageFormat image_format;
654   guint8 *y_src = NULL, *u_src = NULL, *v_src = NULL;
655   guint8 *y_dst = NULL, *u_dst = NULL, *v_dst = NULL;
656   int y_size = 0, u_size = 0;
657   int row = 0, col = 0;
658   guint32 plane_count = 0;
659   guint32 image_width = 0, image_height = 0;
660   guint32 pitchy = 0, pitchu = 0, pitchv = 0;
661   GstVaapiBaseEncoderPrivate *base_prv = GST_VAAPI_BASE_ENCODER_GET_PRIVATE(base_encoder);
662
663   ENCODER_ASSERT(display);
664   VAAPI_UNUSED_ARG(pitchv);
665   VAAPI_UNUSED_ARG(v_dst);
666   /*map image*/
667   image = gst_vaapi_surface_derive_image(surface);
668   gst_vaapi_image_map(image);
669
670   image_format = gst_vaapi_image_get_format(image);
671   image_width = gst_vaapi_image_get_width(image);
672   image_height = gst_vaapi_image_get_height(image);
673
674   /* copy buffer to surface */
675   ENCODER_ASSERT(GST_BUFFER_SIZE(raw_pic) >= y_size + (y_size>>1));
676
677   y_size = ENCODER_WIDTH(base_encoder) * ENCODER_HEIGHT(base_encoder);
678   u_size = ((ENCODER_WIDTH(base_encoder)+1) >> 1) * ((ENCODER_HEIGHT(base_encoder)+1) >> 1);
679
680   y_src = GST_BUFFER_DATA(raw_pic);
681   u_src = y_src + y_size;
682   v_src = u_src + u_size;
683
684   plane_count = gst_vaapi_image_get_plane_count(image);
685   y_dst = gst_vaapi_image_get_plane(image, 0);
686   u_dst = gst_vaapi_image_get_plane(image, 1);
687   pitchy = gst_vaapi_image_get_pitch(image, 0);
688   pitchu = gst_vaapi_image_get_pitch(image, 1);
689
690   if (plane_count > 2) {
691     v_dst = gst_vaapi_image_get_plane(image, 2);
692     pitchv = gst_vaapi_image_get_pitch(image, 2);
693   }
694
695   /* copy from avcenc.c*/
696   /* Y plane */
697   for (row = 0; row < image_height; row++) {
698       memcpy(y_dst, y_src, image_width);
699       y_dst += pitchy;
700       y_src += ENCODER_WIDTH(base_encoder);
701   }
702
703   if (GST_VAAPI_IMAGE_NV12 == image_format) { /* UV plane */
704     if (GST_VAAPI_IMAGE_I420 == base_prv->format) {
705       for (row = 0; row < image_height / 2; row++) {
706           for (col = 0; col < image_width / 2; col++) {
707               u_dst[col * 2] = u_src[col];
708               u_dst[col * 2 + 1] = v_src[col];
709           }
710
711           u_dst += pitchu;
712           u_src += (ENCODER_WIDTH(base_encoder)>>1);
713           v_src += (ENCODER_WIDTH(base_encoder)>>1);
714       }
715     } else if (GST_VAAPI_IMAGE_NV12 == base_prv->format){
716       for (row = 0; row < image_height / 2; row++) {
717         memcpy(u_dst, u_src, image_width);
718         u_src += ENCODER_WIDTH(base_encoder);
719         u_dst += pitchu;
720       }
721     } else {
722       ENCODER_ASSERT(0);
723     }
724   } else {
725       /* FIXME: fix this later */
726       ENCODER_ASSERT(0);
727   }
728
729   /*unmap image*/
730   g_object_unref(image);
731
732   return ret;
733 }
734
735 static EncoderStatus
736 base_query_encoding_status(GstVaapiBaseEncoder *base_encoder,
737                            GstVaapiDisplay *display,
738                            GstVaapiSurface *buffer_surface,
739                            gboolean is_key,
740                            GstVaapiVideoBuffer *surface_buffer,
741                            VABufferID *coded_buf,
742                            GList **coded_pics)
743 {
744   EncoderStatus ret = ENCODER_NO_ERROR;
745   VAStatus va_status = VA_STATUS_SUCCESS;
746   VASurfaceStatus surface_status = 0;
747   VACodedBufferSegment *buf_list = NULL;
748   GstBuffer* ret_buffer = NULL;
749   gboolean has_coded_data = FALSE;
750   gboolean is_locked = FALSE;
751   GstVaapiBaseEncoderClass   *base_class = GST_VAAPI_BASE_ENCODER_GET_CLASS(base_encoder);
752   GstVaapiBaseEncoderPrivate *base_prv = GST_VAAPI_BASE_ENCODER_GET_PRIVATE(base_encoder);
753
754   ENCODER_ASSERT(display);
755   VASurfaceID surface_id = (VASurfaceID)GST_VAAPI_OBJECT_ID(buffer_surface);
756   VADisplay va_dpy = gst_vaapi_display_get_display(display);
757
758   ENCODER_ASSERT(coded_pics);
759   VAAPI_UNUSED_ARG(has_coded_data);
760
761   /* lock display */
762   ENCODER_ACQUIRE_DISPLAY_LOCK(display);
763
764   va_status = vaSyncSurface(va_dpy, surface_id);
765   ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS ==va_status, ENCODER_QUERY_STATUS_ERR, "vaSyncSurface failed.");
766
767   va_status = vaQuerySurfaceStatus(va_dpy, surface_id, &surface_status);
768   ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS ==va_status, ENCODER_QUERY_STATUS_ERR, "vaQuerySurfaceStatus failed.");
769   if (VASurfaceSkipped&surface_status) {
770     ENCODER_LOG_ERROR("frame skipped, dts:%" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(surface_buffer)));
771   }
772
773   va_status = vaMapBuffer(va_dpy, *coded_buf, (void **)(&buf_list));
774   ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS ==va_status, ENCODER_QUERY_STATUS_ERR, "vaMapBuffer failed.");
775
776   /*unlock display*/
777   ENCODER_RELEASE_DISPLAY_LOCK(display);
778
779   while (buf_list != NULL) {
780       if (base_prv->frame_notify_flag && base_class->notify_frame) {
781         base_class->notify_frame(base_encoder, buf_list->buf, buf_list->size);
782       }
783
784       if (base_class->copy_coded_frame) {
785         ret_buffer = base_class->copy_coded_frame(
786                         base_encoder, buf_list->buf,
787                         buf_list->size, coded_buf);
788       } else {
789         ret_buffer = gst_vaapi_base_encoder_copy_buffer_default(
790                           base_encoder, buf_list->buf,
791                           buf_list->size, coded_buf);
792       }
793       GST_BUFFER_TIMESTAMP(ret_buffer) = GST_BUFFER_TIMESTAMP(surface_buffer);
794       GST_BUFFER_DURATION(ret_buffer) = GST_BUFFER_DURATION(surface_buffer);
795       if (!is_key) {
796         GST_BUFFER_FLAG_SET(ret_buffer, GST_BUFFER_FLAG_DELTA_UNIT);
797       }
798       GST_BUFFER_OFFSET_END(ret_buffer) = GST_BUFFER_OFFSET_END(surface_buffer);
799       *coded_pics = g_list_append(*coded_pics, ret_buffer);
800       buf_list = (VACodedBufferSegment*)buf_list->next;
801       ENCODER_ASSERT(NULL == buf_list);
802       has_coded_data = TRUE;
803       FPS_CALCULATION(vaapiencode);
804   }
805
806 #if SHARE_CODED_BUF
807   if (!has_coded_data)
808 #endif
809   { // if non-related, push back to available_code_buffers
810     ENCODER_ACQUIRE_DISPLAY_LOCK(display);
811     vaUnmapBuffer(va_dpy, *coded_buf);
812     ENCODER_RELEASE_DISPLAY_LOCK(display);
813     push_available_coded_buffer(base_prv, coded_buf);
814   }
815
816   return ENCODER_NO_ERROR;
817
818 end:
819   /*unlock display*/
820   ENCODER_RELEASE_DISPLAY_LOCK(display);
821   return ret;
822 }
823
824 static GstBuffer *
825 gst_vaapi_base_encoder_copy_buffer_default(GstVaapiBaseEncoder *encoder,
826                                         guint8 *frame,
827                                         guint32 frame_size,
828                                         VABufferID *coded_buf)
829 {
830   GstBuffer *ret_buffer = NULL;
831 #if SHARE_CODED_BUF
832   ret_buffer = gst_base_encode_share_buffer_new(encoder, coded_buf);
833   ENCODER_ASSERT(ret_buffer);
834   GST_BUFFER_MALLOCDATA(ret_buffer) = NULL;
835   GST_BUFFER_DATA(ret_buffer) = frame;
836   GST_BUFFER_SIZE(ret_buffer) = frame_size;
837 #else
838   ret_buffer = gst_buffer_new_and_alloc(frame_size);
839   memcpy(GST_BUFFER_DATA(ret_buffer),frame, frame_size);
840 #endif
841   return ret_buffer;
842 }
843
844 EncoderStatus
845 gst_vaapi_base_encoder_flush_default(GstVaapiEncoder* encoder, GstVaapiDisplay *display,
846                        GstVaapiContext *context, GList **coded_pics)
847 {
848   GstVaapiBaseEncoder* base_encoder = GST_VAAPI_BASE_ENCODER(encoder);
849   EncoderStatus ret = ENCODER_NO_ERROR;
850   GstVaapiBaseEncoderPrivate *base_prv = GST_VAAPI_BASE_ENCODER_GET_PRIVATE(base_encoder);
851
852   base_prv->frame_count = 0;
853   base_prv->need_flush = TRUE;
854   /*do we need destroy base_prv->seq_parameter? */
855
856   //end:
857   return ret;
858 }
859
860