va: Keep include's code style
[platform/upstream/gstreamer.git] / subprojects / gst-plugins-bad / sys / va / gstvaencoder.c
1 /* GStreamer
2  *  Copyright (C) 2021 Intel Corporation
3  *     Author: He Junyan <junyan.he@intel.com>
4  *     Author: Víctor Jáquez <vjaquez@igalia.com>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 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  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include "gstvaencoder.h"
27
28 #include "gstvacaps.h"
29 #include "gstvadisplay_priv.h"
30 #include "vacompat.h"
31
32 #define VA_ENTRYPOINT_FLAG(entry) (1U << G_PASTE(VAEntrypoint, entry))
33
34 typedef struct _GstVaProfileConfig GstVaProfileConfig;
35
36 struct _GstVaProfileConfig
37 {
38   VAProfile profile;
39   guint32 entrypoints;          /* bits map of GstVaapiEntrypoint */
40 };
41
42 struct _GstVaEncoder
43 {
44   GstObject parent;
45
46   GArray *available_profiles;
47   GstCaps *srcpad_caps;
48   GstCaps *sinkpad_caps;
49   GstVaDisplay *display;
50   VAConfigID config;
51   VAContextID context;
52   VAProfile profile;
53   VAEntrypoint entrypoint;
54   guint rt_format;
55   gint coded_width;
56   gint coded_height;
57   gint codedbuf_size;
58
59   GstBufferPool *recon_pool;
60 };
61
62 GST_DEBUG_CATEGORY_STATIC (gst_va_encoder_debug);
63 #define GST_CAT_DEFAULT gst_va_encoder_debug
64
65 #define gst_va_encoder_parent_class parent_class
66 G_DEFINE_TYPE_WITH_CODE (GstVaEncoder, gst_va_encoder, GST_TYPE_OBJECT,
67     GST_DEBUG_CATEGORY_INIT (gst_va_encoder_debug, "vaencoder", 0,
68         "VA Encoder"));
69
70 enum
71 {
72   PROP_DISPLAY = 1,
73   PROP_PROFILE,
74   PROP_ENTRYPOINT,
75   PROP_WIDTH,
76   PROP_HEIGHT,
77   PROP_CHROMA,
78   PROP_CODED_BUF_SIZE,
79   N_PROPERTIES
80 };
81
82 static GParamSpec *g_properties[N_PROPERTIES];
83
84 static gboolean
85 _destroy_buffer (GstVaDisplay * display, VABufferID buffer)
86 {
87   VAStatus status;
88   gboolean ret = TRUE;
89   VADisplay dpy = gst_va_display_get_va_dpy (display);
90
91   status = vaDestroyBuffer (dpy, buffer);
92   if (status != VA_STATUS_SUCCESS) {
93     ret = FALSE;
94     GST_WARNING ("Failed to destroy the buffer: %s", vaErrorStr (status));
95   }
96
97   return ret;
98 }
99
100 static VABufferID
101 _create_buffer (GstVaEncoder * self, gint type, gpointer data, gsize size)
102 {
103   VAStatus status;
104   VADisplay dpy = gst_va_display_get_va_dpy (self->display);
105   VABufferID buffer;
106   VAContextID context;
107
108   GST_OBJECT_LOCK (self);
109   context = self->context;
110   GST_OBJECT_UNLOCK (self);
111
112   dpy = gst_va_display_get_va_dpy (self->display);
113   status = vaCreateBuffer (dpy, context, type, size, 1, data, &buffer);
114   if (status != VA_STATUS_SUCCESS) {
115     GST_ERROR_OBJECT (self, "vaCreateBuffer: %s", vaErrorStr (status));
116     return VA_INVALID_ID;
117   }
118
119   return buffer;
120 }
121
122 static void
123 gst_va_encoder_set_property (GObject * object, guint prop_id,
124     const GValue * value, GParamSpec * pspec)
125 {
126   GstVaEncoder *self = GST_VA_ENCODER (object);
127
128   GST_OBJECT_LOCK (self);
129
130   switch (prop_id) {
131     case PROP_DISPLAY:{
132       g_assert (!self->display);
133       self->display = g_value_dup_object (value);
134       break;
135     }
136     default:
137       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
138       break;
139   }
140
141   GST_OBJECT_UNLOCK (self);
142 }
143
144 static void
145 gst_va_encoder_get_property (GObject * object, guint prop_id, GValue * value,
146     GParamSpec * pspec)
147 {
148   GstVaEncoder *self = GST_VA_ENCODER (object);
149
150   GST_OBJECT_LOCK (self);
151
152   switch (prop_id) {
153     case PROP_DISPLAY:
154       g_value_set_object (value, self->display);
155       break;
156     case PROP_PROFILE:
157       g_value_set_int (value, self->profile);
158       break;
159     case PROP_ENTRYPOINT:
160       g_value_set_int (value, self->entrypoint);
161       break;
162     case PROP_CHROMA:
163       g_value_set_uint (value, self->rt_format);
164       break;
165     case PROP_WIDTH:
166       g_value_set_int (value, self->coded_width);
167       break;
168     case PROP_HEIGHT:
169       g_value_set_int (value, self->coded_height);
170       break;
171     case PROP_CODED_BUF_SIZE:
172       g_value_set_int (value, self->codedbuf_size);
173       break;
174     default:
175       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
176       break;
177   }
178
179   GST_OBJECT_UNLOCK (self);
180 }
181
182 static void
183 gst_va_encoder_init (GstVaEncoder * self)
184 {
185   self->profile = VAProfileNone;
186   self->entrypoint = 0;
187   self->config = VA_INVALID_ID;
188   self->context = VA_INVALID_ID;
189   self->rt_format = 0;
190   self->coded_width = 0;
191   self->coded_height = 0;
192   self->codedbuf_size = 0;
193   g_clear_pointer (&self->recon_pool, gst_object_unref);
194 }
195
196 static inline gboolean
197 _is_open_unlocked (GstVaEncoder * self)
198 {
199   return (self->config != VA_INVALID_ID && self->profile != VAProfileNone);
200 }
201
202 gboolean
203 gst_va_encoder_is_open (GstVaEncoder * self)
204 {
205   gboolean ret;
206
207   g_return_val_if_fail (GST_IS_VA_ENCODER (self), FALSE);
208
209   GST_OBJECT_LOCK (self);
210   ret = _is_open_unlocked (self);
211   GST_OBJECT_UNLOCK (self);
212   return ret;
213 }
214
215 gboolean
216 gst_va_encoder_close (GstVaEncoder * self)
217 {
218   VADisplay dpy;
219   VAStatus status;
220   VAConfigID config = VA_INVALID_ID;
221   VAContextID context = VA_INVALID_ID;
222   GstBufferPool *recon_pool = NULL;
223
224   g_return_val_if_fail (GST_IS_VA_ENCODER (self), FALSE);
225
226   GST_OBJECT_LOCK (self);
227   if (!_is_open_unlocked (self)) {
228     GST_OBJECT_UNLOCK (self);
229     return TRUE;
230   }
231
232   config = self->config;
233   context = self->context;
234
235   recon_pool = self->recon_pool;
236   self->recon_pool = NULL;
237
238   gst_va_encoder_init (self);
239   GST_OBJECT_UNLOCK (self);
240
241   gst_buffer_pool_set_active (recon_pool, FALSE);
242   g_clear_pointer (&recon_pool, gst_object_unref);
243
244   dpy = gst_va_display_get_va_dpy (self->display);
245
246   if (context != VA_INVALID_ID) {
247     status = vaDestroyContext (dpy, context);
248     if (status != VA_STATUS_SUCCESS)
249       GST_ERROR_OBJECT (self, "vaDestroyContext: %s", vaErrorStr (status));
250   }
251
252   status = vaDestroyConfig (dpy, config);
253   if (status != VA_STATUS_SUCCESS)
254     GST_ERROR_OBJECT (self, "vaDestroyConfig: %s", vaErrorStr (status));
255
256   gst_caps_replace (&self->srcpad_caps, NULL);
257   gst_caps_replace (&self->sinkpad_caps, NULL);
258
259   return TRUE;
260 }
261
262 static GArray *
263 _get_surface_formats (GstVaDisplay * display, VAConfigID config)
264 {
265   GArray *formats;
266   GstVideoFormat format;
267   VASurfaceAttrib *attribs;
268   guint i, attrib_count;
269
270   attribs = gst_va_get_surface_attribs (display, config, &attrib_count);
271   if (!attribs)
272     return NULL;
273
274   formats = g_array_new (FALSE, FALSE, sizeof (GstVideoFormat));
275
276   for (i = 0; i < attrib_count; i++) {
277     if (attribs[i].value.type != VAGenericValueTypeInteger)
278       continue;
279     switch (attribs[i].type) {
280       case VASurfaceAttribPixelFormat:
281         format = gst_va_video_format_from_va_fourcc (attribs[i].value.value.i);
282         if (format != GST_VIDEO_FORMAT_UNKNOWN)
283           g_array_append_val (formats, format);
284         break;
285       default:
286         break;
287     }
288   }
289
290   g_free (attribs);
291
292   if (formats->len == 0) {
293     g_array_unref (formats);
294     return NULL;
295   }
296
297   return formats;
298 }
299
300 static GstBufferPool *
301 _create_reconstruct_pool (GstVaDisplay * display, GArray * surface_formats,
302     GstVideoFormat format, gint coded_width, gint coded_height,
303     guint max_buffers)
304 {
305   GstAllocator *allocator = NULL;
306   guint usage_hint = VA_SURFACE_ATTRIB_USAGE_HINT_ENCODER;
307   GstVideoInfo info;
308   GstAllocationParams params = { 0, };
309   GstBufferPool *pool;
310   guint size;
311   GstCaps *caps = NULL;
312
313   gst_video_info_set_format (&info, format, coded_width, coded_height);
314
315   size = GST_VIDEO_INFO_SIZE (&info);
316
317   caps = gst_video_info_to_caps (&info);
318   gst_caps_set_features_simple (caps,
319       gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_VA));
320
321   allocator = gst_va_allocator_new (display, surface_formats);
322
323   gst_allocation_params_init (&params);
324
325   pool = gst_va_pool_new_with_config (caps, size, 0, max_buffers, usage_hint,
326       GST_VA_FEATURE_AUTO, allocator, &params);
327
328   gst_clear_object (&allocator);
329   gst_clear_caps (&caps);
330
331   return pool;
332 }
333
334 gboolean
335 gst_va_encoder_open (GstVaEncoder * self, VAProfile profile,
336     VAEntrypoint entrypoint, GstVideoFormat video_format, guint rt_format,
337     gint coded_width, gint coded_height, gint codedbuf_size,
338     guint max_reconstruct_surfaces, guint rc_ctrl, guint32 packed_headers)
339 {
340   /* *INDENT-OFF* */
341   VAConfigAttrib attribs[3] = {
342     { .type = VAConfigAttribRTFormat, .value = rt_format, },
343     { .type = VAConfigAttribRateControl, .value = rc_ctrl, },
344   };
345   /* *INDENT-ON* */
346   VAConfigID config = VA_INVALID_ID;
347   VAContextID context = VA_INVALID_ID;
348   VADisplay dpy;
349   GArray *surface_formats = NULL;
350   VAStatus status;
351   GstBufferPool *recon_pool = NULL;
352   guint attrib_idx = 2;
353
354   g_return_val_if_fail (GST_IS_VA_ENCODER (self), FALSE);
355   g_return_val_if_fail (codedbuf_size > 0, FALSE);
356
357   if (gst_va_encoder_is_open (self))
358     return TRUE;
359
360   if (!gst_va_encoder_has_profile_and_entrypoint (self, profile, entrypoint)) {
361     GST_ERROR_OBJECT (self, "Unsupported profile: %d, entrypoint: %d",
362         profile, entrypoint);
363     return FALSE;
364   }
365
366   if (packed_headers > 0) {
367     attribs[attrib_idx].type = VAConfigAttribEncPackedHeaders;
368     attribs[attrib_idx].value = packed_headers;
369     attrib_idx++;
370   }
371
372   dpy = gst_va_display_get_va_dpy (self->display);
373
374   status = vaCreateConfig (dpy, profile, entrypoint, attribs, attrib_idx,
375       &config);
376   if (status != VA_STATUS_SUCCESS) {
377     GST_ERROR_OBJECT (self, "vaCreateConfig: %s", vaErrorStr (status));
378     goto error;
379   }
380
381   surface_formats = _get_surface_formats (self->display, config);
382   if (!surface_formats) {
383     GST_ERROR_OBJECT (self, "Failed to get surface formats");
384     goto error;
385   }
386
387   recon_pool = _create_reconstruct_pool (self->display, surface_formats,
388       video_format, coded_width, coded_height, max_reconstruct_surfaces);
389   if (!recon_pool) {
390     GST_ERROR_OBJECT (self, "Failed to create reconstruct pool");
391     goto error;
392   }
393   gst_buffer_pool_set_active (recon_pool, TRUE);
394
395   status = vaCreateContext (dpy, config, coded_width, coded_height,
396       VA_PROGRESSIVE, NULL, 0, &context);
397   if (status != VA_STATUS_SUCCESS) {
398     GST_ERROR_OBJECT (self, "vaCreateConfig: %s", vaErrorStr (status));
399     goto error;
400   }
401
402   GST_OBJECT_LOCK (self);
403
404   self->config = config;
405   self->context = context;
406   self->profile = profile;
407   self->entrypoint = entrypoint;
408   self->rt_format = rt_format;
409   self->coded_width = coded_width;
410   self->coded_height = coded_height;
411   self->codedbuf_size = codedbuf_size;
412   gst_object_replace ((GstObject **) & self->recon_pool,
413       (GstObject *) recon_pool);
414
415   GST_OBJECT_UNLOCK (self);
416
417   g_clear_pointer (&recon_pool, gst_object_unref);
418   /* now we should return now only this profile's caps */
419   gst_caps_replace (&self->srcpad_caps, NULL);
420
421   return TRUE;
422
423 error:
424   g_clear_pointer (&recon_pool, gst_object_unref);
425
426   if (config != VA_INVALID_ID)
427     vaDestroyConfig (dpy, config);
428
429   if (context != VA_INVALID_ID)
430     vaDestroyContext (dpy, context);
431
432   return FALSE;
433 }
434
435 static void
436 gst_va_encoder_dispose (GObject * object)
437 {
438   GstVaEncoder *self = GST_VA_ENCODER (object);
439
440   gst_va_encoder_close (self);
441
442   g_clear_pointer (&self->available_profiles, g_array_unref);
443   gst_clear_object (&self->display);
444
445   G_OBJECT_CLASS (parent_class)->dispose (object);
446 }
447
448 static void
449 gst_va_encoder_class_init (GstVaEncoderClass * klass)
450 {
451   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
452
453   gobject_class->set_property = gst_va_encoder_set_property;
454   gobject_class->get_property = gst_va_encoder_get_property;
455   gobject_class->dispose = gst_va_encoder_dispose;
456
457   g_properties[PROP_DISPLAY] =
458       g_param_spec_object ("display", "GstVaDisplay", "GstVADisplay object",
459       GST_TYPE_VA_DISPLAY,
460       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
461
462   g_properties[PROP_PROFILE] =
463       g_param_spec_int ("va-profile", "VAProfile", "VA Profile",
464       VAProfileNone, 50, VAProfileNone,
465       G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
466
467   g_properties[PROP_ENTRYPOINT] =
468       g_param_spec_int ("va-entrypoint", "VAEntrypoint", "VA Entrypoint",
469       0, 14, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
470
471   g_properties[PROP_CHROMA] =
472       g_param_spec_uint ("va-rt-format", "VARTFormat", "VA RT Fromat or chroma",
473       VA_RT_FORMAT_YUV420, VA_RT_FORMAT_PROTECTED, VA_RT_FORMAT_YUV420,
474       G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
475
476   g_properties[PROP_WIDTH] =
477       g_param_spec_int ("coded-width", "coded-picture-width",
478       "coded picture width", 0, G_MAXINT, 0,
479       G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
480
481   g_properties[PROP_HEIGHT] =
482       g_param_spec_int ("coded-height", "coded-picture-height",
483       "coded picture height", 0, G_MAXINT, 0,
484       G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
485
486   g_properties[PROP_CODED_BUF_SIZE] =
487       g_param_spec_int ("coded-buf-size", "coded-buffer-size",
488       "coded buffer size", 0, G_MAXINT, 0,
489       G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
490
491   g_object_class_install_properties (gobject_class, N_PROPERTIES, g_properties);
492 }
493
494 static gboolean
495 gst_va_encoder_initialize (GstVaEncoder * self, guint32 codec)
496 {
497   GArray *enc_profiles = NULL;
498   gint i;
499
500   if (self->available_profiles)
501     return FALSE;
502
503   enc_profiles = gst_va_display_get_profiles (self->display, codec,
504       VAEntrypointEncSlice);
505
506   if (!enc_profiles)
507     return FALSE;
508
509   self->available_profiles =
510       g_array_new (FALSE, FALSE, sizeof (GstVaProfileConfig));
511
512   if (enc_profiles) {
513     for (i = 0; i < enc_profiles->len; i++) {
514       GstVaProfileConfig config;
515
516       config.profile = g_array_index (enc_profiles, VAProfile, i);
517       config.entrypoints = VA_ENTRYPOINT_FLAG (EncSlice);
518       g_array_append_val (self->available_profiles, config);
519     }
520   }
521
522   g_clear_pointer (&enc_profiles, g_array_unref);
523
524   if (self->available_profiles->len == 0)
525     return FALSE;
526
527   return TRUE;
528 }
529
530 GstVaEncoder *
531 gst_va_encoder_new (GstVaDisplay * display, guint32 codec)
532 {
533   GstVaEncoder *self;
534
535   g_return_val_if_fail (GST_IS_VA_DISPLAY (display), NULL);
536
537   self = g_object_new (GST_TYPE_VA_ENCODER, "display", display, NULL);
538   if (!gst_va_encoder_initialize (self, codec))
539     gst_clear_object (&self);
540
541   return self;
542 }
543
544 gboolean
545 gst_va_encoder_has_profile_and_entrypoint (GstVaEncoder * self,
546     VAProfile profile, VAEntrypoint entrypoint)
547 {
548   GstVaProfileConfig *config;
549   gint i;
550
551   g_return_val_if_fail (GST_IS_VA_ENCODER (self), FALSE);
552
553   if (profile == VAProfileNone)
554     return FALSE;
555
556   for (i = 0; i < self->available_profiles->len; i++) {
557     config = &g_array_index (self->available_profiles, GstVaProfileConfig, i);
558     if (config->profile == profile) {
559       if (entrypoint == 0)
560         break;
561
562       if (config->entrypoints & (1U << entrypoint))
563         break;
564     }
565   }
566   if (i == self->available_profiles->len)
567     return FALSE;
568
569   return TRUE;
570 }
571
572 gint32
573 gst_va_encoder_get_max_slice_num (GstVaEncoder * self,
574     VAProfile profile, VAEntrypoint entrypoint)
575 {
576   VAStatus status;
577   VADisplay dpy;
578   VAConfigAttrib attrib = {.type = VAConfigAttribEncMaxSlices };
579
580   g_return_val_if_fail (GST_IS_VA_ENCODER (self), -1);
581
582   if (profile == VAProfileNone)
583     return -1;
584
585   if (entrypoint != VAEntrypointEncSlice)
586     return -1;
587
588   dpy = gst_va_display_get_va_dpy (self->display);
589   status = vaGetConfigAttributes (dpy, profile, entrypoint, &attrib, 1);
590   if (status != VA_STATUS_SUCCESS) {
591     GST_WARNING_OBJECT (self, "Failed to query encoding slices: %s",
592         vaErrorStr (status));
593     return -1;
594   }
595
596   if (attrib.value == VA_ATTRIB_NOT_SUPPORTED) {
597     GST_WARNING_OBJECT (self, "Driver does not support encoding picture as "
598         "multiple slices");
599     return -1;
600   }
601
602   return attrib.value;
603 }
604
605 gboolean
606 gst_va_encoder_get_max_num_reference (GstVaEncoder * self,
607     VAProfile profile, VAEntrypoint entrypoint,
608     guint32 * list0, guint32 * list1)
609 {
610   VAStatus status;
611   VADisplay dpy;
612   VAConfigAttrib attrib = {.type = VAConfigAttribEncMaxRefFrames };
613
614   g_return_val_if_fail (GST_IS_VA_ENCODER (self), FALSE);
615
616   if (profile == VAProfileNone)
617     return FALSE;
618
619   if (entrypoint != VAEntrypointEncSlice)
620     return FALSE;
621
622   dpy = gst_va_display_get_va_dpy (self->display);
623   status = vaGetConfigAttributes (dpy, profile, entrypoint, &attrib, 1);
624   if (status != VA_STATUS_SUCCESS) {
625     GST_WARNING_OBJECT (self, "Failed to query reference frames: %s",
626         vaErrorStr (status));
627     return FALSE;
628   }
629
630   if (attrib.value == VA_ATTRIB_NOT_SUPPORTED) {
631     if (list0)
632       *list0 = 0;
633     if (list1)
634       *list1 = 0;
635
636     return TRUE;
637   }
638
639   if (list0)
640     *list0 = attrib.value & 0xffff;
641   if (list1)
642     *list1 = (attrib.value >> 16) & 0xffff;
643
644   return TRUE;
645 }
646
647 guint32
648 gst_va_encoder_get_rate_control_mode (GstVaEncoder * self,
649     VAProfile profile, VAEntrypoint entrypoint)
650 {
651   VAStatus status;
652   VADisplay dpy;
653   VAConfigAttrib attrib = {.type = VAConfigAttribRateControl };
654
655   g_return_val_if_fail (GST_IS_VA_ENCODER (self), 0);
656
657   if (profile == VAProfileNone)
658     return 0;
659
660   if (entrypoint != VAEntrypointEncSlice)
661     return 0;
662
663   dpy = gst_va_display_get_va_dpy (self->display);
664   status = vaGetConfigAttributes (dpy, profile, entrypoint, &attrib, 1);
665   if (status != VA_STATUS_SUCCESS) {
666     GST_WARNING_OBJECT (self, "Failed to query rate control mode: %s",
667         vaErrorStr (status));
668     return 0;
669   }
670
671   if (attrib.value == VA_ATTRIB_NOT_SUPPORTED) {
672     GST_WARNING_OBJECT (self, "Driver does not support any rate control modes");
673     return 0;
674   }
675
676   return attrib.value;
677 }
678
679 guint32
680 gst_va_encoder_get_quality_level (GstVaEncoder * self,
681     VAProfile profile, VAEntrypoint entrypoint)
682 {
683   VAStatus status;
684   VADisplay dpy;
685   VAConfigAttrib attrib = {.type = VAConfigAttribEncQualityRange };
686
687   g_return_val_if_fail (GST_IS_VA_ENCODER (self), 0);
688
689   if (profile == VAProfileNone)
690     return 0;
691
692   if (entrypoint != VAEntrypointEncSlice)
693     return 0;
694
695   dpy = gst_va_display_get_va_dpy (self->display);
696   status = vaGetConfigAttributes (dpy, profile, entrypoint, &attrib, 1);
697   if (status != VA_STATUS_SUCCESS) {
698     GST_WARNING_OBJECT (self, "Failed to query the quality level: %s",
699         vaErrorStr (status));
700     return 0;
701   }
702
703   if (attrib.value == VA_ATTRIB_NOT_SUPPORTED) {
704     GST_WARNING_OBJECT (self, "Driver does not support quality attribute");
705     return 0;
706   }
707
708   return attrib.value;
709 }
710
711 gboolean
712 gst_va_encoder_has_trellis (GstVaEncoder * self,
713     VAProfile profile, VAEntrypoint entrypoint)
714 {
715   VAStatus status;
716   VADisplay dpy;
717   VAConfigAttrib attrib = {.type = VAConfigAttribEncQuantization };
718
719   g_return_val_if_fail (GST_IS_VA_ENCODER (self), FALSE);
720
721   if (profile == VAProfileNone)
722     return FALSE;
723
724   if (entrypoint != VAEntrypointEncSlice)
725     return FALSE;
726
727   dpy = gst_va_display_get_va_dpy (self->display);
728   status = vaGetConfigAttributes (dpy, profile, entrypoint, &attrib, 1);
729   if (status != VA_STATUS_SUCCESS) {
730     GST_WARNING_OBJECT (self, "Failed to query the trellis: %s",
731         vaErrorStr (status));
732     return FALSE;
733   }
734
735   if (attrib.value == VA_ATTRIB_NOT_SUPPORTED) {
736     GST_WARNING_OBJECT (self, "Driver does not support trellis");
737     return FALSE;
738   }
739
740   return attrib.value & VA_ENC_QUANTIZATION_TRELLIS_SUPPORTED;
741 }
742
743 guint32
744 gst_va_encoder_get_rtformat (GstVaEncoder * self,
745     VAProfile profile, VAEntrypoint entrypoint)
746 {
747   VAStatus status;
748   VADisplay dpy;
749   VAConfigAttrib attrib = {.type = VAConfigAttribRTFormat };
750
751   if (profile == VAProfileNone)
752     return 0;
753
754   if (entrypoint != VAEntrypointEncSlice)
755     return 0;
756
757   dpy = gst_va_display_get_va_dpy (self->display);
758   status = vaGetConfigAttributes (dpy, profile, entrypoint, &attrib, 1);
759   if (status != VA_STATUS_SUCCESS) {
760     GST_ERROR_OBJECT (self, "Failed to query rt format: %s",
761         vaErrorStr (status));
762     return 0;
763   }
764
765   if (attrib.value == VA_ATTRIB_NOT_SUPPORTED) {
766     GST_WARNING_OBJECT (self, "Driver does not support any rt format");
767     return 0;
768   }
769
770   return attrib.value;
771 }
772
773 guint32
774 gst_va_encoder_get_packed_headers (GstVaEncoder * self, VAProfile profile,
775     VAEntrypoint entrypoint)
776 {
777   VAStatus status;
778   VADisplay dpy;
779   VAConfigAttrib attrib = {.type = VAConfigAttribEncPackedHeaders };
780
781   if (profile == VAProfileNone)
782     return 0;
783
784   if (entrypoint != VAEntrypointEncSlice)
785     return 0;
786
787   dpy = gst_va_display_get_va_dpy (self->display);
788   status = vaGetConfigAttributes (dpy, profile, entrypoint, &attrib, 1);
789   if (status != VA_STATUS_SUCCESS) {
790     GST_ERROR_OBJECT (self, "Failed to query packed headers: %s",
791         vaErrorStr (status));
792     return 0;
793   }
794
795   if (attrib.value == VA_ATTRIB_NOT_SUPPORTED) {
796     GST_WARNING_OBJECT (self, "Driver does not support any packed headers");
797     return 0;
798   }
799
800   return attrib.value;
801 }
802
803 /* Add packed header such as SPS, PPS, SEI, etc. If adding slice header,
804    it is attached to the last slice parameter. */
805 gboolean
806 gst_va_encoder_add_packed_header (GstVaEncoder * self, GstVaEncodePicture * pic,
807     gint type, gpointer data, gsize size_in_bits, gboolean has_emulation_bytes)
808 {
809   VABufferID buffer;
810   VAEncPackedHeaderParameterBuffer param = {
811     .type = type,
812     .bit_length = size_in_bits,
813     .has_emulation_bytes = has_emulation_bytes,
814   };
815
816   g_return_val_if_fail (GST_IS_VA_ENCODER (self), FALSE);
817   g_return_val_if_fail (self->context != VA_INVALID_ID, FALSE);
818   g_return_val_if_fail (pic && data && size_in_bits > 0, FALSE);
819   g_return_val_if_fail (type >= VAEncPackedHeaderSequence
820       && type <= VAEncPackedHeaderRawData, FALSE);
821
822   if (!gst_va_encoder_is_open (self)) {
823     GST_ERROR_OBJECT (self, "encoder has not been opened yet");
824     return FALSE;
825   }
826
827   buffer = _create_buffer (self, VAEncPackedHeaderParameterBufferType, &param,
828       sizeof (param));
829   if (buffer == VA_INVALID_ID)
830     return FALSE;
831
832   g_array_append_val (pic->params, buffer);
833
834   buffer = _create_buffer (self, VAEncPackedHeaderDataBufferType, data,
835       (size_in_bits + 7) / 8);
836   if (buffer == VA_INVALID_ID)
837     return FALSE;
838
839   g_array_append_val (pic->params, buffer);
840
841   return TRUE;
842 }
843
844 gboolean
845 gst_va_encoder_add_param (GstVaEncoder * self, GstVaEncodePicture * pic,
846     VABufferType type, gpointer data, gsize size)
847 {
848   VABufferID buffer;
849
850   g_return_val_if_fail (GST_IS_VA_ENCODER (self), FALSE);
851   g_return_val_if_fail (self->context != VA_INVALID_ID, FALSE);
852   g_return_val_if_fail (pic && data && size > 0, FALSE);
853
854   if (!gst_va_encoder_is_open (self)) {
855     GST_ERROR_OBJECT (self, "encoder has not been opened yet");
856     return FALSE;
857   }
858
859   buffer = _create_buffer (self, type, data, size);
860   if (buffer == VA_INVALID_ID)
861     return FALSE;
862
863   g_array_append_val (pic->params, buffer);
864
865   return TRUE;
866 }
867
868 GArray *
869 gst_va_encoder_get_surface_formats (GstVaEncoder * self)
870 {
871   g_return_val_if_fail (GST_IS_VA_ENCODER (self), NULL);
872
873   if (!gst_va_encoder_is_open (self))
874     return NULL;
875
876   return _get_surface_formats (self->display, self->config);
877 }
878
879 static gboolean
880 _get_codec_caps (GstVaEncoder * self)
881 {
882   GstCaps *sinkpad_caps = NULL, *srcpad_caps = NULL;
883
884   if (!gst_va_encoder_is_open (self)
885       && GST_IS_VA_DISPLAY_WRAPPED (self->display)) {
886     if (gst_va_caps_from_profiles (self->display, self->available_profiles,
887             VAEntrypointEncSlice, &sinkpad_caps, &srcpad_caps)) {
888       gst_caps_replace (&self->sinkpad_caps, sinkpad_caps);
889       gst_caps_replace (&self->srcpad_caps, srcpad_caps);
890       gst_caps_unref (srcpad_caps);
891       gst_caps_unref (sinkpad_caps);
892
893       return TRUE;
894     }
895   }
896
897   return FALSE;
898 }
899
900 GstCaps *
901 gst_va_encoder_get_sinkpad_caps (GstVaEncoder * self)
902 {
903   GstCaps *sinkpad_caps = NULL;
904
905   g_return_val_if_fail (GST_IS_VA_ENCODER (self), FALSE);
906
907   if (g_atomic_pointer_get (&self->sinkpad_caps))
908     return gst_caps_ref (self->sinkpad_caps);
909
910   if (_get_codec_caps (self))
911     return gst_caps_ref (self->sinkpad_caps);
912
913   if (gst_va_encoder_is_open (self)) {
914     sinkpad_caps = gst_va_create_raw_caps_from_config (self->display,
915         self->config);
916     gst_caps_replace (&self->sinkpad_caps, sinkpad_caps);
917     gst_caps_unref (sinkpad_caps);
918
919     return gst_caps_ref (self->sinkpad_caps);
920   }
921
922   return NULL;
923 }
924
925 GstCaps *
926 gst_va_encoder_get_srcpad_caps (GstVaEncoder * self)
927 {
928   g_return_val_if_fail (GST_IS_VA_ENCODER (self), FALSE);
929
930   if (g_atomic_pointer_get (&self->srcpad_caps))
931     return gst_caps_ref (self->srcpad_caps);
932
933   if (_get_codec_caps (self))
934     return gst_caps_ref (self->srcpad_caps);
935
936   if (gst_va_encoder_is_open (self)) {
937     VAProfile profile;
938     VAEntrypoint entrypoint;
939     GstCaps *caps;
940
941     GST_OBJECT_LOCK (self);
942     profile = self->profile;
943     entrypoint = self->entrypoint;
944     GST_OBJECT_UNLOCK (self);
945
946     caps = gst_va_create_coded_caps (self->display, profile, entrypoint, NULL);
947     if (caps) {
948       gst_caps_replace (&self->srcpad_caps, caps);
949       return gst_caps_ref (self->srcpad_caps);
950     }
951   }
952
953   return NULL;
954 }
955
956 static gboolean
957 _destroy_all_buffers (GstVaEncodePicture * pic)
958 {
959   VABufferID buffer;
960   guint i;
961   gboolean ret = TRUE;
962
963   g_return_val_if_fail (GST_IS_VA_DISPLAY (pic->display), FALSE);
964
965   for (i = 0; i < pic->params->len; i++) {
966     buffer = g_array_index (pic->params, VABufferID, i);
967     ret &= _destroy_buffer (pic->display, buffer);
968   }
969   pic->params = g_array_set_size (pic->params, 0);
970
971   return ret;
972 }
973
974 gboolean
975 gst_va_encoder_encode (GstVaEncoder * self, GstVaEncodePicture * pic)
976 {
977   VADisplay dpy;
978   VAStatus status;
979   VASurfaceID surface;
980   VAContextID context;
981   gboolean ret = FALSE;
982
983   g_return_val_if_fail (pic, FALSE);
984
985   GST_OBJECT_LOCK (self);
986
987   if (!_is_open_unlocked (self)) {
988     GST_OBJECT_UNLOCK (self);
989     GST_ERROR_OBJECT (self, "encoder has not been opened yet");
990     return FALSE;
991   }
992
993   context = self->context;
994   GST_OBJECT_UNLOCK (self);
995
996   surface = gst_va_encode_picture_get_raw_surface (pic);
997   if (surface == VA_INVALID_ID) {
998     GST_ERROR_OBJECT (self, "Encode picture without valid raw surface");
999     goto bail;
1000   }
1001
1002   GST_TRACE_OBJECT (self, "Encode the surface %#x", surface);
1003
1004   dpy = gst_va_display_get_va_dpy (self->display);
1005
1006   status = vaBeginPicture (dpy, context, surface);
1007   if (status != VA_STATUS_SUCCESS) {
1008     GST_WARNING_OBJECT (self, "vaBeginPicture: %s", vaErrorStr (status));
1009     goto bail;
1010   }
1011
1012   if (pic->params->len > 0) {
1013     status = vaRenderPicture (dpy, context, (VABufferID *) pic->params->data,
1014         pic->params->len);
1015     if (status != VA_STATUS_SUCCESS) {
1016       GST_WARNING_OBJECT (self, "vaRenderPicture: %s", vaErrorStr (status));
1017       goto fail_end_pic;
1018     }
1019   }
1020
1021   status = vaEndPicture (dpy, context);
1022   ret = (status == VA_STATUS_SUCCESS);
1023   if (!ret)
1024     GST_WARNING_OBJECT (self, "vaEndPicture: %s", vaErrorStr (status));
1025
1026 bail:
1027   _destroy_all_buffers (pic);
1028
1029   return ret;
1030
1031 fail_end_pic:
1032   {
1033     _destroy_all_buffers (pic);
1034     status = vaEndPicture (dpy, context);
1035     ret = FALSE;
1036     goto bail;
1037   }
1038 }
1039
1040 VASurfaceID
1041 gst_va_encode_picture_get_reconstruct_surface (GstVaEncodePicture * pic)
1042 {
1043   g_return_val_if_fail (pic, VA_INVALID_ID);
1044   g_return_val_if_fail (pic->reconstruct_buffer, VA_INVALID_ID);
1045
1046   return gst_va_buffer_get_surface (pic->reconstruct_buffer);
1047 }
1048
1049 VASurfaceID
1050 gst_va_encode_picture_get_raw_surface (GstVaEncodePicture * pic)
1051 {
1052   g_return_val_if_fail (pic, VA_INVALID_ID);
1053   g_return_val_if_fail (pic->raw_buffer, VA_INVALID_ID);
1054
1055   return gst_va_buffer_get_surface (pic->raw_buffer);
1056 }
1057
1058 GstVaEncodePicture *
1059 gst_va_encode_picture_new (GstVaEncoder * self, GstBuffer * raw_buffer)
1060 {
1061   GstVaEncodePicture *pic;
1062   VABufferID coded_buffer;
1063   VADisplay dpy;
1064   VAStatus status;
1065   gint codedbuf_size;
1066   GstBufferPool *recon_pool = NULL;
1067   GstBuffer *reconstruct_buffer = NULL;
1068   GstFlowReturn ret;
1069   GstBufferPoolAcquireParams buffer_pool_params = {
1070     .flags = GST_BUFFER_POOL_ACQUIRE_FLAG_DONTWAIT,
1071   };
1072
1073   g_return_val_if_fail (self && GST_IS_VA_ENCODER (self), NULL);
1074   g_return_val_if_fail (raw_buffer && GST_IS_BUFFER (raw_buffer), NULL);
1075
1076   GST_OBJECT_LOCK (self);
1077
1078   if (!_is_open_unlocked (self)) {
1079     GST_OBJECT_UNLOCK (self);
1080     GST_ERROR_OBJECT (self, "encoder has not been opened yet");
1081     return NULL;
1082   }
1083
1084   if (self->codedbuf_size <= 0) {
1085     GST_ERROR_OBJECT (self, "codedbuf_size: %d, is invalid",
1086         self->codedbuf_size);
1087     GST_OBJECT_UNLOCK (self);
1088     return NULL;
1089   }
1090   codedbuf_size = self->codedbuf_size;
1091
1092   recon_pool = gst_object_ref (self->recon_pool);
1093
1094   GST_OBJECT_UNLOCK (self);
1095
1096   ret = gst_buffer_pool_acquire_buffer (recon_pool, &reconstruct_buffer,
1097       &buffer_pool_params);
1098   gst_clear_object (&recon_pool);
1099
1100   if (ret != GST_FLOW_OK) {
1101     GST_ERROR_OBJECT (self, "Failed to create the reconstruct picture");
1102     gst_clear_buffer (&reconstruct_buffer);
1103     return NULL;
1104   }
1105
1106   dpy = gst_va_display_get_va_dpy (self->display);
1107   status = vaCreateBuffer (dpy, self->context, VAEncCodedBufferType,
1108       codedbuf_size, 1, NULL, &coded_buffer);
1109   if (status != VA_STATUS_SUCCESS) {
1110     GST_ERROR_OBJECT (self, "vaCreateBuffer: %s", vaErrorStr (status));
1111     gst_clear_buffer (&reconstruct_buffer);
1112     return NULL;
1113   }
1114
1115   pic = g_slice_new (GstVaEncodePicture);
1116   pic->raw_buffer = gst_buffer_ref (raw_buffer);
1117   pic->reconstruct_buffer = reconstruct_buffer;
1118   pic->display = gst_object_ref (self->display);
1119   pic->coded_buffer = coded_buffer;
1120
1121   pic->params = g_array_sized_new (FALSE, FALSE, sizeof (VABufferID), 8);
1122
1123   return pic;
1124 }
1125
1126 void
1127 gst_va_encode_picture_free (GstVaEncodePicture * pic)
1128 {
1129   g_return_if_fail (pic);
1130
1131   _destroy_all_buffers (pic);
1132
1133   if (pic->coded_buffer != VA_INVALID_ID)
1134     _destroy_buffer (pic->display, pic->coded_buffer);
1135
1136   gst_buffer_unref (pic->raw_buffer);
1137   gst_buffer_unref (pic->reconstruct_buffer);
1138
1139   g_clear_pointer (&pic->params, g_array_unref);
1140   gst_clear_object (&pic->display);
1141
1142   g_slice_free (GstVaEncodePicture, pic);
1143 }
1144
1145 /**
1146  * GstVaEncoderRateControl:
1147  *
1148  * Since: 1.22
1149  */
1150 GType
1151 gst_va_encoder_rate_control_get_type (void)
1152 {
1153   static gsize type = 0;
1154   static const GEnumValue values[] = {
1155     {VA_RC_CBR, "Constant Bitrate", "cbr"},
1156     {VA_RC_VBR, "Variable Bitrate", "vbr"},
1157     {VA_RC_VCM, "Video Conferencing Mode (Non HRD compliant)", "vcm"},
1158     {VA_RC_CQP, "Constant Quantizer", "cqp"},
1159     /* {VA_RC_VBR_CONSTRAINED, "VBR with peak rate higher than average bitrate", */
1160     /*  "vbr-constrained"}, */
1161     /* {VA_RC_ICQ, "Intelligent Constant Quality", "icq"}, */
1162     /* {VA_RC_MB, "Macroblock based rate control", "mb"}, */
1163     /* {VA_RC_CFS, "Constant Frame Size", "cfs"}, */
1164     /* {VA_RC_PARALLEL, "Parallel BRC", "parallel"}, */
1165     /* {VA_RC_QVBR, "Quality defined VBR", "qvbr"}, */
1166     /* {VA_RC_AVBR, "Average VBR", "avbr"}, */
1167     {0, NULL, NULL}
1168   };
1169
1170   if (g_once_init_enter (&type)) {
1171     GType _type = g_enum_register_static ("GstVaEncoderRateControl", values);
1172     g_once_init_leave (&type, _type);
1173   }
1174
1175   return type;
1176 }