2 * Copyright (C) 2020 Igalia, S.L.
3 * Author: Víctor Jáquez <vjaquez@igalia.com>
4 * Copyright (C) 2020 Collabora
5 * Author: Nicolas Dufresne <nicolas.dufresne@collabora.com>
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the0
19 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
24 * SECTION:element-vah265dec
26 * @short_description: A VA-API based H265 video decoder
28 * vah265dec decodes H265 bitstreams to VA surfaces using the
29 * installed and chosen [VA-API](https://01.org/linuxmedia/vaapi)
32 * The decoding surfaces can be mapped onto main memory as video
35 * ## Example launch line
37 * gst-launch-1.0 filesrc location=big_buck_bunny.mov ! parsebin ! vah265dec ! autovideosink
46 * + interlaced streams
47 * + mutiview and stereo profiles
48 * + SCC extension buffer
56 #include "gstvah265dec.h"
58 #include "gstvabasedec.h"
60 GST_DEBUG_CATEGORY_STATIC (gst_va_h265dec_debug);
61 #ifndef GST_DISABLE_GST_DEBUG
62 #define GST_CAT_DEFAULT gst_va_h265dec_debug
64 #define GST_CAT_DEFAULT NULL
67 #define GST_VA_H265_DEC(obj) ((GstVaH265Dec *) obj)
68 #define GST_VA_H265_DEC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), G_TYPE_FROM_INSTANCE (obj), GstVaH265DecClass))
69 #define GST_VA_H265_DEC_CLASS(klass) ((GstVaH265DecClass *) klass)
76 VASliceParameterBufferHEVCExtension param;
79 typedef struct _GstVaH265Dec GstVaH265Dec;
80 typedef struct _GstVaH265DecClass GstVaH265DecClass;
82 struct _GstVaH265DecClass
84 GstVaBaseDecClass parent_class;
93 VAPictureParameterBufferHEVCExtension pic_param;
95 gint32 WpOffsetHalfRangeC;
97 struct slice prev_slice;
100 static GstElementClass *parent_class = NULL;
103 static const gchar *src_caps_str =
104 GST_VIDEO_CAPS_MAKE_WITH_FEATURES (GST_CAPS_FEATURE_MEMORY_VA,
105 "{ NV12, P010_10LE }") " ;"
106 GST_VIDEO_CAPS_MAKE ("{ NV12, P010_10LE }");
109 static const gchar *sink_caps_str = "video/x-h265";
112 _is_range_extension_profile (VAProfile profile)
114 if (profile == VAProfileHEVCMain422_10
115 || profile == VAProfileHEVCMain444
116 || profile == VAProfileHEVCMain444_10
117 || profile == VAProfileHEVCMain12
118 || profile == VAProfileHEVCMain444_12
119 || profile == VAProfileHEVCMain422_12)
125 _is_screen_content_ext_profile (VAProfile profile)
127 if (profile == VAProfileHEVCSccMain || profile == VAProfileHEVCSccMain10
128 || profile == VAProfileHEVCSccMain444
129 #if VA_CHECK_VERSION(1, 8, 0)
130 || profile == VAProfileHEVCSccMain444_10
139 _set_last_slice_flag (GstVaH265Dec * self)
141 self->prev_slice.param.base.LongSliceFlags.fields.LastSliceOfPic = 1;
145 _replace_previous_slice (GstVaH265Dec * self, guint8 * data, guint size)
147 struct slice *slice = &self->prev_slice;
148 gboolean do_reset = (slice->size < size);
150 if (!data || do_reset) {
151 g_clear_pointer (&slice->data, g_free);
159 GST_LOG_OBJECT (self, "allocating slice data %u", size);
160 slice->data = g_malloc (size);
163 memcpy (slice->data, data, size);
168 _submit_previous_slice (GstVaBaseDec * base, GstVaDecodePicture * va_pic)
170 GstVaH265Dec *self = GST_VA_H265_DEC (base);
175 slice = &self->prev_slice;
176 if (!slice->data && slice->size == 0)
178 if (!slice->data || slice->size == 0)
181 param_size = _is_range_extension_profile (self->parent.profile)
182 || _is_screen_content_ext_profile (self->parent.profile) ?
183 sizeof (slice->param) : sizeof (slice->param.base);
184 ret = gst_va_decoder_add_slice_buffer (base->decoder, va_pic, &slice->param,
185 param_size, slice->data, slice->size);
191 gst_va_h265_dec_end_picture (GstH265Decoder * decoder, GstH265Picture * picture)
193 GstVaBaseDec *base = GST_VA_BASE_DEC (decoder);
194 GstVaH265Dec *self = GST_VA_H265_DEC (decoder);
195 GstVaDecodePicture *va_pic;
198 GST_LOG_OBJECT (base, "end picture %p, (poc %d)",
199 picture, picture->pic_order_cnt);
201 va_pic = gst_h265_picture_get_user_data (picture);
203 _set_last_slice_flag (self);
204 ret = _submit_previous_slice (base, va_pic);
206 /* TODO(victor): optimization: this could be done at decoder's
208 _replace_previous_slice (self, NULL, 0);
211 GST_ERROR_OBJECT (self, "Failed to submit the previous slice");
212 return GST_FLOW_ERROR;
215 ret = gst_va_decoder_decode (base->decoder, va_pic);
217 GST_ERROR_OBJECT (self, "Failed at end picture %p, (poc %d)",
218 picture, picture->pic_order_cnt);
219 return GST_FLOW_ERROR;
226 gst_va_h265_dec_output_picture (GstH265Decoder * decoder,
227 GstVideoCodecFrame * frame, GstH265Picture * picture)
229 GstVaBaseDec *base = GST_VA_BASE_DEC (decoder);
230 GstVaH265Dec *self = GST_VA_H265_DEC (decoder);
231 GstVideoDecoder *vdec = GST_VIDEO_DECODER (decoder);
232 GstVaDecodePicture *va_pic;
235 va_pic = gst_h265_picture_get_user_data (picture);
236 g_assert (va_pic->gstbuffer);
238 GST_LOG_OBJECT (self,
239 "Outputting picture %p (poc %d)", picture, picture->pic_order_cnt);
241 gst_buffer_replace (&frame->output_buffer, va_pic->gstbuffer);
243 ret = gst_va_base_dec_process_output (base, frame, picture->buffer_flags);
244 gst_h265_picture_unref (picture);
247 return gst_video_decoder_finish_frame (vdec, frame);
248 return GST_FLOW_ERROR;
252 _init_vaapi_pic (VAPictureHEVC * va_picture)
254 va_picture->picture_id = VA_INVALID_ID;
255 va_picture->flags = VA_PICTURE_HEVC_INVALID;
256 va_picture->pic_order_cnt = 0;
260 _find_frame_rps_type (GstH265Decoder * decoder, GstH265Picture * ref_pic)
264 for (i = 0; i < G_N_ELEMENTS (decoder->RefPicSetStCurrBefore); i++) {
265 if (ref_pic == decoder->RefPicSetStCurrBefore[i])
266 return VA_PICTURE_HEVC_RPS_ST_CURR_BEFORE;
269 for (i = 0; i < G_N_ELEMENTS (decoder->RefPicSetStCurrAfter); i++) {
270 if (ref_pic == decoder->RefPicSetStCurrAfter[i])
271 return VA_PICTURE_HEVC_RPS_ST_CURR_AFTER;
274 for (i = 0; i < G_N_ELEMENTS (decoder->RefPicSetLtCurr); i++) {
275 if (ref_pic == decoder->RefPicSetLtCurr[i])
276 return VA_PICTURE_HEVC_RPS_LT_CURR;
284 _fill_vaapi_pic (GstH265Decoder * decoder, VAPictureHEVC * va_picture,
285 GstH265Picture * picture)
287 GstVaDecodePicture *va_pic;
289 va_pic = gst_h265_picture_get_user_data (picture);
292 _init_vaapi_pic (va_picture);
296 va_picture->picture_id = gst_va_decode_picture_get_surface (va_pic);
297 va_picture->pic_order_cnt = picture->pic_order_cnt;
298 va_picture->flags = 0;
300 if (picture->ref && picture->long_term)
301 va_picture->flags |= VA_PICTURE_HEVC_LONG_TERM_REFERENCE;
303 va_picture->flags |= _find_frame_rps_type (decoder, picture);
307 _get_reference_index (GstH265Decoder * decoder, GstH265Picture * picture)
309 GstVaH265Dec *self = GST_VA_H265_DEC (decoder);
315 for (i = 0; i < 15; i++) {
316 VAPictureHEVC *ref_va_pic = &self->pic_param.base.ReferenceFrames[i];
318 if (ref_va_pic->picture_id == VA_INVALID_ID)
321 if (ref_va_pic->pic_order_cnt == picture->pic_order_cnt)
328 /* fill the VA API reference picture lists from the GstCodec reference
331 _fill_ref_pic_list (GstH265Decoder * decoder, GstH265Picture * cur_pic,
332 guint8 va_reflist[15], GArray * reflist)
336 for (i = 0; i < reflist->len && i < 15; i++) {
337 GstH265Picture *picture = g_array_index (reflist, GstH265Picture *, i);
338 va_reflist[i] = _get_reference_index (decoder, picture);
342 va_reflist[i] = 0xFF;
346 _fill_pred_weight_table (GstVaH265Dec * self, GstH265SliceHdr * header,
347 VASliceParameterBufferHEVCExtension * slice_param)
349 gint chroma_weight, chroma_log2_weight_denom;
351 GstH265PPS *pps = header->pps;
352 gboolean is_rext = _is_range_extension_profile (self->parent.profile);
354 if (GST_H265_IS_I_SLICE (header) ||
355 (!pps->weighted_pred_flag && GST_H265_IS_P_SLICE (header)) ||
356 (!pps->weighted_bipred_flag && GST_H265_IS_B_SLICE (header)))
359 slice_param->base.luma_log2_weight_denom =
360 header->pred_weight_table.luma_log2_weight_denom;
362 if (pps->sps->chroma_array_type != 0)
363 slice_param->base.delta_chroma_log2_weight_denom =
364 header->pred_weight_table.delta_chroma_log2_weight_denom;
366 for (i = 0; i <= header->num_ref_idx_l0_active_minus1; i++) {
367 if (!header->pred_weight_table.luma_weight_l0_flag[i])
370 slice_param->base.delta_luma_weight_l0[i] =
371 header->pred_weight_table.delta_luma_weight_l0[i];
372 slice_param->base.luma_offset_l0[i] =
373 header->pred_weight_table.luma_offset_l0[i];
376 slice_param->rext.luma_offset_l0[i] =
377 header->pred_weight_table.luma_offset_l0[i];
381 chroma_log2_weight_denom = slice_param->base.luma_log2_weight_denom +
382 slice_param->base.delta_chroma_log2_weight_denom;
384 for (i = 0; i <= header->num_ref_idx_l0_active_minus1; i++) {
385 if (!header->pred_weight_table.chroma_weight_l0_flag[i])
388 for (j = 0; j < 2; j++) {
389 gint16 delta_chroma_offset_l0 =
390 header->pred_weight_table.delta_chroma_offset_l0[i][j];
393 slice_param->base.delta_chroma_weight_l0[i][j] =
394 header->pred_weight_table.delta_chroma_weight_l0[i][j];
396 /* Find ChromaWeightL0 */
397 chroma_weight = (1 << chroma_log2_weight_denom) +
398 header->pred_weight_table.delta_chroma_weight_l0[i][j];
399 chroma_offset = self->WpOffsetHalfRangeC + delta_chroma_offset_l0
400 - ((self->WpOffsetHalfRangeC * chroma_weight)
401 >> chroma_log2_weight_denom);
404 slice_param->base.ChromaOffsetL0[i][j] = CLAMP (chroma_offset,
405 -self->WpOffsetHalfRangeC, self->WpOffsetHalfRangeC - 1);
408 slice_param->rext.ChromaOffsetL0[i][j] =
409 slice_param->base.ChromaOffsetL0[i][j];
414 /* Skip l1 if this is not a B-Frame. */
415 if (!GST_H265_IS_B_SLICE (header))
418 for (i = 0; i <= header->num_ref_idx_l1_active_minus1; i++) {
419 if (!header->pred_weight_table.luma_weight_l1_flag[i])
422 slice_param->base.delta_luma_weight_l1[i] =
423 header->pred_weight_table.delta_luma_weight_l1[i];
424 slice_param->base.luma_offset_l1[i] =
425 header->pred_weight_table.luma_offset_l1[i];
428 slice_param->rext.luma_offset_l1[i] =
429 header->pred_weight_table.luma_offset_l1[i];
433 for (i = 0; i <= header->num_ref_idx_l1_active_minus1; i++) {
434 if (!header->pred_weight_table.chroma_weight_l1_flag[i])
437 for (j = 0; j < 2; j++) {
438 gint16 delta_chroma_offset_l1 =
439 header->pred_weight_table.delta_chroma_offset_l1[i][j];
442 slice_param->base.delta_chroma_weight_l1[i][j] =
443 header->pred_weight_table.delta_chroma_weight_l1[i][j];
445 /* Find ChromaWeightL1 */
446 chroma_weight = (1 << chroma_log2_weight_denom) +
447 header->pred_weight_table.delta_chroma_weight_l1[i][j];
449 chroma_offset = self->WpOffsetHalfRangeC + delta_chroma_offset_l1
450 - ((self->WpOffsetHalfRangeC * chroma_weight)
451 >> chroma_log2_weight_denom);
454 slice_param->base.ChromaOffsetL1[i][j] = CLAMP (chroma_offset,
455 -self->WpOffsetHalfRangeC, self->WpOffsetHalfRangeC - 1);
458 slice_param->rext.ChromaOffsetL1[i][j] =
459 slice_param->base.ChromaOffsetL1[i][j];
466 _get_slice_data_byte_offset (GstH265SliceHdr * slice_hdr,
467 guint nal_header_bytes)
471 epb_count = slice_hdr->n_emulation_prevention_bytes;
472 return nal_header_bytes + (slice_hdr->header_size + 7) / 8 - epb_count;
476 gst_va_h265_dec_decode_slice (GstH265Decoder * decoder,
477 GstH265Picture * picture, GstH265Slice * slice, GArray * ref_pic_list0,
478 GArray * ref_pic_list1)
480 GstH265SliceHdr *header = &slice->header;
481 GstH265NalUnit *nalu = &slice->nalu;
482 GstVaBaseDec *base = GST_VA_BASE_DEC (decoder);
483 GstVaH265Dec *self = GST_VA_H265_DEC (decoder);
484 GstVaDecodePicture *va_pic;
485 VASliceParameterBufferHEVCExtension *slice_param;
487 va_pic = gst_h265_picture_get_user_data (picture);
488 if (!_submit_previous_slice (base, va_pic)) {
489 _replace_previous_slice (self, NULL, 0);
490 GST_ERROR_OBJECT (base, "Failed to submit previous slice buffers");
491 return GST_FLOW_ERROR;
494 slice_param = &self->prev_slice.param;
497 slice_param->base = (VASliceParameterBufferHEVC) {
498 .slice_data_size = nalu->size,
499 .slice_data_offset = 0,
500 .slice_data_flag = VA_SLICE_DATA_FLAG_ALL,
501 .slice_data_byte_offset = _get_slice_data_byte_offset (header, nalu->header_bytes),
502 .slice_segment_address = header->segment_address,
503 .collocated_ref_idx = header->temporal_mvp_enabled_flag ? header->collocated_ref_idx : 0xFF,
504 .num_ref_idx_l0_active_minus1 = header->num_ref_idx_l0_active_minus1,
505 .num_ref_idx_l1_active_minus1 = header->num_ref_idx_l1_active_minus1,
506 .slice_qp_delta = header->qp_delta,
507 .slice_cb_qp_offset = header->cb_qp_offset,
508 .slice_cr_qp_offset = header->cr_qp_offset,
509 .slice_beta_offset_div2 = header->beta_offset_div2,
510 .slice_tc_offset_div2 = header->tc_offset_div2,
511 .five_minus_max_num_merge_cand = header->five_minus_max_num_merge_cand,
512 .num_entry_point_offsets = header->num_entry_point_offsets,
513 .entry_offset_to_subset_array = 0, /* does not exist in spec */
514 .slice_data_num_emu_prevn_bytes = header->n_emulation_prevention_bytes,
515 .LongSliceFlags.fields = {
516 .LastSliceOfPic = 0, /* the last one will be set on end_picture() */
517 .dependent_slice_segment_flag = header->dependent_slice_segment_flag,
518 .slice_type = header->type,
519 .color_plane_id = header->colour_plane_id,
520 .slice_sao_luma_flag = header->sao_luma_flag,
521 .slice_sao_chroma_flag = header->sao_chroma_flag,
522 .mvd_l1_zero_flag = header->mvd_l1_zero_flag,
523 .cabac_init_flag = header->cabac_init_flag,
524 .slice_temporal_mvp_enabled_flag = header->temporal_mvp_enabled_flag,
525 .slice_deblocking_filter_disabled_flag =
526 header->deblocking_filter_disabled_flag,
527 .collocated_from_l0_flag = header->collocated_from_l0_flag,
528 .slice_loop_filter_across_slices_enabled_flag =
529 header->loop_filter_across_slices_enabled_flag,
534 if (_is_range_extension_profile (base->profile)
535 || _is_screen_content_ext_profile (base->profile)) {
537 slice_param->rext = (VASliceParameterBufferHEVCRext) {
538 .slice_ext_flags.bits = {
539 .cu_chroma_qp_offset_enabled_flag = header->cu_chroma_qp_offset_enabled_flag,
540 .use_integer_mv_flag = header->use_integer_mv_flag,
542 .slice_act_y_qp_offset = header->slice_act_y_qp_offset,
543 .slice_act_cb_qp_offset = header->slice_act_cb_qp_offset,
544 .slice_act_cr_qp_offset = header->slice_act_cr_qp_offset,
549 _fill_ref_pic_list (decoder, picture, slice_param->base.RefPicList[0],
551 _fill_ref_pic_list (decoder, picture, slice_param->base.RefPicList[1],
554 _fill_pred_weight_table (GST_VA_H265_DEC (decoder), header, slice_param);
556 _replace_previous_slice (self, slice->nalu.data + slice->nalu.offset,
563 _fill_picture_range_ext_parameter (GstVaH265Dec * decoder,
564 GstH265SPS * sps, GstH265PPS * pps)
566 VAPictureParameterBufferHEVCRext *pic_param = &decoder->pic_param.rext;
568 GstH265SPSExtensionParams *sps_ext = &sps->sps_extension_params;
569 GstH265PPSExtensionParams *pps_ext = &pps->pps_extension_params;
572 *pic_param = (VAPictureParameterBufferHEVCRext) {
573 .range_extension_pic_fields.bits = {
574 .transform_skip_rotation_enabled_flag = sps_ext->transform_skip_rotation_enabled_flag,
575 .transform_skip_context_enabled_flag = sps_ext->transform_skip_context_enabled_flag,
576 .implicit_rdpcm_enabled_flag = sps_ext->implicit_rdpcm_enabled_flag,
577 .explicit_rdpcm_enabled_flag = sps_ext->explicit_rdpcm_enabled_flag,
578 .extended_precision_processing_flag = sps_ext->extended_precision_processing_flag,
579 .intra_smoothing_disabled_flag = sps_ext->intra_smoothing_disabled_flag,
580 .high_precision_offsets_enabled_flag = sps_ext->high_precision_offsets_enabled_flag,
581 .persistent_rice_adaptation_enabled_flag = sps_ext->persistent_rice_adaptation_enabled_flag,
582 .cabac_bypass_alignment_enabled_flag = sps_ext->cabac_bypass_alignment_enabled_flag,
583 .cross_component_prediction_enabled_flag = pps_ext->cross_component_prediction_enabled_flag,
584 .chroma_qp_offset_list_enabled_flag = pps_ext->chroma_qp_offset_list_enabled_flag,
586 .diff_cu_chroma_qp_offset_depth = pps_ext->diff_cu_chroma_qp_offset_depth,
587 .chroma_qp_offset_list_len_minus1 = pps_ext->chroma_qp_offset_list_len_minus1,
588 .log2_sao_offset_scale_luma = pps_ext->log2_sao_offset_scale_luma,
589 .log2_sao_offset_scale_chroma = pps_ext->log2_sao_offset_scale_chroma,
590 .log2_max_transform_skip_block_size_minus2 = pps_ext->log2_max_transform_skip_block_size_minus2,
594 memcpy (pic_param->cb_qp_offset_list, pps_ext->cb_qp_offset_list,
595 sizeof (pic_param->cb_qp_offset_list));
596 memcpy (pic_param->cr_qp_offset_list, pps_ext->cr_qp_offset_list,
597 sizeof (pic_param->cr_qp_offset_list));
601 _fill_screen_content_ext_parameter (GstVaH265Dec * decoder,
602 GstH265SPS * sps, GstH265PPS * pps)
604 VAPictureParameterBufferHEVCScc *pic_param = &decoder->pic_param.scc;
605 const GstH265PPSSccExtensionParams *pps_scc = &pps->pps_scc_extension_params;
606 const GstH265SPSSccExtensionParams *sps_scc = &sps->sps_scc_extension_params;
611 *pic_param = (VAPictureParameterBufferHEVCScc) {
612 .screen_content_pic_fields.bits = {
613 .pps_curr_pic_ref_enabled_flag = pps_scc->pps_curr_pic_ref_enabled_flag,
614 .palette_mode_enabled_flag = sps_scc->palette_mode_enabled_flag,
615 .motion_vector_resolution_control_idc = sps_scc->motion_vector_resolution_control_idc,
616 .intra_boundary_filtering_disabled_flag = sps_scc->intra_boundary_filtering_disabled_flag,
617 .residual_adaptive_colour_transform_enabled_flag = pps_scc->residual_adaptive_colour_transform_enabled_flag,
618 .pps_slice_act_qp_offsets_present_flag = pps_scc->pps_slice_act_qp_offsets_present_flag,
620 .palette_max_size = sps_scc->palette_max_size,
621 .delta_palette_max_predictor_size = sps_scc->delta_palette_max_predictor_size,
622 .pps_act_y_qp_offset_plus5 = pps_scc->pps_act_y_qp_offset_plus5,
623 .pps_act_cb_qp_offset_plus5 = pps_scc->pps_act_cb_qp_offset_plus5,
624 .pps_act_cr_qp_offset_plus3 = pps_scc->pps_act_cr_qp_offset_plus3,
628 /* firstly use the pps, then sps */
629 num_comps = sps->chroma_format_idc ? 3 : 1;
631 if (pps_scc->pps_palette_predictor_initializers_present_flag) {
632 pic_param->predictor_palette_size =
633 pps_scc->pps_num_palette_predictor_initializer;
634 for (n = 0; n < num_comps; n++)
635 for (i = 0; i < pps_scc->pps_num_palette_predictor_initializer; i++)
636 pic_param->predictor_palette_entries[n][i] =
637 (uint16_t) pps_scc->pps_palette_predictor_initializer[n][i];
638 } else if (sps_scc->sps_palette_predictor_initializers_present_flag) {
639 pic_param->predictor_palette_size =
640 sps_scc->sps_num_palette_predictor_initializer_minus1 + 1;
641 for (n = 0; n < num_comps; n++)
643 i < sps_scc->sps_num_palette_predictor_initializer_minus1 + 1; i++)
644 pic_param->predictor_palette_entries[n][i] =
645 (uint16_t) sps_scc->sps_palette_predictor_initializer[n][i];
650 gst_va_h265_dec_start_picture (GstH265Decoder * decoder,
651 GstH265Picture * picture, GstH265Slice * slice, GstH265Dpb * dpb)
655 GstVaH265Dec *self = GST_VA_H265_DEC (decoder);
656 GstVaBaseDec *base = &self->parent;
657 GstVaDecodePicture *va_pic;
658 GstH265ScalingList *scaling_list = NULL;
659 VAIQMatrixBufferHEVC iq_matrix = { 0, };
660 VAPictureParameterBufferHEVCExtension *pic_param = &self->pic_param;
661 gsize pic_param_size;
664 va_pic = gst_h265_picture_get_user_data (picture);
666 pps = slice->header.pps;
670 pic_param->base = (VAPictureParameterBufferHEVC) {
671 .pic_width_in_luma_samples = sps->pic_width_in_luma_samples,
672 .pic_height_in_luma_samples = sps->pic_height_in_luma_samples,
673 .sps_max_dec_pic_buffering_minus1 = sps->max_dec_pic_buffering_minus1[sps->max_sub_layers_minus1],
674 .bit_depth_luma_minus8 = sps->bit_depth_luma_minus8,
675 .bit_depth_chroma_minus8 = sps->bit_depth_chroma_minus8,
676 .pcm_sample_bit_depth_luma_minus1 = sps->pcm_sample_bit_depth_luma_minus1,
677 .pcm_sample_bit_depth_chroma_minus1 = sps->pcm_sample_bit_depth_chroma_minus1,
678 .log2_min_luma_coding_block_size_minus3 = sps->log2_min_luma_coding_block_size_minus3,
679 .log2_diff_max_min_luma_coding_block_size = sps->log2_diff_max_min_luma_coding_block_size,
680 .log2_min_transform_block_size_minus2 = sps->log2_min_transform_block_size_minus2,
681 .log2_diff_max_min_transform_block_size = sps->log2_diff_max_min_transform_block_size,
682 .log2_min_pcm_luma_coding_block_size_minus3 = sps->log2_min_pcm_luma_coding_block_size_minus3,
683 .log2_diff_max_min_pcm_luma_coding_block_size = sps->log2_diff_max_min_pcm_luma_coding_block_size,
684 .max_transform_hierarchy_depth_intra = sps->max_transform_hierarchy_depth_intra,
685 .max_transform_hierarchy_depth_inter = sps->max_transform_hierarchy_depth_inter,
686 .init_qp_minus26 = pps->init_qp_minus26,
687 .diff_cu_qp_delta_depth = pps->diff_cu_qp_delta_depth,
688 .pps_cb_qp_offset = pps->cb_qp_offset,
689 .pps_cr_qp_offset = pps->cr_qp_offset,
690 .log2_parallel_merge_level_minus2 = pps->log2_parallel_merge_level_minus2,
691 .num_tile_columns_minus1 = pps->num_tile_columns_minus1,
692 .num_tile_rows_minus1 = pps->num_tile_rows_minus1,
693 .log2_max_pic_order_cnt_lsb_minus4 = sps->log2_max_pic_order_cnt_lsb_minus4,
694 .num_short_term_ref_pic_sets = sps->num_short_term_ref_pic_sets,
695 .num_long_term_ref_pic_sps = sps->num_long_term_ref_pics_sps,
696 .num_ref_idx_l0_default_active_minus1 = pps->num_ref_idx_l0_default_active_minus1,
697 .num_ref_idx_l1_default_active_minus1 = pps->num_ref_idx_l1_default_active_minus1,
698 .pps_beta_offset_div2 = pps->beta_offset_div2,
699 .pps_tc_offset_div2 = pps->tc_offset_div2,
700 .num_extra_slice_header_bits = pps->num_extra_slice_header_bits,
701 .st_rps_bits = slice->header.short_term_ref_pic_set_size, /* FIXME missing emulation bits removal */
703 .chroma_format_idc = sps->chroma_format_idc,
704 .separate_colour_plane_flag = sps->separate_colour_plane_flag,
705 .pcm_enabled_flag = sps->pcm_enabled_flag,
706 .scaling_list_enabled_flag = sps->scaling_list_enabled_flag,
707 .transform_skip_enabled_flag = pps->transform_skip_enabled_flag,
708 .amp_enabled_flag = sps->amp_enabled_flag,
709 .strong_intra_smoothing_enabled_flag = sps->strong_intra_smoothing_enabled_flag,
710 .sign_data_hiding_enabled_flag = pps->sign_data_hiding_enabled_flag,
711 .constrained_intra_pred_flag = pps->constrained_intra_pred_flag,
712 .cu_qp_delta_enabled_flag = pps->cu_qp_delta_enabled_flag,
713 .weighted_pred_flag = pps->weighted_pred_flag,
714 .weighted_bipred_flag = pps->weighted_bipred_flag,
715 .transquant_bypass_enabled_flag = pps->transquant_bypass_enabled_flag,
716 .tiles_enabled_flag = pps->tiles_enabled_flag,
717 .entropy_coding_sync_enabled_flag = pps->entropy_coding_sync_enabled_flag,
718 .pps_loop_filter_across_slices_enabled_flag = pps->loop_filter_across_slices_enabled_flag,
719 .loop_filter_across_tiles_enabled_flag = pps->loop_filter_across_tiles_enabled_flag,
720 .pcm_loop_filter_disabled_flag = sps->pcm_loop_filter_disabled_flag,
721 /* Not set by FFMPEG either */
722 .NoPicReorderingFlag = 0,
725 .slice_parsing_fields.bits = {
726 .lists_modification_present_flag = pps->lists_modification_present_flag,
727 .long_term_ref_pics_present_flag = sps->long_term_ref_pics_present_flag,
728 .sps_temporal_mvp_enabled_flag = sps->temporal_mvp_enabled_flag,
729 .cabac_init_present_flag = pps->cabac_init_present_flag,
730 .output_flag_present_flag = pps->output_flag_present_flag,
731 .dependent_slice_segments_enabled_flag = pps->dependent_slice_segments_enabled_flag,
732 .pps_slice_chroma_qp_offsets_present_flag = pps->slice_chroma_qp_offsets_present_flag,
733 .sample_adaptive_offset_enabled_flag = sps->sample_adaptive_offset_enabled_flag,
734 .deblocking_filter_override_enabled_flag = pps->deblocking_filter_override_enabled_flag,
735 .pps_disable_deblocking_filter_flag = pps->deblocking_filter_disabled_flag,
736 .slice_segment_header_extension_present_flag = pps->slice_segment_header_extension_present_flag,
737 .RapPicFlag = picture->RapPicFlag,
738 .IdrPicFlag = GST_H265_IS_NAL_TYPE_IDR (slice->nalu.type),
739 .IntraPicFlag = GST_H265_IS_NAL_TYPE_IRAP (slice->nalu.type),
744 if (_is_range_extension_profile (self->parent.profile)
745 || _is_screen_content_ext_profile (self->parent.profile)) {
746 _fill_picture_range_ext_parameter (self, sps, pps);
747 if (_is_screen_content_ext_profile (self->parent.profile))
748 _fill_screen_content_ext_parameter (self, sps, pps);
751 for (i = 0; i <= pps->num_tile_columns_minus1; i++)
752 pic_param->base.column_width_minus1[i] = pps->column_width_minus1[i];
754 for (i = 0; i <= pps->num_tile_rows_minus1; i++)
755 pic_param->base.row_height_minus1[i] = pps->row_height_minus1[i];
757 _fill_vaapi_pic (decoder, &pic_param->base.CurrPic, picture);
759 /* reference frames */
761 GArray *ref_list = gst_h265_dpb_get_pictures_all (dpb);
765 for (j = 0; j < 15 && j < ref_list->len; j++) {
766 GstH265Picture *pic = g_array_index (ref_list, GstH265Picture *, j);
769 _fill_vaapi_pic (decoder, &pic_param->base.ReferenceFrames[i], pic);
773 g_array_unref (ref_list);
775 /* 7.4.3.3.3, the current decoded picture is marked as "used for
776 long-term reference". Current picture is not in the DPB now. */
777 if (pps->pps_scc_extension_params.pps_curr_pic_ref_enabled_flag && i < 15) {
778 pic_param->base.ReferenceFrames[i].picture_id =
779 gst_va_decode_picture_get_surface (gst_h265_picture_get_user_data
781 pic_param->base.ReferenceFrames[i].pic_order_cnt = picture->pic_order_cnt;
782 pic_param->base.ReferenceFrames[i].flags |=
783 VA_PICTURE_HEVC_LONG_TERM_REFERENCE;
784 pic_param->base.ReferenceFrames[i].flags |=
785 _find_frame_rps_type (decoder, picture);
790 _init_vaapi_pic (&pic_param->base.ReferenceFrames[i]);
793 pic_param_size = _is_range_extension_profile (self->parent.profile)
794 || _is_screen_content_ext_profile (self->parent.profile) ?
795 sizeof (*pic_param) : sizeof (pic_param->base);
796 if (!gst_va_decoder_add_param_buffer (base->decoder, va_pic,
797 VAPictureParameterBufferType, pic_param, pic_param_size))
798 return GST_FLOW_ERROR;
800 if (pps->scaling_list_data_present_flag ||
801 (sps->scaling_list_enabled_flag
802 && !sps->scaling_list_data_present_flag)) {
803 scaling_list = &pps->scaling_list;
804 GST_DEBUG_OBJECT (decoder, "Passing scaling list from PPS");
805 } else if (sps->scaling_list_enabled_flag &&
806 sps->scaling_list_data_present_flag) {
807 scaling_list = &sps->scaling_list;
808 GST_DEBUG_OBJECT (decoder, "Passing scaling list from SPS");
812 for (i = 0; i < G_N_ELEMENTS (iq_matrix.ScalingList4x4); i++)
813 gst_h265_quant_matrix_4x4_get_raster_from_uprightdiagonal
814 (iq_matrix.ScalingList4x4[i], scaling_list->scaling_lists_4x4[i]);
816 for (i = 0; i < G_N_ELEMENTS (iq_matrix.ScalingList8x8); i++)
817 gst_h265_quant_matrix_8x8_get_raster_from_uprightdiagonal
818 (iq_matrix.ScalingList8x8[i], scaling_list->scaling_lists_8x8[i]);
820 for (i = 0; i < G_N_ELEMENTS (iq_matrix.ScalingList16x16); i++)
821 gst_h265_quant_matrix_16x16_get_raster_from_uprightdiagonal
822 (iq_matrix.ScalingList16x16[i], scaling_list->scaling_lists_16x16[i]);
824 for (i = 0; i < G_N_ELEMENTS (iq_matrix.ScalingList32x32); i++)
825 gst_h265_quant_matrix_32x32_get_raster_from_uprightdiagonal
826 (iq_matrix.ScalingList32x32[i], scaling_list->scaling_lists_32x32[i]);
828 for (i = 0; i < 6; i++)
829 iq_matrix.ScalingListDC16x16[i] =
830 scaling_list->scaling_list_dc_coef_minus8_16x16[i] + 8;
832 for (i = 0; i < 2; i++)
833 iq_matrix.ScalingListDC32x32[i] =
834 scaling_list->scaling_list_dc_coef_minus8_32x32[i] + 8;
836 if (!gst_va_decoder_add_param_buffer (base->decoder, va_pic,
837 VAIQMatrixBufferType, &iq_matrix, sizeof (iq_matrix))) {
838 return GST_FLOW_ERROR;
846 gst_va_h265_dec_new_picture (GstH265Decoder * decoder,
847 GstVideoCodecFrame * frame, GstH265Picture * picture)
849 GstVaBaseDec *base = GST_VA_BASE_DEC (decoder);
850 GstVaH265Dec *self = GST_VA_H265_DEC (decoder);
851 GstVaDecodePicture *pic;
852 GstBuffer *output_buffer;
853 GstVideoDecoder *vdec = GST_VIDEO_DECODER (decoder);
854 GstFlowReturn ret = GST_FLOW_ERROR;
856 if (base->need_negotiation) {
857 if (!gst_video_decoder_negotiate (vdec)) {
858 GST_ERROR_OBJECT (self, "Failed to negotiate with downstream");
859 return GST_FLOW_NOT_NEGOTIATED;
863 output_buffer = gst_video_decoder_allocate_output_buffer (vdec);
867 pic = gst_va_decode_picture_new (base->decoder, output_buffer);
868 gst_buffer_unref (output_buffer);
870 gst_h265_picture_set_user_data (picture, pic,
871 (GDestroyNotify) gst_va_decode_picture_free);
873 GST_LOG_OBJECT (self, "New va decode picture %p - %#x", pic,
874 gst_va_decode_picture_get_surface (pic));
880 GST_WARNING_OBJECT (self,
881 "Failed to allocated output buffer, return %s",
882 gst_flow_get_name (ret));
888 _get_rtformat (GstVaH265Dec * self, guint8 bit_depth_luma,
889 guint8 bit_depth_chroma, guint8 chroma_format_idc)
891 guint8 bit_num = MAX (bit_depth_luma, bit_depth_chroma);
896 if (chroma_format_idc == 3)
897 return VA_RT_FORMAT_YUV444_12;
898 if (chroma_format_idc == 2)
899 return VA_RT_FORMAT_YUV422_12;
901 return VA_RT_FORMAT_YUV420_12;
905 if (chroma_format_idc == 3)
906 return VA_RT_FORMAT_YUV444_10;
907 if (chroma_format_idc == 2)
908 return VA_RT_FORMAT_YUV422_10;
910 return VA_RT_FORMAT_YUV420_10;
913 if (chroma_format_idc == 3)
914 return VA_RT_FORMAT_YUV444;
915 if (chroma_format_idc == 2)
916 return VA_RT_FORMAT_YUV422;
918 return VA_RT_FORMAT_YUV420;
921 GST_ERROR_OBJECT (self, "Unsupported chroma format: %d "
922 "(with depth luma: %d, with depth chroma: %d)",
923 chroma_format_idc, bit_depth_luma, bit_depth_chroma);
931 GstH265Profile profile;
932 VAProfile va_profile;
934 #define P(idc, va) { G_PASTE (GST_H265_PROFILE_, idc), G_PASTE (VAProfileHEVC, va) }
937 /*P (MAIN_STILL_PICTURE, ),
940 P (MONOCHROME_16, ),*/
942 P (MAIN_422_10, Main422_10),
943 P (MAIN_422_12, Main422_12),
944 P (MAIN_444, Main444),
945 P (MAIN_444_10, Main444_10),
946 P (MAIN_444_12, Main444_12),
950 P (MAIN_422_10_INTRA, ),
951 P (MAIN_422_12_INTRA, ),
952 P (MAIN_444_INTRA, ),
953 P (MAIN_444_10_INTRA, ),
954 P (MAIN_444_12_INTRA, ),
955 P (MAIN_444_16_INTRA, ),
956 P (MAIN_444_STILL_PICTURE, ),
957 P (MAIN_444_16_STILL_PICTURE, ),
959 P (HIGH_THROUGHPUT_444, ),
960 P (HIGH_THROUGHPUT_444_10, ),
961 P (HIGH_THROUGHPUT_444_14, ),
962 P (HIGH_THROUGHPUT_444_16_INTRA, ),*/
963 P (SCREEN_EXTENDED_MAIN, SccMain),
964 P (SCREEN_EXTENDED_MAIN_10, SccMain10),
965 P (SCREEN_EXTENDED_MAIN_444, SccMain444),
966 #if VA_CHECK_VERSION(1, 8, 0)
967 P (SCREEN_EXTENDED_MAIN_444_10, SccMain444_10),
969 /*P (SCREEN_EXTENDED_HIGH_THROUGHPUT_444, ),
970 P (SCREEN_EXTENDED_HIGH_THROUGHPUT_444_10, ),
971 P (SCREEN_EXTENDED_HIGH_THROUGHPUT_444_14, ),
972 P (MULTIVIEW_MAIN, ),
974 P (SCALABLE_MAIN_10, ),
975 P (SCALABLE_MONOCHROME, ),
976 P (SCALABLE_MONOCHROME_12, ),
977 P (SCALABLE_MONOCHROME_16, ),
978 P (SCALABLE_MAIN_444, ),
985 _get_profile (GstVaH265Dec * self, const GstH265SPS * sps, gint max_dpb_size)
987 GstH265Decoder *h265_decoder = GST_H265_DECODER (self);
988 GstVaBaseDec *base = GST_VA_BASE_DEC (self);
989 GstH265Profile profile = gst_h265_get_profile_from_sps ((GstH265SPS *) sps);
990 VAProfile profiles[4];
993 /* 1. The profile directly specified by the SPS should always be the
994 first choice. It is the exact one.
995 2. The profile in the input caps may contain the compatible profile
996 chosen by the upstream element. Upstream element such as the parse
997 may already decide the best compatible profile for us. We also need
998 to consider it as a choice. */
1000 for (j = 0; j < G_N_ELEMENTS (profile_map); j++) {
1001 if (profile_map[j].profile == profile) {
1002 profiles[i++] = profile_map[j].va_profile;
1007 if (h265_decoder->input_state->caps
1008 && gst_caps_is_fixed (h265_decoder->input_state->caps)) {
1009 GstH265Profile compatible_profile = GST_H265_PROFILE_INVALID;
1010 GstStructure *structure;
1011 const gchar *profile_str;
1013 structure = gst_caps_get_structure (h265_decoder->input_state->caps, 0);
1015 profile_str = gst_structure_get_string (structure, "profile");
1017 compatible_profile = gst_h265_profile_from_string (profile_str);
1019 if (compatible_profile != profile) {
1020 GST_INFO_OBJECT (self, "The upstream set the compatible profile %s, "
1021 "also consider it as a candidate.", profile_str);
1023 for (j = 0; j < G_N_ELEMENTS (profile_map); j++) {
1024 if (profile_map[j].profile == compatible_profile) {
1025 profiles[i++] = profile_map[j].va_profile;
1032 for (j = 0; j < i && j < G_N_ELEMENTS (profiles); j++) {
1033 if (gst_va_decoder_has_profile (base->decoder, profiles[j]))
1037 GST_ERROR_OBJECT (self, "Unsupported profile: %d", profile);
1039 return VAProfileNone;
1042 static GstFlowReturn
1043 gst_va_h265_dec_new_sequence (GstH265Decoder * decoder, const GstH265SPS * sps,
1046 GstVaBaseDec *base = GST_VA_BASE_DEC (decoder);
1047 GstVaH265Dec *self = GST_VA_H265_DEC (decoder);
1048 GstVideoInfo *info = &base->output_info;
1051 gint display_height;
1052 gint padding_left, padding_right, padding_top, padding_bottom;
1054 gboolean negotiation_needed = FALSE;
1056 if (self->dpb_size < max_dpb_size)
1057 self->dpb_size = max_dpb_size;
1059 if (sps->conformance_window_flag) {
1060 display_width = sps->crop_rect_width;
1061 display_height = sps->crop_rect_height;
1062 padding_left = sps->crop_rect_x;
1063 padding_right = sps->width - sps->crop_rect_x - display_width;
1064 padding_top = sps->crop_rect_y;
1065 padding_bottom = sps->height - sps->crop_rect_y - display_height;
1067 display_width = sps->width;
1068 display_height = sps->height;
1069 padding_left = padding_right = padding_top = padding_bottom = 0;
1072 profile = _get_profile (self, sps, max_dpb_size);
1073 if (profile == VAProfileNone)
1074 return GST_FLOW_NOT_NEGOTIATED;
1076 rt_format = _get_rtformat (self, sps->bit_depth_luma_minus8 + 8,
1077 sps->bit_depth_chroma_minus8 + 8, sps->chroma_format_idc);
1079 return GST_FLOW_NOT_NEGOTIATED;
1081 if (!gst_va_decoder_config_is_equal (base->decoder, profile,
1082 rt_format, sps->width, sps->height)) {
1083 base->profile = profile;
1084 base->rt_format = rt_format;
1085 base->width = sps->width;
1086 base->height = sps->height;
1088 negotiation_needed = TRUE;
1089 GST_INFO_OBJECT (self, "Format changed to %s [%x] (%dx%d)",
1090 gst_va_profile_name (profile), rt_format, base->width, base->height);
1093 if (GST_VIDEO_INFO_WIDTH (info) != display_width ||
1094 GST_VIDEO_INFO_HEIGHT (info) != display_height) {
1095 GST_VIDEO_INFO_WIDTH (info) = display_width;
1096 GST_VIDEO_INFO_HEIGHT (info) = display_height;
1098 negotiation_needed = TRUE;
1099 GST_INFO_OBJECT (self, "Resolution changed to %dx%d",
1100 GST_VIDEO_INFO_WIDTH (info), GST_VIDEO_INFO_HEIGHT (info));
1103 base->need_valign = GST_VIDEO_INFO_WIDTH (info) < base->width ||
1104 GST_VIDEO_INFO_HEIGHT (info) < base->height;
1105 if (base->need_valign) {
1107 if (base->valign.padding_left != padding_left ||
1108 base->valign.padding_right != padding_right ||
1109 base->valign.padding_top != padding_top ||
1110 base->valign.padding_bottom != padding_bottom) {
1111 negotiation_needed = TRUE;
1112 GST_INFO_OBJECT (self, "crop rect changed to (%d,%d)-->(%d,%d)",
1113 padding_left, padding_top, padding_right, padding_bottom);
1115 base->valign = (GstVideoAlignment) {
1116 .padding_left = padding_left,
1117 .padding_right = padding_right,
1118 .padding_top = padding_top,
1119 .padding_bottom = padding_bottom,
1124 base->min_buffers = self->dpb_size + 4; /* dpb size + scratch surfaces */
1125 base->need_negotiation = negotiation_needed;
1126 g_clear_pointer (&base->input_state, gst_video_codec_state_unref);
1127 base->input_state = gst_video_codec_state_ref (decoder->input_state);
1130 /* FIXME: We don't have parser API for sps_range_extension, so
1131 * assuming high_precision_offsets_enabled_flag as zero */
1132 guint high_precision_offsets_enabled_flag = 0, bitdepthC = 0;
1134 /* Calculate WpOffsetHalfRangeC: (7-34) */
1135 bitdepthC = sps->bit_depth_chroma_minus8 + 8;
1136 self->WpOffsetHalfRangeC =
1137 1 << (high_precision_offsets_enabled_flag ? (bitdepthC - 1) : 7);
1144 _complete_sink_caps (GstCaps * sinkcaps)
1146 GstCaps *caps = gst_caps_copy (sinkcaps);
1147 GValue val = G_VALUE_INIT;
1148 const gchar *streamformat[] = { "hvc1", "hev1", "byte-stream" };
1151 g_value_init (&val, G_TYPE_STRING);
1152 g_value_set_string (&val, "au");
1153 gst_caps_set_value (caps, "alignment", &val);
1154 g_value_unset (&val);
1156 gst_value_list_init (&val, G_N_ELEMENTS (streamformat));
1157 for (i = 0; i < G_N_ELEMENTS (streamformat); i++) {
1158 GValue v = G_VALUE_INIT;
1160 g_value_init (&v, G_TYPE_STRING);
1161 g_value_set_string (&v, streamformat[i]);
1162 gst_value_list_append_value (&val, &v);
1165 gst_caps_set_value (caps, "stream-format", &val);
1166 g_value_unset (&val);
1172 gst_va_h265_dec_getcaps (GstVideoDecoder * decoder, GstCaps * filter)
1174 GstCaps *sinkcaps, *caps = NULL, *tmp;
1175 GstVaBaseDec *base = GST_VA_BASE_DEC (decoder);
1178 caps = gst_va_decoder_get_sinkpad_caps (base->decoder);
1181 sinkcaps = _complete_sink_caps (caps);
1182 gst_caps_unref (caps);
1184 tmp = gst_caps_intersect_full (filter, sinkcaps,
1185 GST_CAPS_INTERSECT_FIRST);
1186 gst_caps_unref (sinkcaps);
1191 GST_LOG_OBJECT (base, "Returning caps %" GST_PTR_FORMAT, caps);
1193 caps = gst_video_decoder_proxy_getcaps (decoder, NULL, filter);
1200 gst_va_h265_dec_dispose (GObject * object)
1202 g_free (GST_VA_H265_DEC (object)->prev_slice.data);
1204 gst_va_base_dec_close (GST_VIDEO_DECODER (object));
1206 G_OBJECT_CLASS (parent_class)->dispose (object);
1210 gst_va_h265_dec_class_init (gpointer g_class, gpointer class_data)
1212 GstCaps *src_doc_caps, *sink_doc_caps;
1213 GObjectClass *gobject_class = G_OBJECT_CLASS (g_class);
1214 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
1215 GstH265DecoderClass *h265decoder_class = GST_H265_DECODER_CLASS (g_class);
1216 GstVideoDecoderClass *decoder_class = GST_VIDEO_DECODER_CLASS (g_class);
1217 struct CData *cdata = class_data;
1220 if (cdata->description) {
1221 long_name = g_strdup_printf ("VA-API H.265 Decoder in %s",
1222 cdata->description);
1224 long_name = g_strdup ("VA-API H.265 Decoder");
1227 gst_element_class_set_metadata (element_class, long_name,
1228 "Codec/Decoder/Video/Hardware",
1229 "VA-API based H.265 video decoder",
1230 "Nicolas Dufresne <nicolas.dufresne@collabora.com>");
1232 sink_doc_caps = gst_caps_from_string (sink_caps_str);
1233 src_doc_caps = gst_caps_from_string (src_caps_str);
1235 parent_class = g_type_class_peek_parent (g_class);
1238 * GstVaH265Dec:device-path:
1240 * It shows the DRM device path used for the VA operation, if any.
1244 gst_va_base_dec_class_init (GST_VA_BASE_DEC_CLASS (g_class), HEVC,
1245 cdata->render_device_path, cdata->sink_caps, cdata->src_caps,
1246 src_doc_caps, sink_doc_caps);
1248 gobject_class->dispose = gst_va_h265_dec_dispose;
1250 decoder_class->getcaps = GST_DEBUG_FUNCPTR (gst_va_h265_dec_getcaps);
1252 h265decoder_class->new_sequence =
1253 GST_DEBUG_FUNCPTR (gst_va_h265_dec_new_sequence);
1254 h265decoder_class->decode_slice =
1255 GST_DEBUG_FUNCPTR (gst_va_h265_dec_decode_slice);
1257 h265decoder_class->new_picture =
1258 GST_DEBUG_FUNCPTR (gst_va_h265_dec_new_picture);
1259 h265decoder_class->output_picture =
1260 GST_DEBUG_FUNCPTR (gst_va_h265_dec_output_picture);
1261 h265decoder_class->start_picture =
1262 GST_DEBUG_FUNCPTR (gst_va_h265_dec_start_picture);
1263 h265decoder_class->end_picture =
1264 GST_DEBUG_FUNCPTR (gst_va_h265_dec_end_picture);
1267 g_free (cdata->description);
1268 g_free (cdata->render_device_path);
1269 gst_caps_unref (cdata->src_caps);
1270 gst_caps_unref (cdata->sink_caps);
1275 gst_va_h265_dec_init (GTypeInstance * instance, gpointer g_class)
1277 gst_va_base_dec_init (GST_VA_BASE_DEC (instance), GST_CAT_DEFAULT);
1278 gst_h265_decoder_set_process_ref_pic_lists (GST_H265_DECODER (instance),
1283 _register_debug_category (gpointer data)
1285 GST_DEBUG_CATEGORY_INIT (gst_va_h265dec_debug, "vah265dec", 0,
1292 gst_va_h265_dec_register (GstPlugin * plugin, GstVaDevice * device,
1293 GstCaps * sink_caps, GstCaps * src_caps, guint rank)
1295 static GOnce debug_once = G_ONCE_INIT;
1297 GTypeInfo type_info = {
1298 .class_size = sizeof (GstVaH265DecClass),
1299 .class_init = gst_va_h265_dec_class_init,
1300 .instance_size = sizeof (GstVaH265Dec),
1301 .instance_init = gst_va_h265_dec_init,
1303 struct CData *cdata;
1305 gchar *type_name, *feature_name;
1307 g_return_val_if_fail (GST_IS_PLUGIN (plugin), FALSE);
1308 g_return_val_if_fail (GST_IS_VA_DEVICE (device), FALSE);
1309 g_return_val_if_fail (GST_IS_CAPS (sink_caps), FALSE);
1310 g_return_val_if_fail (GST_IS_CAPS (src_caps), FALSE);
1312 cdata = g_new (struct CData, 1);
1313 cdata->description = NULL;
1314 cdata->render_device_path = g_strdup (device->render_device_path);
1315 cdata->sink_caps = _complete_sink_caps (sink_caps);
1316 cdata->src_caps = gst_caps_ref (src_caps);
1318 /* class data will be leaked if the element never gets instantiated */
1319 GST_MINI_OBJECT_FLAG_SET (cdata->sink_caps,
1320 GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
1321 GST_MINI_OBJECT_FLAG_SET (src_caps, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
1323 type_info.class_data = cdata;
1325 /* The first decoder to be registered should use a constant name,
1326 * like vah265dec, for any additional decoders, we create unique
1327 * names, using inserting the render device name. */
1328 if (device->index == 0) {
1329 type_name = g_strdup ("GstVaH265Dec");
1330 feature_name = g_strdup ("vah265dec");
1332 gchar *basename = g_path_get_basename (device->render_device_path);
1333 type_name = g_strdup_printf ("GstVa%sH265Dec", basename);
1334 feature_name = g_strdup_printf ("va%sh265dec", basename);
1335 cdata->description = basename;
1337 /* lower rank for non-first device */
1342 g_once (&debug_once, _register_debug_category, NULL);
1344 type = g_type_register_static (GST_TYPE_H265_DECODER,
1345 type_name, &type_info, 0);
1347 ret = gst_element_register (plugin, feature_name, rank, type);
1350 g_free (feature_name);