2 * gstvaapidecode.c - VA-API video decoder
4 * Copyright (C) 2010-2011 Splitted-Desktop Systems
5 * Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
6 * Copyright (C) 2011-2014 Intel Corporation
7 * Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public License
11 * as published by the Free Software Foundation; either version 2.1
12 * of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free
21 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 * Boston, MA 02110-1301 USA
25 #include "gstcompat.h"
26 #include <gst/vaapi/gstvaapidisplay.h>
27 #include <gst/vaapi/gstvaapiprofilecaps.h>
29 #include "gstvaapidecode.h"
30 #include "gstvaapidecode_props.h"
31 #include "gstvaapipluginutil.h"
32 #include "gstvaapivideobuffer.h"
33 #if (USE_GLX || USE_EGL)
34 #include "gstvaapivideometa_texture.h"
36 #include "gstvaapivideobufferpool.h"
37 #include "gstvaapivideomemory.h"
39 #include <gst/vaapi/gstvaapidecoder_h264.h>
40 #include <gst/vaapi/gstvaapidecoder_jpeg.h>
41 #include <gst/vaapi/gstvaapidecoder_mpeg2.h>
42 #include <gst/vaapi/gstvaapidecoder_mpeg4.h>
43 #include <gst/vaapi/gstvaapidecoder_vc1.h>
44 #include <gst/vaapi/gstvaapidecoder_vp8.h>
45 #include <gst/vaapi/gstvaapidecoder_h265.h>
46 #include <gst/vaapi/gstvaapidecoder_vp9.h>
48 #include <gst/vaapi/gstvaapidecoder_av1.h>
51 #define GST_PLUGIN_NAME "vaapidecode"
52 #define GST_PLUGIN_DESC "A VA-API based video decoder"
54 #define GST_VAAPI_DECODE_FLOW_PARSE_DATA GST_FLOW_CUSTOM_SUCCESS_2
56 GST_DEBUG_CATEGORY_STATIC (gst_debug_vaapidecode);
57 #ifndef GST_DISABLE_GST_DEBUG
58 #define GST_CAT_DEFAULT gst_debug_vaapidecode
60 #define GST_CAT_DEFAULT NULL
63 #define GST_VAAPI_DECODE_PARAMS_QDATA \
64 g_quark_from_static_string("vaapidec-params")
66 /* Default templates */
67 #define GST_CAPS_CODEC(CODEC) CODEC "; "
70 char *gst_vaapidecode_sink_caps_str = NULL;
72 static const char gst_vaapidecode_src_caps_str[] =
73 GST_VAAPI_MAKE_SURFACE_CAPS "; "
74 GST_VIDEO_CAPS_MAKE_WITH_FEATURES(GST_CAPS_FEATURE_MEMORY_DMABUF, GST_VAAPI_FORMATS_ALL) " ;"
75 #if (USE_GLX || USE_EGL)
76 GST_VAAPI_MAKE_GLTEXUPLOAD_CAPS "; "
78 GST_VIDEO_CAPS_MAKE(GST_VAAPI_FORMATS_ALL);
80 static GstStaticPadTemplate gst_vaapidecode_src_factory =
81 GST_STATIC_PAD_TEMPLATE(
85 GST_STATIC_CAPS(gst_vaapidecode_src_caps_str));
88 typedef struct _GstVaapiDecoderMap GstVaapiDecoderMap;
89 struct _GstVaapiDecoderMap
94 const gchar *caps_str;
96 void (*install_properties) (GObjectClass * klass);
99 static const GstVaapiDecoderMap vaapi_decode_map[] = {
100 {GST_VAAPI_CODEC_JPEG, GST_RANK_MARGINAL, "jpeg", "image/jpeg", NULL},
101 {GST_VAAPI_CODEC_MPEG2, GST_RANK_PRIMARY, "mpeg2",
102 "video/mpeg, mpegversion=2, systemstream=(boolean)false", NULL},
103 {GST_VAAPI_CODEC_MPEG4, GST_RANK_PRIMARY, "mpeg4",
104 "video/mpeg, mpegversion=4", NULL},
105 {GST_VAAPI_CODEC_H263, GST_RANK_PRIMARY, "h263", "video/x-h263", NULL},
106 {GST_VAAPI_CODEC_H264, GST_RANK_PRIMARY, "h264", "video/x-h264",
107 gst_vaapi_decode_h264_install_properties},
108 {GST_VAAPI_CODEC_VC1, GST_RANK_PRIMARY, "vc1",
109 "video/x-wmv, wmvversion=3, format={WMV3,WVC1}", NULL},
110 {GST_VAAPI_CODEC_VP8, GST_RANK_PRIMARY, "vp8", "video/x-vp8", NULL},
111 {GST_VAAPI_CODEC_VP9, GST_RANK_PRIMARY, "vp9", "video/x-vp9", NULL},
112 {GST_VAAPI_CODEC_H265, GST_RANK_PRIMARY, "h265", "video/x-h265", NULL},
113 {GST_VAAPI_CODEC_AV1, GST_RANK_PRIMARY, "av1", "video/x-av1", NULL},
114 {0 /* the rest */ , GST_RANK_PRIMARY + 1, NULL, NULL, NULL},
117 static GstElementClass *parent_class = NULL;
118 GST_VAAPI_PLUGIN_BASE_DEFINE_SET_CONTEXT (parent_class);
120 static gboolean gst_vaapidecode_update_sink_caps (GstVaapiDecode * decode,
122 static gboolean gst_vaapi_decode_input_state_replace (GstVaapiDecode * decode,
123 const GstVideoCodecState * new_state);
125 /* invoked if actual VASurface size (not the cropped values)
128 gst_vaapi_decoder_state_changed (GstVaapiDecoder * decoder,
129 const GstVideoCodecState * codec_state, gpointer user_data)
131 GstVaapiDecode *const decode = GST_VAAPIDECODE (user_data);
133 g_assert (decode->decoder == decoder);
135 if (!gst_vaapi_decode_input_state_replace (decode, codec_state))
137 if (!gst_vaapidecode_update_sink_caps (decode, decode->input_state->caps))
141 static GstVideoCodecState *
142 copy_video_codec_state (const GstVideoCodecState * in_state)
144 GstVideoCodecState *state;
146 g_return_val_if_fail (in_state != NULL, NULL);
148 state = g_slice_new0 (GstVideoCodecState);
149 state->ref_count = 1;
150 state->info = in_state->info;
151 state->caps = gst_caps_copy (in_state->caps);
152 if (in_state->codec_data)
153 state->codec_data = gst_buffer_copy_deep (in_state->codec_data);
159 gst_vaapi_decode_input_state_replace (GstVaapiDecode * decode,
160 const GstVideoCodecState * new_state)
162 if (decode->input_state) {
164 const GstCaps *curcaps = decode->input_state->caps;
165 /* If existing caps are equal of the new state, keep the
166 * existing state without renegotiating. */
167 if (gst_caps_is_strictly_equal (curcaps, new_state->caps)) {
168 GST_DEBUG ("Ignoring new caps %" GST_PTR_FORMAT
169 " since are equal to current ones", new_state->caps);
173 gst_video_codec_state_unref (decode->input_state);
177 decode->input_state = copy_video_codec_state (new_state);
179 decode->input_state = NULL;
184 static inline gboolean
185 gst_vaapidecode_update_sink_caps (GstVaapiDecode * decode, GstCaps * caps)
187 GST_INFO_OBJECT (decode, "new sink caps = %" GST_PTR_FORMAT, caps);
188 gst_caps_replace (&decode->sinkpad_caps, caps);
193 gst_vaapidecode_ensure_allowed_srcpad_caps (GstVaapiDecode * decode)
195 GstVaapiDisplay *const display = GST_VAAPI_PLUGIN_BASE_DISPLAY (decode);
196 GstCaps *out_caps, *raw_caps, *va_caps, *dma_caps, *gltexup_caps, *base_caps;
198 gint min_width, min_height, max_width, max_height;
200 gboolean ret = FALSE;
202 if (decode->allowed_srcpad_caps)
208 if (!decode->decoder)
211 dma_caps = gltexup_caps = NULL;
213 formats = gst_vaapi_decoder_get_surface_attributes (decode->decoder,
214 &min_width, &min_height, &max_width, &max_height, &mem_types);
218 base_caps = gst_vaapi_video_format_new_template_caps_from_list (formats);
221 gst_vaapi_caps_set_width_and_height_range (base_caps, min_width, min_height,
222 max_width, max_height);
225 GArray *img_formats = gst_vaapi_display_get_image_formats (display);
226 GstVideoFormat decoded_format =
227 GST_VIDEO_INFO_FORMAT (&decode->decoded_info);
230 img_formats = g_array_ref (formats);
232 if (decoded_format != GST_VIDEO_FORMAT_UNKNOWN) {
233 guint decoded_chroma =
234 gst_vaapi_video_format_get_chroma_type (decoded_format);
235 GArray *new_img_formats =
236 g_array_new (FALSE, FALSE, sizeof (GstVideoFormat));
239 for (i = 0; i < img_formats->len; i++) {
240 const GstVideoFormat fmt =
241 g_array_index (img_formats, GstVideoFormat, i);
242 if (gst_vaapi_video_format_get_chroma_type (fmt) == decoded_chroma)
243 g_array_append_val (new_img_formats, fmt);
246 if (new_img_formats->len == 0) {
247 g_clear_pointer (&new_img_formats, g_array_unref);
249 g_clear_pointer (&img_formats, g_array_unref);
250 img_formats = new_img_formats;
254 raw_caps = gst_vaapi_video_format_new_template_caps_from_list (img_formats);
255 gst_vaapi_caps_set_width_and_height_range (raw_caps, min_width, min_height,
256 max_width, max_height);
257 g_array_unref (img_formats);
260 va_caps = gst_caps_copy (base_caps);
261 gst_caps_set_features_simple (va_caps,
262 gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_VAAPI_SURFACE));
264 if (gst_vaapi_mem_type_supports (mem_types,
265 GST_VAAPI_BUFFER_MEMORY_TYPE_DMA_BUF) ||
266 gst_vaapi_mem_type_supports (mem_types,
267 GST_VAAPI_BUFFER_MEMORY_TYPE_DMA_BUF2)) {
268 dma_caps = gst_caps_copy (base_caps);
269 gst_caps_set_features_simple (dma_caps,
270 gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_DMABUF));
272 #if (USE_GLX || USE_EGL)
273 if (!GST_VAAPI_PLUGIN_BASE_SRC_PAD_CAN_DMABUF (decode)
274 && gst_vaapi_display_has_opengl (GST_VAAPI_PLUGIN_BASE_DISPLAY (decode))) {
275 gltexup_caps = gst_caps_from_string (GST_VAAPI_MAKE_GLTEXUPLOAD_CAPS);
277 gst_vaapi_caps_set_width_and_height_range (base_caps, min_width,
278 min_height, max_width, max_height);
285 gst_caps_append (out_caps, dma_caps);
287 gst_caps_append (out_caps, gltexup_caps);
288 gst_caps_append (out_caps, raw_caps);
289 decode->allowed_srcpad_caps = out_caps;
291 GST_INFO_OBJECT (decode, "allowed srcpad caps: %" GST_PTR_FORMAT,
292 decode->allowed_srcpad_caps);
298 g_array_unref (formats);
300 gst_caps_unref (base_caps);
305 gst_vaapidecode_get_allowed_srcpad_caps (GstVaapiDecode * decode)
307 GstPad *const srcpad = GST_VIDEO_DECODER_SRC_PAD (decode);
309 if (gst_vaapidecode_ensure_allowed_srcpad_caps (decode))
310 return gst_caps_ref (decode->allowed_srcpad_caps);
311 return gst_pad_get_pad_template_caps (srcpad);
315 gst_vaapidecode_update_src_caps (GstVaapiDecode * decode)
317 GstVideoDecoder *const vdec = GST_VIDEO_DECODER (decode);
318 GstPad *const srcpad = GST_VIDEO_DECODER_SRC_PAD (vdec);
320 GstVideoCodecState *state, *ref_state;
321 GstVaapiCapsFeature feature;
322 GstCapsFeatures *features;
323 GstCaps *allocation_caps;
325 GstVideoFormat format;
326 GstClockTime latency;
329 const gchar *format_str, *feature_str;
331 if (!decode->input_state)
334 ref_state = decode->input_state;
336 format = GST_VIDEO_INFO_FORMAT (&decode->decoded_info);
337 allowed = gst_vaapidecode_get_allowed_srcpad_caps (decode);
338 feature = gst_vaapi_find_preferred_caps_feature (srcpad, allowed, &format);
339 gst_caps_unref (allowed);
341 if (feature == GST_VAAPI_CAPS_FEATURE_NOT_NEGOTIATED)
344 #if (!USE_GLX && !USE_EGL)
345 /* This is a very pathological situation. Should not happen. */
346 if (feature == GST_VAAPI_CAPS_FEATURE_GL_TEXTURE_UPLOAD_META)
350 if ((feature == GST_VAAPI_CAPS_FEATURE_SYSTEM_MEMORY ||
351 feature == GST_VAAPI_CAPS_FEATURE_VAAPI_SURFACE)
352 && format != GST_VIDEO_INFO_FORMAT (&decode->decoded_info)) {
353 GST_FIXME_OBJECT (decode, "validate if driver can convert from %s to %s",
354 gst_video_format_to_string (GST_VIDEO_INFO_FORMAT
355 (&decode->decoded_info)), gst_video_format_to_string (format));
358 width = decode->display_width;
359 height = decode->display_height;
361 if (!width || !height) {
362 width = GST_VIDEO_INFO_WIDTH (&ref_state->info);
363 height = GST_VIDEO_INFO_HEIGHT (&ref_state->info);
366 state = gst_video_decoder_set_output_state (vdec, format, width, height,
371 if (GST_VIDEO_INFO_WIDTH (&state->info) == 0
372 || GST_VIDEO_INFO_HEIGHT (&state->info) == 0) {
373 gst_video_codec_state_unref (state);
378 state->caps = gst_video_info_to_caps (vi);
381 case GST_VAAPI_CAPS_FEATURE_GL_TEXTURE_UPLOAD_META:
382 case GST_VAAPI_CAPS_FEATURE_DMABUF:
383 case GST_VAAPI_CAPS_FEATURE_VAAPI_SURFACE:{
384 GstStructure *structure = gst_caps_get_structure (state->caps, 0);
387 feature_str = gst_vaapi_caps_feature_to_string (feature);
388 features = gst_caps_features_new (feature_str, NULL);
389 gst_caps_set_features (state->caps, 0, features);
396 /* Allocation query is different from pad's caps */
397 allocation_caps = NULL;
398 if (GST_VIDEO_INFO_WIDTH (&decode->decoded_info) != width
399 || GST_VIDEO_INFO_HEIGHT (&decode->decoded_info) != height) {
400 allocation_caps = gst_caps_copy (state->caps);
401 format_str = gst_video_format_to_string (format);
402 gst_caps_set_simple (allocation_caps,
403 "width", G_TYPE_INT, GST_VIDEO_INFO_WIDTH (&decode->decoded_info),
404 "height", G_TYPE_INT, GST_VIDEO_INFO_HEIGHT (&decode->decoded_info),
405 "format", G_TYPE_STRING, format_str, NULL);
406 GST_INFO_OBJECT (decode, "new alloc caps = %" GST_PTR_FORMAT,
409 gst_caps_replace (&state->allocation_caps, allocation_caps);
411 gst_caps_unref (allocation_caps);
413 GST_INFO_OBJECT (decode, "new src caps = %" GST_PTR_FORMAT, state->caps);
414 gst_caps_replace (&decode->srcpad_caps, state->caps);
415 gst_video_codec_state_unref (state);
417 fps_n = GST_VIDEO_INFO_FPS_N (vi);
418 fps_d = GST_VIDEO_INFO_FPS_D (vi);
419 if (fps_n <= 0 || fps_d <= 0) {
420 GST_DEBUG_OBJECT (decode, "forcing 25/1 framerate for latency calculation");
425 /* For parsing/preparation purposes we'd need at least 1 frame
426 * latency in general, with perfectly known unit boundaries (NALU,
427 * AU), and up to 2 frames when we need to wait for the second frame
428 * start to determine the first frame is complete */
429 latency = gst_util_uint64_scale (2 * GST_SECOND, fps_d, fps_n);
430 gst_video_decoder_set_latency (vdec, latency, latency);
435 /* check whether the decoded surface size has changed */
437 is_surface_resolution_changed (GstVaapiDecode * decode,
438 GstVaapiSurface * surface)
440 GstVideoInfo *vinfo = &decode->decoded_info;
441 GstVideoFormat surface_format;
442 guint surface_width, surface_height;
444 g_return_val_if_fail (surface != NULL, FALSE);
446 gst_vaapi_surface_get_size (surface, &surface_width, &surface_height);
448 if (GST_VIDEO_INFO_WIDTH (vinfo) == surface_width
449 && GST_VIDEO_INFO_HEIGHT (vinfo) == surface_height)
452 /* doing gst_vaapi_surface_get_format() only if necessary since it
453 * execute vaDeriveImage in the background. This will usually get
454 * executed only once */
455 surface_format = GST_VIDEO_INFO_FORMAT (vinfo);
456 if (surface_format == GST_VIDEO_FORMAT_UNKNOWN) {
457 surface_format = gst_vaapi_surface_get_format (surface);
459 /* if the VA context delivers a currently unrecognized format
460 * (ICM3, e.g.), we can assume one according surface chroma
461 * type. If fail, then use NV12 "safely" */
462 if (surface_format == GST_VIDEO_FORMAT_UNKNOWN
463 || surface_format == GST_VIDEO_FORMAT_ENCODED)
465 gst_vaapi_video_format_from_chroma (gst_vaapi_surface_get_chroma_type
467 if (surface_format == GST_VIDEO_FORMAT_UNKNOWN)
468 surface_format = GST_VIDEO_FORMAT_NV12;
471 /* reset allowed source caps since they are dependant of the decoded
473 gst_caps_replace (&decode->allowed_srcpad_caps, NULL);
475 gst_video_info_set_format (vinfo, surface_format, surface_width,
481 /* check whether display resolution changed */
483 is_display_resolution_changed (GstVaapiDecode * decode,
484 const GstVaapiRectangle * crop_rect)
486 GstVideoDecoder *const vdec = GST_VIDEO_DECODER (decode);
487 GstVideoCodecState *state;
488 guint display_width, display_height;
489 guint negotiated_width, negotiated_height;
491 display_width = GST_VIDEO_INFO_WIDTH (&decode->decoded_info);
492 display_height = GST_VIDEO_INFO_HEIGHT (&decode->decoded_info);
494 display_width = crop_rect->width;
495 display_height = crop_rect->height;
498 state = gst_video_decoder_get_output_state (vdec);
499 if (G_UNLIKELY (!state))
500 goto set_display_res;
502 negotiated_width = GST_VIDEO_INFO_WIDTH (&state->info);
503 negotiated_height = GST_VIDEO_INFO_HEIGHT (&state->info);
504 gst_video_codec_state_unref (state);
506 if ((display_width == negotiated_width && display_height == negotiated_height)
507 && (decode->display_width == negotiated_width
508 && decode->display_height == negotiated_height))
512 decode->display_width = display_width;
513 decode->display_height = display_height;
518 gst_vaapidecode_negotiate (GstVaapiDecode * decode)
520 GstVideoDecoder *const vdec = GST_VIDEO_DECODER (decode);
521 GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (vdec);
523 GST_DEBUG_OBJECT (decode, "input codec state changed: renegotiating");
525 GST_VIDEO_DECODER_STREAM_LOCK (vdec);
526 if (!gst_vaapidecode_update_src_caps (decode))
527 goto caps_negotiation_failed;
528 if (!gst_vaapi_plugin_base_set_caps (plugin, NULL, decode->srcpad_caps))
529 goto caps_negotiation_failed;
530 GST_VIDEO_DECODER_STREAM_UNLOCK (vdec);
532 if (!gst_video_decoder_negotiate (vdec))
537 caps_negotiation_failed:
539 GST_VIDEO_DECODER_STREAM_UNLOCK (vdec);
545 is_src_allocator_dmabuf (GstVaapiDecode * decode)
547 GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (decode);
549 if (!GST_VAAPI_PLUGIN_BASE_SRC_PAD_CAN_DMABUF (plugin))
552 gst_vaapi_is_dmabuf_allocator (GST_VAAPI_PLUGIN_BASE_SRC_PAD_ALLOCATOR
557 gst_vaapidecode_push_decoded_frame (GstVideoDecoder * vdec,
558 GstVideoCodecFrame * out_frame)
560 GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);
561 GstVaapiSurfaceProxy *proxy;
562 GstVaapiSurface *surface;
564 const GstVaapiRectangle *crop_rect;
565 GstVaapiVideoMeta *meta;
566 GstBufferPoolAcquireParams *params = NULL;
567 GstVaapiVideoBufferPoolAcquireParams vaapi_params = { {0,}, };
568 guint flags, out_flags = 0;
569 gboolean alloc_renegotiate, caps_renegotiate;
571 if (!GST_VIDEO_CODEC_FRAME_IS_DECODE_ONLY (out_frame)) {
572 proxy = gst_video_codec_frame_get_user_data (out_frame);
573 surface = GST_VAAPI_SURFACE_PROXY_SURFACE (proxy);
574 crop_rect = gst_vaapi_surface_proxy_get_crop_rect (proxy);
576 /* in theory, we are not supposed to check the surface resolution
577 * change here since it should be advertised before from ligstvaapi.
578 * But there are issues with it especially for some vp9 streams where
579 * upstream element set un-cropped values in set_format() which make
580 * everything a mess. So better doing the explicit check here irrespective
581 * of what notification we get from upstream or libgstvaapi.Also, even if
582 * we received notification from libgstvaapi, the frame we are going to
583 * be pushed at this point might not have the notified resolution if there
584 * are queued frames in decoded picture buffer. */
585 alloc_renegotiate = is_surface_resolution_changed (decode, surface);
586 caps_renegotiate = is_display_resolution_changed (decode, crop_rect);
588 if (gst_pad_needs_reconfigure (GST_VIDEO_DECODER_SRC_PAD (vdec))
589 || alloc_renegotiate || caps_renegotiate || decode->do_renego) {
591 g_atomic_int_set (&decode->do_renego, FALSE);
592 if (!gst_vaapidecode_negotiate (decode))
593 return GST_FLOW_ERROR;
596 if (is_src_allocator_dmabuf (decode)) {
597 vaapi_params.proxy = gst_vaapi_surface_proxy_ref (proxy);
598 params = (GstBufferPoolAcquireParams *) & vaapi_params;
601 ret = gst_video_decoder_allocate_output_frame_with_params (vdec, out_frame,
604 gst_vaapi_surface_proxy_unref (vaapi_params.proxy);
605 if (ret != GST_FLOW_OK)
606 goto error_create_buffer;
608 /* if not dmabuf is negotiated set the vaapi video meta in the
611 meta = gst_buffer_get_vaapi_video_meta (out_frame->output_buffer);
614 gst_vaapi_video_meta_set_surface_proxy (meta, proxy);
617 flags = gst_vaapi_surface_proxy_get_flags (proxy);
618 if (flags & GST_VAAPI_SURFACE_PROXY_FLAG_CORRUPTED)
619 out_flags |= GST_BUFFER_FLAG_CORRUPTED;
620 if (flags & GST_VAAPI_SURFACE_PROXY_FLAG_INTERLACED) {
621 out_flags |= GST_VIDEO_BUFFER_FLAG_INTERLACED;
622 if (flags & GST_VAAPI_SURFACE_PROXY_FLAG_TFF)
623 out_flags |= GST_VIDEO_BUFFER_FLAG_TFF;
624 if (flags & GST_VAAPI_SURFACE_PROXY_FLAG_RFF)
625 out_flags |= GST_VIDEO_BUFFER_FLAG_RFF;
626 if (flags & GST_VAAPI_SURFACE_PROXY_FLAG_ONEFIELD)
627 out_flags |= GST_VIDEO_BUFFER_FLAG_ONEFIELD;
629 GST_BUFFER_FLAG_SET (out_frame->output_buffer, out_flags);
631 if (flags & GST_VAAPI_SURFACE_PROXY_FLAG_FFB) {
632 GST_BUFFER_FLAG_SET (out_frame->output_buffer,
633 GST_VIDEO_BUFFER_FLAG_FIRST_IN_BUNDLE);
635 #if (USE_GLX || USE_EGL)
636 if (decode->has_texture_upload_meta)
637 gst_buffer_ensure_texture_upload_meta (out_frame->output_buffer);
640 /* Generate a system allocated output buffer if downstream doesn't
641 * support GstVideoMeta */
642 if (GST_VAAPI_PLUGIN_BASE_COPY_OUTPUT_FRAME (vdec)) {
643 GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (vdec);
644 GstBuffer *sys_buf, *va_buf;
646 va_buf = out_frame->output_buffer;
648 gst_buffer_new_allocate (GST_VAAPI_PLUGIN_BASE_OTHER_ALLOCATOR
650 GST_VIDEO_INFO_SIZE (GST_VAAPI_PLUGIN_BASE_SRC_PAD_INFO (plugin)),
651 &GST_VAAPI_PLUGIN_BASE_OTHER_ALLOCATOR_PARAMS (plugin));
653 goto error_no_sys_buffer;
655 if (!gst_vaapi_plugin_copy_va_buffer (plugin, va_buf, sys_buf)) {
656 gst_buffer_unref (sys_buf);
657 goto error_cannot_copy;
660 gst_buffer_replace (&out_frame->output_buffer, sys_buf);
661 gst_buffer_unref (sys_buf);
665 ret = gst_video_decoder_finish_frame (vdec, out_frame);
666 if (ret != GST_FLOW_OK)
667 goto error_commit_buffer;
673 const GstVaapiID surface_id =
674 gst_vaapi_surface_get_id (GST_VAAPI_SURFACE_PROXY_SURFACE (proxy));
676 GST_ELEMENT_ERROR (vdec, STREAM, FAILED,
677 ("Failed to create sink buffer"),
678 ("video sink failed to create video buffer for proxy'ed "
679 "surface %" GST_VAAPI_ID_FORMAT, GST_VAAPI_ID_ARGS (surface_id)));
680 gst_video_decoder_drop_frame (vdec, out_frame);
681 return GST_FLOW_ERROR;
685 GST_ELEMENT_ERROR (vdec, STREAM, FAILED,
686 ("Failed to get vaapi video meta attached to video buffer"),
687 ("Failed to get vaapi video meta attached to video buffer"));
688 gst_video_decoder_drop_frame (vdec, out_frame);
689 return GST_FLOW_ERROR;
693 GST_ELEMENT_ERROR (vdec, STREAM, FAILED,
694 ("Failed to create system allocated buffer"),
695 ("Failed to create system allocated buffer"));
696 gst_video_decoder_drop_frame (vdec, out_frame);
697 return GST_FLOW_ERROR;
701 GST_ELEMENT_ERROR (vdec, STREAM, FAILED,
702 ("Failed to copy system allocated buffer"),
703 ("Failed to copy system allocated buffer"));
704 gst_video_decoder_drop_frame (vdec, out_frame);
705 return GST_FLOW_ERROR;
709 GST_LOG_OBJECT (decode, "downstream element rejected the frame (%s [%d])",
710 gst_flow_get_name (ret), ret);
716 gst_vaapidecode_push_all_decoded_frames (GstVaapiDecode * decode)
718 GstVideoDecoder *const vdec = GST_VIDEO_DECODER (decode);
719 GstVaapiDecoderStatus status;
720 GstVideoCodecFrame *out_frame;
724 status = gst_vaapi_decoder_get_frame (decode->decoder, &out_frame);
727 case GST_VAAPI_DECODER_STATUS_SUCCESS:
728 /* GstVaapiDecode's queue adds an extra reference */
729 gst_video_codec_frame_unref (out_frame);
730 ret = gst_vaapidecode_push_decoded_frame (vdec, out_frame);
731 if (ret != GST_FLOW_OK)
734 case GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA:
737 GST_VIDEO_DECODER_ERROR (vdec, 1, STREAM, DECODE, ("Decoding failed"),
738 ("Unknown decoding error"), ret);
742 g_assert_not_reached ();
746 gst_vaapidecode_handle_frame (GstVideoDecoder * vdec,
747 GstVideoCodecFrame * frame)
749 GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);
750 GstVaapiDecoderStatus status;
752 if (!decode->input_state)
755 /* Decode current frame */
757 status = gst_vaapi_decoder_decode (decode->decoder, frame);
758 if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
763 /* Note that gst_vaapi_decoder_decode cannot return success without
764 completing the decode and pushing all decoded frames into the output
766 return gst_vaapidecode_push_all_decoded_frames (decode);
771 GstFlowReturn ret = GST_FLOW_OK;
773 GST_WARNING_OBJECT (decode, "decode error %d", status);
776 case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC:
777 case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE:
778 case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CHROMA_FORMAT:
779 ret = GST_FLOW_NOT_SUPPORTED;
782 GST_VIDEO_DECODER_ERROR (vdec, 1, STREAM, DECODE, ("Decoding error"),
783 ("Decode error %d", status), ret);
784 GST_INFO_OBJECT (decode, "requesting upstream a key unit");
785 gst_pad_push_event (GST_VIDEO_DECODER_SINK_PAD (decode),
786 gst_video_event_new_upstream_force_key_unit (GST_CLOCK_TIME_NONE,
790 gst_video_decoder_drop_frame (vdec, frame);
795 GST_ERROR_OBJECT (decode, "not negotiated");
796 gst_video_decoder_drop_frame (vdec, frame);
797 return GST_FLOW_NOT_NEGOTIATED;
801 /* If there is something in GstVideoDecoder's output adapter, then
802 submit the frame for decoding */
804 gst_vaapidecode_flush_output_adapter (GstVaapiDecode * decode)
806 if (decode->current_frame_size == 0)
808 gst_video_decoder_have_frame (GST_VIDEO_DECODER (decode));
809 decode->current_frame_size = 0;
813 gst_vaapidecode_drain (GstVideoDecoder * vdec)
815 GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);
817 if (!decode->decoder)
818 return GST_FLOW_NOT_NEGOTIATED;
820 GST_LOG_OBJECT (decode, "drain");
822 gst_vaapidecode_flush_output_adapter (decode);
823 return gst_vaapidecode_push_all_decoded_frames (decode);
827 gst_vaapidecode_finish (GstVideoDecoder * vdec)
829 GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);
830 GstVaapiDecoderStatus status;
833 if (!decode->decoder)
836 gst_vaapidecode_flush_output_adapter (decode);
837 status = gst_vaapi_decoder_flush (decode->decoder);
838 ret = gst_vaapidecode_push_all_decoded_frames (decode);
839 if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
840 goto error_decoder_flush;
846 GST_WARNING_OBJECT (decode, "failed to flush decoder (status %d)", status);
847 return GST_FLOW_ERROR;
852 gst_vaapidecode_decide_allocation (GstVideoDecoder * vdec, GstQuery * query)
854 GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);
855 GstCaps *caps = NULL;
857 gst_query_parse_allocation (query, &caps, NULL);
861 decode->has_texture_upload_meta = FALSE;
863 #if (USE_GLX || USE_EGL)
864 decode->has_texture_upload_meta =
865 gst_query_find_allocation_meta (query,
866 GST_VIDEO_GL_TEXTURE_UPLOAD_META_API_TYPE, NULL) &&
867 gst_vaapi_caps_feature_contains (caps,
868 GST_VAAPI_CAPS_FEATURE_GL_TEXTURE_UPLOAD_META);
871 return gst_vaapi_plugin_base_decide_allocation (GST_VAAPI_PLUGIN_BASE (vdec),
877 GST_ERROR_OBJECT (decode, "no caps specified");
882 static inline gboolean
883 gst_vaapidecode_ensure_display (GstVaapiDecode * decode)
885 return gst_vaapi_plugin_base_ensure_display (GST_VAAPI_PLUGIN_BASE (decode));
889 gst_vaapidecode_create (GstVaapiDecode * decode, GstCaps * caps)
891 GstVaapiDisplay *dpy;
893 if (!gst_vaapidecode_ensure_display (decode))
895 dpy = GST_VAAPI_PLUGIN_BASE_DISPLAY (decode);
897 switch (gst_vaapi_get_codec_from_caps (caps)) {
898 case GST_VAAPI_CODEC_MPEG2:
899 decode->decoder = gst_vaapi_decoder_mpeg2_new (dpy, caps);
901 case GST_VAAPI_CODEC_MPEG4:
902 case GST_VAAPI_CODEC_H263:
903 decode->decoder = gst_vaapi_decoder_mpeg4_new (dpy, caps);
905 case GST_VAAPI_CODEC_H264:
906 decode->decoder = gst_vaapi_decoder_h264_new (dpy, caps);
908 /* Set the stream buffer alignment for better optimizations */
909 if (decode->decoder && caps) {
910 GstVaapiDecodeH264Private *priv =
911 gst_vaapi_decode_h264_get_instance_private (decode);
912 GstStructure *const structure = gst_caps_get_structure (caps, 0);
913 const gchar *str = NULL;
918 if ((str = gst_structure_get_string (structure, "alignment"))) {
919 GstVaapiStreamAlignH264 alignment;
920 if (g_strcmp0 (str, "au") == 0)
921 alignment = GST_VAAPI_STREAM_ALIGN_H264_AU;
922 else if (g_strcmp0 (str, "nal") == 0)
923 alignment = GST_VAAPI_STREAM_ALIGN_H264_NALU;
925 alignment = GST_VAAPI_STREAM_ALIGN_H264_NONE;
926 gst_vaapi_decoder_h264_set_alignment (GST_VAAPI_DECODER_H264
927 (decode->decoder), alignment);
931 gst_vaapi_decoder_h264_set_low_latency (GST_VAAPI_DECODER_H264
932 (decode->decoder), priv->is_low_latency);
933 gst_vaapi_decoder_h264_set_base_only (GST_VAAPI_DECODER_H264
934 (decode->decoder), priv->base_only);
938 case GST_VAAPI_CODEC_H265:
939 decode->decoder = gst_vaapi_decoder_h265_new (dpy, caps);
941 /* Set the stream buffer alignment for better optimizations */
942 if (decode->decoder && caps) {
943 GstStructure *const structure = gst_caps_get_structure (caps, 0);
944 const gchar *str = NULL;
949 if ((str = gst_structure_get_string (structure, "alignment"))) {
950 GstVaapiStreamAlignH265 alignment;
951 if (g_strcmp0 (str, "au") == 0)
952 alignment = GST_VAAPI_STREAM_ALIGN_H265_AU;
953 else if (g_strcmp0 (str, "nal") == 0)
954 alignment = GST_VAAPI_STREAM_ALIGN_H265_NALU;
956 alignment = GST_VAAPI_STREAM_ALIGN_H265_NONE;
957 gst_vaapi_decoder_h265_set_alignment (GST_VAAPI_DECODER_H265
958 (decode->decoder), alignment);
962 case GST_VAAPI_CODEC_WMV3:
963 case GST_VAAPI_CODEC_VC1:
964 decode->decoder = gst_vaapi_decoder_vc1_new (dpy, caps);
966 case GST_VAAPI_CODEC_JPEG:
967 decode->decoder = gst_vaapi_decoder_jpeg_new (dpy, caps);
969 case GST_VAAPI_CODEC_VP8:
970 decode->decoder = gst_vaapi_decoder_vp8_new (dpy, caps);
972 case GST_VAAPI_CODEC_VP9:
973 decode->decoder = gst_vaapi_decoder_vp9_new (dpy, caps);
976 case GST_VAAPI_CODEC_AV1:
977 decode->decoder = gst_vaapi_decoder_av1_new (dpy, caps);
981 decode->decoder = NULL;
984 if (!decode->decoder)
987 gst_vaapi_decoder_set_codec_state_changed_func (decode->decoder,
988 gst_vaapi_decoder_state_changed, decode);
994 gst_vaapidecode_purge (GstVaapiDecode * decode)
996 GstVaapiDecoderStatus status;
998 if (!decode->decoder)
1001 status = gst_vaapi_decoder_flush (decode->decoder);
1002 if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
1003 GST_INFO_OBJECT (decode, "failed to flush decoder (status %d)", status);
1005 /* Purge all decoded frames as we don't need them (e.g. flush and close)
1006 * Releasing the frames is important, otherwise the frames are not
1009 GstVideoCodecFrame *frame = NULL;
1012 gst_vaapi_decoder_get_frame_with_timeout (decode->decoder, &frame, 0);
1014 gst_video_decoder_release_frame (GST_VIDEO_DECODER (decode), frame);
1015 gst_video_codec_frame_unref (frame);
1017 } while (status == GST_VAAPI_DECODER_STATUS_SUCCESS);
1021 gst_vaapidecode_destroy (GstVaapiDecode * decode)
1023 gst_vaapidecode_purge (decode);
1025 gst_vaapi_decoder_replace (&decode->decoder, NULL);
1026 /* srcpad caps are decoder's context dependant */
1027 gst_caps_replace (&decode->allowed_srcpad_caps, NULL);
1031 gst_vaapidecode_reset (GstVaapiDecode * decode, GstCaps * caps,
1032 gboolean force_reset)
1034 /* Reset tracked frame size */
1035 decode->current_frame_size = 0;
1037 if (decode->decoder) {
1038 if (!gst_caps_is_equal (caps, gst_vaapi_decoder_get_caps (decode->decoder))) {
1039 if (gst_vaapi_decoder_update_caps (decode->decoder, caps)) {
1040 g_atomic_int_set (&decode->do_renego, TRUE);
1045 return (gst_vaapi_decoder_reset (decode->decoder) ==
1046 GST_VAAPI_DECODER_STATUS_SUCCESS);
1049 return gst_vaapidecode_create (decode, caps);
1053 gst_vaapidecode_finalize (GObject * object)
1055 gst_vaapi_plugin_base_finalize (GST_VAAPI_PLUGIN_BASE (object));
1056 G_OBJECT_CLASS (parent_class)->finalize (object);
1060 gst_vaapidecode_open (GstVideoDecoder * vdec)
1062 GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);
1064 if (!gst_vaapi_plugin_base_open (GST_VAAPI_PLUGIN_BASE (decode)))
1067 decode->display_width = 0;
1068 decode->display_height = 0;
1069 gst_video_info_init (&decode->decoded_info);
1075 gst_vaapidecode_close (GstVideoDecoder * vdec)
1077 GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);
1079 gst_vaapidecode_destroy (decode);
1080 gst_caps_replace (&decode->allowed_srcpad_caps, NULL);
1081 gst_caps_replace (&decode->allowed_sinkpad_caps, NULL);
1082 gst_vaapi_plugin_base_close (GST_VAAPI_PLUGIN_BASE (decode));
1087 gst_vaapidecode_start (GstVideoDecoder * vdec)
1089 GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);
1090 GstVaapiDisplay *const old_display = GST_VAAPI_PLUGIN_BASE_DISPLAY (decode);
1093 /* Let GstVideoContext ask for a proper display to its neighbours */
1094 /* Note: steal old display that may be allocated from get_caps()
1095 so that to retain a reference to it, thus avoiding extra
1096 initialization steps if we turn out to simply re-use the
1097 existing (cached) VA display */
1098 GST_VAAPI_PLUGIN_BASE_DISPLAY (decode) = NULL;
1100 gst_vaapi_plugin_base_ensure_display (GST_VAAPI_PLUGIN_BASE (decode));
1102 gst_object_unref (old_display);
1104 /* Disable errors on decode errors */
1105 gst_video_decoder_set_max_errors (vdec, -1);
1111 gst_vaapidecode_stop (GstVideoDecoder * vdec)
1113 GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);
1115 gst_vaapidecode_purge (decode);
1116 gst_vaapi_decode_input_state_replace (decode, NULL);
1117 gst_vaapi_decoder_replace (&decode->decoder, NULL);
1118 gst_caps_replace (&decode->sinkpad_caps, NULL);
1119 gst_caps_replace (&decode->srcpad_caps, NULL);
1124 gst_vaapidecode_flush (GstVideoDecoder * vdec)
1126 GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);
1127 if (!decode->decoder)
1130 GST_LOG_OBJECT (vdec, "flushing");
1132 gst_vaapidecode_purge (decode);
1134 /* There could be issues if we avoid the reset() while doing
1135 * seeking: we have to reset the internal state */
1136 return gst_vaapidecode_reset (decode, decode->sinkpad_caps, TRUE);
1140 gst_vaapidecode_set_format (GstVideoDecoder * vdec, GstVideoCodecState * state)
1142 GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (vdec);
1143 GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);
1145 if (!gst_vaapi_decode_input_state_replace (decode, state))
1147 if (gst_vaapidecode_drain (vdec) == GST_FLOW_ERROR)
1149 if (!gst_vaapidecode_update_sink_caps (decode, state->caps))
1151 if (!gst_vaapi_plugin_base_set_caps (plugin, decode->sinkpad_caps, NULL))
1153 if (!gst_vaapidecode_reset (decode, decode->sinkpad_caps, FALSE))
1159 static GstFlowReturn
1160 gst_vaapidecode_parse_frame (GstVideoDecoder * vdec,
1161 GstVideoCodecFrame * frame, GstAdapter * adapter, gboolean at_eos)
1163 GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);
1164 GstVaapiDecoderStatus status;
1166 guint got_unit_size;
1169 status = gst_vaapi_decoder_parse (decode->decoder, frame,
1170 adapter, at_eos, &got_unit_size, &got_frame);
1173 case GST_VAAPI_DECODER_STATUS_SUCCESS:
1174 if (got_unit_size > 0) {
1175 gst_video_decoder_add_to_frame (vdec, got_unit_size);
1176 decode->current_frame_size += got_unit_size;
1179 ret = gst_video_decoder_have_frame (vdec);
1180 decode->current_frame_size = 0;
1182 ret = GST_VAAPI_DECODE_FLOW_PARSE_DATA;
1184 case GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA:
1185 ret = GST_VIDEO_DECODER_FLOW_NEED_DATA;
1187 case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC:
1188 case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE:
1189 case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CHROMA_FORMAT:
1190 GST_WARNING ("parse error %d", status);
1191 ret = GST_FLOW_NOT_SUPPORTED;
1192 decode->current_frame_size = 0;
1195 GST_WARNING ("parse error %d", status);
1196 /* just keep parsing, the decoder should have flushed the broken unit */
1197 ret = GST_VAAPI_DECODE_FLOW_PARSE_DATA;
1198 decode->current_frame_size = 0;
1200 GST_INFO ("requesting upstream a key unit");
1201 gst_pad_push_event (GST_VIDEO_DECODER_SINK_PAD (decode),
1202 gst_video_event_new_upstream_force_key_unit (GST_CLOCK_TIME_NONE,
1209 static GstFlowReturn
1210 gst_vaapidecode_parse (GstVideoDecoder * vdec,
1211 GstVideoCodecFrame * frame, GstAdapter * adapter, gboolean at_eos)
1216 ret = gst_vaapidecode_parse_frame (vdec, frame, adapter, at_eos);
1217 } while (ret == GST_VAAPI_DECODE_FLOW_PARSE_DATA);
1222 is_mvc_profile (GstVaapiProfile profile)
1224 return profile == GST_VAAPI_PROFILE_H264_MULTIVIEW_HIGH
1225 || profile == GST_VAAPI_PROFILE_H264_STEREO_HIGH;
1229 is_svc_profile (GstVaapiProfile profile)
1231 return profile == GST_VAAPI_PROFILE_H264_SCALABLE_BASELINE
1232 || profile == GST_VAAPI_PROFILE_H264_SCALABLE_HIGH;
1236 find_mvc_and_svc (GArray * profiles, gboolean * have_mvc, gboolean * have_svc)
1240 for (i = 0; i < profiles->len; i++) {
1241 const GstVaapiProfile profile =
1242 g_array_index (profiles, GstVaapiProfile, i);
1244 *have_mvc |= is_mvc_profile (profile);
1245 *have_svc |= is_svc_profile (profile);
1250 gst_vaapidecode_ensure_allowed_sinkpad_caps (GstVaapiDecode * decode)
1252 GstCaps *caps, *allowed_sinkpad_caps;
1253 GstPad *const sinkpad = GST_VIDEO_DECODER_SINK_PAD (decode);
1255 GstVaapiDisplay *const display = GST_VAAPI_PLUGIN_BASE_DISPLAY (decode);
1257 gboolean base_only = FALSE;
1258 gboolean have_mvc = FALSE;
1259 gboolean have_svc = FALSE;
1261 profiles = gst_vaapi_display_get_decode_profiles (display);
1263 goto error_no_profiles;
1265 allowed_sinkpad_caps = gst_caps_new_empty ();
1266 if (!allowed_sinkpad_caps)
1267 goto error_no_memory;
1269 if (g_object_class_find_property (G_OBJECT_GET_CLASS (decode), "base-only")) {
1270 g_object_get (decode, "base-only", &base_only, NULL);
1273 find_mvc_and_svc (profiles, &have_mvc, &have_svc);
1275 for (i = 0; i < profiles->len; i++) {
1276 const GstVaapiProfile profile =
1277 g_array_index (profiles, GstVaapiProfile, i);
1278 const gchar *media_type_name;
1279 const gchar *profile_name;
1280 GstStructure *structure;
1282 media_type_name = gst_vaapi_profile_get_media_type_name (profile);
1283 if (!media_type_name)
1286 caps = gst_caps_from_string (media_type_name);
1289 structure = gst_caps_get_structure (caps, 0);
1293 profile_name = gst_vaapi_profile_get_name (profile);
1297 /* Add all according -intra profile for HEVC */
1298 if (profile == GST_VAAPI_PROFILE_H265_MAIN
1299 || profile == GST_VAAPI_PROFILE_H265_MAIN10
1300 || profile == GST_VAAPI_PROFILE_H265_MAIN_422_10
1301 || profile == GST_VAAPI_PROFILE_H265_MAIN_444
1302 || profile == GST_VAAPI_PROFILE_H265_MAIN_444_10
1303 || profile == GST_VAAPI_PROFILE_H265_MAIN12
1304 || profile == GST_VAAPI_PROFILE_H265_MAIN_444_12
1305 || profile == GST_VAAPI_PROFILE_H265_MAIN_422_12) {
1306 gchar *profiles[3], *intra_name;
1308 intra_name = g_strdup_printf ("%s-intra", profile_name);
1310 profiles[0] = (gchar *) profile_name;
1311 profiles[1] = intra_name;
1314 gst_vaapi_structure_set_profiles (structure, profiles);
1315 g_free (intra_name);
1317 } else if (profile == GST_VAAPI_PROFILE_H264_CONSTRAINED_BASELINE) {
1318 /* XXX: artificially adding baseline if constrained_baseline is
1320 gchar *profiles[] = { (gchar *) profile_name, "baseline", NULL };
1322 gst_vaapi_structure_set_profiles (structure, profiles);
1323 } else if (profile == GST_VAAPI_PROFILE_H264_HIGH) {
1324 gchar *profiles[11] = { (gchar *) profile_name, "progressive-high",
1329 if (base_only && !have_mvc) {
1330 GST_DEBUG ("base_only: force adding MVC profiles in caps");
1332 profiles[i++] = "multiview-high";
1333 profiles[i++] = "stereo-high";
1336 if (base_only && !have_svc) {
1337 GST_DEBUG ("base_only: force adding SVC profiles in caps");
1339 profiles[i++] = "scalable-constrained-baseline";
1340 profiles[i++] = "scalable-baseline";
1341 profiles[i++] = "scalable-high-intra";
1342 profiles[i++] = "scalable-constrained-high";
1343 profiles[i++] = "scalable-high";
1346 profiles[i++] = NULL;
1348 gst_vaapi_structure_set_profiles (structure, profiles);
1350 gst_structure_set (structure, "profile", G_TYPE_STRING,
1351 profile_name, NULL);
1355 gst_vaapi_profile_caps_append_decoder (display, profile, structure);
1356 allowed_sinkpad_caps = gst_caps_merge (allowed_sinkpad_caps, caps);
1359 caps = gst_pad_get_pad_template_caps (sinkpad);
1360 decode->allowed_sinkpad_caps =
1361 gst_caps_intersect (allowed_sinkpad_caps, caps);
1362 gst_caps_unref (caps);
1363 gst_caps_unref (allowed_sinkpad_caps);
1364 decode->allowed_sinkpad_caps =
1365 gst_caps_simplify (decode->allowed_sinkpad_caps);
1366 GST_DEBUG_OBJECT (decode, "allowed sink caps %" GST_PTR_FORMAT,
1367 decode->allowed_sinkpad_caps);
1369 g_array_unref (profiles);
1375 GST_ERROR ("failed to retrieve VA decode profiles");
1380 GST_ERROR ("failed to allocate allowed-caps set");
1381 g_array_unref (profiles);
1387 gst_vaapidecode_sink_getcaps (GstVideoDecoder * vdec, GstCaps * filter)
1389 GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);
1392 if (decode->allowed_sinkpad_caps)
1395 /* if we haven't a display yet, return our pad's template caps */
1396 if (!GST_VAAPI_PLUGIN_BASE_DISPLAY (decode))
1399 /* if the allowed caps calculation fails, return an empty caps, so
1400 * the auto-plug can try other decoder */
1401 if (!gst_vaapidecode_ensure_allowed_sinkpad_caps (decode))
1402 return gst_caps_new_empty ();
1405 result = gst_video_decoder_proxy_getcaps (vdec, decode->allowed_sinkpad_caps,
1408 GST_DEBUG_OBJECT (decode, "Returning sink caps %" GST_PTR_FORMAT, result);
1414 gst_vaapidecode_sink_query (GstVideoDecoder * vdec, GstQuery * query)
1416 gboolean ret = TRUE;
1417 GstElement *const element = GST_ELEMENT (vdec);
1419 switch (GST_QUERY_TYPE (query)) {
1420 case GST_QUERY_CONTEXT:{
1421 ret = gst_vaapi_handle_context_query (element, query);
1425 ret = GST_VIDEO_DECODER_CLASS (parent_class)->sink_query (vdec, query);
1434 gst_vaapidecode_src_query (GstVideoDecoder * vdec, GstQuery * query)
1436 gboolean ret = TRUE;
1437 GstElement *const element = GST_ELEMENT (vdec);
1439 switch (GST_QUERY_TYPE (query)) {
1440 case GST_QUERY_CONTEXT:{
1441 ret = gst_vaapi_handle_context_query (element, query);
1444 case GST_QUERY_CAPS:{
1445 GstCaps *caps, *filter = NULL;
1446 gboolean fixed_caps;
1448 fixed_caps = GST_PAD_IS_FIXED_CAPS (GST_VIDEO_DECODER_SRC_PAD (vdec));
1450 gst_query_parse_caps (query, &filter);
1451 caps = gst_vaapidecode_get_allowed_srcpad_caps (GST_VAAPIDECODE (vdec));
1454 GstCaps *tmp = caps;
1456 gst_caps_intersect_full (filter, tmp, GST_CAPS_INTERSECT_FIRST);
1457 gst_caps_unref (tmp);
1460 gst_query_set_caps_result (query, caps);
1461 gst_caps_unref (caps);
1464 /* else jump to default */
1467 ret = GST_VIDEO_DECODER_CLASS (parent_class)->src_query (vdec, query);
1476 gst_vaapidecode_transform_meta (GstVideoDecoder *
1477 vdec, GstVideoCodecFrame * frame, GstMeta * meta)
1479 const GstMetaInfo *info = meta->info;
1481 if (GST_VIDEO_DECODER_CLASS (parent_class)->transform_meta (vdec, frame,
1485 if (!g_strcmp0 (g_type_name (info->type), "GstVideoRegionOfInterestMeta"))
1492 gst_vaapidecode_class_init (GstVaapiDecodeClass * klass)
1494 GObjectClass *const object_class = G_OBJECT_CLASS (klass);
1495 GstElementClass *const element_class = GST_ELEMENT_CLASS (klass);
1496 GstVideoDecoderClass *const vdec_class = GST_VIDEO_DECODER_CLASS (klass);
1497 GstPadTemplate *pad_template;
1498 GstVaapiDecoderMap *map;
1499 gchar *name, *longname, *description;
1502 GST_DEBUG_CATEGORY_INIT (gst_debug_vaapidecode,
1503 GST_PLUGIN_NAME, 0, GST_PLUGIN_DESC);
1505 parent_class = g_type_class_peek_parent (klass);
1507 gst_vaapi_plugin_base_class_init (GST_VAAPI_PLUGIN_BASE_CLASS (klass));
1509 object_class->finalize = gst_vaapidecode_finalize;
1511 vdec_class->open = GST_DEBUG_FUNCPTR (gst_vaapidecode_open);
1512 vdec_class->close = GST_DEBUG_FUNCPTR (gst_vaapidecode_close);
1513 vdec_class->start = GST_DEBUG_FUNCPTR (gst_vaapidecode_start);
1514 vdec_class->stop = GST_DEBUG_FUNCPTR (gst_vaapidecode_stop);
1515 vdec_class->set_format = GST_DEBUG_FUNCPTR (gst_vaapidecode_set_format);
1516 vdec_class->flush = GST_DEBUG_FUNCPTR (gst_vaapidecode_flush);
1517 vdec_class->parse = GST_DEBUG_FUNCPTR (gst_vaapidecode_parse);
1518 vdec_class->handle_frame = GST_DEBUG_FUNCPTR (gst_vaapidecode_handle_frame);
1519 vdec_class->finish = GST_DEBUG_FUNCPTR (gst_vaapidecode_finish);
1520 vdec_class->drain = GST_DEBUG_FUNCPTR (gst_vaapidecode_drain);
1521 vdec_class->decide_allocation =
1522 GST_DEBUG_FUNCPTR (gst_vaapidecode_decide_allocation);
1523 vdec_class->src_query = GST_DEBUG_FUNCPTR (gst_vaapidecode_src_query);
1524 vdec_class->sink_query = GST_DEBUG_FUNCPTR (gst_vaapidecode_sink_query);
1525 vdec_class->getcaps = GST_DEBUG_FUNCPTR (gst_vaapidecode_sink_getcaps);
1526 vdec_class->transform_meta =
1527 GST_DEBUG_FUNCPTR (gst_vaapidecode_transform_meta);
1529 map = (GstVaapiDecoderMap *) g_type_get_qdata (G_OBJECT_CLASS_TYPE (klass),
1530 GST_VAAPI_DECODE_PARAMS_QDATA);
1533 name = g_ascii_strup (map->name, -1);
1534 longname = g_strdup_printf ("VA-API %s decoder", name);
1535 description = g_strdup_printf ("A VA-API based %s video decoder", name);
1538 longname = g_strdup ("VA-API decoder");
1539 description = g_strdup (GST_PLUGIN_DESC);
1542 element_class->set_context = gst_vaapi_base_set_context;
1543 gst_element_class_set_static_metadata (element_class, longname,
1544 "Codec/Decoder/Video/Hardware", description,
1545 "Gwenole Beauchesne <gwenole.beauchesne@intel.com>, "
1546 "Halley Zhao <halley.zhao@intel.com>, "
1547 "Sreerenj Balachandran <sreerenj.balachandran@intel.com>, "
1548 "Wind Yuan <feng.yuan@intel.com>, Junyan He <junyan.he@intel.com>");
1551 g_free (description);
1553 if (map->install_properties)
1554 map->install_properties (object_class);
1557 if (map->caps_str) {
1558 caps = gst_caps_from_string (map->caps_str);
1560 caps = gst_caps_from_string (gst_vaapidecode_sink_caps_str);
1561 g_free (gst_vaapidecode_sink_caps_str);
1563 pad_template = gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
1565 gst_caps_unref (caps);
1566 gst_element_class_add_pad_template (element_class, pad_template);
1569 gst_element_class_add_static_pad_template (element_class,
1570 &gst_vaapidecode_src_factory);
1574 gst_vaapidecode_init (GstVaapiDecode * decode)
1576 GstVideoDecoder *const vdec = GST_VIDEO_DECODER (decode);
1578 gst_vaapi_plugin_base_init (GST_VAAPI_PLUGIN_BASE (decode), GST_CAT_DEFAULT);
1580 gst_video_decoder_set_packetized (vdec, FALSE);
1584 gst_vaapidecode_register (GstPlugin * plugin, GArray * decoders)
1586 gboolean ret = FALSE;
1587 guint i, codec, rank;
1588 gchar *type_name, *element_name, *sink_caps_str;
1591 GTypeInfo typeinfo = {
1592 sizeof (GstVaapiDecodeClass),
1595 (GClassInitFunc) gst_vaapidecode_class_init,
1598 sizeof (GstVaapiDecode),
1600 (GInstanceInitFunc) gst_vaapidecode_init,
1603 for (i = 0; i < G_N_ELEMENTS (vaapi_decode_map); i++) {
1604 codec = vaapi_decode_map[i].codec;
1605 rank = vaapi_decode_map[i].rank;
1606 name = vaapi_decode_map[i].name;
1608 if (codec && !gst_vaapi_codecs_has_codec (decoders, codec))
1611 if (!gst_vaapidecode_sink_caps_str) {
1612 gst_vaapidecode_sink_caps_str = g_strdup (vaapi_decode_map[i].caps_str);
1614 sink_caps_str = g_strconcat (gst_vaapidecode_sink_caps_str, "; ",
1615 vaapi_decode_map[i].caps_str, NULL);
1616 g_clear_pointer (&gst_vaapidecode_sink_caps_str, g_free);
1619 gst_vaapidecode_sink_caps_str = sink_caps_str;
1623 type_name = g_strdup_printf ("GstVaapiDecode_%s", name);
1624 element_name = g_strdup_printf ("vaapi%sdec", name);
1626 type_name = g_strdup ("GstVaapiDecode");
1627 element_name = g_strdup_printf ("vaapidecode");
1630 type = g_type_from_name (type_name);
1632 /* create the gtype now */
1633 type = g_type_register_static (GST_TYPE_VIDEO_DECODER, type_name,
1635 gst_vaapi_plugin_base_init_interfaces (type);
1636 g_type_set_qdata (type, GST_VAAPI_DECODE_PARAMS_QDATA,
1637 (gpointer) & vaapi_decode_map[i]);
1640 /* Register GstVaapiDecode as GObject type, but not in GStreamer, so
1641 * vaapidecodebin can use it internally, but no exposed as a plugin
1644 ret |= gst_element_register (plugin, element_name, rank, type);
1646 g_free (element_name);