va: encoder: Fix regression since commit 2042c2d4f0.
[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 typedef struct _GstVaProfileConfig GstVaProfileConfig;
33
34 struct _GstVaProfileConfig
35 {
36   VAProfile profile;
37   guint32 entrypoint;
38 };
39
40 struct _GstVaEncoder
41 {
42   GstObject parent;
43
44   GArray *available_profiles;
45   GstCaps *srcpad_caps;
46   GstCaps *sinkpad_caps;
47   GstVaDisplay *display;
48   VAConfigID config;
49   VAContextID context;
50   VAProfile profile;
51   VAEntrypoint entrypoint;
52   guint rt_format;
53   gint coded_width;
54   gint coded_height;
55   gint codedbuf_size;
56
57   GstBufferPool *recon_pool;
58 };
59
60 GST_DEBUG_CATEGORY_STATIC (gst_va_encoder_debug);
61 #define GST_CAT_DEFAULT gst_va_encoder_debug
62
63 #define gst_va_encoder_parent_class parent_class
64 G_DEFINE_TYPE_WITH_CODE (GstVaEncoder, gst_va_encoder, GST_TYPE_OBJECT,
65     GST_DEBUG_CATEGORY_INIT (gst_va_encoder_debug, "vaencoder", 0,
66         "VA Encoder"));
67
68 enum
69 {
70   PROP_DISPLAY = 1,
71   PROP_PROFILE,
72   PROP_ENTRYPOINT,
73   PROP_WIDTH,
74   PROP_HEIGHT,
75   PROP_CHROMA,
76   PROP_CODED_BUF_SIZE,
77   N_PROPERTIES
78 };
79
80 static GParamSpec *g_properties[N_PROPERTIES];
81
82 static gboolean
83 _destroy_buffer (GstVaDisplay * display, VABufferID buffer)
84 {
85   VAStatus status;
86   gboolean ret = TRUE;
87   VADisplay dpy = gst_va_display_get_va_dpy (display);
88
89   status = vaDestroyBuffer (dpy, buffer);
90   if (status != VA_STATUS_SUCCESS) {
91     ret = FALSE;
92     GST_WARNING ("Failed to destroy the buffer: %s", vaErrorStr (status));
93   }
94
95   return ret;
96 }
97
98 static VABufferID
99 _create_buffer (GstVaEncoder * self, gint type, gpointer data, gsize size)
100 {
101   VAStatus status;
102   VADisplay dpy = gst_va_display_get_va_dpy (self->display);
103   VABufferID buffer;
104   VAContextID context;
105
106   GST_OBJECT_LOCK (self);
107   context = self->context;
108   GST_OBJECT_UNLOCK (self);
109
110   dpy = gst_va_display_get_va_dpy (self->display);
111   status = vaCreateBuffer (dpy, context, type, size, 1, data, &buffer);
112   if (status != VA_STATUS_SUCCESS) {
113     GST_ERROR_OBJECT (self, "vaCreateBuffer: %s", vaErrorStr (status));
114     return VA_INVALID_ID;
115   }
116
117   return buffer;
118 }
119
120 static void
121 gst_va_encoder_set_property (GObject * object, guint prop_id,
122     const GValue * value, GParamSpec * pspec)
123 {
124   GstVaEncoder *self = GST_VA_ENCODER (object);
125
126   GST_OBJECT_LOCK (self);
127
128   switch (prop_id) {
129     case PROP_DISPLAY:{
130       g_assert (!self->display);
131       self->display = g_value_dup_object (value);
132       break;
133     }
134     case PROP_ENTRYPOINT:{
135       self->entrypoint = g_value_get_int (value);
136       break;
137     }
138     default:
139       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
140       break;
141   }
142
143   GST_OBJECT_UNLOCK (self);
144 }
145
146 static void
147 gst_va_encoder_get_property (GObject * object, guint prop_id, GValue * value,
148     GParamSpec * pspec)
149 {
150   GstVaEncoder *self = GST_VA_ENCODER (object);
151
152   GST_OBJECT_LOCK (self);
153
154   switch (prop_id) {
155     case PROP_DISPLAY:
156       g_value_set_object (value, self->display);
157       break;
158     case PROP_PROFILE:
159       g_value_set_int (value, self->profile);
160       break;
161     case PROP_ENTRYPOINT:
162       g_value_set_int (value, self->entrypoint);
163       break;
164     case PROP_CHROMA:
165       g_value_set_uint (value, self->rt_format);
166       break;
167     case PROP_WIDTH:
168       g_value_set_int (value, self->coded_width);
169       break;
170     case PROP_HEIGHT:
171       g_value_set_int (value, self->coded_height);
172       break;
173     case PROP_CODED_BUF_SIZE:
174       g_value_set_int (value, self->codedbuf_size);
175       break;
176     default:
177       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
178       break;
179   }
180
181   GST_OBJECT_UNLOCK (self);
182 }
183
184 static void
185 gst_va_encoder_init (GstVaEncoder * self)
186 {
187   self->profile = VAProfileNone;
188   self->entrypoint = 0;
189   self->config = VA_INVALID_ID;
190   self->context = VA_INVALID_ID;
191   self->rt_format = 0;
192   self->coded_width = 0;
193   self->coded_height = 0;
194   self->codedbuf_size = 0;
195   g_clear_pointer (&self->recon_pool, gst_object_unref);
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_init (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     VAEntrypoint entrypoint, GstVideoFormat video_format, guint rt_format,
339     gint coded_width, gint coded_height, gint codedbuf_size,
340     guint max_reconstruct_surfaces, guint rc_ctrl, guint32 packed_headers)
341 {
342   /* *INDENT-OFF* */
343   VAConfigAttrib attribs[3] = {
344     { .type = VAConfigAttribRTFormat, .value = rt_format, },
345     { .type = VAConfigAttribRateControl, .value = rc_ctrl, },
346   };
347   /* *INDENT-ON* */
348   VAConfigID config = VA_INVALID_ID;
349   VAContextID context = VA_INVALID_ID;
350   VADisplay dpy;
351   GArray *surface_formats = NULL;
352   VAStatus status;
353   GstBufferPool *recon_pool = NULL;
354   guint attrib_idx = 2;
355
356   g_return_val_if_fail (GST_IS_VA_ENCODER (self), FALSE);
357   g_return_val_if_fail (codedbuf_size > 0, FALSE);
358
359   if (gst_va_encoder_is_open (self))
360     return TRUE;
361
362   if (!gst_va_encoder_has_profile_and_entrypoint (self, profile, entrypoint)) {
363     GST_ERROR_OBJECT (self, "Unsupported profile: %d, entrypoint: %d",
364         profile, entrypoint);
365     return FALSE;
366   }
367
368   if (packed_headers > 0) {
369     attribs[attrib_idx].type = VAConfigAttribEncPackedHeaders;
370     attribs[attrib_idx].value = packed_headers;
371     attrib_idx++;
372   }
373
374   dpy = gst_va_display_get_va_dpy (self->display);
375
376   status = vaCreateConfig (dpy, profile, entrypoint, attribs, attrib_idx,
377       &config);
378   if (status != VA_STATUS_SUCCESS) {
379     GST_ERROR_OBJECT (self, "vaCreateConfig: %s", vaErrorStr (status));
380     goto error;
381   }
382
383   surface_formats = _get_surface_formats (self->display, config);
384   if (!surface_formats) {
385     GST_ERROR_OBJECT (self, "Failed to get surface formats");
386     goto error;
387   }
388
389   recon_pool = _create_reconstruct_pool (self->display, surface_formats,
390       video_format, coded_width, coded_height, max_reconstruct_surfaces);
391   if (!recon_pool) {
392     GST_ERROR_OBJECT (self, "Failed to create reconstruct pool");
393     goto error;
394   }
395   gst_buffer_pool_set_active (recon_pool, TRUE);
396
397   status = vaCreateContext (dpy, config, coded_width, coded_height,
398       VA_PROGRESSIVE, NULL, 0, &context);
399   if (status != VA_STATUS_SUCCESS) {
400     GST_ERROR_OBJECT (self, "vaCreateConfig: %s", vaErrorStr (status));
401     goto error;
402   }
403
404   GST_OBJECT_LOCK (self);
405
406   self->config = config;
407   self->context = context;
408   self->profile = profile;
409   self->rt_format = rt_format;
410   self->coded_width = coded_width;
411   self->coded_height = coded_height;
412   self->codedbuf_size = codedbuf_size;
413   gst_object_replace ((GstObject **) & self->recon_pool,
414       (GstObject *) recon_pool);
415
416   GST_OBJECT_UNLOCK (self);
417
418   g_clear_pointer (&recon_pool, gst_object_unref);
419   /* now we should return now only this profile's caps */
420   gst_caps_replace (&self->srcpad_caps, NULL);
421
422   return TRUE;
423
424 error:
425   g_clear_pointer (&recon_pool, gst_object_unref);
426
427   if (config != VA_INVALID_ID)
428     vaDestroyConfig (dpy, config);
429
430   if (context != VA_INVALID_ID)
431     vaDestroyContext (dpy, context);
432
433   return FALSE;
434 }
435
436 static void
437 gst_va_encoder_dispose (GObject * object)
438 {
439   GstVaEncoder *self = GST_VA_ENCODER (object);
440
441   gst_va_encoder_close (self);
442
443   g_clear_pointer (&self->available_profiles, g_array_unref);
444   gst_clear_object (&self->display);
445
446   G_OBJECT_CLASS (parent_class)->dispose (object);
447 }
448
449 static void
450 gst_va_encoder_class_init (GstVaEncoderClass * klass)
451 {
452   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
453
454   gobject_class->set_property = gst_va_encoder_set_property;
455   gobject_class->get_property = gst_va_encoder_get_property;
456   gobject_class->dispose = gst_va_encoder_dispose;
457
458   g_properties[PROP_DISPLAY] =
459       g_param_spec_object ("display", "GstVaDisplay", "GstVADisplay object",
460       GST_TYPE_VA_DISPLAY,
461       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
462
463   g_properties[PROP_PROFILE] =
464       g_param_spec_int ("va-profile", "VAProfile", "VA Profile",
465       VAProfileNone, 50, VAProfileNone,
466       G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
467
468   g_properties[PROP_ENTRYPOINT] =
469       g_param_spec_int ("va-entrypoint", "VAEntrypoint", "VA Entrypoint",
470       0, 14, 0,
471       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
472
473   g_properties[PROP_CHROMA] =
474       g_param_spec_uint ("va-rt-format", "VARTFormat", "VA RT Fromat or chroma",
475       VA_RT_FORMAT_YUV420, VA_RT_FORMAT_PROTECTED, VA_RT_FORMAT_YUV420,
476       G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
477
478   g_properties[PROP_WIDTH] =
479       g_param_spec_int ("coded-width", "coded-picture-width",
480       "coded picture width", 0, G_MAXINT, 0,
481       G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
482
483   g_properties[PROP_HEIGHT] =
484       g_param_spec_int ("coded-height", "coded-picture-height",
485       "coded picture height", 0, G_MAXINT, 0,
486       G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
487
488   g_properties[PROP_CODED_BUF_SIZE] =
489       g_param_spec_int ("coded-buf-size", "coded-buffer-size",
490       "coded buffer size", 0, G_MAXINT, 0,
491       G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
492
493   g_object_class_install_properties (gobject_class, N_PROPERTIES, g_properties);
494 }
495
496 static gboolean
497 gst_va_encoder_initialize (GstVaEncoder * self, guint32 codec)
498 {
499   GArray *enc_profiles = NULL;
500   gint i;
501
502   if (self->available_profiles)
503     return FALSE;
504
505   enc_profiles = gst_va_display_get_profiles (self->display, codec,
506       self->entrypoint);
507
508   if (!enc_profiles)
509     return FALSE;
510
511   self->available_profiles =
512       g_array_new (FALSE, FALSE, sizeof (GstVaProfileConfig));
513
514   if (enc_profiles) {
515     for (i = 0; i < enc_profiles->len; i++) {
516       GstVaProfileConfig config;
517
518       config.profile = g_array_index (enc_profiles, VAProfile, i);
519       config.entrypoint = self->entrypoint;
520       g_array_append_val (self->available_profiles, config);
521     }
522   }
523
524   g_clear_pointer (&enc_profiles, g_array_unref);
525
526   if (self->available_profiles->len == 0)
527     return FALSE;
528
529   return TRUE;
530 }
531
532 GstVaEncoder *
533 gst_va_encoder_new (GstVaDisplay * display, guint32 codec,
534     VAEntrypoint entrypoint)
535 {
536   GstVaEncoder *self;
537
538   g_return_val_if_fail (GST_IS_VA_DISPLAY (display), NULL);
539
540   self = g_object_new (GST_TYPE_VA_ENCODER, "display", display,
541       "va-entrypoint", entrypoint, NULL);
542   if (!gst_va_encoder_initialize (self, codec))
543     gst_clear_object (&self);
544
545   return self;
546 }
547
548 gboolean
549 gst_va_encoder_has_profile_and_entrypoint (GstVaEncoder * self,
550     VAProfile profile, VAEntrypoint entrypoint)
551 {
552   GstVaProfileConfig *config;
553   gint i;
554
555   g_return_val_if_fail (GST_IS_VA_ENCODER (self), FALSE);
556
557   if (profile == VAProfileNone)
558     return FALSE;
559
560   for (i = 0; i < self->available_profiles->len; i++) {
561     config = &g_array_index (self->available_profiles, GstVaProfileConfig, i);
562     if (config->profile == profile) {
563       if (entrypoint == 0)
564         break;
565
566       if (config->entrypoint == entrypoint)
567         break;
568     }
569   }
570   if (i == self->available_profiles->len)
571     return FALSE;
572
573   return TRUE;
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 gboolean
607 gst_va_encoder_get_max_num_reference (GstVaEncoder * self,
608     VAProfile profile, VAEntrypoint entrypoint,
609     guint32 * list0, guint32 * list1)
610 {
611   VAStatus status;
612   VADisplay dpy;
613   VAConfigAttrib attrib = {.type = VAConfigAttribEncMaxRefFrames };
614
615   g_return_val_if_fail (GST_IS_VA_ENCODER (self), FALSE);
616
617   if (profile == VAProfileNone)
618     return FALSE;
619
620   dpy = gst_va_display_get_va_dpy (self->display);
621   status = vaGetConfigAttributes (dpy, profile, entrypoint, &attrib, 1);
622   if (status != VA_STATUS_SUCCESS) {
623     GST_WARNING_OBJECT (self, "Failed to query reference frames: %s",
624         vaErrorStr (status));
625     return FALSE;
626   }
627
628   if (attrib.value == VA_ATTRIB_NOT_SUPPORTED) {
629     if (list0)
630       *list0 = 0;
631     if (list1)
632       *list1 = 0;
633
634     return TRUE;
635   }
636
637   if (list0)
638     *list0 = attrib.value & 0xffff;
639   if (list1)
640     *list1 = (attrib.value >> 16) & 0xffff;
641
642   return TRUE;
643 }
644
645 guint32
646 gst_va_encoder_get_rate_control_mode (GstVaEncoder * self,
647     VAProfile profile, VAEntrypoint entrypoint)
648 {
649   VAStatus status;
650   VADisplay dpy;
651   VAConfigAttrib attrib = {.type = VAConfigAttribRateControl };
652
653   g_return_val_if_fail (GST_IS_VA_ENCODER (self), 0);
654
655   if (profile == VAProfileNone)
656     return 0;
657
658   dpy = gst_va_display_get_va_dpy (self->display);
659   status = vaGetConfigAttributes (dpy, profile, entrypoint, &attrib, 1);
660   if (status != VA_STATUS_SUCCESS) {
661     GST_WARNING_OBJECT (self, "Failed to query rate control mode: %s",
662         vaErrorStr (status));
663     return 0;
664   }
665
666   if (attrib.value == VA_ATTRIB_NOT_SUPPORTED) {
667     GST_WARNING_OBJECT (self, "Driver does not support any rate control modes");
668     return 0;
669   }
670
671   return attrib.value;
672 }
673
674 guint32
675 gst_va_encoder_get_quality_level (GstVaEncoder * self,
676     VAProfile profile, VAEntrypoint entrypoint)
677 {
678   VAStatus status;
679   VADisplay dpy;
680   VAConfigAttrib attrib = {.type = VAConfigAttribEncQualityRange };
681
682   g_return_val_if_fail (GST_IS_VA_ENCODER (self), 0);
683
684   if (profile == VAProfileNone)
685     return 0;
686
687   dpy = gst_va_display_get_va_dpy (self->display);
688   status = vaGetConfigAttributes (dpy, profile, entrypoint, &attrib, 1);
689   if (status != VA_STATUS_SUCCESS) {
690     GST_WARNING_OBJECT (self, "Failed to query the quality level: %s",
691         vaErrorStr (status));
692     return 0;
693   }
694
695   if (attrib.value == VA_ATTRIB_NOT_SUPPORTED) {
696     GST_WARNING_OBJECT (self, "Driver does not support quality attribute");
697     return 0;
698   }
699
700   return attrib.value;
701 }
702
703 gboolean
704 gst_va_encoder_has_trellis (GstVaEncoder * self,
705     VAProfile profile, VAEntrypoint entrypoint)
706 {
707   VAStatus status;
708   VADisplay dpy;
709   VAConfigAttrib attrib = {.type = VAConfigAttribEncQuantization };
710
711   g_return_val_if_fail (GST_IS_VA_ENCODER (self), FALSE);
712
713   if (profile == VAProfileNone)
714     return FALSE;
715
716   dpy = gst_va_display_get_va_dpy (self->display);
717   status = vaGetConfigAttributes (dpy, profile, entrypoint, &attrib, 1);
718   if (status != VA_STATUS_SUCCESS) {
719     GST_WARNING_OBJECT (self, "Failed to query the trellis: %s",
720         vaErrorStr (status));
721     return FALSE;
722   }
723
724   if (attrib.value == VA_ATTRIB_NOT_SUPPORTED) {
725     GST_WARNING_OBJECT (self, "Driver does not support trellis");
726     return FALSE;
727   }
728
729   return attrib.value & VA_ENC_QUANTIZATION_TRELLIS_SUPPORTED;
730 }
731
732 guint32
733 gst_va_encoder_get_rtformat (GstVaEncoder * self,
734     VAProfile profile, VAEntrypoint entrypoint)
735 {
736   VAStatus status;
737   VADisplay dpy;
738   VAConfigAttrib attrib = {.type = VAConfigAttribRTFormat };
739
740   if (profile == VAProfileNone)
741     return 0;
742
743   dpy = gst_va_display_get_va_dpy (self->display);
744   status = vaGetConfigAttributes (dpy, profile, entrypoint, &attrib, 1);
745   if (status != VA_STATUS_SUCCESS) {
746     GST_ERROR_OBJECT (self, "Failed to query rt format: %s",
747         vaErrorStr (status));
748     return 0;
749   }
750
751   if (attrib.value == VA_ATTRIB_NOT_SUPPORTED) {
752     GST_WARNING_OBJECT (self, "Driver does not support any rt format");
753     return 0;
754   }
755
756   return attrib.value;
757 }
758
759 guint32
760 gst_va_encoder_get_packed_headers (GstVaEncoder * self, VAProfile profile,
761     VAEntrypoint entrypoint)
762 {
763   VAStatus status;
764   VADisplay dpy;
765   VAConfigAttrib attrib = {.type = VAConfigAttribEncPackedHeaders };
766
767   if (profile == VAProfileNone)
768     return 0;
769
770   dpy = gst_va_display_get_va_dpy (self->display);
771   status = vaGetConfigAttributes (dpy, profile, entrypoint, &attrib, 1);
772   if (status != VA_STATUS_SUCCESS) {
773     GST_ERROR_OBJECT (self, "Failed to query packed headers: %s",
774         vaErrorStr (status));
775     return 0;
776   }
777
778   if (attrib.value == VA_ATTRIB_NOT_SUPPORTED) {
779     GST_WARNING_OBJECT (self, "Driver does not support any packed headers");
780     return 0;
781   }
782
783   return attrib.value;
784 }
785
786 /* Add packed header such as SPS, PPS, SEI, etc. If adding slice header,
787    it is attached to the last slice parameter. */
788 gboolean
789 gst_va_encoder_add_packed_header (GstVaEncoder * self, GstVaEncodePicture * pic,
790     gint type, gpointer data, gsize size_in_bits, gboolean has_emulation_bytes)
791 {
792   VABufferID buffer;
793   VAEncPackedHeaderParameterBuffer param = {
794     .type = type,
795     .bit_length = size_in_bits,
796     .has_emulation_bytes = has_emulation_bytes,
797   };
798
799   g_return_val_if_fail (GST_IS_VA_ENCODER (self), FALSE);
800   g_return_val_if_fail (self->context != VA_INVALID_ID, FALSE);
801   g_return_val_if_fail (pic && data && size_in_bits > 0, FALSE);
802   g_return_val_if_fail (type >= VAEncPackedHeaderSequence
803       && type <= VAEncPackedHeaderRawData, FALSE);
804
805   if (!gst_va_encoder_is_open (self)) {
806     GST_ERROR_OBJECT (self, "encoder has not been opened yet");
807     return FALSE;
808   }
809
810   buffer = _create_buffer (self, VAEncPackedHeaderParameterBufferType, &param,
811       sizeof (param));
812   if (buffer == VA_INVALID_ID)
813     return FALSE;
814
815   g_array_append_val (pic->params, buffer);
816
817   buffer = _create_buffer (self, VAEncPackedHeaderDataBufferType, data,
818       (size_in_bits + 7) / 8);
819   if (buffer == VA_INVALID_ID)
820     return FALSE;
821
822   g_array_append_val (pic->params, buffer);
823
824   return TRUE;
825 }
826
827 gboolean
828 gst_va_encoder_add_param (GstVaEncoder * self, GstVaEncodePicture * pic,
829     VABufferType type, gpointer data, gsize size)
830 {
831   VABufferID buffer;
832
833   g_return_val_if_fail (GST_IS_VA_ENCODER (self), FALSE);
834   g_return_val_if_fail (self->context != VA_INVALID_ID, FALSE);
835   g_return_val_if_fail (pic && data && size > 0, FALSE);
836
837   if (!gst_va_encoder_is_open (self)) {
838     GST_ERROR_OBJECT (self, "encoder has not been opened yet");
839     return FALSE;
840   }
841
842   buffer = _create_buffer (self, type, data, size);
843   if (buffer == VA_INVALID_ID)
844     return FALSE;
845
846   g_array_append_val (pic->params, buffer);
847
848   return TRUE;
849 }
850
851 GArray *
852 gst_va_encoder_get_surface_formats (GstVaEncoder * self)
853 {
854   g_return_val_if_fail (GST_IS_VA_ENCODER (self), NULL);
855
856   if (!gst_va_encoder_is_open (self))
857     return NULL;
858
859   return _get_surface_formats (self->display, self->config);
860 }
861
862 static gboolean
863 _get_codec_caps (GstVaEncoder * self)
864 {
865   GstCaps *sinkpad_caps = NULL, *srcpad_caps = NULL;
866
867   if (!gst_va_encoder_is_open (self)
868       && GST_IS_VA_DISPLAY_WRAPPED (self->display)) {
869     if (gst_va_caps_from_profiles (self->display, self->available_profiles,
870             self->entrypoint, &sinkpad_caps, &srcpad_caps)) {
871       gst_caps_replace (&self->sinkpad_caps, sinkpad_caps);
872       gst_caps_replace (&self->srcpad_caps, srcpad_caps);
873       gst_caps_unref (srcpad_caps);
874       gst_caps_unref (sinkpad_caps);
875
876       return TRUE;
877     }
878   }
879
880   return FALSE;
881 }
882
883 GstCaps *
884 gst_va_encoder_get_sinkpad_caps (GstVaEncoder * self)
885 {
886   GstCaps *sinkpad_caps = NULL;
887
888   g_return_val_if_fail (GST_IS_VA_ENCODER (self), FALSE);
889
890   if (g_atomic_pointer_get (&self->sinkpad_caps))
891     return gst_caps_ref (self->sinkpad_caps);
892
893   if (_get_codec_caps (self))
894     return gst_caps_ref (self->sinkpad_caps);
895
896   if (gst_va_encoder_is_open (self)) {
897     sinkpad_caps = gst_va_create_raw_caps_from_config (self->display,
898         self->config);
899     gst_caps_replace (&self->sinkpad_caps, sinkpad_caps);
900     gst_caps_unref (sinkpad_caps);
901
902     return gst_caps_ref (self->sinkpad_caps);
903   }
904
905   return NULL;
906 }
907
908 GstCaps *
909 gst_va_encoder_get_srcpad_caps (GstVaEncoder * self)
910 {
911   g_return_val_if_fail (GST_IS_VA_ENCODER (self), FALSE);
912
913   if (g_atomic_pointer_get (&self->srcpad_caps))
914     return gst_caps_ref (self->srcpad_caps);
915
916   if (_get_codec_caps (self))
917     return gst_caps_ref (self->srcpad_caps);
918
919   if (gst_va_encoder_is_open (self)) {
920     VAProfile profile;
921     VAEntrypoint entrypoint;
922     GstCaps *caps;
923
924     GST_OBJECT_LOCK (self);
925     profile = self->profile;
926     entrypoint = self->entrypoint;
927     GST_OBJECT_UNLOCK (self);
928
929     caps = gst_va_create_coded_caps (self->display, profile, entrypoint, NULL);
930     if (caps) {
931       gst_caps_replace (&self->srcpad_caps, caps);
932       return gst_caps_ref (self->srcpad_caps);
933     }
934   }
935
936   return NULL;
937 }
938
939 static gboolean
940 _destroy_all_buffers (GstVaEncodePicture * pic)
941 {
942   VABufferID buffer;
943   guint i;
944   gboolean ret = TRUE;
945
946   g_return_val_if_fail (GST_IS_VA_DISPLAY (pic->display), FALSE);
947
948   for (i = 0; i < pic->params->len; i++) {
949     buffer = g_array_index (pic->params, VABufferID, i);
950     ret &= _destroy_buffer (pic->display, buffer);
951   }
952   pic->params = g_array_set_size (pic->params, 0);
953
954   return ret;
955 }
956
957 gboolean
958 gst_va_encoder_encode (GstVaEncoder * self, GstVaEncodePicture * pic)
959 {
960   VADisplay dpy;
961   VAStatus status;
962   VASurfaceID surface;
963   VAContextID context;
964   gboolean ret = FALSE;
965
966   g_return_val_if_fail (pic, FALSE);
967
968   GST_OBJECT_LOCK (self);
969
970   if (!_is_open_unlocked (self)) {
971     GST_OBJECT_UNLOCK (self);
972     GST_ERROR_OBJECT (self, "encoder has not been opened yet");
973     return FALSE;
974   }
975
976   context = self->context;
977   GST_OBJECT_UNLOCK (self);
978
979   surface = gst_va_encode_picture_get_raw_surface (pic);
980   if (surface == VA_INVALID_ID) {
981     GST_ERROR_OBJECT (self, "Encode picture without valid raw surface");
982     goto bail;
983   }
984
985   GST_TRACE_OBJECT (self, "Encode the surface %#x", surface);
986
987   dpy = gst_va_display_get_va_dpy (self->display);
988
989   status = vaBeginPicture (dpy, context, surface);
990   if (status != VA_STATUS_SUCCESS) {
991     GST_WARNING_OBJECT (self, "vaBeginPicture: %s", vaErrorStr (status));
992     goto bail;
993   }
994
995   if (pic->params->len > 0) {
996     status = vaRenderPicture (dpy, context, (VABufferID *) pic->params->data,
997         pic->params->len);
998     if (status != VA_STATUS_SUCCESS) {
999       GST_WARNING_OBJECT (self, "vaRenderPicture: %s", vaErrorStr (status));
1000       goto fail_end_pic;
1001     }
1002   }
1003
1004   status = vaEndPicture (dpy, context);
1005   ret = (status == VA_STATUS_SUCCESS);
1006   if (!ret)
1007     GST_WARNING_OBJECT (self, "vaEndPicture: %s", vaErrorStr (status));
1008
1009 bail:
1010   _destroy_all_buffers (pic);
1011
1012   return ret;
1013
1014 fail_end_pic:
1015   {
1016     _destroy_all_buffers (pic);
1017     status = vaEndPicture (dpy, context);
1018     ret = FALSE;
1019     goto bail;
1020   }
1021 }
1022
1023 VASurfaceID
1024 gst_va_encode_picture_get_reconstruct_surface (GstVaEncodePicture * pic)
1025 {
1026   g_return_val_if_fail (pic, VA_INVALID_ID);
1027   g_return_val_if_fail (pic->reconstruct_buffer, VA_INVALID_ID);
1028
1029   return gst_va_buffer_get_surface (pic->reconstruct_buffer);
1030 }
1031
1032 VASurfaceID
1033 gst_va_encode_picture_get_raw_surface (GstVaEncodePicture * pic)
1034 {
1035   g_return_val_if_fail (pic, VA_INVALID_ID);
1036   g_return_val_if_fail (pic->raw_buffer, VA_INVALID_ID);
1037
1038   return gst_va_buffer_get_surface (pic->raw_buffer);
1039 }
1040
1041 GstVaEncodePicture *
1042 gst_va_encode_picture_new (GstVaEncoder * self, GstBuffer * raw_buffer)
1043 {
1044   GstVaEncodePicture *pic;
1045   VABufferID coded_buffer;
1046   VADisplay dpy;
1047   VAStatus status;
1048   gint codedbuf_size;
1049   GstBufferPool *recon_pool = NULL;
1050   GstBuffer *reconstruct_buffer = NULL;
1051   GstFlowReturn ret;
1052   GstBufferPoolAcquireParams buffer_pool_params = {
1053     .flags = GST_BUFFER_POOL_ACQUIRE_FLAG_DONTWAIT,
1054   };
1055
1056   g_return_val_if_fail (self && GST_IS_VA_ENCODER (self), NULL);
1057   g_return_val_if_fail (raw_buffer && GST_IS_BUFFER (raw_buffer), NULL);
1058
1059   GST_OBJECT_LOCK (self);
1060
1061   if (!_is_open_unlocked (self)) {
1062     GST_OBJECT_UNLOCK (self);
1063     GST_ERROR_OBJECT (self, "encoder has not been opened yet");
1064     return NULL;
1065   }
1066
1067   if (self->codedbuf_size <= 0) {
1068     GST_ERROR_OBJECT (self, "codedbuf_size: %d, is invalid",
1069         self->codedbuf_size);
1070     GST_OBJECT_UNLOCK (self);
1071     return NULL;
1072   }
1073   codedbuf_size = self->codedbuf_size;
1074
1075   recon_pool = gst_object_ref (self->recon_pool);
1076
1077   GST_OBJECT_UNLOCK (self);
1078
1079   ret = gst_buffer_pool_acquire_buffer (recon_pool, &reconstruct_buffer,
1080       &buffer_pool_params);
1081   gst_clear_object (&recon_pool);
1082
1083   if (ret != GST_FLOW_OK) {
1084     GST_ERROR_OBJECT (self, "Failed to create the reconstruct picture");
1085     gst_clear_buffer (&reconstruct_buffer);
1086     return NULL;
1087   }
1088
1089   dpy = gst_va_display_get_va_dpy (self->display);
1090   status = vaCreateBuffer (dpy, self->context, VAEncCodedBufferType,
1091       codedbuf_size, 1, NULL, &coded_buffer);
1092   if (status != VA_STATUS_SUCCESS) {
1093     GST_ERROR_OBJECT (self, "vaCreateBuffer: %s", vaErrorStr (status));
1094     gst_clear_buffer (&reconstruct_buffer);
1095     return NULL;
1096   }
1097
1098   pic = g_slice_new (GstVaEncodePicture);
1099   pic->raw_buffer = gst_buffer_ref (raw_buffer);
1100   pic->reconstruct_buffer = reconstruct_buffer;
1101   pic->display = gst_object_ref (self->display);
1102   pic->coded_buffer = coded_buffer;
1103
1104   pic->params = g_array_sized_new (FALSE, FALSE, sizeof (VABufferID), 8);
1105
1106   return pic;
1107 }
1108
1109 void
1110 gst_va_encode_picture_free (GstVaEncodePicture * pic)
1111 {
1112   g_return_if_fail (pic);
1113
1114   _destroy_all_buffers (pic);
1115
1116   if (pic->coded_buffer != VA_INVALID_ID)
1117     _destroy_buffer (pic->display, pic->coded_buffer);
1118
1119   gst_buffer_unref (pic->raw_buffer);
1120   gst_buffer_unref (pic->reconstruct_buffer);
1121
1122   g_clear_pointer (&pic->params, g_array_unref);
1123   gst_clear_object (&pic->display);
1124
1125   g_slice_free (GstVaEncodePicture, pic);
1126 }
1127
1128 /**
1129  * GstVaEncoderRateControl:
1130  *
1131  * Since: 1.22
1132  */
1133 GType
1134 gst_va_encoder_rate_control_get_type (void)
1135 {
1136   static gsize type = 0;
1137   static const GEnumValue values[] = {
1138     {VA_RC_CBR, "Constant Bitrate", "cbr"},
1139     {VA_RC_VBR, "Variable Bitrate", "vbr"},
1140     {VA_RC_VCM, "Video Conferencing Mode (Non HRD compliant)", "vcm"},
1141     {VA_RC_CQP, "Constant Quantizer", "cqp"},
1142     /* {VA_RC_VBR_CONSTRAINED, "VBR with peak rate higher than average bitrate", */
1143     /*  "vbr-constrained"}, */
1144     /* {VA_RC_ICQ, "Intelligent Constant Quality", "icq"}, */
1145     /* {VA_RC_MB, "Macroblock based rate control", "mb"}, */
1146     /* {VA_RC_CFS, "Constant Frame Size", "cfs"}, */
1147     /* {VA_RC_PARALLEL, "Parallel BRC", "parallel"}, */
1148     /* {VA_RC_QVBR, "Quality defined VBR", "qvbr"}, */
1149     /* {VA_RC_AVBR, "Average VBR", "avbr"}, */
1150     {0, NULL, NULL}
1151   };
1152
1153   if (g_once_init_enter (&type)) {
1154     GType _type = g_enum_register_static ("GstVaEncoderRateControl", values);
1155     g_once_init_leave (&type, _type);
1156   }
1157
1158   return type;
1159 }