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