2 * Copyright (C) 2021 Intel Corporation
3 * Author: He Junyan <junyan.he@intel.com>
4 * Author: Víctor Jáquez <vjaquez@igalia.com>
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.
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.
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.
26 #include "gstvaencoder.h"
28 #include <gst/va/gstvavideoformat.h>
30 #include "gstvacaps.h"
31 #include "gstvaprofile.h"
32 #include "gstvadisplay_priv.h"
39 GArray *available_profiles;
41 GstCaps *sinkpad_caps;
42 GstVaDisplay *display;
46 VAEntrypoint entrypoint;
52 GstBufferPool *recon_pool;
55 GST_DEBUG_CATEGORY_STATIC (gst_va_encoder_debug);
56 #define GST_CAT_DEFAULT gst_va_encoder_debug
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,
75 static GParamSpec *g_properties[N_PROPERTIES];
78 _destroy_buffer (GstVaDisplay * display, VABufferID buffer)
82 VADisplay dpy = gst_va_display_get_va_dpy (display);
84 status = vaDestroyBuffer (dpy, buffer);
85 if (status != VA_STATUS_SUCCESS) {
87 GST_WARNING ("Failed to destroy the buffer: %s", vaErrorStr (status));
94 _create_buffer (GstVaEncoder * self, gint type, gpointer data, gsize size)
97 VADisplay dpy = gst_va_display_get_va_dpy (self->display);
101 GST_OBJECT_LOCK (self);
102 context = self->context;
103 GST_OBJECT_UNLOCK (self);
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;
116 gst_va_encoder_set_property (GObject * object, guint prop_id,
117 const GValue * value, GParamSpec * pspec)
119 GstVaEncoder *self = GST_VA_ENCODER (object);
121 GST_OBJECT_LOCK (self);
125 g_assert (!self->display);
126 self->display = g_value_dup_object (value);
129 case PROP_ENTRYPOINT:{
130 self->entrypoint = g_value_get_int (value);
134 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
138 GST_OBJECT_UNLOCK (self);
142 gst_va_encoder_get_property (GObject * object, guint prop_id, GValue * value,
145 GstVaEncoder *self = GST_VA_ENCODER (object);
147 GST_OBJECT_LOCK (self);
151 g_value_set_object (value, self->display);
154 g_value_set_int (value, self->profile);
156 case PROP_ENTRYPOINT:
157 g_value_set_int (value, self->entrypoint);
160 g_value_set_uint (value, self->rt_format);
163 g_value_set_int (value, self->coded_width);
166 g_value_set_int (value, self->coded_height);
168 case PROP_CODED_BUF_SIZE:
169 g_value_set_int (value, self->codedbuf_size);
172 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
176 GST_OBJECT_UNLOCK (self);
180 gst_va_encoder_init (GstVaEncoder * self)
182 self->profile = VAProfileNone;
183 self->config = VA_INVALID_ID;
187 gst_va_encoder_reset (GstVaEncoder * self)
189 self->profile = VAProfileNone;
190 self->config = VA_INVALID_ID;
191 self->context = VA_INVALID_ID;
193 self->coded_width = 0;
194 self->coded_height = 0;
195 self->codedbuf_size = 0;
198 static inline gboolean
199 _is_open_unlocked (GstVaEncoder * self)
201 return (self->config != VA_INVALID_ID && self->profile != VAProfileNone);
205 gst_va_encoder_is_open (GstVaEncoder * self)
209 g_return_val_if_fail (GST_IS_VA_ENCODER (self), FALSE);
211 GST_OBJECT_LOCK (self);
212 ret = _is_open_unlocked (self);
213 GST_OBJECT_UNLOCK (self);
218 gst_va_encoder_close (GstVaEncoder * self)
222 VAConfigID config = VA_INVALID_ID;
223 VAContextID context = VA_INVALID_ID;
224 GstBufferPool *recon_pool = NULL;
226 g_return_val_if_fail (GST_IS_VA_ENCODER (self), FALSE);
228 GST_OBJECT_LOCK (self);
229 if (!_is_open_unlocked (self)) {
230 GST_OBJECT_UNLOCK (self);
234 config = self->config;
235 context = self->context;
237 recon_pool = self->recon_pool;
238 self->recon_pool = NULL;
240 gst_va_encoder_reset (self);
241 GST_OBJECT_UNLOCK (self);
243 gst_buffer_pool_set_active (recon_pool, FALSE);
244 g_clear_pointer (&recon_pool, gst_object_unref);
246 dpy = gst_va_display_get_va_dpy (self->display);
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));
254 status = vaDestroyConfig (dpy, config);
255 if (status != VA_STATUS_SUCCESS)
256 GST_ERROR_OBJECT (self, "vaDestroyConfig: %s", vaErrorStr (status));
258 gst_caps_replace (&self->srcpad_caps, NULL);
259 gst_caps_replace (&self->sinkpad_caps, NULL);
265 _get_surface_formats (GstVaDisplay * display, VAConfigID config)
268 GstVideoFormat format;
269 VASurfaceAttrib *attribs;
270 guint i, attrib_count;
272 attribs = gst_va_get_surface_attribs (display, config, &attrib_count);
276 formats = g_array_new (FALSE, FALSE, sizeof (GstVideoFormat));
278 for (i = 0; i < attrib_count; i++) {
279 if (attribs[i].value.type != VAGenericValueTypeInteger)
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);
294 if (formats->len == 0) {
295 g_array_unref (formats);
302 static GstBufferPool *
303 _create_reconstruct_pool (GstVaDisplay * display, GArray * surface_formats,
304 GstVideoFormat format, gint coded_width, gint coded_height,
307 GstAllocator *allocator = NULL;
308 guint usage_hint = VA_SURFACE_ATTRIB_USAGE_HINT_ENCODER;
310 GstAllocationParams params = { 0, };
313 GstCaps *caps = NULL;
315 gst_video_info_set_format (&info, format, coded_width, coded_height);
317 size = GST_VIDEO_INFO_SIZE (&info);
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));
323 allocator = gst_va_allocator_new (display, surface_formats);
325 gst_allocation_params_init (¶ms);
327 pool = gst_va_pool_new_with_config (caps, size, 0, max_buffers, usage_hint,
328 GST_VA_FEATURE_AUTO, allocator, ¶ms);
330 gst_clear_object (&allocator);
331 gst_clear_caps (&caps);
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)
343 VAConfigAttrib attribs[3] = {
344 { .type = VAConfigAttribRTFormat, .value = rt_format, },
347 VAConfigID config = VA_INVALID_ID;
348 VAContextID context = VA_INVALID_ID;
350 GArray *surface_formats = NULL;
352 GstBufferPool *recon_pool = NULL;
353 guint attrib_idx = 1;
355 g_return_val_if_fail (GST_IS_VA_ENCODER (self), FALSE);
356 g_return_val_if_fail (codedbuf_size > 0, FALSE);
358 if (gst_va_encoder_is_open (self))
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);
367 if (rc_ctrl != VA_RC_NONE) {
368 attribs[attrib_idx].type = VAConfigAttribRateControl;
369 attribs[attrib_idx].value = rc_ctrl;
373 if (packed_headers > 0) {
374 attribs[attrib_idx].type = VAConfigAttribEncPackedHeaders;
375 attribs[attrib_idx].value = packed_headers;
379 dpy = gst_va_display_get_va_dpy (self->display);
381 status = vaCreateConfig (dpy, profile, self->entrypoint, attribs, attrib_idx,
383 if (status != VA_STATUS_SUCCESS) {
384 GST_ERROR_OBJECT (self, "vaCreateConfig: %s", vaErrorStr (status));
388 surface_formats = _get_surface_formats (self->display, config);
389 if (!surface_formats) {
390 GST_ERROR_OBJECT (self, "Failed to get surface formats");
394 recon_pool = _create_reconstruct_pool (self->display, surface_formats,
395 video_format, coded_width, coded_height, max_reconstruct_surfaces);
397 GST_ERROR_OBJECT (self, "Failed to create reconstruct pool");
400 gst_buffer_pool_set_active (recon_pool, TRUE);
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));
409 GST_OBJECT_LOCK (self);
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);
421 GST_OBJECT_UNLOCK (self);
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);
430 g_clear_pointer (&recon_pool, gst_object_unref);
432 if (config != VA_INVALID_ID)
433 vaDestroyConfig (dpy, config);
435 if (context != VA_INVALID_ID)
436 vaDestroyContext (dpy, context);
442 gst_va_encoder_dispose (GObject * object)
444 GstVaEncoder *self = GST_VA_ENCODER (object);
446 gst_va_encoder_close (self);
448 g_clear_pointer (&self->available_profiles, g_array_unref);
449 gst_clear_object (&self->display);
451 G_OBJECT_CLASS (parent_class)->dispose (object);
455 gst_va_encoder_class_init (GstVaEncoderClass * klass)
457 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
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;
463 g_properties[PROP_DISPLAY] =
464 g_param_spec_object ("display", "GstVaDisplay", "GstVaDisplay object",
466 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
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);
473 g_properties[PROP_ENTRYPOINT] =
474 g_param_spec_int ("va-entrypoint", "VAEntrypoint", "VA Entrypoint",
476 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
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);
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);
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);
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);
498 g_object_class_install_properties (gobject_class, N_PROPERTIES, g_properties);
502 gst_va_encoder_initialize (GstVaEncoder * self, guint32 codec)
504 if (self->available_profiles)
507 self->available_profiles =
508 gst_va_display_get_profiles (self->display, codec, self->entrypoint);
510 if (!self->available_profiles)
513 if (self->available_profiles->len == 0) {
514 g_clear_pointer (&self->available_profiles, g_array_unref);
522 gst_va_encoder_new (GstVaDisplay * display, guint32 codec,
523 VAEntrypoint entrypoint)
527 g_return_val_if_fail (GST_IS_VA_DISPLAY (display), NULL);
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);
538 gst_va_encoder_get_reconstruct_pool_config (GstVaEncoder * self,
539 GstCaps ** caps, guint * max_surfaces)
541 GstStructure *config;
544 g_return_val_if_fail (GST_IS_VA_ENCODER (self), FALSE);
546 if (!gst_va_encoder_is_open (self))
549 if (!self->recon_pool)
552 config = gst_buffer_pool_get_config (self->recon_pool);
553 ret = gst_buffer_pool_config_get_params (config, caps, NULL, NULL,
555 gst_structure_free (config);
560 gst_va_encoder_has_profile (GstVaEncoder * self, VAProfile profile)
565 g_return_val_if_fail (GST_IS_VA_ENCODER (self), FALSE);
567 for (i = 0; i < self->available_profiles->len; i++) {
568 p = g_array_index (self->available_profiles, VAProfile, i);
577 gst_va_encoder_get_max_slice_num (GstVaEncoder * self,
578 VAProfile profile, VAEntrypoint entrypoint)
582 VAConfigAttrib attrib = {.type = VAConfigAttribEncMaxSlices };
584 g_return_val_if_fail (GST_IS_VA_ENCODER (self), -1);
586 if (profile == VAProfileNone)
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));
597 if (attrib.value == VA_ATTRIB_NOT_SUPPORTED) {
598 GST_WARNING_OBJECT (self, "Driver does not support encoding picture as "
607 gst_va_encoder_get_slice_structure (GstVaEncoder * self,
608 VAProfile profile, VAEntrypoint entrypoint)
612 VAConfigAttrib attrib = {.type = VAConfigAttribEncSliceStructure };
614 g_return_val_if_fail (GST_IS_VA_ENCODER (self), 0);
616 if (profile == VAProfileNone)
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));
627 if (attrib.value == VA_ATTRIB_NOT_SUPPORTED) {
628 GST_WARNING_OBJECT (self, "Driver does not support slice structure");
636 gst_va_encoder_get_max_num_reference (GstVaEncoder * self,
637 VAProfile profile, VAEntrypoint entrypoint,
638 guint32 * list0, guint32 * list1)
642 VAConfigAttrib attrib = {.type = VAConfigAttribEncMaxRefFrames };
644 g_return_val_if_fail (GST_IS_VA_ENCODER (self), FALSE);
646 if (profile == VAProfileNone)
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));
657 if (attrib.value == VA_ATTRIB_NOT_SUPPORTED) {
667 *list0 = attrib.value & 0xffff;
669 *list1 = (attrib.value >> 16) & 0xffff;
675 gst_va_encoder_get_prediction_direction (GstVaEncoder * self,
676 VAProfile profile, VAEntrypoint entrypoint)
678 #if VA_CHECK_VERSION(1,9,0)
681 VAConfigAttrib attrib = {.type = VAConfigAttribPredictionDirection };
683 g_return_val_if_fail (GST_IS_VA_ENCODER (self), 0);
685 if (profile == VAProfileNone)
688 if (entrypoint != self->entrypoint)
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));
699 if (attrib.value == VA_ATTRIB_NOT_SUPPORTED) {
700 GST_WARNING_OBJECT (self, "Driver does not support query"
701 " prediction direction");
705 return attrib.value & (VA_PREDICTION_DIRECTION_PREVIOUS |
706 VA_PREDICTION_DIRECTION_FUTURE | VA_PREDICTION_DIRECTION_BI_NOT_EMPTY);
713 gst_va_encoder_get_rate_control_mode (GstVaEncoder * self,
714 VAProfile profile, VAEntrypoint entrypoint)
718 VAConfigAttrib attrib = {.type = VAConfigAttribRateControl };
720 g_return_val_if_fail (GST_IS_VA_ENCODER (self), 0);
722 if (profile == VAProfileNone)
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));
733 if (attrib.value == VA_ATTRIB_NOT_SUPPORTED) {
734 GST_WARNING_OBJECT (self, "Driver does not support any rate control modes");
742 gst_va_encoder_get_quality_level (GstVaEncoder * self,
743 VAProfile profile, VAEntrypoint entrypoint)
747 VAConfigAttrib attrib = {.type = VAConfigAttribEncQualityRange };
749 g_return_val_if_fail (GST_IS_VA_ENCODER (self), 0);
751 if (profile == VAProfileNone)
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));
762 if (attrib.value == VA_ATTRIB_NOT_SUPPORTED) {
763 GST_WARNING_OBJECT (self, "Driver does not support quality attribute");
771 gst_va_encoder_has_trellis (GstVaEncoder * self,
772 VAProfile profile, VAEntrypoint entrypoint)
776 VAConfigAttrib attrib = {.type = VAConfigAttribEncQuantization };
778 g_return_val_if_fail (GST_IS_VA_ENCODER (self), FALSE);
780 if (profile == VAProfileNone)
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));
791 if (attrib.value == VA_ATTRIB_NOT_SUPPORTED) {
792 GST_WARNING_OBJECT (self, "Driver does not support trellis");
796 return attrib.value & VA_ENC_QUANTIZATION_TRELLIS_SUPPORTED;
800 gst_va_encoder_has_tile (GstVaEncoder * self,
801 VAProfile profile, VAEntrypoint entrypoint)
805 VAConfigAttrib attrib = {.type = VAConfigAttribEncTileSupport };
807 g_return_val_if_fail (GST_IS_VA_ENCODER (self), FALSE);
809 if (profile == VAProfileNone)
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));
820 if (attrib.value == VA_ATTRIB_NOT_SUPPORTED) {
821 GST_WARNING_OBJECT (self, "Driver does not support tile");
825 return attrib.value > 0;
829 gst_va_encoder_get_rtformat (GstVaEncoder * self,
830 VAProfile profile, VAEntrypoint entrypoint)
834 VAConfigAttrib attrib = {.type = VAConfigAttribRTFormat };
836 if (profile == VAProfileNone)
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));
847 if (attrib.value == VA_ATTRIB_NOT_SUPPORTED) {
848 GST_WARNING_OBJECT (self, "Driver does not support any rt format");
856 gst_va_encoder_get_packed_headers (GstVaEncoder * self, VAProfile profile,
857 VAEntrypoint entrypoint, guint * packed_headers)
861 VAConfigAttrib attrib = {.type = VAConfigAttribEncPackedHeaders };
863 if (profile == VAProfileNone)
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));
874 if (attrib.value == VA_ATTRIB_NOT_SUPPORTED) {
875 GST_WARNING_OBJECT (self, "Driver does not support any packed headers");
880 *packed_headers = attrib.value;
884 /* Add packed header such as SPS, PPS, SEI, etc. If adding slice header,
885 it is attached to the last slice parameter. */
887 gst_va_encoder_add_packed_header (GstVaEncoder * self, GstVaEncodePicture * pic,
888 gint type, gpointer data, gsize size_in_bits, gboolean has_emulation_bytes)
891 VAEncPackedHeaderParameterBuffer param = {
893 .bit_length = size_in_bits,
894 .has_emulation_bytes = has_emulation_bytes,
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);
903 if (!gst_va_encoder_is_open (self)) {
904 GST_ERROR_OBJECT (self, "encoder has not been opened yet");
908 buffer = _create_buffer (self, VAEncPackedHeaderParameterBufferType, ¶m,
910 if (buffer == VA_INVALID_ID)
913 g_array_append_val (pic->params, buffer);
915 buffer = _create_buffer (self, VAEncPackedHeaderDataBufferType, data,
916 (size_in_bits + 7) / 8);
917 if (buffer == VA_INVALID_ID)
920 g_array_append_val (pic->params, buffer);
926 gst_va_encoder_add_param (GstVaEncoder * self, GstVaEncodePicture * pic,
927 VABufferType type, gpointer data, gsize size)
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);
935 if (!gst_va_encoder_is_open (self)) {
936 GST_ERROR_OBJECT (self, "encoder has not been opened yet");
940 buffer = _create_buffer (self, type, data, size);
941 if (buffer == VA_INVALID_ID)
944 g_array_append_val (pic->params, buffer);
950 gst_va_encoder_get_surface_formats (GstVaEncoder * self)
952 g_return_val_if_fail (GST_IS_VA_ENCODER (self), NULL);
954 if (!gst_va_encoder_is_open (self))
957 return _get_surface_formats (self->display, self->config);
961 _get_codec_caps (GstVaEncoder * self)
963 GstCaps *sinkpad_caps = NULL, *srcpad_caps = NULL;
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);
982 gst_va_encoder_get_sinkpad_caps (GstVaEncoder * self)
984 GstCaps *sinkpad_caps = NULL;
986 g_return_val_if_fail (GST_IS_VA_ENCODER (self), FALSE);
988 if (g_atomic_pointer_get (&self->sinkpad_caps))
989 return gst_caps_ref (self->sinkpad_caps);
991 if (_get_codec_caps (self))
992 return gst_caps_ref (self->sinkpad_caps);
994 if (gst_va_encoder_is_open (self)) {
995 sinkpad_caps = gst_va_create_raw_caps_from_config (self->display,
998 GST_WARNING_OBJECT (self, "Invalid configuration caps");
1001 gst_caps_replace (&self->sinkpad_caps, sinkpad_caps);
1002 gst_caps_unref (sinkpad_caps);
1004 return gst_caps_ref (self->sinkpad_caps);
1011 gst_va_encoder_get_srcpad_caps (GstVaEncoder * self)
1013 g_return_val_if_fail (GST_IS_VA_ENCODER (self), FALSE);
1015 if (g_atomic_pointer_get (&self->srcpad_caps))
1016 return gst_caps_ref (self->srcpad_caps);
1018 if (_get_codec_caps (self))
1019 return gst_caps_ref (self->srcpad_caps);
1021 if (gst_va_encoder_is_open (self)) {
1023 VAEntrypoint entrypoint;
1026 GST_OBJECT_LOCK (self);
1027 profile = self->profile;
1028 entrypoint = self->entrypoint;
1029 GST_OBJECT_UNLOCK (self);
1031 caps = gst_va_create_coded_caps (self->display, profile, entrypoint, NULL);
1033 gst_caps_replace (&self->srcpad_caps, caps);
1034 return gst_caps_ref (self->srcpad_caps);
1042 _destroy_all_buffers (GstVaEncodePicture * pic)
1046 gboolean ret = TRUE;
1048 g_return_val_if_fail (GST_IS_VA_DISPLAY (pic->display), FALSE);
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);
1054 pic->params = g_array_set_size (pic->params, 0);
1060 gst_va_encoder_encode (GstVaEncoder * self, GstVaEncodePicture * pic)
1064 VASurfaceID surface;
1065 VAContextID context;
1066 gboolean ret = FALSE;
1068 g_return_val_if_fail (pic, FALSE);
1070 GST_OBJECT_LOCK (self);
1072 if (!_is_open_unlocked (self)) {
1073 GST_OBJECT_UNLOCK (self);
1074 GST_ERROR_OBJECT (self, "encoder has not been opened yet");
1078 context = self->context;
1079 GST_OBJECT_UNLOCK (self);
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");
1087 GST_TRACE_OBJECT (self, "Encode the surface %#x", surface);
1089 dpy = gst_va_display_get_va_dpy (self->display);
1091 status = vaBeginPicture (dpy, context, surface);
1092 if (status != VA_STATUS_SUCCESS) {
1093 GST_WARNING_OBJECT (self, "vaBeginPicture: %s", vaErrorStr (status));
1097 if (pic->params->len > 0) {
1098 status = vaRenderPicture (dpy, context, (VABufferID *) pic->params->data,
1100 if (status != VA_STATUS_SUCCESS) {
1101 GST_WARNING_OBJECT (self, "vaRenderPicture: %s", vaErrorStr (status));
1106 status = vaEndPicture (dpy, context);
1107 ret = (status == VA_STATUS_SUCCESS);
1109 GST_WARNING_OBJECT (self, "vaEndPicture: %s", vaErrorStr (status));
1112 _destroy_all_buffers (pic);
1118 _destroy_all_buffers (pic);
1119 status = vaEndPicture (dpy, context);
1126 gst_va_encode_picture_get_reconstruct_surface (GstVaEncodePicture * pic)
1128 g_return_val_if_fail (pic, VA_INVALID_ID);
1129 g_return_val_if_fail (pic->reconstruct_buffer, VA_INVALID_ID);
1131 return gst_va_buffer_get_surface (pic->reconstruct_buffer);
1135 gst_va_encode_picture_get_raw_surface (GstVaEncodePicture * pic)
1137 g_return_val_if_fail (pic, VA_INVALID_ID);
1138 g_return_val_if_fail (pic->raw_buffer, VA_INVALID_ID);
1140 return gst_va_buffer_get_surface (pic->raw_buffer);
1143 GstVaEncodePicture *
1144 gst_va_encode_picture_new (GstVaEncoder * self, GstBuffer * raw_buffer)
1146 GstVaEncodePicture *pic;
1147 VABufferID coded_buffer;
1151 GstBufferPool *recon_pool = NULL;
1152 GstBuffer *reconstruct_buffer = NULL;
1154 GstBufferPoolAcquireParams buffer_pool_params = {
1155 .flags = GST_BUFFER_POOL_ACQUIRE_FLAG_DONTWAIT,
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);
1161 GST_OBJECT_LOCK (self);
1163 if (!_is_open_unlocked (self)) {
1164 GST_OBJECT_UNLOCK (self);
1165 GST_ERROR_OBJECT (self, "encoder has not been opened yet");
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);
1175 codedbuf_size = self->codedbuf_size;
1177 recon_pool = gst_object_ref (self->recon_pool);
1179 GST_OBJECT_UNLOCK (self);
1181 ret = gst_buffer_pool_acquire_buffer (recon_pool, &reconstruct_buffer,
1182 &buffer_pool_params);
1183 gst_clear_object (&recon_pool);
1185 if (ret != GST_FLOW_OK) {
1186 GST_ERROR_OBJECT (self, "Failed to create the reconstruct picture");
1187 gst_clear_buffer (&reconstruct_buffer);
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);
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;
1206 pic->params = g_array_sized_new (FALSE, FALSE, sizeof (VABufferID), 8);
1212 gst_va_encode_picture_free (GstVaEncodePicture * pic)
1214 g_return_if_fail (pic);
1216 _destroy_all_buffers (pic);
1218 if (pic->coded_buffer != VA_INVALID_ID)
1219 _destroy_buffer (pic->display, pic->coded_buffer);
1221 gst_buffer_unref (pic->raw_buffer);
1222 gst_buffer_unref (pic->reconstruct_buffer);
1224 g_clear_pointer (&pic->params, g_array_unref);
1225 gst_clear_object (&pic->display);
1227 g_slice_free (GstVaEncodePicture, pic);
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"}, */
1247 _guint32_cmp (gconstpointer a, gconstpointer b)
1249 return *((const guint32 *) a) - *((const guint32 *) b);
1253 gst_va_encoder_get_rate_control_enum (GstVaEncoder * self,
1254 GEnumValue ratectl[16])
1257 guint32 rc, rc_prev = 0;
1261 g_return_val_if_fail (GST_IS_VA_ENCODER (self), FALSE);
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);
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);
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);
1279 if (rcs->len == 0) {
1280 g_clear_pointer (&rcs, g_array_unref);
1284 g_array_sort (rcs, _guint32_cmp);
1286 for (i = 0; i < rcs->len; i++) {
1287 rc = g_array_index (rcs, guint32, i);
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];
1299 g_clear_pointer (&rcs, g_array_unref);
1303 ratectl[k] = (GEnumValue) { 0, NULL, NULL };