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