Tizen 2.0 Release
[framework/multimedia/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 <glib-object.h>
28
29 #include <X11/Xlib.h>
30
31 #include <va/va.h>
32 #include "va/va_x11.h"
33
34 #include "gst/gstclock.h"
35 #include "gst/gstvalue.h"
36
37 #include "gstvaapiobject.h"
38 #include "gstvaapiobject_priv.h"
39 #include "gstvaapicontext.h"
40 #include "gstvaapisurface.h"
41 #include "gstvaapisurfacepool.h"
42 #include "gstvaapivideobuffer.h"
43 #include "gstvaapidisplay_priv.h"
44 #include "gstvaapidebug.h"
45
46 GST_DEBUG_CATEGORY_STATIC (gst_vaapi_base_encoder_debug);
47 #define GST_CAT_DEFAULT gst_vaapi_base_encoder_debug
48
49 #define VA_INVALID_PROFILE 0xffffffff
50 #define DEFAULT_VA_CODEDBUF_NUM  4
51 #define GST_VAAPI_ENCODER_SURFACE_COUNT 3
52
53 #define GST_VAAPI_BASE_ENCODER_LOCK(encoder)              \
54     G_STMT_START {                                        \
55       g_static_rec_mutex_lock(                            \
56         &((GstVaapiBaseEncoder*)(encoder))->priv->mutex); \
57     } G_STMT_END
58
59 #define GST_VAAPI_BASE_ENCODER_UNLOCK(encoder)             \
60     G_STMT_START {                                         \
61       g_static_rec_mutex_unlock(                           \
62         &((GstVaapiBaseEncoder*)(encoder))->priv->mutex);  \
63     } G_STMT_END
64
65 struct _GstVaapiBaseEncoderPrivate {
66   guint32           format;   /*NV12, I420,*/
67   VAProfile         profile;
68   /*total encoded frames*/
69   guint32           frame_count;
70   VABufferID       *coded_bufs;
71   guint32           coded_buf_num;
72   GStaticRecMutex   mutex;
73   GQueue           *idle_buf_queue;
74   GQueue           *busy_buf_queue;
75
76   GstVaapiSurfacePool            *surfaces_pool;
77   GstVaapiBaseEncoderNotifyStatus notify_status;
78   gpointer                        user_data;
79
80   guint             buffer_sharing_flag : 1;
81   guint             buffer_notify_flag : 1;
82   guint             need_flush        : 1;
83 };
84
85 G_DEFINE_TYPE(GstVaapiBaseEncoder, gst_vaapi_base_encoder, GST_TYPE_VAAPI_ENCODER)
86
87 typedef struct _GstVaapiEncoderBufferInfo      GstVaapiEncoderBufferInfo;
88 typedef struct _GstVaapiEncoderBufferInfoClass GstVaapiEncoderBufferInfoClass;
89
90 #define GST_TYPE_VAAPI_ENCODER_BUFFER_INFO  \
91     (gst_vaapi_encoder_buffer_info_get_type())
92
93 #define GST_VAAPI_ENCODER_BUFFER_INFO(obj)                          \
94     (G_TYPE_CHECK_INSTANCE_CAST ((obj),                             \
95                                  GST_TYPE_VAAPI_ENCODER_BUFFER_INFO,\
96                                  GstVaapiEncoderBufferInfo))
97
98 struct _GstVaapiEncoderBufferInfo {
99   GObject              base;
100   GstVaapiBaseEncoder *encoder;
101   VABufferID          *id;
102   GstClockTime         timestamp;
103   GstClockTime         duration;
104
105   void                *data;
106
107   guint32              is_key    : 1;
108   guint32              is_mapped : 1;
109 };
110
111 struct _GstVaapiEncoderBufferInfoClass {
112   GObjectClass   base_class;
113 };
114
115 G_DEFINE_TYPE(
116     GstVaapiEncoderBufferInfo,
117     gst_vaapi_encoder_buffer_info,
118     G_TYPE_OBJECT)
119
120 static gboolean
121 gst_vaapi_encoder_buffer_info_map(
122     GstVaapiEncoderBufferInfo *info,
123     void **buf
124 )
125 {
126   g_return_val_if_fail(info, FALSE);
127   g_return_val_if_fail(info->encoder && info->id && buf, FALSE);
128
129   GstVaapiDisplay *display = ENCODER_DISPLAY(info->encoder);
130   VADisplay va_dpy = ENCODER_VA_DISPLAY(info->encoder);
131   VAStatus va_status = VA_STATUS_SUCCESS;
132
133   if (info->is_mapped)
134     return TRUE;
135
136   GST_VAAPI_DISPLAY_LOCK(display);
137   va_status = vaMapBuffer(va_dpy, *info->id, &info->data);
138   GST_VAAPI_DISPLAY_UNLOCK(display);
139
140   g_return_val_if_fail(va_status == VA_STATUS_SUCCESS, FALSE);
141   info->is_mapped = TRUE;
142   *buf = info->data;
143   return TRUE;
144 }
145
146 static gboolean
147 gst_vaapi_encoder_buffer_info_unmap(
148     GstVaapiEncoderBufferInfo *info
149 )
150 {
151   g_return_val_if_fail(info, FALSE);
152   g_return_val_if_fail(info->encoder && info->id, FALSE);
153
154   GstVaapiDisplay *display = ENCODER_DISPLAY(info->encoder);
155   VADisplay va_dpy = ENCODER_VA_DISPLAY(info->encoder);
156   VAStatus va_status = VA_STATUS_SUCCESS;
157
158   if (!info->is_mapped)
159     return TRUE;
160
161   GST_VAAPI_DISPLAY_LOCK(display);
162   va_status = vaUnmapBuffer(va_dpy, *info->id);
163   GST_VAAPI_DISPLAY_UNLOCK(display);
164   info->data = NULL;
165   info->is_mapped = FALSE;
166
167   g_return_val_if_fail(va_status == VA_STATUS_SUCCESS, FALSE);
168   return TRUE;
169 }
170
171 static GstVaapiEncoderBufferInfo*
172 pop_busy_buffer_info(GstVaapiBaseEncoder *encoder)
173 {
174   GstVaapiBaseEncoderPrivate *priv = encoder->priv;
175   GstVaapiEncoderBufferInfo *info = NULL;
176
177   g_return_val_if_fail(priv->busy_buf_queue, NULL);
178
179   GST_VAAPI_BASE_ENCODER_LOCK(encoder);
180
181   if (g_queue_is_empty(priv->busy_buf_queue))
182     goto end;
183
184   info = (GstVaapiEncoderBufferInfo*)g_queue_pop_head(priv->busy_buf_queue);
185
186 end:
187   GST_VAAPI_BASE_ENCODER_UNLOCK(encoder);
188   return info;
189 }
190
191 static void
192 push_busy_buffer_info(
193     GstVaapiBaseEncoder *encoder,
194     GstVaapiEncoderBufferInfo *info)
195 {
196   GstVaapiBaseEncoderPrivate *priv = encoder->priv;
197
198   GST_VAAPI_BASE_ENCODER_LOCK(encoder);
199   g_queue_push_tail(priv->busy_buf_queue, info);
200   GST_VAAPI_BASE_ENCODER_UNLOCK(encoder);
201 }
202
203 static VABufferID *
204 pop_idle_buffer_id(GstVaapiBaseEncoder *encoder)
205 {
206   GstVaapiBaseEncoderPrivate *priv = encoder->priv;
207   VABufferID *coded_buf = NULL;
208
209   g_return_val_if_fail(priv->idle_buf_queue, NULL);
210
211   GST_VAAPI_BASE_ENCODER_LOCK(encoder);
212
213   if (g_queue_is_empty(priv->idle_buf_queue))
214     goto end;
215
216   coded_buf = (VABufferID*)g_queue_pop_head(priv->idle_buf_queue);
217
218 end:
219   GST_VAAPI_BASE_ENCODER_UNLOCK(encoder);
220   return coded_buf;
221 }
222
223 static void
224 push_idle_buffer_id(
225     GstVaapiBaseEncoder *encoder,
226     VABufferID *buf
227 )
228 {
229   GstVaapiBaseEncoderPrivate *priv = encoder->priv;
230
231   GST_VAAPI_BASE_ENCODER_LOCK(encoder);
232   g_queue_push_tail(priv->idle_buf_queue, buf);
233   GST_VAAPI_BASE_ENCODER_UNLOCK(encoder);
234 }
235
236 static void
237 gst_vaapi_encoder_buffer_info_init(
238     GstVaapiEncoderBufferInfo *info
239 )
240 {
241     info->encoder   = NULL;
242     info->id        = NULL;
243     info->timestamp = 0;
244     info->duration  = 0;
245     info->data      = NULL;
246     info->is_key    = FALSE;
247     info->is_mapped = FALSE;
248 }
249
250 static void
251 gst_vaapi_encoder_buffer_info_finalize(GObject *object)
252 {
253   GstVaapiEncoderBufferInfo *info = GST_VAAPI_ENCODER_BUFFER_INFO(object);
254
255   if (info->id && *info->id != VA_INVALID_ID && info->encoder) {
256     if (info->is_mapped)
257       gst_vaapi_encoder_buffer_info_unmap(info);
258     push_idle_buffer_id(info->encoder, info->id);
259   }
260
261   if (info->encoder) {
262     g_object_unref(info->encoder);
263     info->encoder = NULL;
264   }
265   info->id = NULL;
266 }
267
268 static GstVaapiEncoderBufferInfo*
269 gst_vaapi_encoder_buffer_info_new(
270     GstVaapiBaseEncoder *encoder
271 )
272 {
273     GstVaapiEncoderBufferInfo *ret;
274
275     g_return_val_if_fail(encoder, NULL);
276
277     ret = GST_VAAPI_ENCODER_BUFFER_INFO(
278             g_object_new(GST_TYPE_VAAPI_ENCODER_BUFFER_INFO,
279                          NULL));
280     if (!ret)
281         return NULL;
282     ret->encoder = g_object_ref(encoder);
283     return ret;
284 }
285
286 static void
287 gst_vaapi_encoder_buffer_info_class_init(
288     GstVaapiEncoderBufferInfoClass *klass
289 )
290 {
291   GObjectClass * const obj_class = G_OBJECT_CLASS(klass);
292
293   obj_class->finalize = gst_vaapi_encoder_buffer_info_finalize;
294 }
295
296 void
297 gst_vaapi_base_encoder_set_frame_notify(
298     GstVaapiBaseEncoder *encoder,
299     gboolean flag
300 )
301 {
302   GstVaapiBaseEncoderPrivate *priv = encoder->priv;
303   priv->buffer_notify_flag = flag;
304 }
305
306 gboolean
307 gst_vaapi_base_encoder_set_va_profile(
308     GstVaapiBaseEncoder *encoder,
309     guint profile
310 )
311 {
312   GstVaapiBaseEncoderPrivate *priv = encoder->priv;
313   priv->profile = profile;
314   return TRUE;
315 }
316
317 void
318 gst_vaapi_base_encoder_set_input_format(
319     GstVaapiBaseEncoder* encoder,
320     guint32 format
321 )
322 {
323   GstVaapiBaseEncoderPrivate *priv = encoder->priv;
324   priv->format = format;
325 }
326
327 gboolean
328 gst_vaapi_base_encoder_set_notify_status(
329     GstVaapiBaseEncoder *encoder,
330     GstVaapiBaseEncoderNotifyStatus func,
331     gpointer             user_data
332 )
333 {
334   GstVaapiBaseEncoderPrivate *priv = encoder->priv;
335
336   priv->notify_status = func;
337   priv->user_data = user_data;
338   return TRUE;
339 }
340
341 void
342 gst_vaapi_base_encoder_set_buffer_sharing(
343     GstVaapiBaseEncoder *encoder,
344     gboolean is_buffer_sharing
345 )
346 {
347   GstVaapiBaseEncoderPrivate *priv = encoder->priv;
348
349   priv->buffer_sharing_flag = is_buffer_sharing;
350 }
351
352 static gboolean
353 default_validate_encoder_parameters(
354     GstVaapiBaseEncoder *encoder
355 )
356 {
357   if (!ENCODER_WIDTH(encoder) ||
358       !ENCODER_HEIGHT(encoder) ||
359       !ENCODER_FPS(encoder)) {
360     return FALSE;
361   }
362   return TRUE;
363 }
364
365 static gboolean
366 base_encoder_alloc_coded_buffers(
367     GstVaapiBaseEncoder *base_encoder,
368     GstVaapiContext *context
369 )
370 {
371   GstVaapiBaseEncoderPrivate *priv = base_encoder->priv;
372   VADisplay va_dpy;
373   VAContextID context_id;
374   VAStatus va_status = VA_STATUS_SUCCESS;
375   guint i = 0;
376   gboolean ret = TRUE;
377   guint32 buffer_size =
378       (ENCODER_WIDTH(base_encoder) * ENCODER_HEIGHT(base_encoder) * 400) /
379       (16*16);
380
381   ENCODER_ASSERT(context);
382   ENCODER_ASSERT(priv->idle_buf_queue);
383   ENCODER_ASSERT(!priv->coded_bufs);
384
385   va_dpy = ENCODER_VA_DISPLAY(base_encoder);
386   context_id = gst_vaapi_context_get_id(context);
387
388   priv->coded_bufs = (VABufferID*)
389       g_malloc0(priv->coded_buf_num * sizeof(priv->coded_bufs[0]));
390
391   for (i = 0; i < priv->coded_buf_num; i++) {
392     va_status = vaCreateBuffer(va_dpy,
393                                context_id,
394                                VAEncCodedBufferType,
395                                buffer_size, 1,
396                                NULL,
397                                &priv->coded_bufs[i]);
398     if (VA_STATUS_SUCCESS != va_status)
399       break;
400   }
401   ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS == va_status,
402                        FALSE,
403                        "create coded buffer failed.");
404
405   /* init queue idle_buf_queue */
406   GST_VAAPI_BASE_ENCODER_LOCK(base_encoder);
407   for (i = 0; i < priv->coded_buf_num; i++) {
408     g_queue_push_head(priv->idle_buf_queue, &priv->coded_bufs[i]);
409   }
410   GST_VAAPI_BASE_ENCODER_UNLOCK(base_encoder);
411
412 end:
413   return ret;
414
415 }
416
417 static EncoderStatus
418 release_coded_buffers(GstVaapiBaseEncoder *base_encoder)
419 {
420   VAStatus va_status = VA_STATUS_SUCCESS;
421   GstVaapiBaseEncoderPrivate *priv = base_encoder->priv;
422   GstVaapiDisplay *display = ENCODER_DISPLAY(base_encoder);
423   guint32 available_buf_count = priv->coded_buf_num;
424   GstVaapiEncoderBufferInfo *info;
425   guint32 i;
426
427   ENCODER_ASSERT(display);
428   VAAPI_UNUSED_ARG(va_status);
429   VADisplay va_dpy = gst_vaapi_display_get_display(display);
430
431   /* wait clear all available coded buffers */
432   GST_VAAPI_BASE_ENCODER_LOCK(base_encoder);
433   if (available_buf_count) {
434     while (!g_queue_is_empty(priv->busy_buf_queue)) {
435       info = (GstVaapiEncoderBufferInfo*)g_queue_pop_head(priv->busy_buf_queue);
436       g_object_unref(info);
437     }
438     while(!g_queue_is_empty(priv->idle_buf_queue)) {
439       g_queue_pop_head(priv->idle_buf_queue);
440       available_buf_count--;
441     }
442   }
443   GST_VAAPI_BASE_ENCODER_UNLOCK(base_encoder);
444   ENCODER_ASSERT(available_buf_count == 0);
445
446   for (i = 0; i < priv->coded_buf_num; i++) {
447     va_status = vaDestroyBuffer(va_dpy, priv->coded_bufs[i]);
448   }
449
450   return ENCODER_NO_ERROR;
451 }
452
453 static EncoderStatus
454 gst_vaapi_base_encoder_close_default(GstVaapiEncoder* encoder)
455 {
456   GstVaapiBaseEncoder* base_encoder = GST_VAAPI_BASE_ENCODER(encoder);
457   GstVaapiBaseEncoderClass *base_class =
458       GST_VAAPI_BASE_ENCODER_GET_CLASS(encoder);
459   GstVaapiBaseEncoderPrivate *priv = base_encoder->priv;
460   EncoderStatus ret = ENCODER_NO_ERROR;
461
462   /* release buffers first */
463   priv->need_flush = FALSE;
464
465   if (base_class->release_resource) {
466     base_class->release_resource(base_encoder);
467   }
468   release_coded_buffers(base_encoder);
469   priv->frame_count = 0;
470
471   return ret;
472 }
473
474 static EncoderStatus
475 gst_vaapi_base_encoder_open_default(
476     GstVaapiEncoder* encoder,
477     GstVaapiContext **context
478 )
479 {
480   GstVaapiBaseEncoder* base_encoder = GST_VAAPI_BASE_ENCODER(encoder);
481   GstVaapiBaseEncoderClass *base_class =
482       GST_VAAPI_BASE_ENCODER_GET_CLASS(encoder);
483   GstVaapiBaseEncoderPrivate *priv = base_encoder->priv;
484   GstVaapiDisplay *display = ENCODER_DISPLAY(encoder);
485
486   GstVaapiContext *out_context = NULL;
487
488   EncoderStatus ret = ENCODER_NO_ERROR;
489   gboolean check_attri_ret = TRUE;
490   /*check and set default values*/
491   if (base_class->validate_attributes) {
492     check_attri_ret = base_class->validate_attributes(base_encoder);
493   } else {
494     check_attri_ret = default_validate_encoder_parameters(base_encoder);
495   }
496   ENCODER_CHECK_STATUS(check_attri_ret,
497                        ENCODER_PARAMETER_ERR,
498                        "vaapi encoder paramerter error.");
499   ENCODER_CHECK_STATUS(VA_INVALID_PROFILE != priv->profile,
500                        ENCODER_PROFILE_ERR,
501                        "vaapi encoder profile not set.");
502
503   ENCODER_ASSERT(ENCODER_DISPLAY(encoder));
504
505   out_context = gst_vaapi_context_new(display,
506                         gst_vaapi_profile(priv->profile),
507                         gst_vaapi_entrypoint(VAEntrypointEncSlice),
508                         ENCODER_RATE_CONTROL(encoder),
509                         ENCODER_WIDTH(encoder),
510                         ENCODER_HEIGHT(encoder),
511                         GST_VAAPI_ENCODER_SURFACE_COUNT);
512   ENCODER_CHECK_STATUS(out_context,
513                        ENCODER_CONTEXT_ERR,
514                        "gst_vaapi_context_new failed.");
515   ENCODER_CHECK_STATUS(VA_INVALID_ID != GST_VAAPI_OBJECT_ID(out_context),
516                        ENCODER_CONTEXT_ERR,
517                        "gst_vaapi_context_new failed.");
518
519   if (base_class->pre_alloc_resource) {
520     ENCODER_CHECK_STATUS(
521         base_class->pre_alloc_resource(base_encoder, out_context),
522         ENCODER_MEM_ERR,
523         "encoder <pre_alloc_resource> failed."
524     );
525   }
526   ENCODER_CHECK_STATUS(
527     base_encoder_alloc_coded_buffers(base_encoder, out_context),
528     ENCODER_MEM_ERR,
529     "encoder <base_encoder_alloc_coded_buffers> failed."
530   );
531   *context = out_context;
532
533   return ENCODER_NO_ERROR;
534
535 end:
536   // clear resources
537   if (ENCODER_NO_ERROR != ret) {
538     gst_vaapi_base_encoder_close_default(encoder);
539     if (out_context) {
540       g_object_unref(out_context);
541     }
542   }
543   return ret;
544 }
545
546 static EncoderStatus
547 query_encoding_status(
548     GstVaapiBaseEncoder *base_encoder,
549     GstVaapiSurface *buffer_surface
550 )
551 {
552   EncoderStatus ret = ENCODER_NO_ERROR;
553   GstVaapiSurfaceStatus surface_status;
554
555   ENCODER_CHECK_STATUS(gst_vaapi_surface_sync(buffer_surface),
556                        ENCODER_SURFACE_ERR,
557                        "gst_vaapi_surface_sync failed.");
558
559   ENCODER_CHECK_STATUS(
560       gst_vaapi_surface_query_status(buffer_surface, &surface_status),
561       ENCODER_SURFACE_ERR,
562       "gst_vaapi_surface_query_status failed."
563       );
564   if (GST_VAAPI_SURFACE_STATUS_SKIPPED & surface_status) {
565     ENCODER_LOG_ERROR("frame skipped"); /* not sure continue or not */
566   }
567
568   return ENCODER_NO_ERROR;
569
570 end:
571   return ret;
572 }
573
574 static inline guint
575 get_buf_list_size(VACodedBufferSegment *buf_list)
576 {
577   guint size = 0;
578   while(buf_list) {
579     size += buf_list->size;
580     buf_list = (VACodedBufferSegment*)buf_list->next;
581   }
582   return size;
583 }
584
585 static inline guint
586 move_buf_list_to_buf(
587     VACodedBufferSegment *buf_list,
588     guint8 *data,
589     guint max_len
590 )
591 {
592     guint left_size = max_len;
593     guint cur_size;
594     while (buf_list && left_size) {
595       if (buf_list->size <= left_size)
596         cur_size = buf_list->size;
597       else
598         cur_size = left_size;
599       memcpy(data, buf_list->buf, cur_size);
600       data += cur_size;
601       buf_list = (VACodedBufferSegment*)buf_list->next;
602       left_size -= cur_size;
603     }
604     return max_len - left_size;
605 }
606
607 static EncoderStatus
608 gst_vaapi_base_encoder_get_coded_buffer(
609     GstVaapiEncoder* base,
610     GstBuffer **out_buf
611 )
612 {
613   GstVaapiBaseEncoder *encoder = GST_VAAPI_BASE_ENCODER(base);
614   GstVaapiBaseEncoderPrivate *priv = encoder->priv;
615   GstVaapiBaseEncoderClass   *klass =
616       GST_VAAPI_BASE_ENCODER_GET_CLASS(encoder);
617   GstVaapiEncoderBufferInfo* info;
618   EncoderStatus ret;
619   VACodedBufferSegment *buf_list = NULL;
620   GstBuffer* buffer = NULL;
621   guint buf_size;
622
623   while((info = pop_busy_buffer_info(encoder)) == NULL){
624     ret = ENCODER_NO_BUSY_BUF;
625     if (!priv->notify_status ||
626         !priv->notify_status(encoder, ret, priv->user_data))
627       goto end;
628   }
629   ret = ENCODER_NO_ERROR;
630
631   ENCODER_CHECK_STATUS(
632       info->id && *info->id != VA_INVALID_ID,
633       ENCODER_DATA_ERR,
634       "get invalid buffer info"
635       );
636
637   ENCODER_CHECK_STATUS(
638       gst_vaapi_encoder_buffer_info_map(info, (void**)&buf_list),
639       ENCODER_DATA_ERR,
640       "vaMapBuffer failed");
641
642   buf_size = get_buf_list_size(buf_list);
643   ENCODER_CHECK_STATUS(
644       buf_size,
645       ENCODER_DATA_ERR,
646       "encoded size:0");
647   buffer = gst_buffer_new_and_alloc(buf_size);
648   GST_BUFFER_SIZE(buffer) = move_buf_list_to_buf(
649                                 buf_list,
650                                 GST_BUFFER_DATA(buffer),
651                                 buf_size);
652
653   if (priv->buffer_notify_flag && klass->notify_buffer) {
654     klass->notify_buffer(
655         encoder,
656         GST_BUFFER_DATA(buffer),
657         GST_BUFFER_SIZE(buffer));
658   }
659
660   if (klass->wrap_buffer) {
661     GstBuffer *new_buf = klass->wrap_buffer(encoder, buffer);
662     gst_buffer_unref(buffer);
663     buffer = new_buf;
664   }
665
666   if (buffer) {
667     GST_BUFFER_TIMESTAMP(buffer) = info->timestamp;
668     GST_BUFFER_DURATION(buffer) = info->duration;
669     if (!info->is_key)
670       GST_BUFFER_FLAG_SET(buffer, GST_BUFFER_FLAG_DELTA_UNIT);
671   }
672   FPS_CALCULATION(vaapiencode);
673
674   *out_buf = buffer;
675
676 end:
677   if (info) {
678     gst_vaapi_encoder_buffer_info_unmap(info);
679     g_object_unref(info);
680   }
681   return ret;
682 }
683
684 static GstVaapiVideoBuffer *
685 _get_video_buffer(
686     GstVaapiBaseEncoder* encoder,
687     GstBuffer *buf
688 )
689 {
690   GstVaapiBaseEncoderPrivate *priv = encoder->priv;
691   GstBuffer *video_buffer;
692
693   if (priv->buffer_sharing_flag)
694     video_buffer = (GstBuffer *)buf->data;
695   else
696     video_buffer = buf;
697
698   if (GST_VAAPI_IS_VIDEO_BUFFER(video_buffer))
699     return GST_VAAPI_VIDEO_BUFFER(video_buffer);
700   return NULL;
701 }
702
703 static EncoderStatus
704 gst_vaapi_base_encoder_encode_default(
705     GstVaapiEncoder* base,
706     GstBuffer *pic
707 )
708 {
709   GstVaapiBaseEncoder* encoder = GST_VAAPI_BASE_ENCODER(base);
710   GstVaapiBaseEncoderClass *base_class =
711       GST_VAAPI_BASE_ENCODER_GET_CLASS(encoder);
712   GstVaapiBaseEncoderPrivate *priv = encoder->priv;
713   GstVaapiDisplay *display = ENCODER_DISPLAY(encoder);
714   GstVaapiContext *context = ENCODER_CONTEXT(encoder);
715   EncoderStatus ret = ENCODER_NO_ERROR;
716   gboolean is_key = FALSE;
717   VABufferID* coded_buf = NULL;
718   GstVaapiSurface *buffer_surface = NULL;
719   gboolean is_prepared_buffer = FALSE;
720
721   ENCODER_ASSERT(display && context);
722
723   /* Video Buffer */
724   GstVaapiVideoBuffer *video_buffer = NULL;
725
726   ENCODER_CHECK_STATUS(pic || base_class->prepare_next_input_buffer,
727                        ENCODER_DATA_ERR,
728                        "Need a picture to encode");
729   if (!pic)
730     priv->need_flush = TRUE;
731
732 again:
733   if (base_class->prepare_next_input_buffer) {
734     GstBuffer* tmp_buf = NULL;
735     ret = base_class->prepare_next_input_buffer(encoder,
736                                                 pic,
737                                                 priv->need_flush,
738                                                 &tmp_buf);
739     priv->need_flush = FALSE;
740     if (ret != ENCODER_NO_ERROR || !tmp_buf)
741       goto end;
742
743     is_prepared_buffer = TRUE;
744     pic = tmp_buf;
745   }
746
747   video_buffer = _get_video_buffer(encoder, pic);
748   ENCODER_CHECK_STATUS(
749       video_buffer,
750       ENCODER_SURFACE_ERR,
751       "vaapi encoder doesn't has video buffer");
752
753   buffer_surface = gst_vaapi_video_buffer_get_surface(video_buffer);
754
755   while ((coded_buf = pop_idle_buffer_id(encoder)) == NULL) {
756     ret = ENCODER_NO_IDLE_BUF;
757     if (!priv->notify_status ||
758         !priv->notify_status(encoder, ret, priv->user_data))
759       goto end;
760   }
761   ret = ENCODER_NO_ERROR;
762
763   /* prepare frame*/
764   ret = base_class->render_frame(encoder,
765                                  buffer_surface,
766                                  priv->frame_count,
767                                  *coded_buf,
768                                  &is_key);
769   /* prepare failed, push back */
770   if (ENCODER_NO_ERROR != ret) {
771     push_idle_buffer_id(encoder, coded_buf);
772   }
773   ENCODER_CHECK_STATUS(ENCODER_NO_ERROR == ret,
774                        ENCODER_PICTURE_ERR,
775                        "base_prepare_encoding failed");
776
777   /*query surface result*/
778   ret = query_encoding_status(encoder, buffer_surface);
779   if (ENCODER_NO_ERROR != ret) {
780     goto end;
781   }
782
783   /* Push coded buffer to another task */
784   GstVaapiEncoderBufferInfo* info = gst_vaapi_encoder_buffer_info_new(encoder);
785   info->id = coded_buf;
786   info->timestamp = GST_BUFFER_TIMESTAMP(pic);
787   info->duration = GST_BUFFER_DURATION(pic);
788   info->is_key = is_key;
789   push_busy_buffer_info(encoder, info);
790
791   priv->frame_count++;
792
793   if (is_prepared_buffer) {
794     if (pic)
795       gst_buffer_unref(pic);
796     pic = NULL;
797     buffer_surface = NULL;
798     coded_buf = NULL;
799     goto again;
800   }
801
802 end:
803   if (ret < ENCODER_NO_ERROR && base_class->encode_frame_failed) {
804     base_class->encode_frame_failed(encoder, video_buffer);
805   }
806   if (pic && is_prepared_buffer)
807     gst_buffer_unref(pic);
808
809   return ret;
810 }
811
812 #if 0
813 static EncoderStatus
814 base_put_raw_buffer_to_surface(GstVaapiBaseEncoder *base_encoder,
815                                GstVaapiDisplay *display,
816                                GstBuffer *raw_pic,
817                                GstVaapiSurface *surface)
818 {
819   EncoderStatus ret = ENCODER_NO_ERROR;
820   GstVaapiImage *image;
821   GstVaapiImageFormat image_format;
822   guint8 *y_src = NULL, *u_src = NULL, *v_src = NULL;
823   guint8 *y_dst = NULL, *u_dst = NULL, *v_dst = NULL;
824   int y_size = 0, u_size = 0;
825   int row = 0, col = 0;
826   guint32 plane_count = 0;
827   guint32 image_width = 0, image_height = 0;
828   guint32 pitchy = 0, pitchu = 0, pitchv = 0;
829   GstVaapiBaseEncoderPrivate *priv = base_encoder->priv;
830
831   ENCODER_ASSERT(display);
832   VAAPI_UNUSED_ARG(pitchv);
833   VAAPI_UNUSED_ARG(v_dst);
834   /*map image*/
835   image = gst_vaapi_surface_derive_image(surface);
836   gst_vaapi_image_map(image);
837
838   image_format = gst_vaapi_image_get_format(image);
839   image_width = gst_vaapi_image_get_width(image);
840   image_height = gst_vaapi_image_get_height(image);
841
842   /* copy buffer to surface */
843   ENCODER_ASSERT(GST_BUFFER_SIZE(raw_pic) >= y_size + (y_size>>1));
844
845   y_size = ENCODER_WIDTH(base_encoder) * ENCODER_HEIGHT(base_encoder);
846   u_size = ((ENCODER_WIDTH(base_encoder)+1) >> 1) * ((ENCODER_HEIGHT(base_encoder)+1) >> 1);
847
848   y_src = GST_BUFFER_DATA(raw_pic);
849   u_src = y_src + y_size;
850   v_src = u_src + u_size;
851
852   plane_count = gst_vaapi_image_get_plane_count(image);
853   y_dst = gst_vaapi_image_get_plane(image, 0);
854   u_dst = gst_vaapi_image_get_plane(image, 1);
855   pitchy = gst_vaapi_image_get_pitch(image, 0);
856   pitchu = gst_vaapi_image_get_pitch(image, 1);
857
858   if (plane_count > 2) {
859     v_dst = gst_vaapi_image_get_plane(image, 2);
860     pitchv = gst_vaapi_image_get_pitch(image, 2);
861   }
862
863   /* copy from avcenc.c*/
864   /* Y plane */
865   for (row = 0; row < image_height; row++) {
866       memcpy(y_dst, y_src, image_width);
867       y_dst += pitchy;
868       y_src += ENCODER_WIDTH(base_encoder);
869   }
870
871   if (GST_VAAPI_IMAGE_NV12 == image_format) { /* UV plane */
872     if (GST_VAAPI_IMAGE_I420 == priv->format) {
873       for (row = 0; row < image_height / 2; row++) {
874           for (col = 0; col < image_width / 2; col++) {
875               u_dst[col * 2] = u_src[col];
876               u_dst[col * 2 + 1] = v_src[col];
877           }
878
879           u_dst += pitchu;
880           u_src += (ENCODER_WIDTH(base_encoder)>>1);
881           v_src += (ENCODER_WIDTH(base_encoder)>>1);
882       }
883     } else if (GST_VAAPI_IMAGE_NV12 == priv->format){
884       for (row = 0; row < image_height / 2; row++) {
885         memcpy(u_dst, u_src, image_width);
886         u_src += ENCODER_WIDTH(base_encoder);
887         u_dst += pitchu;
888       }
889     } else {
890       ENCODER_ASSERT(0);
891     }
892   } else {
893       /* FIXME: fix this later */
894       ENCODER_ASSERT(0);
895   }
896
897   /*unmap image*/
898   g_object_unref(image);
899
900   return ret;
901 }
902 #endif
903
904 static EncoderStatus
905 gst_vaapi_base_encoder_flush_default(
906     GstVaapiEncoder* encoder
907 )
908 {
909   GstVaapiBaseEncoder* base_encoder = GST_VAAPI_BASE_ENCODER(encoder);
910   EncoderStatus ret = ENCODER_NO_ERROR;
911   GstVaapiBaseEncoderPrivate *priv = base_encoder->priv;
912
913   priv->frame_count = 0;
914   priv->need_flush = TRUE;
915   /*do we need destroy priv->seq_parameter? */
916
917   //end:
918   return ret;
919 }
920
921
922 static void
923 gst_vaapi_base_encoder_finalize(GObject *object)
924 {
925   /*free private buffers*/
926   GstVaapiEncoder *encoder = GST_VAAPI_ENCODER(object);
927   GstVaapiBaseEncoderPrivate *priv =
928       GST_VAAPI_BASE_ENCODER_GET_PRIVATE(object);
929
930   if (gst_vaapi_encoder_get_state(encoder) != VAAPI_ENC_NULL) {
931     gst_vaapi_encoder_uninitialize(encoder);
932   }
933
934   g_static_rec_mutex_free(&priv->mutex);
935   if (priv->idle_buf_queue)
936     g_queue_free(priv->idle_buf_queue);
937
938   if (priv->busy_buf_queue)
939     g_queue_free(priv->busy_buf_queue);
940
941   G_OBJECT_CLASS(gst_vaapi_base_encoder_parent_class)->finalize(object);
942 }
943
944 static void
945 gst_vaapi_base_encoder_init(GstVaapiBaseEncoder *encoder)
946 {
947   GstVaapiBaseEncoderPrivate *priv =
948       GST_VAAPI_BASE_ENCODER_GET_PRIVATE(encoder);
949   ENCODER_ASSERT(priv);
950   encoder->priv = priv;
951
952   /* init private values*/
953   priv->format = 0;
954   priv->profile= VA_INVALID_PROFILE;
955   priv->frame_count = 0;
956   priv->buffer_sharing_flag = FALSE;
957   priv->buffer_notify_flag = FALSE;
958
959   priv->coded_bufs = NULL;
960   priv->coded_buf_num = DEFAULT_VA_CODEDBUF_NUM;
961   priv->idle_buf_queue = g_queue_new();
962   priv->busy_buf_queue = g_queue_new();
963   g_static_rec_mutex_init(&priv->mutex);
964
965   priv->notify_status = NULL;
966   priv->user_data = NULL;
967
968   priv->need_flush = FALSE;
969 }
970
971 static void
972 gst_vaapi_base_encoder_class_init(GstVaapiBaseEncoderClass *klass)
973 {
974   GObjectClass * const object_class = G_OBJECT_CLASS(klass);
975   GstVaapiEncoderClass * const encoder_class = GST_VAAPI_ENCODER_CLASS(klass);
976   g_type_class_add_private(klass, sizeof(GstVaapiBaseEncoderPrivate));
977
978   GST_DEBUG_CATEGORY_INIT (gst_vaapi_base_encoder_debug,
979                            "gst_vaapi_base_encoder",
980                            0,
981                            "gst_vaapi_base_encoder element");
982
983   object_class->finalize = gst_vaapi_base_encoder_finalize;
984
985   encoder_class->open = gst_vaapi_base_encoder_open_default;
986   encoder_class->close = gst_vaapi_base_encoder_close_default;
987   encoder_class->encode = gst_vaapi_base_encoder_encode_default;
988   encoder_class->flush = gst_vaapi_base_encoder_flush_default;
989   encoder_class->get_buf = gst_vaapi_base_encoder_get_coded_buffer;
990   encoder_class->get_codec_data = NULL;
991
992   /* user defined functions*/
993   klass->validate_attributes = NULL;
994   klass->pre_alloc_resource = NULL;
995   klass->release_resource = NULL;
996   klass->prepare_next_input_buffer = NULL;
997   klass->render_frame = NULL;
998   klass->notify_buffer = NULL;
999   klass->wrap_buffer = NULL;
1000   klass->encode_frame_failed = NULL;
1001
1002   /*
1003   object_class->set_property = gst_vaapi_base_encoder_set_property;
1004   object_class->get_property = gst_vaapi_base_encoder_get_property;
1005   */
1006 }