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