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"
29 #include "gstvaallocator.h"
30 #include "gstvapool.h"
31 #include "gstvacaps.h"
32 #include "gstvadisplay_priv.h"
33 #include "gstvavideoformat.h"
34 #include <gst/va/gstvadisplay_wrapped.h>
36 #define VA_ENTRYPOINT_FLAG(entry) (1U << G_PASTE(VAEntrypoint, entry))
38 typedef struct _GstVaProfileConfig GstVaProfileConfig;
39 typedef struct _GstVaPackedHeader GstVaPackedHeader;
40 typedef struct _GstVaEncSlice GstVaEncSlice;
41 typedef struct _GstVaEncReconstruct GstVaEncReconstruct;
43 struct _GstVaProfileConfig
46 guint32 entrypoints; /* bits map of GstVaapiEntrypoint */
53 GArray *available_profiles;
55 GstCaps *sinkpad_caps;
56 GstVaDisplay *display;
60 VAEntrypoint entrypoint;
66 GstBufferPool *recon_pool;
69 GST_DEBUG_CATEGORY_STATIC (gst_va_encoder_debug);
70 #define GST_CAT_DEFAULT gst_va_encoder_debug
72 #define gst_va_encoder_parent_class parent_class
73 G_DEFINE_TYPE_WITH_CODE (GstVaEncoder, gst_va_encoder, GST_TYPE_OBJECT,
74 GST_DEBUG_CATEGORY_INIT (gst_va_encoder_debug, "vaencoder", 0,
89 static GParamSpec *g_properties[N_PROPERTIES];
92 _destroy_buffer (GstVaDisplay * display, VABufferID buffer)
96 VADisplay dpy = gst_va_display_get_va_dpy (display);
98 status = vaDestroyBuffer (dpy, buffer);
99 if (status != VA_STATUS_SUCCESS) {
101 GST_WARNING ("Failed to destroy the buffer: %s", vaErrorStr (status));
108 _create_buffer (GstVaEncoder * self, gint type, gpointer data, gsize size)
111 VADisplay dpy = gst_va_display_get_va_dpy (self->display);
115 GST_OBJECT_LOCK (self);
116 context = self->context;
117 GST_OBJECT_UNLOCK (self);
119 dpy = gst_va_display_get_va_dpy (self->display);
120 status = vaCreateBuffer (dpy, context, type, size, 1, data, &buffer);
121 if (status != VA_STATUS_SUCCESS) {
122 GST_ERROR_OBJECT (self, "vaCreateBuffer: %s", vaErrorStr (status));
123 return VA_INVALID_ID;
130 gst_va_encoder_set_property (GObject * object, guint prop_id,
131 const GValue * value, GParamSpec * pspec)
133 GstVaEncoder *self = GST_VA_ENCODER (object);
135 GST_OBJECT_LOCK (self);
139 g_assert (!self->display);
140 self->display = g_value_dup_object (value);
144 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
148 GST_OBJECT_UNLOCK (self);
152 gst_va_encoder_get_property (GObject * object, guint prop_id, GValue * value,
155 GstVaEncoder *self = GST_VA_ENCODER (object);
157 GST_OBJECT_LOCK (self);
161 g_value_set_object (value, self->display);
164 g_value_set_int (value, self->profile);
166 case PROP_ENTRYPOINT:
167 g_value_set_int (value, self->entrypoint);
170 g_value_set_uint (value, self->rt_format);
173 g_value_set_int (value, self->coded_width);
176 g_value_set_int (value, self->coded_height);
178 case PROP_CODED_BUF_SIZE:
179 g_value_set_int (value, self->codedbuf_size);
182 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
186 GST_OBJECT_UNLOCK (self);
190 gst_va_encoder_init (GstVaEncoder * self)
192 self->profile = VAProfileNone;
193 self->entrypoint = 0;
194 self->config = VA_INVALID_ID;
195 self->context = VA_INVALID_ID;
197 self->coded_width = 0;
198 self->coded_height = 0;
199 self->codedbuf_size = 0;
200 g_clear_pointer (&self->recon_pool, gst_object_unref);
203 static inline gboolean
204 _is_open_unlocked (GstVaEncoder * self)
206 return (self->config != VA_INVALID_ID && self->profile != VAProfileNone);
210 gst_va_encoder_is_open (GstVaEncoder * self)
214 g_return_val_if_fail (GST_IS_VA_ENCODER (self), FALSE);
216 GST_OBJECT_LOCK (self);
217 ret = _is_open_unlocked (self);
218 GST_OBJECT_UNLOCK (self);
223 gst_va_encoder_close (GstVaEncoder * self)
227 VAConfigID config = VA_INVALID_ID;
228 VAContextID context = VA_INVALID_ID;
229 GstBufferPool *recon_pool = NULL;
231 g_return_val_if_fail (GST_IS_VA_ENCODER (self), FALSE);
233 GST_OBJECT_LOCK (self);
234 if (!_is_open_unlocked (self)) {
235 GST_OBJECT_UNLOCK (self);
239 config = self->config;
240 context = self->context;
242 recon_pool = self->recon_pool;
243 self->recon_pool = NULL;
245 gst_va_encoder_init (self);
246 GST_OBJECT_UNLOCK (self);
248 gst_buffer_pool_set_active (recon_pool, FALSE);
249 g_clear_pointer (&recon_pool, gst_object_unref);
251 dpy = gst_va_display_get_va_dpy (self->display);
253 if (context != VA_INVALID_ID) {
254 status = vaDestroyContext (dpy, context);
255 if (status != VA_STATUS_SUCCESS)
256 GST_ERROR_OBJECT (self, "vaDestroyContext: %s", vaErrorStr (status));
259 status = vaDestroyConfig (dpy, config);
260 if (status != VA_STATUS_SUCCESS)
261 GST_ERROR_OBJECT (self, "vaDestroyConfig: %s", vaErrorStr (status));
263 gst_caps_replace (&self->srcpad_caps, NULL);
264 gst_caps_replace (&self->sinkpad_caps, NULL);
270 _get_surface_formats (GstVaDisplay * display, VAConfigID config)
273 GstVideoFormat format;
274 VASurfaceAttrib *attribs;
275 guint i, attrib_count;
277 attribs = gst_va_get_surface_attribs (display, config, &attrib_count);
281 formats = g_array_new (FALSE, FALSE, sizeof (GstVideoFormat));
283 for (i = 0; i < attrib_count; i++) {
284 if (attribs[i].value.type != VAGenericValueTypeInteger)
286 switch (attribs[i].type) {
287 case VASurfaceAttribPixelFormat:
288 format = gst_va_video_format_from_va_fourcc (attribs[i].value.value.i);
289 if (format != GST_VIDEO_FORMAT_UNKNOWN)
290 g_array_append_val (formats, format);
299 if (formats->len == 0) {
300 g_array_unref (formats);
307 static GstBufferPool *
308 _create_reconstruct_pool (GstVaDisplay * display, GArray * surface_formats,
309 GstVideoFormat format, gint coded_width, gint coded_height, guint max_num)
311 GstAllocator *allocator = NULL;
312 guint usage_hint = VA_SURFACE_ATTRIB_USAGE_HINT_ENCODER;
314 GstAllocationParams params = { 0, };
317 GstCaps *caps = NULL;
319 gst_video_info_set_format (&info, format, coded_width, coded_height);
321 size = GST_VIDEO_INFO_SIZE (&info);
323 caps = gst_video_info_to_caps (&info);
324 gst_caps_set_features_simple (caps,
325 gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_VA));
327 allocator = gst_va_allocator_new (display, surface_formats);
329 if (!gst_va_allocator_set_format (allocator, &info, usage_hint)) {
330 gst_clear_object (&allocator);
331 gst_clear_caps (&caps);
335 gst_allocation_params_init (¶ms);
337 pool = gst_va_pool_new_with_config (caps, size, 1, max_num,
338 usage_hint, allocator, ¶ms);
340 gst_clear_object (&allocator);
341 gst_clear_caps (&caps);
347 gst_va_encoder_open (GstVaEncoder * self, VAProfile profile,
348 VAEntrypoint entrypoint, GstVideoFormat video_format, guint rt_format,
349 gint coded_width, gint coded_height, gint codedbuf_size,
350 guint reconstruct_buffer_num, guint rc_ctrl, guint32 packed_headers)
353 VAConfigAttrib attribs[3] = {
354 { .type = VAConfigAttribRTFormat, .value = rt_format, },
355 { .type = VAConfigAttribRateControl, .value = rc_ctrl, },
358 VAConfigID config = VA_INVALID_ID;
359 VAContextID context = VA_INVALID_ID;
361 GPtrArray *reconstruct_buffers = NULL;
362 GArray *surfaces = NULL;
363 GArray *surface_formats = NULL;
365 GstBufferPool *recon_pool = NULL;
366 guint i, attrib_idx = 2;
368 g_return_val_if_fail (GST_IS_VA_ENCODER (self), FALSE);
369 g_return_val_if_fail (reconstruct_buffer_num > 0, FALSE);
370 g_return_val_if_fail (codedbuf_size > 0, FALSE);
372 if (gst_va_encoder_is_open (self))
375 if (!gst_va_encoder_has_profile_and_entrypoint (self, profile, entrypoint)) {
376 GST_ERROR_OBJECT (self, "Unsupported profile: %d, entrypoint: %d",
377 profile, entrypoint);
381 if (packed_headers > 0) {
382 attribs[attrib_idx].type = VAConfigAttribEncPackedHeaders;
383 attribs[attrib_idx].value = packed_headers;
387 dpy = gst_va_display_get_va_dpy (self->display);
389 status = vaCreateConfig (dpy, profile, entrypoint, attribs, attrib_idx,
391 if (status != VA_STATUS_SUCCESS) {
392 GST_ERROR_OBJECT (self, "vaCreateConfig: %s", vaErrorStr (status));
396 surface_formats = _get_surface_formats (self->display, config);
397 if (!surface_formats) {
398 GST_ERROR_OBJECT (self, "Failed to get surface formats");
402 recon_pool = _create_reconstruct_pool (self->display, surface_formats,
403 video_format, coded_width, coded_height, reconstruct_buffer_num);
405 GST_ERROR_OBJECT (self, "Failed to create reconstruct pool");
408 gst_buffer_pool_set_active (recon_pool, TRUE);
410 /* Create VA surfaces list for vaCreateContext() */
411 surfaces = g_array_sized_new (FALSE, FALSE, sizeof (VASurfaceID),
412 reconstruct_buffer_num);
416 reconstruct_buffers = g_ptr_array_sized_new (reconstruct_buffer_num);
417 if (!reconstruct_buffers)
420 g_ptr_array_set_free_func (reconstruct_buffers,
421 (GDestroyNotify) gst_buffer_unref);
423 /* The encoder need to binding all reconstruct surface when create contex,
424 we have to allocate them all here. */
425 for (i = 0; i < reconstruct_buffer_num; i++) {
427 VASurfaceID surface_id;
429 GstBufferPoolAcquireParams buffer_pool_params = { 0, };
431 buffer_pool_params.flags = GST_BUFFER_POOL_ACQUIRE_FLAG_DONTWAIT;
432 ret = gst_buffer_pool_acquire_buffer (recon_pool, &buffer,
433 &buffer_pool_params);
434 if (ret != GST_FLOW_OK) {
435 GST_ERROR_OBJECT (self, "Failed to create the reconstruct picture.");
439 surface_id = gst_va_buffer_get_surface (buffer);
440 g_assert (surface_id != VA_INVALID_ID);
442 g_ptr_array_add (reconstruct_buffers, buffer);
443 g_array_append_val (surfaces, surface_id);
446 g_assert (surfaces->len == reconstruct_buffer_num);
448 status = vaCreateContext (dpy, config, coded_width, coded_height,
449 VA_PROGRESSIVE, (VASurfaceID *) surfaces->data, reconstruct_buffer_num,
451 if (status != VA_STATUS_SUCCESS) {
452 GST_ERROR_OBJECT (self, "vaCreateConfig: %s", vaErrorStr (status));
456 g_clear_pointer (&surfaces, g_array_unref);
457 g_clear_pointer (&reconstruct_buffers, g_ptr_array_unref);
459 GST_OBJECT_LOCK (self);
461 self->config = config;
462 self->context = context;
463 self->profile = profile;
464 self->entrypoint = entrypoint;
465 self->rt_format = rt_format;
466 self->coded_width = coded_width;
467 self->coded_height = coded_height;
468 self->codedbuf_size = codedbuf_size;
469 gst_object_replace ((GstObject **) & self->recon_pool,
470 (GstObject *) recon_pool);
472 GST_OBJECT_UNLOCK (self);
474 g_clear_pointer (&recon_pool, gst_object_unref);
475 /* now we should return now only this profile's caps */
476 gst_caps_replace (&self->srcpad_caps, NULL);
481 g_clear_pointer (&surfaces, g_array_unref);
482 g_clear_pointer (&reconstruct_buffers, g_ptr_array_unref);
483 g_clear_pointer (&recon_pool, gst_object_unref);
485 if (config == VA_INVALID_ID)
486 vaDestroyConfig (dpy, config);
488 if (context == VA_INVALID_ID)
489 vaDestroyContext (dpy, context);
495 gst_va_encoder_dispose (GObject * object)
497 GstVaEncoder *self = GST_VA_ENCODER (object);
499 gst_va_encoder_close (self);
501 g_clear_pointer (&self->available_profiles, g_array_unref);
502 gst_clear_object (&self->display);
504 G_OBJECT_CLASS (parent_class)->dispose (object);
508 gst_va_encoder_class_init (GstVaEncoderClass * klass)
510 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
512 gobject_class->set_property = gst_va_encoder_set_property;
513 gobject_class->get_property = gst_va_encoder_get_property;
514 gobject_class->dispose = gst_va_encoder_dispose;
516 g_properties[PROP_DISPLAY] =
517 g_param_spec_object ("display", "GstVaDisplay", "GstVADisplay object",
519 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
521 g_properties[PROP_PROFILE] =
522 g_param_spec_int ("va-profile", "VAProfile", "VA Profile",
523 VAProfileNone, 50, VAProfileNone,
524 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
526 g_properties[PROP_ENTRYPOINT] =
527 g_param_spec_int ("va-entrypoint", "VAEntrypoint", "VA Entrypoint",
528 0, 14, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
530 g_properties[PROP_CHROMA] =
531 g_param_spec_uint ("va-rt-format", "VARTFormat", "VA RT Fromat or chroma",
532 VA_RT_FORMAT_YUV420, VA_RT_FORMAT_PROTECTED, VA_RT_FORMAT_YUV420,
533 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
535 g_properties[PROP_WIDTH] =
536 g_param_spec_int ("coded-width", "coded-picture-width",
537 "coded picture width", 0, G_MAXINT, 0,
538 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
540 g_properties[PROP_HEIGHT] =
541 g_param_spec_int ("coded-height", "coded-picture-height",
542 "coded picture height", 0, G_MAXINT, 0,
543 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
545 g_properties[PROP_CODED_BUF_SIZE] =
546 g_param_spec_int ("coded-buf-size", "coded-buffer-size",
547 "coded buffer size", 0, G_MAXINT, 0,
548 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
550 g_object_class_install_properties (gobject_class, N_PROPERTIES, g_properties);
554 gst_va_encoder_initialize (GstVaEncoder * self, guint32 codec)
556 GArray *enc_profiles = NULL;
559 if (self->available_profiles)
562 enc_profiles = gst_va_display_get_profiles (self->display, codec,
563 VAEntrypointEncSlice);
568 self->available_profiles =
569 g_array_new (FALSE, FALSE, sizeof (GstVaProfileConfig));
572 for (i = 0; i < enc_profiles->len; i++) {
573 GstVaProfileConfig config;
575 config.profile = g_array_index (enc_profiles, VAProfile, i);
576 config.entrypoints = VA_ENTRYPOINT_FLAG (EncSlice);
577 g_array_append_val (self->available_profiles, config);
581 g_clear_pointer (&enc_profiles, g_array_unref);
583 if (self->available_profiles->len == 0)
590 gst_va_encoder_new (GstVaDisplay * display, guint32 codec)
594 g_return_val_if_fail (GST_IS_VA_DISPLAY (display), NULL);
596 self = g_object_new (GST_TYPE_VA_ENCODER, "display", display, NULL);
597 if (!gst_va_encoder_initialize (self, codec))
598 gst_clear_object (&self);
604 gst_va_encoder_has_profile_and_entrypoint (GstVaEncoder * self,
605 VAProfile profile, VAEntrypoint entrypoint)
607 GstVaProfileConfig *config;
610 g_return_val_if_fail (GST_IS_VA_ENCODER (self), FALSE);
612 if (profile == VAProfileNone)
615 for (i = 0; i < self->available_profiles->len; i++) {
616 config = &g_array_index (self->available_profiles, GstVaProfileConfig, i);
617 if (config->profile == profile) {
621 if (config->entrypoints & (1U << entrypoint))
625 if (i == self->available_profiles->len)
632 gst_va_encoder_get_max_slice_num (GstVaEncoder * self,
633 VAProfile profile, VAEntrypoint entrypoint)
637 VAConfigAttrib attrib = {.type = VAConfigAttribEncMaxSlices };
639 g_return_val_if_fail (GST_IS_VA_ENCODER (self), -1);
641 if (profile == VAProfileNone)
644 if (entrypoint != VAEntrypointEncSlice)
647 dpy = gst_va_display_get_va_dpy (self->display);
648 status = vaGetConfigAttributes (dpy, profile, entrypoint, &attrib, 1);
649 if (status != VA_STATUS_SUCCESS) {
650 GST_WARNING_OBJECT (self, "Failed to query encoding slices: %s",
651 vaErrorStr (status));
655 if (attrib.value == VA_ATTRIB_NOT_SUPPORTED) {
656 GST_WARNING_OBJECT (self, "Driver does not support encoding picture as "
665 gst_va_encoder_get_max_num_reference (GstVaEncoder * self,
666 VAProfile profile, VAEntrypoint entrypoint,
667 guint32 * list0, guint32 * list1)
671 VAConfigAttrib attrib = {.type = VAConfigAttribEncMaxRefFrames };
673 g_return_val_if_fail (GST_IS_VA_ENCODER (self), FALSE);
675 if (profile == VAProfileNone)
678 if (entrypoint != VAEntrypointEncSlice)
681 dpy = gst_va_display_get_va_dpy (self->display);
682 status = vaGetConfigAttributes (dpy, profile, entrypoint, &attrib, 1);
683 if (status != VA_STATUS_SUCCESS) {
684 GST_WARNING_OBJECT (self, "Failed to query reference frames: %s",
685 vaErrorStr (status));
689 if (attrib.value == VA_ATTRIB_NOT_SUPPORTED) {
699 *list0 = attrib.value & 0xffff;
701 *list1 = (attrib.value >> 16) & 0xffff;
707 gst_va_encoder_get_rate_control_mode (GstVaEncoder * self,
708 VAProfile profile, VAEntrypoint entrypoint)
712 VAConfigAttrib attrib = {.type = VAConfigAttribRateControl };
714 g_return_val_if_fail (GST_IS_VA_ENCODER (self), 0);
716 if (profile == VAProfileNone)
719 if (entrypoint != VAEntrypointEncSlice)
722 dpy = gst_va_display_get_va_dpy (self->display);
723 status = vaGetConfigAttributes (dpy, profile, entrypoint, &attrib, 1);
724 if (status != VA_STATUS_SUCCESS) {
725 GST_WARNING_OBJECT (self, "Failed to query rate control mode: %s",
726 vaErrorStr (status));
730 if (attrib.value == VA_ATTRIB_NOT_SUPPORTED) {
731 GST_WARNING_OBJECT (self, "Driver does not support any rate control modes");
739 gst_va_encoder_get_quality_level (GstVaEncoder * self,
740 VAProfile profile, VAEntrypoint entrypoint)
744 VAConfigAttrib attrib = {.type = VAConfigAttribEncQualityRange };
746 g_return_val_if_fail (GST_IS_VA_ENCODER (self), 0);
748 if (profile == VAProfileNone)
751 if (entrypoint != VAEntrypointEncSlice)
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 if (entrypoint != VAEntrypointEncSlice)
786 dpy = gst_va_display_get_va_dpy (self->display);
787 status = vaGetConfigAttributes (dpy, profile, entrypoint, &attrib, 1);
788 if (status != VA_STATUS_SUCCESS) {
789 GST_WARNING_OBJECT (self, "Failed to query the trellis: %s",
790 vaErrorStr (status));
794 if (attrib.value == VA_ATTRIB_NOT_SUPPORTED) {
795 GST_WARNING_OBJECT (self, "Driver does not support trellis");
799 return attrib.value & VA_ENC_QUANTIZATION_TRELLIS_SUPPORTED;
803 gst_va_encoder_get_rtformat (GstVaEncoder * self,
804 VAProfile profile, VAEntrypoint entrypoint)
808 VAConfigAttrib attrib = {.type = VAConfigAttribRTFormat };
810 if (profile == VAProfileNone)
813 if (entrypoint != VAEntrypointEncSlice)
816 dpy = gst_va_display_get_va_dpy (self->display);
817 status = vaGetConfigAttributes (dpy, profile, entrypoint, &attrib, 1);
818 if (status != VA_STATUS_SUCCESS) {
819 GST_ERROR_OBJECT (self, "Failed to query rt format: %s",
820 vaErrorStr (status));
824 if (attrib.value == VA_ATTRIB_NOT_SUPPORTED) {
825 GST_WARNING_OBJECT (self, "Driver does not support any rt format");
833 gst_va_encoder_get_packed_headers (GstVaEncoder * self, VAProfile profile,
834 VAEntrypoint entrypoint)
838 VAConfigAttrib attrib = {.type = VAConfigAttribEncPackedHeaders };
840 if (profile == VAProfileNone)
843 if (entrypoint != VAEntrypointEncSlice)
846 dpy = gst_va_display_get_va_dpy (self->display);
847 status = vaGetConfigAttributes (dpy, profile, entrypoint, &attrib, 1);
848 if (status != VA_STATUS_SUCCESS) {
849 GST_ERROR_OBJECT (self, "Failed to query packed headers: %s",
850 vaErrorStr (status));
854 if (attrib.value == VA_ATTRIB_NOT_SUPPORTED) {
855 GST_WARNING_OBJECT (self, "Driver does not support any packed headers");
862 /* Add packed header such as SPS, PPS, SEI, etc. If adding slice header,
863 it is attached to the last slice parameter. */
865 gst_va_encoder_add_packed_header (GstVaEncoder * self, GstVaEncodePicture * pic,
866 gint type, gpointer data, gsize size_in_bits, gboolean has_emulation_bytes)
869 VAEncPackedHeaderParameterBuffer param = {
871 .bit_length = size_in_bits,
872 .has_emulation_bytes = has_emulation_bytes,
875 g_return_val_if_fail (GST_IS_VA_ENCODER (self), FALSE);
876 g_return_val_if_fail (self->context != VA_INVALID_ID, FALSE);
877 g_return_val_if_fail (pic && data && size_in_bits > 0, FALSE);
878 g_return_val_if_fail (type >= VAEncPackedHeaderSequence
879 && type <= VAEncPackedHeaderRawData, FALSE);
881 if (!gst_va_encoder_is_open (self)) {
882 GST_ERROR_OBJECT (self, "encoder has not been opened yet");
886 buffer = _create_buffer (self, VAEncPackedHeaderParameterBufferType, ¶m,
888 if (buffer == VA_INVALID_ID)
891 g_array_append_val (pic->params, buffer);
893 buffer = _create_buffer (self, VAEncPackedHeaderDataBufferType, data,
894 (size_in_bits + 7) / 8);
895 if (buffer == VA_INVALID_ID)
898 g_array_append_val (pic->params, buffer);
904 gst_va_encoder_add_param (GstVaEncoder * self, GstVaEncodePicture * pic,
905 VABufferType type, gpointer data, gsize size)
909 g_return_val_if_fail (GST_IS_VA_ENCODER (self), FALSE);
910 g_return_val_if_fail (self->context != VA_INVALID_ID, FALSE);
911 g_return_val_if_fail (pic && data && size > 0, FALSE);
913 if (!gst_va_encoder_is_open (self)) {
914 GST_ERROR_OBJECT (self, "encoder has not been opened yet");
918 buffer = _create_buffer (self, type, data, size);
919 if (buffer == VA_INVALID_ID)
922 g_array_append_val (pic->params, buffer);
928 gst_va_encoder_get_surface_formats (GstVaEncoder * self)
930 g_return_val_if_fail (GST_IS_VA_ENCODER (self), NULL);
932 if (!gst_va_encoder_is_open (self))
935 return _get_surface_formats (self->display, self->config);
939 _get_codec_caps (GstVaEncoder * self)
941 GstCaps *sinkpad_caps = NULL, *srcpad_caps = NULL;
943 if (!gst_va_encoder_is_open (self)
944 && GST_IS_VA_DISPLAY_WRAPPED (self->display)) {
945 if (gst_va_caps_from_profiles (self->display, self->available_profiles,
946 VAEntrypointEncSlice, &sinkpad_caps, &srcpad_caps)) {
947 gst_caps_replace (&self->sinkpad_caps, sinkpad_caps);
948 gst_caps_replace (&self->srcpad_caps, srcpad_caps);
949 gst_caps_unref (srcpad_caps);
950 gst_caps_unref (sinkpad_caps);
960 gst_va_encoder_get_sinkpad_caps (GstVaEncoder * self)
962 GstCaps *sinkpad_caps = NULL;
964 g_return_val_if_fail (GST_IS_VA_ENCODER (self), FALSE);
966 if (g_atomic_pointer_get (&self->sinkpad_caps))
967 return gst_caps_ref (self->sinkpad_caps);
969 if (_get_codec_caps (self))
970 return gst_caps_ref (self->sinkpad_caps);
972 if (gst_va_encoder_is_open (self)) {
973 sinkpad_caps = gst_va_create_raw_caps_from_config (self->display,
975 gst_caps_replace (&self->sinkpad_caps, sinkpad_caps);
976 gst_caps_unref (sinkpad_caps);
978 return gst_caps_ref (self->sinkpad_caps);
985 gst_va_encoder_get_srcpad_caps (GstVaEncoder * self)
987 g_return_val_if_fail (GST_IS_VA_ENCODER (self), FALSE);
989 if (g_atomic_pointer_get (&self->srcpad_caps))
990 return gst_caps_ref (self->srcpad_caps);
992 if (_get_codec_caps (self))
993 return gst_caps_ref (self->srcpad_caps);
995 if (gst_va_encoder_is_open (self)) {
997 VAEntrypoint entrypoint;
1000 GST_OBJECT_LOCK (self);
1001 profile = self->profile;
1002 entrypoint = self->entrypoint;
1003 GST_OBJECT_UNLOCK (self);
1005 caps = gst_va_create_coded_caps (self->display, profile, entrypoint, NULL);
1007 gst_caps_replace (&self->srcpad_caps, caps);
1008 return gst_caps_ref (self->srcpad_caps);
1016 _destroy_all_buffers (GstVaEncodePicture * pic)
1020 gboolean ret = TRUE;
1022 g_return_val_if_fail (GST_IS_VA_DISPLAY (pic->display), FALSE);
1024 for (i = 0; i < pic->params->len; i++) {
1025 buffer = g_array_index (pic->params, VABufferID, i);
1026 ret &= _destroy_buffer (pic->display, buffer);
1028 pic->params = g_array_set_size (pic->params, 0);
1034 gst_va_encoder_encode (GstVaEncoder * self, GstVaEncodePicture * pic)
1038 VASurfaceID surface;
1039 VAContextID context;
1040 gboolean ret = FALSE;
1042 g_return_val_if_fail (pic, FALSE);
1044 GST_OBJECT_LOCK (self);
1046 if (!_is_open_unlocked (self)) {
1047 GST_OBJECT_UNLOCK (self);
1048 GST_ERROR_OBJECT (self, "encoder has not been opened yet");
1052 context = self->context;
1053 GST_OBJECT_UNLOCK (self);
1055 surface = gst_va_encode_picture_get_raw_surface (pic);
1056 if (surface == VA_INVALID_ID) {
1057 GST_ERROR_OBJECT (self, "Encode picture without valid raw surface");
1061 GST_TRACE_OBJECT (self, "Encode the surface %#x", surface);
1063 dpy = gst_va_display_get_va_dpy (self->display);
1065 status = vaBeginPicture (dpy, context, surface);
1066 if (status != VA_STATUS_SUCCESS) {
1067 GST_WARNING_OBJECT (self, "vaBeginPicture: %s", vaErrorStr (status));
1071 if (pic->params->len > 0) {
1072 status = vaRenderPicture (dpy, context, (VABufferID *) pic->params->data,
1074 if (status != VA_STATUS_SUCCESS) {
1075 GST_WARNING_OBJECT (self, "vaRenderPicture: %s", vaErrorStr (status));
1080 status = vaEndPicture (dpy, context);
1081 ret = (status == VA_STATUS_SUCCESS);
1083 GST_WARNING_OBJECT (self, "vaEndPicture: %s", vaErrorStr (status));
1086 _destroy_all_buffers (pic);
1092 _destroy_all_buffers (pic);
1093 status = vaEndPicture (dpy, context);
1100 gst_va_encode_picture_get_reconstruct_surface (GstVaEncodePicture * pic)
1102 g_return_val_if_fail (pic, VA_INVALID_ID);
1103 g_return_val_if_fail (pic->reconstruct_buffer, VA_INVALID_ID);
1105 return gst_va_buffer_get_surface (pic->reconstruct_buffer);
1109 gst_va_encode_picture_get_raw_surface (GstVaEncodePicture * pic)
1111 g_return_val_if_fail (pic, VA_INVALID_ID);
1112 g_return_val_if_fail (pic->raw_buffer, VA_INVALID_ID);
1114 return gst_va_buffer_get_surface (pic->raw_buffer);
1117 GstVaEncodePicture *
1118 gst_va_encode_picture_new (GstVaEncoder * self, GstBuffer * raw_buffer)
1120 GstVaEncodePicture *pic;
1121 VABufferID coded_buffer;
1125 GstBufferPool *recon_pool = NULL;
1126 GstBuffer *reconstruct_buffer = NULL;
1128 GstBufferPoolAcquireParams buffer_pool_params = {
1129 .flags = GST_BUFFER_POOL_ACQUIRE_FLAG_DONTWAIT,
1132 g_return_val_if_fail (self && GST_IS_VA_ENCODER (self), NULL);
1133 g_return_val_if_fail (raw_buffer && GST_IS_BUFFER (raw_buffer), NULL);
1135 GST_OBJECT_LOCK (self);
1137 if (!_is_open_unlocked (self)) {
1138 GST_OBJECT_UNLOCK (self);
1139 GST_ERROR_OBJECT (self, "encoder has not been opened yet");
1143 if (self->codedbuf_size <= 0) {
1144 GST_ERROR_OBJECT (self, "codedbuf_size: %d, is invalid",
1145 self->codedbuf_size);
1146 GST_OBJECT_UNLOCK (self);
1149 codedbuf_size = self->codedbuf_size;
1151 recon_pool = gst_object_ref (self->recon_pool);
1153 GST_OBJECT_UNLOCK (self);
1155 ret = gst_buffer_pool_acquire_buffer (self->recon_pool, &reconstruct_buffer,
1156 &buffer_pool_params);
1157 gst_clear_object (&recon_pool);
1159 if (ret != GST_FLOW_OK) {
1160 GST_ERROR_OBJECT (self, "Failed to create the reconstruct picture");
1161 gst_clear_buffer (&reconstruct_buffer);
1165 dpy = gst_va_display_get_va_dpy (self->display);
1166 status = vaCreateBuffer (dpy, self->context, VAEncCodedBufferType,
1167 codedbuf_size, 1, NULL, &coded_buffer);
1168 if (status != VA_STATUS_SUCCESS) {
1169 GST_ERROR_OBJECT (self, "vaCreateBuffer: %s", vaErrorStr (status));
1170 gst_clear_buffer (&reconstruct_buffer);
1174 pic = g_slice_new (GstVaEncodePicture);
1175 pic->raw_buffer = gst_buffer_ref (raw_buffer);
1176 pic->reconstruct_buffer = reconstruct_buffer;
1177 pic->display = gst_object_ref (self->display);
1178 pic->coded_buffer = coded_buffer;
1180 pic->params = g_array_sized_new (FALSE, FALSE, sizeof (VABufferID), 8);
1186 gst_va_encode_picture_free (GstVaEncodePicture * pic)
1188 g_return_if_fail (pic);
1190 _destroy_all_buffers (pic);
1192 if (pic->coded_buffer != VA_INVALID_ID)
1193 _destroy_buffer (pic->display, pic->coded_buffer);
1195 gst_buffer_unref (pic->raw_buffer);
1196 gst_buffer_unref (pic->reconstruct_buffer);
1198 g_clear_pointer (&pic->params, g_array_unref);
1199 gst_clear_object (&pic->display);
1201 g_slice_free (GstVaEncodePicture, pic);