2 * Copyright (C) 2022 Intel Corporation
3 * Author: He Junyan <junyan.he@intel.com>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the0
17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
21 #include "gstvabaseenc.h"
23 #include <gst/va/gstva.h>
24 #include <gst/va/vasurfaceimage.h>
27 #include "gstvacaps.h"
29 #define GST_CAT_DEFAULT gst_va_base_enc_debug
30 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
32 struct _GstVaBaseEncPrivate
34 GstVideoInfo sinkpad_info;
35 GstBufferPool *raw_pool;
44 static GParamSpec *properties[N_PROPERTIES];
49 * A base class implementation for VA-API Encoders.
54 #define gst_va_base_enc_parent_class parent_class
55 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstVaBaseEnc, gst_va_base_enc,
56 GST_TYPE_VIDEO_ENCODER, G_ADD_PRIVATE (GstVaBaseEnc)
57 GST_DEBUG_CATEGORY_INIT (gst_va_base_enc_debug,
58 "vabaseenc", 0, "vabaseenc element"););
62 gst_va_base_enc_reset_state_default (GstVaBaseEnc * base)
64 base->frame_duration = GST_CLOCK_TIME_NONE;
68 base->profile = VAProfileNone;
70 base->codedbuf_size = 0;
71 g_atomic_int_set (&base->reconf, FALSE);
75 _flush_all_frames (GstVaBaseEnc * base)
77 g_queue_clear_full (&base->reorder_list,
78 (GDestroyNotify) gst_video_codec_frame_unref);
79 g_queue_clear_full (&base->output_list,
80 (GDestroyNotify) gst_video_codec_frame_unref);
81 g_queue_clear_full (&base->ref_list,
82 (GDestroyNotify) gst_video_codec_frame_unref);
86 gst_va_base_enc_open (GstVideoEncoder * venc)
88 GstVaBaseEnc *base = GST_VA_BASE_ENC (venc);
89 GstVaBaseEncClass *klass = GST_VA_BASE_ENC_GET_CLASS (venc);
92 if (!gst_va_ensure_element_data (venc, klass->render_device_path,
96 g_object_notify (G_OBJECT (base), "device-path");
98 if (!g_atomic_pointer_get (&base->encoder)) {
99 GstVaEncoder *va_encoder;
101 va_encoder = gst_va_encoder_new (base->display, klass->codec,
106 gst_object_replace ((GstObject **) (&base->encoder),
107 (GstObject *) va_encoder);
108 gst_clear_object (&va_encoder);
117 gst_va_base_enc_start (GstVideoEncoder * venc)
119 GstVaBaseEnc *base = GST_VA_BASE_ENC (venc);
121 gst_va_base_enc_reset_state (base);
123 base->input_frame_count = 0;
124 base->output_frame_count = 0;
126 base->input_state = NULL;
128 /* Set the minimum pts to some huge value (1000 hours). This keeps
129 * the dts at the start of the stream from needing to be
131 base->start_pts = GST_SECOND * 60 * 60 * 1000;
132 gst_video_encoder_set_min_pts (venc, base->start_pts);
138 gst_va_base_enc_close (GstVideoEncoder * venc)
140 GstVaBaseEnc *base = GST_VA_BASE_ENC (venc);
142 gst_clear_object (&base->encoder);
143 gst_clear_object (&base->display);
149 gst_va_base_enc_stop (GstVideoEncoder * venc)
151 GstVaBaseEnc *base = GST_VA_BASE_ENC (venc);
153 _flush_all_frames (base);
155 if (!gst_va_encoder_close (base->encoder)) {
156 GST_ERROR_OBJECT (base, "Failed to close the VA encoder");
160 if (base->priv->raw_pool)
161 gst_buffer_pool_set_active (base->priv->raw_pool, FALSE);
162 gst_clear_object (&base->priv->raw_pool);
164 if (base->input_state)
165 gst_video_codec_state_unref (base->input_state);
171 gst_va_base_enc_get_caps (GstVideoEncoder * venc, GstCaps * filter)
173 GstVaBaseEnc *base = GST_VA_BASE_ENC (venc);
174 GstCaps *caps = NULL, *tmp;
177 caps = gst_va_encoder_get_sinkpad_caps (base->encoder);
181 tmp = gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
182 gst_caps_unref (caps);
186 caps = gst_video_encoder_proxy_getcaps (venc, NULL, filter);
189 GST_LOG_OBJECT (base, "Returning caps %" GST_PTR_FORMAT, caps);
193 static GstBufferPool *
194 _get_sinkpad_pool (GstVaBaseEnc * base)
196 GstAllocator *allocator;
197 GstAllocationParams params = { 0, };
198 guint size, usage_hint = 0;
199 GArray *surface_formats = NULL;
200 GstCaps *caps = NULL;
202 if (base->priv->raw_pool)
203 return base->priv->raw_pool;
205 g_assert (base->input_state);
206 caps = gst_caps_copy (base->input_state->caps);
207 gst_caps_set_features_simple (caps,
208 gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_VA));
210 gst_allocation_params_init (¶ms);
212 size = GST_VIDEO_INFO_SIZE (&base->input_state->info);
214 surface_formats = gst_va_encoder_get_surface_formats (base->encoder);
216 allocator = gst_va_allocator_new (base->display, surface_formats);
218 base->priv->raw_pool = gst_va_pool_new_with_config (caps, size, 1, 0,
219 usage_hint, GST_VA_FEATURE_AUTO, allocator, ¶ms);
220 gst_clear_caps (&caps);
222 if (!base->priv->raw_pool) {
223 gst_object_unref (allocator);
227 gst_va_allocator_get_format (allocator, &base->priv->sinkpad_info, NULL,
230 gst_object_unref (allocator);
232 if (!gst_buffer_pool_set_active (base->priv->raw_pool, TRUE)) {
233 GST_WARNING_OBJECT (base, "Failed to activate sinkpad pool");
237 return base->priv->raw_pool;
241 _try_import_buffer (GstVaBaseEnc * base, GstBuffer * inbuf)
246 surface = gst_va_buffer_get_surface (inbuf);
247 if (surface != VA_INVALID_ID &&
248 (gst_va_buffer_peek_display (inbuf) == base->display))
251 /* TODO: DMA buffer. */
257 gst_va_base_enc_import_input_buffer (GstVaBaseEnc * base,
258 GstBuffer * inbuf, GstBuffer ** buf)
260 GstBuffer *buffer = NULL;
263 GstVideoFrame in_frame, out_frame;
264 gboolean imported, copied;
266 imported = _try_import_buffer (base, inbuf);
268 *buf = gst_buffer_ref (inbuf);
272 /* input buffer doesn't come from a vapool, thus it is required to
273 * have a pool, grab from it a new buffer and copy the input
274 * buffer to the new one */
275 if (!(pool = _get_sinkpad_pool (base)))
276 return GST_FLOW_ERROR;
278 ret = gst_buffer_pool_acquire_buffer (pool, &buffer, NULL);
279 if (ret != GST_FLOW_OK)
282 GST_LOG_OBJECT (base, "copying input frame");
284 if (!gst_video_frame_map (&in_frame, &base->input_state->info,
285 inbuf, GST_MAP_READ))
287 if (!gst_video_frame_map (&out_frame, &base->priv->sinkpad_info, buffer,
289 gst_video_frame_unmap (&in_frame);
293 copied = gst_video_frame_copy (&out_frame, &in_frame);
295 gst_video_frame_unmap (&out_frame);
296 gst_video_frame_unmap (&in_frame);
301 /* strictly speaking this is not needed but let's play safe */
302 if (!gst_buffer_copy_into (buffer, inbuf, GST_BUFFER_COPY_FLAGS |
303 GST_BUFFER_COPY_TIMESTAMPS, 0, -1))
304 return GST_FLOW_ERROR;
312 GST_ELEMENT_WARNING (base, CORE, NOT_IMPLEMENTED, (NULL),
313 ("invalid video buffer received"));
315 gst_buffer_unref (buffer);
316 return GST_FLOW_ERROR;
321 gst_va_base_enc_create_output_buffer (GstVaBaseEnc * base,
322 GstVaEncodePicture * picture)
326 GstBuffer *buf = NULL;
328 VACodedBufferSegment *seg, *seg_list;
330 /* Wait for encoding to finish */
331 surface = gst_va_encode_picture_get_raw_surface (picture);
332 if (!va_sync_surface (base->display, surface))
336 if (!va_map_buffer (base->display, picture->coded_buffer,
337 (gpointer *) & seg_list))
341 va_unmap_buffer (base->display, picture->coded_buffer);
342 GST_WARNING_OBJECT (base, "coded buffer has no segment list");
347 for (seg = seg_list; seg; seg = seg->next)
348 coded_size += seg->size;
350 buf = gst_video_encoder_allocate_output_buffer (GST_VIDEO_ENCODER_CAST (base),
353 va_unmap_buffer (base->display, picture->coded_buffer);
354 GST_ERROR_OBJECT (base, "Failed to allocate output buffer, size %d",
360 for (seg = seg_list; seg; seg = seg->next) {
363 write_size = gst_buffer_fill (buf, offset, seg->buf, seg->size);
364 if (write_size != seg->size) {
365 GST_WARNING_OBJECT (base, "Segment size is %d, but copied %"
366 G_GSIZE_FORMAT, seg->size, write_size);
372 va_unmap_buffer (base->display, picture->coded_buffer);
377 gst_clear_buffer (&buf);
381 static GstAllocator *
382 _allocator_from_caps (GstVaBaseEnc * base, GstCaps * caps)
384 GstAllocator *allocator = NULL;
386 if (gst_caps_is_dmabuf (caps)) {
387 allocator = gst_va_dmabuf_allocator_new (base->display);
389 GArray *surface_formats =
390 gst_va_encoder_get_surface_formats (base->encoder);
391 allocator = gst_va_allocator_new (base->display, surface_formats);
398 gst_va_base_enc_propose_allocation (GstVideoEncoder * venc, GstQuery * query)
400 GstVaBaseEnc *base = GST_VA_BASE_ENC (venc);
401 GstAllocator *allocator = NULL;
402 GstAllocationParams params = { 0, };
406 gboolean need_pool = FALSE;
407 guint size, usage_hint = 0;
409 gst_query_parse_allocation (query, &caps, &need_pool);
413 if (!gst_video_info_from_caps (&info, caps)) {
414 GST_ERROR_OBJECT (base, "Cannot parse caps %" GST_PTR_FORMAT, caps);
418 size = GST_VIDEO_INFO_SIZE (&info);
420 gst_allocation_params_init (¶ms);
422 if (!(allocator = _allocator_from_caps (base, caps)))
425 pool = gst_va_pool_new_with_config (caps, size, 1, 0, usage_hint,
426 GST_VA_FEATURE_AUTO, allocator, ¶ms);
428 gst_object_unref (allocator);
432 gst_query_add_allocation_param (query, allocator, ¶ms);
433 gst_query_add_allocation_pool (query, pool, size, 0, 0);
435 GST_DEBUG_OBJECT (base,
436 "proposing %" GST_PTR_FORMAT " with allocator %" GST_PTR_FORMAT,
439 gst_object_unref (allocator);
440 gst_object_unref (pool);
442 gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
449 GST_ERROR_OBJECT (base, "failed to set config");
455 _push_buffer_to_downstream (GstVaBaseEnc * base, GstVideoCodecFrame * frame)
457 GstVaEncodePicture *enc_picture;
458 GstVaBaseEncClass *base_class = GST_VA_BASE_ENC_GET_CLASS (base);
461 if (base_class->prepare_output)
462 base_class->prepare_output (base, frame);
465 *((GstVaEncodePicture **) gst_video_codec_frame_get_user_data (frame));
467 buf = gst_va_base_enc_create_output_buffer (base, enc_picture);
469 GST_ERROR_OBJECT (base, "Failed to create output buffer");
473 gst_buffer_replace (&frame->output_buffer, buf);
474 gst_clear_buffer (&buf);
476 GST_LOG_OBJECT (base, "Push to downstream: frame system_frame_number: %d,"
477 " pts: %" GST_TIME_FORMAT ", dts: %" GST_TIME_FORMAT
478 " duration: %" GST_TIME_FORMAT ", buffer size: %" G_GSIZE_FORMAT,
479 frame->system_frame_number, GST_TIME_ARGS (frame->pts),
480 GST_TIME_ARGS (frame->dts), GST_TIME_ARGS (frame->duration),
481 gst_buffer_get_size (frame->output_buffer));
483 return gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (base), frame);
486 gst_clear_buffer (&frame->output_buffer);
487 gst_clear_buffer (&buf);
488 gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (base), frame);
490 return GST_FLOW_ERROR;
494 _push_out_one_buffer (GstVaBaseEnc * base)
496 GstVideoCodecFrame *frame_out;
498 guint32 system_frame_number;
500 frame_out = g_queue_pop_head (&base->output_list);
501 gst_video_codec_frame_unref (frame_out);
503 system_frame_number = frame_out->system_frame_number;
505 ret = _push_buffer_to_downstream (base, frame_out);
507 if (ret != GST_FLOW_OK) {
508 GST_DEBUG_OBJECT (base, "fails to push one buffer, system_frame_number "
509 "%d: %s", system_frame_number, gst_flow_get_name (ret));
516 gst_va_base_enc_drain (GstVideoEncoder * venc)
518 GstVaBaseEnc *base = GST_VA_BASE_ENC (venc);
519 GstVaBaseEncClass *base_class = GST_VA_BASE_ENC_GET_CLASS (base);
520 GstFlowReturn ret = GST_FLOW_OK;
521 GstVideoCodecFrame *frame_enc = NULL;
522 gboolean is_last = FALSE;
524 GST_DEBUG_OBJECT (base, "Encoder is draining");
526 /* Kickout all cached frames */
527 if (!base_class->reorder_frame (base, NULL, TRUE, &frame_enc)) {
528 ret = GST_FLOW_ERROR;
529 goto error_and_purge_all;
535 if (g_queue_is_empty (&base->reorder_list))
538 ret = base_class->encode_frame (base, frame_enc, is_last);
539 if (ret != GST_FLOW_OK)
540 goto error_and_purge_all;
544 ret = _push_out_one_buffer (base);
545 if (ret != GST_FLOW_OK)
546 goto error_and_purge_all;
548 if (!base_class->reorder_frame (base, NULL, TRUE, &frame_enc)) {
549 ret = GST_FLOW_ERROR;
550 goto error_and_purge_all;
554 g_assert (g_queue_is_empty (&base->reorder_list));
556 /* Output all frames. */
557 while (!g_queue_is_empty (&base->output_list)) {
558 ret = _push_out_one_buffer (base);
559 if (ret != GST_FLOW_OK)
560 goto error_and_purge_all;
563 /* Also clear the reference list. */
564 g_queue_clear_full (&base->ref_list,
565 (GDestroyNotify) gst_video_codec_frame_unref);
571 gst_clear_buffer (&frame_enc->output_buffer);
572 gst_video_encoder_finish_frame (venc, frame_enc);
575 if (!g_queue_is_empty (&base->output_list)) {
576 GST_WARNING_OBJECT (base, "Still %d frame in the output list"
577 " after drain", g_queue_get_length (&base->output_list));
578 while (!g_queue_is_empty (&base->output_list)) {
579 frame_enc = g_queue_pop_head (&base->output_list);
580 gst_video_codec_frame_unref (frame_enc);
581 gst_clear_buffer (&frame_enc->output_buffer);
582 gst_video_encoder_finish_frame (venc, frame_enc);
586 if (!g_queue_is_empty (&base->reorder_list)) {
587 GST_WARNING_OBJECT (base, "Still %d frame in the reorder list"
588 " after drain", g_queue_get_length (&base->reorder_list));
589 while (!g_queue_is_empty (&base->reorder_list)) {
590 frame_enc = g_queue_pop_head (&base->reorder_list);
591 gst_video_codec_frame_unref (frame_enc);
592 gst_clear_buffer (&frame_enc->output_buffer);
593 gst_video_encoder_finish_frame (venc, frame_enc);
597 /* Also clear the reference list. */
598 g_queue_clear_full (&base->ref_list,
599 (GDestroyNotify) gst_video_codec_frame_unref);
605 gst_va_base_enc_reset (GstVaBaseEnc * base)
607 GstVaBaseEncClass *base_class = GST_VA_BASE_ENC_GET_CLASS (base);
609 GST_DEBUG_OBJECT (base, "Reconfiguration");
610 if (gst_va_base_enc_drain (GST_VIDEO_ENCODER (base)) != GST_FLOW_OK)
613 if (!base_class->reconfig (base)) {
614 GST_ERROR_OBJECT (base, "Error at reconfiguration error");
622 gst_va_base_enc_handle_frame (GstVideoEncoder * venc,
623 GstVideoCodecFrame * frame)
625 GstVaBaseEnc *base = GST_VA_BASE_ENC (venc);
626 GstVaBaseEncClass *base_class = GST_VA_BASE_ENC_GET_CLASS (base);
628 GstBuffer *in_buf = NULL;
629 GstVideoCodecFrame *frame_encode = NULL;
631 GST_LOG_OBJECT (venc,
632 "handle frame id %d, dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT,
633 frame->system_frame_number,
634 GST_TIME_ARGS (GST_BUFFER_DTS (frame->input_buffer)),
635 GST_TIME_ARGS (GST_BUFFER_PTS (frame->input_buffer)));
637 if (g_atomic_int_compare_and_exchange (&base->reconf, TRUE, FALSE)) {
638 if (!gst_va_base_enc_reset (base))
639 return GST_FLOW_ERROR;
642 ret = gst_va_base_enc_import_input_buffer (base,
643 frame->input_buffer, &in_buf);
644 if (ret != GST_FLOW_OK)
645 goto error_buffer_invalid;
647 gst_buffer_replace (&frame->input_buffer, in_buf);
648 gst_clear_buffer (&in_buf);
650 if (!base_class->new_frame (base, frame))
651 goto error_new_frame;
653 if (!base_class->reorder_frame (base, frame, FALSE, &frame_encode))
656 /* pass it to reorder list and we should not use it again. */
659 while (frame_encode) {
660 ret = base_class->encode_frame (base, frame_encode, FALSE);
661 if (ret != GST_FLOW_OK)
664 while (g_queue_get_length (&base->output_list) > 0)
665 ret = _push_out_one_buffer (base);
668 if (!base_class->reorder_frame (base, NULL, FALSE, &frame_encode))
674 error_buffer_invalid:
676 GST_ELEMENT_ERROR (venc, STREAM, ENCODE,
677 ("Failed to import the input frame: %s.", gst_flow_get_name (ret)),
679 gst_clear_buffer (&in_buf);
680 gst_clear_buffer (&frame->output_buffer);
681 gst_video_encoder_finish_frame (venc, frame);
686 GST_ELEMENT_ERROR (venc, STREAM, ENCODE,
687 ("Failed to create the input frame."), (NULL));
688 gst_clear_buffer (&frame->output_buffer);
689 gst_video_encoder_finish_frame (venc, frame);
690 return GST_FLOW_ERROR;
694 GST_ELEMENT_ERROR (venc, STREAM, ENCODE,
695 ("Failed to reorder the input frame."), (NULL));
697 gst_clear_buffer (&frame->output_buffer);
698 gst_video_encoder_finish_frame (venc, frame);
700 return GST_FLOW_ERROR;
704 GST_ELEMENT_ERROR (venc, STREAM, ENCODE,
705 ("Failed to encode the frame %s.", gst_flow_get_name (ret)), (NULL));
706 gst_clear_buffer (&frame_encode->output_buffer);
707 gst_video_encoder_finish_frame (venc, frame_encode);
713 gst_va_base_enc_finish (GstVideoEncoder * venc)
715 return gst_va_base_enc_drain (venc);
719 gst_va_base_enc_set_format (GstVideoEncoder * venc, GstVideoCodecState * state)
721 GstVaBaseEnc *base = GST_VA_BASE_ENC (venc);
723 g_return_val_if_fail (state->caps != NULL, FALSE);
725 if (base->input_state)
726 gst_video_codec_state_unref (base->input_state);
727 base->input_state = gst_video_codec_state_ref (state);
729 if (!gst_va_base_enc_reset (base))
732 /* Sub class should open the encoder if reconfig succeeds. */
733 return gst_va_encoder_is_open (base->encoder);
737 gst_va_base_enc_flush (GstVideoEncoder * venc)
739 _flush_all_frames (GST_VA_BASE_ENC (venc));
744 _query_context (GstVaBaseEnc * base, GstQuery * query)
746 GstVaDisplay *display = NULL;
749 gst_object_replace ((GstObject **) & display, (GstObject *) base->display);
750 ret = gst_va_handle_context_query (GST_ELEMENT_CAST (base), query, display);
751 gst_clear_object (&display);
757 gst_va_base_enc_src_query (GstVideoEncoder * venc, GstQuery * query)
759 GstVaBaseEnc *base = GST_VA_BASE_ENC (venc);
760 gboolean ret = FALSE;
762 switch (GST_QUERY_TYPE (query)) {
763 case GST_QUERY_CONTEXT:{
764 ret = _query_context (base, query);
767 case GST_QUERY_CAPS:{
768 GstCaps *caps = NULL, *tmp, *filter = NULL;
769 GstVaEncoder *va_encoder = NULL;
772 gst_object_replace ((GstObject **) & va_encoder,
773 (GstObject *) base->encoder);
775 gst_query_parse_caps (query, &filter);
777 fixed_caps = GST_PAD_IS_FIXED_CAPS (GST_VIDEO_ENCODER_SRC_PAD (venc));
779 if (!fixed_caps && va_encoder)
780 caps = gst_va_encoder_get_srcpad_caps (va_encoder);
782 gst_clear_object (&va_encoder);
786 tmp = gst_caps_intersect_full (filter, caps,
787 GST_CAPS_INTERSECT_FIRST);
788 gst_caps_unref (caps);
792 GST_LOG_OBJECT (base, "Returning caps %" GST_PTR_FORMAT, caps);
793 gst_query_set_caps_result (query, caps);
794 gst_caps_unref (caps);
798 /* else jump to default */
801 ret = GST_VIDEO_ENCODER_CLASS (parent_class)->src_query (venc, query);
809 gst_va_base_enc_sink_query (GstVideoEncoder * venc, GstQuery * query)
811 GstVaBaseEnc *base = GST_VA_BASE_ENC (venc);
813 if (GST_QUERY_TYPE (query) == GST_QUERY_CONTEXT)
814 return _query_context (base, query);
816 return GST_VIDEO_ENCODER_CLASS (parent_class)->sink_query (venc, query);
820 gst_va_base_enc_set_context (GstElement * element, GstContext * context)
822 GstVaDisplay *old_display, *new_display;
823 GstVaBaseEnc *base = GST_VA_BASE_ENC (element);
824 GstVaBaseEncClass *klass = GST_VA_BASE_ENC_GET_CLASS (base);
827 old_display = base->display ? gst_object_ref (base->display) : NULL;
829 ret = gst_va_handle_set_context (element, context, klass->render_device_path,
832 new_display = base->display ? gst_object_ref (base->display) : NULL;
834 if (!ret || (old_display && new_display && old_display != new_display
836 GST_ELEMENT_WARNING (element, RESOURCE, BUSY,
837 ("Can't replace VA display while operating"), (NULL));
840 gst_clear_object (&old_display);
841 gst_clear_object (&new_display);
843 GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
847 gst_va_base_enc_get_property (GObject * object, guint prop_id,
848 GValue * value, GParamSpec * pspec)
850 GstVaBaseEnc *base = GST_VA_BASE_ENC (object);
853 case PROP_DEVICE_PATH:{
854 if (!(base->display && GST_IS_VA_DISPLAY_DRM (base->display))) {
855 g_value_set_string (value, NULL);
858 g_object_get_property (G_OBJECT (base->display), "path", value);
862 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
867 gst_va_base_enc_init (GstVaBaseEnc * self)
869 g_queue_init (&self->reorder_list);
870 g_queue_init (&self->ref_list);
871 g_queue_init (&self->output_list);
873 self->priv = gst_va_base_enc_get_instance_private (self);
877 gst_va_base_enc_dispose (GObject * object)
879 _flush_all_frames (GST_VA_BASE_ENC (object));
880 gst_va_base_enc_close (GST_VIDEO_ENCODER (object));
882 G_OBJECT_CLASS (parent_class)->dispose (object);
886 gst_va_base_enc_class_init (GstVaBaseEncClass * klass)
888 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
889 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
890 GstVideoEncoderClass *encoder_class = GST_VIDEO_ENCODER_CLASS (klass);
892 gobject_class->get_property = gst_va_base_enc_get_property;
893 gobject_class->dispose = gst_va_base_enc_dispose;
895 element_class->set_context = GST_DEBUG_FUNCPTR (gst_va_base_enc_set_context);
897 encoder_class->open = GST_DEBUG_FUNCPTR (gst_va_base_enc_open);
898 encoder_class->close = GST_DEBUG_FUNCPTR (gst_va_base_enc_close);
899 encoder_class->start = GST_DEBUG_FUNCPTR (gst_va_base_enc_start);
900 encoder_class->stop = GST_DEBUG_FUNCPTR (gst_va_base_enc_stop);
901 encoder_class->getcaps = GST_DEBUG_FUNCPTR (gst_va_base_enc_get_caps);
902 encoder_class->src_query = GST_DEBUG_FUNCPTR (gst_va_base_enc_src_query);
903 encoder_class->sink_query = GST_DEBUG_FUNCPTR (gst_va_base_enc_sink_query);
904 encoder_class->propose_allocation =
905 GST_DEBUG_FUNCPTR (gst_va_base_enc_propose_allocation);
906 encoder_class->handle_frame =
907 GST_DEBUG_FUNCPTR (gst_va_base_enc_handle_frame);
908 encoder_class->set_format = GST_DEBUG_FUNCPTR (gst_va_base_enc_set_format);
909 encoder_class->finish = GST_DEBUG_FUNCPTR (gst_va_base_enc_finish);
910 encoder_class->flush = GST_DEBUG_FUNCPTR (gst_va_base_enc_flush);
912 klass->reset_state = GST_DEBUG_FUNCPTR (gst_va_base_enc_reset_state_default);
915 * GstVaBaseEnc:device-path:
917 * It shows the DRM device path used for the VA operation, if any.
919 properties[PROP_DEVICE_PATH] = g_param_spec_string ("device-path",
920 "Device Path", "DRM device path", NULL,
921 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
923 g_object_class_install_properties (gobject_class, N_PROPERTIES, properties);
925 gst_type_mark_as_plugin_api (GST_TYPE_VA_BASE_ENC, 0);
928 /*********************** Helper Functions ****************************/
930 gst_va_base_enc_add_rate_control_parameter (GstVaBaseEnc * base,
931 GstVaEncodePicture * picture, guint32 rc_mode,
932 guint max_bitrate_bits, guint target_percentage,
933 guint32 qp_i, guint32 min_qp, guint32 max_qp, guint32 mbbrc)
935 uint32_t window_size;
936 struct VAEncMiscParameterRateControlWrap
938 VAEncMiscParameterType type;
939 VAEncMiscParameterRateControl rate_control;
942 if (rc_mode == VA_RC_NONE || rc_mode == VA_RC_CQP)
945 window_size = rc_mode == VA_RC_VBR ? max_bitrate_bits / 2 : max_bitrate_bits;
948 rate_control = (struct VAEncMiscParameterRateControlWrap) {
949 .type = VAEncMiscParameterTypeRateControl,
951 .bits_per_second = max_bitrate_bits,
952 .target_percentage = target_percentage,
953 .window_size = window_size,
957 .rc_flags.bits.mb_rate_control = mbbrc,
963 if (!gst_va_encoder_add_param (base->encoder, picture,
964 VAEncMiscParameterBufferType, &rate_control, sizeof (rate_control))) {
965 GST_ERROR_OBJECT (base, "Failed to create the race control parameter");
973 gst_va_base_enc_add_quality_level_parameter (GstVaBaseEnc * base,
974 GstVaEncodePicture * picture, guint target_usage)
979 VAEncMiscParameterType type;
980 VAEncMiscParameterBufferQualityLevel ql;
982 .type = VAEncMiscParameterTypeQualityLevel,
983 .ql.quality_level = target_usage,
987 if (target_usage == 0)
990 if (!gst_va_encoder_add_param (base->encoder, picture,
991 VAEncMiscParameterBufferType, &quality_level,
992 sizeof (quality_level))) {
993 GST_ERROR_OBJECT (base, "Failed to create the quality level parameter");
1001 gst_va_base_enc_add_frame_rate_parameter (GstVaBaseEnc * base,
1002 GstVaEncodePicture * picture)
1007 VAEncMiscParameterType type;
1008 VAEncMiscParameterFrameRate fr;
1010 .type = VAEncMiscParameterTypeFrameRate,
1011 /* denominator = framerate >> 16 & 0xffff;
1012 * numerator = framerate & 0xffff; */
1014 (GST_VIDEO_INFO_FPS_N (&base->input_state->info) & 0xffff) |
1015 ((GST_VIDEO_INFO_FPS_D (&base->input_state->info) & 0xffff) << 16)
1019 if (!gst_va_encoder_add_param (base->encoder, picture,
1020 VAEncMiscParameterBufferType, &framerate, sizeof (framerate))) {
1021 GST_ERROR_OBJECT (base, "Failed to create the frame rate parameter");
1029 gst_va_base_enc_add_hrd_parameter (GstVaBaseEnc * base,
1030 GstVaEncodePicture * picture, guint32 rc_mode, guint cpb_length_bits)
1035 VAEncMiscParameterType type;
1036 VAEncMiscParameterHRD hrd;
1038 .type = VAEncMiscParameterTypeHRD,
1040 .buffer_size = cpb_length_bits,
1041 .initial_buffer_fullness = cpb_length_bits / 2,
1046 if (rc_mode == VA_RC_NONE || rc_mode == VA_RC_CQP || rc_mode == VA_RC_VCM)
1049 if (!gst_va_encoder_add_param (base->encoder, picture,
1050 VAEncMiscParameterBufferType, &hrd, sizeof (hrd))) {
1051 GST_ERROR_OBJECT (base, "Failed to create the HRD parameter");
1059 gst_va_base_enc_add_trellis_parameter (GstVaBaseEnc * base,
1060 GstVaEncodePicture * picture, gboolean use_trellis)
1065 VAEncMiscParameterType type;
1066 VAEncMiscParameterQuantization tr;
1068 .type = VAEncMiscParameterTypeQuantization,
1069 .tr.quantization_flags.bits = {
1070 .disable_trellis = 0,
1071 .enable_trellis_I = 1,
1072 .enable_trellis_B = 1,
1073 .enable_trellis_P = 1,
1081 if (!gst_va_encoder_add_param (base->encoder, picture,
1082 VAEncMiscParameterBufferType, &trellis, sizeof (trellis))) {
1083 GST_ERROR_OBJECT (base, "Failed to create the trellis parameter");
1091 gst_va_base_enc_add_codec_tag (GstVaBaseEnc * base, const gchar * codec_name)
1093 GstVideoEncoder *venc = GST_VIDEO_ENCODER (base);
1094 GstTagList *tags = gst_tag_list_new_empty ();
1095 const gchar *encoder_name;
1098 g_object_get (venc, "bitrate", &bitrate, NULL);
1100 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_NOMINAL_BITRATE,
1104 gst_element_class_get_metadata (GST_ELEMENT_GET_CLASS (venc),
1105 GST_ELEMENT_METADATA_LONGNAME)))
1106 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_ENCODER,
1107 encoder_name, NULL);
1109 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CODEC, codec_name,
1112 gst_video_encoder_merge_tags (venc, tags, GST_TAG_MERGE_REPLACE);
1113 gst_tag_list_unref (tags);
1117 gst_va_base_enc_reset_state (GstVaBaseEnc * base)
1119 GstVaBaseEncClass *klass = GST_VA_BASE_ENC_GET_CLASS (base);
1121 g_assert (klass->reset_state);
1122 klass->reset_state (base);
1126 #define UPDATE_PROPERTY \
1127 GST_OBJECT_LOCK (base); \
1128 if (*old_val == new_val) { \
1129 GST_OBJECT_UNLOCK (base); \
1132 *old_val = new_val; \
1133 GST_OBJECT_UNLOCK (base); \
1135 g_object_notify_by_pspec (G_OBJECT (base), pspec); \
1138 gst_va_base_enc_update_property_uint (GstVaBaseEnc * base, guint32 * old_val,
1139 guint32 new_val, GParamSpec * pspec)
1145 gst_va_base_enc_update_property_bool (GstVaBaseEnc * base, gboolean * old_val,
1146 gboolean new_val, GParamSpec * pspec)
1151 #undef UPDATE_PROPERTY