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