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;
95 VAPictureParameterBufferHEVCExtension pic_param;
97 gint32 WpOffsetHalfRangeC;
99 struct slice prev_slice;
102 static GstElementClass *parent_class = NULL;
105 static const gchar *src_caps_str =
106 GST_VIDEO_CAPS_MAKE_WITH_FEATURES (GST_CAPS_FEATURE_MEMORY_VA,
107 "{ NV12, P010_10LE }") " ;"
108 GST_VIDEO_CAPS_MAKE ("{ NV12, P010_10LE }");
111 static const gchar *sink_caps_str = "video/x-h265";
114 _is_range_extension_profile (VAProfile profile)
116 if (profile == VAProfileHEVCMain422_10
117 || profile == VAProfileHEVCMain444
118 || profile == VAProfileHEVCMain444_10
119 || profile == VAProfileHEVCMain12
120 || profile == VAProfileHEVCMain444_12
121 || profile == VAProfileHEVCMain422_12)
127 _is_screen_content_ext_profile (VAProfile profile)
129 if (profile == VAProfileHEVCSccMain || profile == VAProfileHEVCSccMain10
130 || profile == VAProfileHEVCSccMain444
131 #if VA_CHECK_VERSION(1, 8, 0)
132 || profile == VAProfileHEVCSccMain444_10
141 _set_last_slice_flag (GstVaH265Dec * self)
143 self->prev_slice.param.base.LongSliceFlags.fields.LastSliceOfPic = 1;
147 _replace_previous_slice (GstVaH265Dec * self, guint8 * data, guint size)
149 struct slice *slice = &self->prev_slice;
150 gboolean do_reset = (slice->size < size);
152 if (!data || do_reset) {
153 g_clear_pointer (&slice->data, g_free);
161 GST_LOG_OBJECT (self, "allocating slice data %u", size);
162 slice->data = g_malloc (size);
165 memcpy (slice->data, data, size);
170 _submit_previous_slice (GstVaBaseDec * base, GstVaDecodePicture * va_pic)
172 GstVaH265Dec *self = GST_VA_H265_DEC (base);
177 slice = &self->prev_slice;
178 if (!slice->data && slice->size == 0)
180 if (!slice->data || slice->size == 0)
183 param_size = _is_range_extension_profile (self->parent.profile)
184 || _is_screen_content_ext_profile (self->parent.profile) ?
185 sizeof (slice->param) : sizeof (slice->param.base);
186 ret = gst_va_decoder_add_slice_buffer (base->decoder, va_pic, &slice->param,
187 param_size, slice->data, slice->size);
193 gst_va_h265_dec_end_picture (GstH265Decoder * decoder, GstH265Picture * picture)
195 GstVaBaseDec *base = GST_VA_BASE_DEC (decoder);
196 GstVaH265Dec *self = GST_VA_H265_DEC (decoder);
197 GstVaDecodePicture *va_pic;
200 GST_LOG_OBJECT (base, "end picture %p, (poc %d)",
201 picture, picture->pic_order_cnt);
203 va_pic = gst_h265_picture_get_user_data (picture);
205 _set_last_slice_flag (self);
206 ret = _submit_previous_slice (base, va_pic);
208 /* TODO(victor): optimization: this could be done at decoder's
210 _replace_previous_slice (self, NULL, 0);
213 GST_ERROR_OBJECT (self, "Failed to submit the previous slice");
214 return GST_FLOW_ERROR;
217 ret = gst_va_decoder_decode (base->decoder, va_pic);
219 GST_ERROR_OBJECT (self, "Failed at end picture %p, (poc %d)",
220 picture, picture->pic_order_cnt);
221 return GST_FLOW_ERROR;
228 gst_va_h265_dec_output_picture (GstH265Decoder * decoder,
229 GstVideoCodecFrame * frame, GstH265Picture * picture)
231 GstVaBaseDec *base = GST_VA_BASE_DEC (decoder);
232 GstVaH265Dec *self = GST_VA_H265_DEC (decoder);
233 GstVideoDecoder *vdec = GST_VIDEO_DECODER (decoder);
234 GstVaDecodePicture *va_pic;
237 va_pic = gst_h265_picture_get_user_data (picture);
238 g_assert (va_pic->gstbuffer);
240 GST_LOG_OBJECT (self,
241 "Outputting picture %p (poc %d)", picture, picture->pic_order_cnt);
243 gst_buffer_replace (&frame->output_buffer, va_pic->gstbuffer);
245 ret = gst_va_base_dec_process_output (base, frame, picture->buffer_flags);
246 gst_h265_picture_unref (picture);
249 return gst_video_decoder_finish_frame (vdec, frame);
250 return GST_FLOW_ERROR;
254 _init_vaapi_pic (VAPictureHEVC * va_picture)
256 va_picture->picture_id = VA_INVALID_ID;
257 va_picture->flags = VA_PICTURE_HEVC_INVALID;
258 va_picture->pic_order_cnt = 0;
262 _find_frame_rps_type (GstH265Decoder * decoder, GstH265Picture * ref_pic)
266 for (i = 0; i < G_N_ELEMENTS (decoder->RefPicSetStCurrBefore); i++) {
267 if (ref_pic == decoder->RefPicSetStCurrBefore[i])
268 return VA_PICTURE_HEVC_RPS_ST_CURR_BEFORE;
271 for (i = 0; i < G_N_ELEMENTS (decoder->RefPicSetStCurrAfter); i++) {
272 if (ref_pic == decoder->RefPicSetStCurrAfter[i])
273 return VA_PICTURE_HEVC_RPS_ST_CURR_AFTER;
276 for (i = 0; i < G_N_ELEMENTS (decoder->RefPicSetLtCurr); i++) {
277 if (ref_pic == decoder->RefPicSetLtCurr[i])
278 return VA_PICTURE_HEVC_RPS_LT_CURR;
286 _fill_vaapi_pic (GstH265Decoder * decoder, VAPictureHEVC * va_picture,
287 GstH265Picture * picture)
289 GstVaDecodePicture *va_pic;
291 va_pic = gst_h265_picture_get_user_data (picture);
294 _init_vaapi_pic (va_picture);
298 va_picture->picture_id = gst_va_decode_picture_get_surface (va_pic);
299 va_picture->pic_order_cnt = picture->pic_order_cnt;
300 va_picture->flags = 0;
302 if (picture->ref && picture->long_term)
303 va_picture->flags |= VA_PICTURE_HEVC_LONG_TERM_REFERENCE;
305 va_picture->flags |= _find_frame_rps_type (decoder, picture);
309 _get_reference_index (GstH265Decoder * decoder, GstH265Picture * picture)
311 GstVaH265Dec *self = GST_VA_H265_DEC (decoder);
317 for (i = 0; i < 15; i++) {
318 VAPictureHEVC *ref_va_pic = &self->pic_param.base.ReferenceFrames[i];
320 if (ref_va_pic->picture_id == VA_INVALID_ID)
323 if (ref_va_pic->pic_order_cnt == picture->pic_order_cnt)
330 /* fill the VA API reference picture lists from the GstCodec reference
333 _fill_ref_pic_list (GstH265Decoder * decoder, GstH265Picture * cur_pic,
334 guint8 va_reflist[15], GArray * reflist)
338 for (i = 0; i < reflist->len && i < 15; i++) {
339 GstH265Picture *picture = g_array_index (reflist, GstH265Picture *, i);
340 va_reflist[i] = _get_reference_index (decoder, picture);
344 va_reflist[i] = 0xFF;
348 _fill_pred_weight_table (GstVaH265Dec * self, GstH265SliceHdr * header,
349 VASliceParameterBufferHEVCExtension * slice_param)
351 gint chroma_weight, chroma_log2_weight_denom;
353 GstH265PPS *pps = header->pps;
354 gboolean is_rext = _is_range_extension_profile (self->parent.profile);
356 if (GST_H265_IS_I_SLICE (header) ||
357 (!pps->weighted_pred_flag && GST_H265_IS_P_SLICE (header)) ||
358 (!pps->weighted_bipred_flag && GST_H265_IS_B_SLICE (header)))
361 slice_param->base.luma_log2_weight_denom =
362 header->pred_weight_table.luma_log2_weight_denom;
364 if (pps->sps->chroma_array_type != 0)
365 slice_param->base.delta_chroma_log2_weight_denom =
366 header->pred_weight_table.delta_chroma_log2_weight_denom;
368 for (i = 0; i <= header->num_ref_idx_l0_active_minus1; i++) {
369 if (!header->pred_weight_table.luma_weight_l0_flag[i])
372 slice_param->base.delta_luma_weight_l0[i] =
373 header->pred_weight_table.delta_luma_weight_l0[i];
374 slice_param->base.luma_offset_l0[i] =
375 header->pred_weight_table.luma_offset_l0[i];
378 slice_param->rext.luma_offset_l0[i] =
379 header->pred_weight_table.luma_offset_l0[i];
383 chroma_log2_weight_denom = slice_param->base.luma_log2_weight_denom +
384 slice_param->base.delta_chroma_log2_weight_denom;
386 for (i = 0; i <= header->num_ref_idx_l0_active_minus1; i++) {
387 if (!header->pred_weight_table.chroma_weight_l0_flag[i])
390 for (j = 0; j < 2; j++) {
391 gint16 delta_chroma_offset_l0 =
392 header->pred_weight_table.delta_chroma_offset_l0[i][j];
395 slice_param->base.delta_chroma_weight_l0[i][j] =
396 header->pred_weight_table.delta_chroma_weight_l0[i][j];
398 /* Find ChromaWeightL0 */
399 chroma_weight = (1 << chroma_log2_weight_denom) +
400 header->pred_weight_table.delta_chroma_weight_l0[i][j];
401 chroma_offset = self->WpOffsetHalfRangeC + delta_chroma_offset_l0
402 - ((self->WpOffsetHalfRangeC * chroma_weight)
403 >> chroma_log2_weight_denom);
406 slice_param->base.ChromaOffsetL0[i][j] = CLAMP (chroma_offset,
407 -self->WpOffsetHalfRangeC, self->WpOffsetHalfRangeC - 1);
410 slice_param->rext.ChromaOffsetL0[i][j] =
411 slice_param->base.ChromaOffsetL0[i][j];
416 /* Skip l1 if this is not a B-Frame. */
417 if (!GST_H265_IS_B_SLICE (header))
420 for (i = 0; i <= header->num_ref_idx_l1_active_minus1; i++) {
421 if (!header->pred_weight_table.luma_weight_l1_flag[i])
424 slice_param->base.delta_luma_weight_l1[i] =
425 header->pred_weight_table.delta_luma_weight_l1[i];
426 slice_param->base.luma_offset_l1[i] =
427 header->pred_weight_table.luma_offset_l1[i];
430 slice_param->rext.luma_offset_l1[i] =
431 header->pred_weight_table.luma_offset_l1[i];
435 for (i = 0; i <= header->num_ref_idx_l1_active_minus1; i++) {
436 if (!header->pred_weight_table.chroma_weight_l1_flag[i])
439 for (j = 0; j < 2; j++) {
440 gint16 delta_chroma_offset_l1 =
441 header->pred_weight_table.delta_chroma_offset_l1[i][j];
444 slice_param->base.delta_chroma_weight_l1[i][j] =
445 header->pred_weight_table.delta_chroma_weight_l1[i][j];
447 /* Find ChromaWeightL1 */
448 chroma_weight = (1 << chroma_log2_weight_denom) +
449 header->pred_weight_table.delta_chroma_weight_l1[i][j];
451 chroma_offset = self->WpOffsetHalfRangeC + delta_chroma_offset_l1
452 - ((self->WpOffsetHalfRangeC * chroma_weight)
453 >> chroma_log2_weight_denom);
456 slice_param->base.ChromaOffsetL1[i][j] = CLAMP (chroma_offset,
457 -self->WpOffsetHalfRangeC, self->WpOffsetHalfRangeC - 1);
460 slice_param->rext.ChromaOffsetL1[i][j] =
461 slice_param->base.ChromaOffsetL1[i][j];
468 _get_slice_data_byte_offset (GstH265SliceHdr * slice_hdr,
469 guint nal_header_bytes)
473 epb_count = slice_hdr->n_emulation_prevention_bytes;
474 return nal_header_bytes + (slice_hdr->header_size + 7) / 8 - epb_count;
478 gst_va_h265_dec_decode_slice (GstH265Decoder * decoder,
479 GstH265Picture * picture, GstH265Slice * slice, GArray * ref_pic_list0,
480 GArray * ref_pic_list1)
482 GstH265SliceHdr *header = &slice->header;
483 GstH265NalUnit *nalu = &slice->nalu;
484 GstVaBaseDec *base = GST_VA_BASE_DEC (decoder);
485 GstVaH265Dec *self = GST_VA_H265_DEC (decoder);
486 GstVaDecodePicture *va_pic;
487 VASliceParameterBufferHEVCExtension *slice_param;
489 va_pic = gst_h265_picture_get_user_data (picture);
490 if (!_submit_previous_slice (base, va_pic)) {
491 _replace_previous_slice (self, NULL, 0);
492 GST_ERROR_OBJECT (base, "Failed to submit previous slice buffers");
493 return GST_FLOW_ERROR;
496 slice_param = &self->prev_slice.param;
499 slice_param->base = (VASliceParameterBufferHEVC) {
500 .slice_data_size = nalu->size,
501 .slice_data_offset = 0,
502 .slice_data_flag = VA_SLICE_DATA_FLAG_ALL,
503 .slice_data_byte_offset = _get_slice_data_byte_offset (header, nalu->header_bytes),
504 .slice_segment_address = header->segment_address,
505 .collocated_ref_idx = header->temporal_mvp_enabled_flag ? header->collocated_ref_idx : 0xFF,
506 .num_ref_idx_l0_active_minus1 = header->num_ref_idx_l0_active_minus1,
507 .num_ref_idx_l1_active_minus1 = header->num_ref_idx_l1_active_minus1,
508 .slice_qp_delta = header->qp_delta,
509 .slice_cb_qp_offset = header->cb_qp_offset,
510 .slice_cr_qp_offset = header->cr_qp_offset,
511 .slice_beta_offset_div2 = header->beta_offset_div2,
512 .slice_tc_offset_div2 = header->tc_offset_div2,
513 .five_minus_max_num_merge_cand = header->five_minus_max_num_merge_cand,
514 .num_entry_point_offsets = header->num_entry_point_offsets,
515 .entry_offset_to_subset_array = 0, /* does not exist in spec */
516 .slice_data_num_emu_prevn_bytes = header->n_emulation_prevention_bytes,
517 .LongSliceFlags.fields = {
518 .LastSliceOfPic = 0, /* the last one will be set on end_picture() */
519 .dependent_slice_segment_flag = header->dependent_slice_segment_flag,
520 .slice_type = header->type,
521 .color_plane_id = header->colour_plane_id,
522 .slice_sao_luma_flag = header->sao_luma_flag,
523 .slice_sao_chroma_flag = header->sao_chroma_flag,
524 .mvd_l1_zero_flag = header->mvd_l1_zero_flag,
525 .cabac_init_flag = header->cabac_init_flag,
526 .slice_temporal_mvp_enabled_flag = header->temporal_mvp_enabled_flag,
527 .slice_deblocking_filter_disabled_flag =
528 header->deblocking_filter_disabled_flag,
529 .collocated_from_l0_flag = header->collocated_from_l0_flag,
530 .slice_loop_filter_across_slices_enabled_flag =
531 header->loop_filter_across_slices_enabled_flag,
536 if (_is_range_extension_profile (base->profile)
537 || _is_screen_content_ext_profile (base->profile)) {
539 slice_param->rext = (VASliceParameterBufferHEVCRext) {
540 .slice_ext_flags.bits = {
541 .cu_chroma_qp_offset_enabled_flag = header->cu_chroma_qp_offset_enabled_flag,
542 .use_integer_mv_flag = header->use_integer_mv_flag,
544 .slice_act_y_qp_offset = header->slice_act_y_qp_offset,
545 .slice_act_cb_qp_offset = header->slice_act_cb_qp_offset,
546 .slice_act_cr_qp_offset = header->slice_act_cr_qp_offset,
551 _fill_ref_pic_list (decoder, picture, slice_param->base.RefPicList[0],
553 _fill_ref_pic_list (decoder, picture, slice_param->base.RefPicList[1],
556 _fill_pred_weight_table (GST_VA_H265_DEC (decoder), header, slice_param);
558 _replace_previous_slice (self, slice->nalu.data + slice->nalu.offset,
565 _fill_picture_range_ext_parameter (GstVaH265Dec * decoder,
566 GstH265SPS * sps, GstH265PPS * pps)
568 VAPictureParameterBufferHEVCRext *pic_param = &decoder->pic_param.rext;
570 GstH265SPSExtensionParams *sps_ext = &sps->sps_extension_params;
571 GstH265PPSExtensionParams *pps_ext = &pps->pps_extension_params;
574 *pic_param = (VAPictureParameterBufferHEVCRext) {
575 .range_extension_pic_fields.bits = {
576 .transform_skip_rotation_enabled_flag = sps_ext->transform_skip_rotation_enabled_flag,
577 .transform_skip_context_enabled_flag = sps_ext->transform_skip_context_enabled_flag,
578 .implicit_rdpcm_enabled_flag = sps_ext->implicit_rdpcm_enabled_flag,
579 .explicit_rdpcm_enabled_flag = sps_ext->explicit_rdpcm_enabled_flag,
580 .extended_precision_processing_flag = sps_ext->extended_precision_processing_flag,
581 .intra_smoothing_disabled_flag = sps_ext->intra_smoothing_disabled_flag,
582 .high_precision_offsets_enabled_flag = sps_ext->high_precision_offsets_enabled_flag,
583 .persistent_rice_adaptation_enabled_flag = sps_ext->persistent_rice_adaptation_enabled_flag,
584 .cabac_bypass_alignment_enabled_flag = sps_ext->cabac_bypass_alignment_enabled_flag,
585 .cross_component_prediction_enabled_flag = pps_ext->cross_component_prediction_enabled_flag,
586 .chroma_qp_offset_list_enabled_flag = pps_ext->chroma_qp_offset_list_enabled_flag,
588 .diff_cu_chroma_qp_offset_depth = pps_ext->diff_cu_chroma_qp_offset_depth,
589 .chroma_qp_offset_list_len_minus1 = pps_ext->chroma_qp_offset_list_len_minus1,
590 .log2_sao_offset_scale_luma = pps_ext->log2_sao_offset_scale_luma,
591 .log2_sao_offset_scale_chroma = pps_ext->log2_sao_offset_scale_chroma,
592 .log2_max_transform_skip_block_size_minus2 = pps_ext->log2_max_transform_skip_block_size_minus2,
596 memcpy (pic_param->cb_qp_offset_list, pps_ext->cb_qp_offset_list,
597 sizeof (pic_param->cb_qp_offset_list));
598 memcpy (pic_param->cr_qp_offset_list, pps_ext->cr_qp_offset_list,
599 sizeof (pic_param->cr_qp_offset_list));
603 _fill_screen_content_ext_parameter (GstVaH265Dec * decoder,
604 GstH265SPS * sps, GstH265PPS * pps)
606 VAPictureParameterBufferHEVCScc *pic_param = &decoder->pic_param.scc;
607 const GstH265PPSSccExtensionParams *pps_scc = &pps->pps_scc_extension_params;
608 const GstH265SPSSccExtensionParams *sps_scc = &sps->sps_scc_extension_params;
613 *pic_param = (VAPictureParameterBufferHEVCScc) {
614 .screen_content_pic_fields.bits = {
615 .pps_curr_pic_ref_enabled_flag = pps_scc->pps_curr_pic_ref_enabled_flag,
616 .palette_mode_enabled_flag = sps_scc->palette_mode_enabled_flag,
617 .motion_vector_resolution_control_idc = sps_scc->motion_vector_resolution_control_idc,
618 .intra_boundary_filtering_disabled_flag = sps_scc->intra_boundary_filtering_disabled_flag,
619 .residual_adaptive_colour_transform_enabled_flag = pps_scc->residual_adaptive_colour_transform_enabled_flag,
620 .pps_slice_act_qp_offsets_present_flag = pps_scc->pps_slice_act_qp_offsets_present_flag,
622 .palette_max_size = sps_scc->palette_max_size,
623 .delta_palette_max_predictor_size = sps_scc->delta_palette_max_predictor_size,
624 .pps_act_y_qp_offset_plus5 = pps_scc->pps_act_y_qp_offset_plus5,
625 .pps_act_cb_qp_offset_plus5 = pps_scc->pps_act_cb_qp_offset_plus5,
626 .pps_act_cr_qp_offset_plus3 = pps_scc->pps_act_cr_qp_offset_plus3,
630 /* firstly use the pps, then sps */
631 num_comps = sps->chroma_format_idc ? 3 : 1;
633 if (pps_scc->pps_palette_predictor_initializers_present_flag) {
634 pic_param->predictor_palette_size =
635 pps_scc->pps_num_palette_predictor_initializer;
636 for (n = 0; n < num_comps; n++)
637 for (i = 0; i < pps_scc->pps_num_palette_predictor_initializer; i++)
638 pic_param->predictor_palette_entries[n][i] =
639 (uint16_t) pps_scc->pps_palette_predictor_initializer[n][i];
640 } else if (sps_scc->sps_palette_predictor_initializers_present_flag) {
641 pic_param->predictor_palette_size =
642 sps_scc->sps_num_palette_predictor_initializer_minus1 + 1;
643 for (n = 0; n < num_comps; n++)
645 i < sps_scc->sps_num_palette_predictor_initializer_minus1 + 1; i++)
646 pic_param->predictor_palette_entries[n][i] =
647 (uint16_t) sps_scc->sps_palette_predictor_initializer[n][i];
652 gst_va_h265_dec_start_picture (GstH265Decoder * decoder,
653 GstH265Picture * picture, GstH265Slice * slice, GstH265Dpb * dpb)
657 GstVaH265Dec *self = GST_VA_H265_DEC (decoder);
658 GstVaBaseDec *base = &self->parent;
659 GstVaDecodePicture *va_pic;
660 GstH265ScalingList *scaling_list = NULL;
661 VAIQMatrixBufferHEVC iq_matrix = { 0, };
662 VAPictureParameterBufferHEVCExtension *pic_param = &self->pic_param;
663 gsize pic_param_size;
666 va_pic = gst_h265_picture_get_user_data (picture);
668 pps = slice->header.pps;
672 pic_param->base = (VAPictureParameterBufferHEVC) {
673 .pic_width_in_luma_samples = sps->pic_width_in_luma_samples,
674 .pic_height_in_luma_samples = sps->pic_height_in_luma_samples,
675 .sps_max_dec_pic_buffering_minus1 = sps->max_dec_pic_buffering_minus1[sps->max_sub_layers_minus1],
676 .bit_depth_luma_minus8 = sps->bit_depth_luma_minus8,
677 .bit_depth_chroma_minus8 = sps->bit_depth_chroma_minus8,
678 .pcm_sample_bit_depth_luma_minus1 = sps->pcm_sample_bit_depth_luma_minus1,
679 .pcm_sample_bit_depth_chroma_minus1 = sps->pcm_sample_bit_depth_chroma_minus1,
680 .log2_min_luma_coding_block_size_minus3 = sps->log2_min_luma_coding_block_size_minus3,
681 .log2_diff_max_min_luma_coding_block_size = sps->log2_diff_max_min_luma_coding_block_size,
682 .log2_min_transform_block_size_minus2 = sps->log2_min_transform_block_size_minus2,
683 .log2_diff_max_min_transform_block_size = sps->log2_diff_max_min_transform_block_size,
684 .log2_min_pcm_luma_coding_block_size_minus3 = sps->log2_min_pcm_luma_coding_block_size_minus3,
685 .log2_diff_max_min_pcm_luma_coding_block_size = sps->log2_diff_max_min_pcm_luma_coding_block_size,
686 .max_transform_hierarchy_depth_intra = sps->max_transform_hierarchy_depth_intra,
687 .max_transform_hierarchy_depth_inter = sps->max_transform_hierarchy_depth_inter,
688 .init_qp_minus26 = pps->init_qp_minus26,
689 .diff_cu_qp_delta_depth = pps->diff_cu_qp_delta_depth,
690 .pps_cb_qp_offset = pps->cb_qp_offset,
691 .pps_cr_qp_offset = pps->cr_qp_offset,
692 .log2_parallel_merge_level_minus2 = pps->log2_parallel_merge_level_minus2,
693 .num_tile_columns_minus1 = pps->num_tile_columns_minus1,
694 .num_tile_rows_minus1 = pps->num_tile_rows_minus1,
695 .log2_max_pic_order_cnt_lsb_minus4 = sps->log2_max_pic_order_cnt_lsb_minus4,
696 .num_short_term_ref_pic_sets = sps->num_short_term_ref_pic_sets,
697 .num_long_term_ref_pic_sps = sps->num_long_term_ref_pics_sps,
698 .num_ref_idx_l0_default_active_minus1 = pps->num_ref_idx_l0_default_active_minus1,
699 .num_ref_idx_l1_default_active_minus1 = pps->num_ref_idx_l1_default_active_minus1,
700 .pps_beta_offset_div2 = pps->beta_offset_div2,
701 .pps_tc_offset_div2 = pps->tc_offset_div2,
702 .num_extra_slice_header_bits = pps->num_extra_slice_header_bits,
703 .st_rps_bits = slice->header.short_term_ref_pic_set_size, /* FIXME missing emulation bits removal */
705 .chroma_format_idc = sps->chroma_format_idc,
706 .separate_colour_plane_flag = sps->separate_colour_plane_flag,
707 .pcm_enabled_flag = sps->pcm_enabled_flag,
708 .scaling_list_enabled_flag = sps->scaling_list_enabled_flag,
709 .transform_skip_enabled_flag = pps->transform_skip_enabled_flag,
710 .amp_enabled_flag = sps->amp_enabled_flag,
711 .strong_intra_smoothing_enabled_flag = sps->strong_intra_smoothing_enabled_flag,
712 .sign_data_hiding_enabled_flag = pps->sign_data_hiding_enabled_flag,
713 .constrained_intra_pred_flag = pps->constrained_intra_pred_flag,
714 .cu_qp_delta_enabled_flag = pps->cu_qp_delta_enabled_flag,
715 .weighted_pred_flag = pps->weighted_pred_flag,
716 .weighted_bipred_flag = pps->weighted_bipred_flag,
717 .transquant_bypass_enabled_flag = pps->transquant_bypass_enabled_flag,
718 .tiles_enabled_flag = pps->tiles_enabled_flag,
719 .entropy_coding_sync_enabled_flag = pps->entropy_coding_sync_enabled_flag,
720 .pps_loop_filter_across_slices_enabled_flag = pps->loop_filter_across_slices_enabled_flag,
721 .loop_filter_across_tiles_enabled_flag = pps->loop_filter_across_tiles_enabled_flag,
722 .pcm_loop_filter_disabled_flag = sps->pcm_loop_filter_disabled_flag,
723 /* Not set by FFMPEG either */
724 .NoPicReorderingFlag = 0,
727 .slice_parsing_fields.bits = {
728 .lists_modification_present_flag = pps->lists_modification_present_flag,
729 .long_term_ref_pics_present_flag = sps->long_term_ref_pics_present_flag,
730 .sps_temporal_mvp_enabled_flag = sps->temporal_mvp_enabled_flag,
731 .cabac_init_present_flag = pps->cabac_init_present_flag,
732 .output_flag_present_flag = pps->output_flag_present_flag,
733 .dependent_slice_segments_enabled_flag = pps->dependent_slice_segments_enabled_flag,
734 .pps_slice_chroma_qp_offsets_present_flag = pps->slice_chroma_qp_offsets_present_flag,
735 .sample_adaptive_offset_enabled_flag = sps->sample_adaptive_offset_enabled_flag,
736 .deblocking_filter_override_enabled_flag = pps->deblocking_filter_override_enabled_flag,
737 .pps_disable_deblocking_filter_flag = pps->deblocking_filter_disabled_flag,
738 .slice_segment_header_extension_present_flag = pps->slice_segment_header_extension_present_flag,
739 .RapPicFlag = picture->RapPicFlag,
740 .IdrPicFlag = GST_H265_IS_NAL_TYPE_IDR (slice->nalu.type),
741 .IntraPicFlag = GST_H265_IS_NAL_TYPE_IRAP (slice->nalu.type),
746 if (_is_range_extension_profile (self->parent.profile)
747 || _is_screen_content_ext_profile (self->parent.profile)) {
748 _fill_picture_range_ext_parameter (self, sps, pps);
749 if (_is_screen_content_ext_profile (self->parent.profile))
750 _fill_screen_content_ext_parameter (self, sps, pps);
753 for (i = 0; i <= pps->num_tile_columns_minus1; i++)
754 pic_param->base.column_width_minus1[i] = pps->column_width_minus1[i];
756 for (i = 0; i <= pps->num_tile_rows_minus1; i++)
757 pic_param->base.row_height_minus1[i] = pps->row_height_minus1[i];
759 _fill_vaapi_pic (decoder, &pic_param->base.CurrPic, picture);
761 /* reference frames */
763 GArray *ref_list = gst_h265_dpb_get_pictures_all (dpb);
767 for (j = 0; j < 15 && j < ref_list->len; j++) {
768 GstH265Picture *pic = g_array_index (ref_list, GstH265Picture *, j);
771 _fill_vaapi_pic (decoder, &pic_param->base.ReferenceFrames[i], pic);
775 g_array_unref (ref_list);
777 /* 7.4.3.3.3, the current decoded picture is marked as "used for
778 long-term reference". Current picture is not in the DPB now. */
779 if (pps->pps_scc_extension_params.pps_curr_pic_ref_enabled_flag && i < 15) {
780 pic_param->base.ReferenceFrames[i].picture_id =
781 gst_va_decode_picture_get_surface (gst_h265_picture_get_user_data
783 pic_param->base.ReferenceFrames[i].pic_order_cnt = picture->pic_order_cnt;
784 pic_param->base.ReferenceFrames[i].flags |=
785 VA_PICTURE_HEVC_LONG_TERM_REFERENCE;
786 pic_param->base.ReferenceFrames[i].flags |=
787 _find_frame_rps_type (decoder, picture);
792 _init_vaapi_pic (&pic_param->base.ReferenceFrames[i]);
795 pic_param_size = _is_range_extension_profile (self->parent.profile)
796 || _is_screen_content_ext_profile (self->parent.profile) ?
797 sizeof (*pic_param) : sizeof (pic_param->base);
798 if (!gst_va_decoder_add_param_buffer (base->decoder, va_pic,
799 VAPictureParameterBufferType, pic_param, pic_param_size))
800 return GST_FLOW_ERROR;
802 if (pps->scaling_list_data_present_flag ||
803 (sps->scaling_list_enabled_flag
804 && !sps->scaling_list_data_present_flag)) {
805 scaling_list = &pps->scaling_list;
806 GST_DEBUG_OBJECT (decoder, "Passing scaling list from PPS");
807 } else if (sps->scaling_list_enabled_flag &&
808 sps->scaling_list_data_present_flag) {
809 scaling_list = &sps->scaling_list;
810 GST_DEBUG_OBJECT (decoder, "Passing scaling list from SPS");
814 for (i = 0; i < G_N_ELEMENTS (iq_matrix.ScalingList4x4); i++)
815 gst_h265_quant_matrix_4x4_get_raster_from_uprightdiagonal
816 (iq_matrix.ScalingList4x4[i], scaling_list->scaling_lists_4x4[i]);
818 for (i = 0; i < G_N_ELEMENTS (iq_matrix.ScalingList8x8); i++)
819 gst_h265_quant_matrix_8x8_get_raster_from_uprightdiagonal
820 (iq_matrix.ScalingList8x8[i], scaling_list->scaling_lists_8x8[i]);
822 for (i = 0; i < G_N_ELEMENTS (iq_matrix.ScalingList16x16); i++)
823 gst_h265_quant_matrix_16x16_get_raster_from_uprightdiagonal
824 (iq_matrix.ScalingList16x16[i], scaling_list->scaling_lists_16x16[i]);
826 for (i = 0; i < G_N_ELEMENTS (iq_matrix.ScalingList32x32); i++)
827 gst_h265_quant_matrix_32x32_get_raster_from_uprightdiagonal
828 (iq_matrix.ScalingList32x32[i], scaling_list->scaling_lists_32x32[i]);
830 for (i = 0; i < 6; i++)
831 iq_matrix.ScalingListDC16x16[i] =
832 scaling_list->scaling_list_dc_coef_minus8_16x16[i] + 8;
834 for (i = 0; i < 2; i++)
835 iq_matrix.ScalingListDC32x32[i] =
836 scaling_list->scaling_list_dc_coef_minus8_32x32[i] + 8;
838 if (!gst_va_decoder_add_param_buffer (base->decoder, va_pic,
839 VAIQMatrixBufferType, &iq_matrix, sizeof (iq_matrix))) {
840 return GST_FLOW_ERROR;
848 gst_va_h265_dec_new_picture (GstH265Decoder * decoder,
849 GstVideoCodecFrame * frame, GstH265Picture * picture)
851 GstVaBaseDec *base = GST_VA_BASE_DEC (decoder);
852 GstVaH265Dec *self = GST_VA_H265_DEC (decoder);
853 GstVaDecodePicture *pic;
854 GstBuffer *output_buffer;
855 GstVideoDecoder *vdec = GST_VIDEO_DECODER (decoder);
856 GstFlowReturn ret = GST_FLOW_ERROR;
858 if (base->need_negotiation) {
859 if (!gst_video_decoder_negotiate (vdec)) {
860 GST_ERROR_OBJECT (self, "Failed to negotiate with downstream");
861 return GST_FLOW_NOT_NEGOTIATED;
865 output_buffer = gst_video_decoder_allocate_output_buffer (vdec);
869 pic = gst_va_decode_picture_new (base->decoder, output_buffer);
870 gst_buffer_unref (output_buffer);
872 gst_h265_picture_set_user_data (picture, pic,
873 (GDestroyNotify) gst_va_decode_picture_free);
875 GST_LOG_OBJECT (self, "New va decode picture %p - %#x", pic,
876 gst_va_decode_picture_get_surface (pic));
882 GST_WARNING_OBJECT (self,
883 "Failed to allocated output buffer, return %s",
884 gst_flow_get_name (ret));
890 _get_rtformat (GstVaH265Dec * self, guint8 bit_depth_luma,
891 guint8 bit_depth_chroma, guint8 chroma_format_idc)
893 guint8 bit_num = MAX (bit_depth_luma, bit_depth_chroma);
898 if (chroma_format_idc == 3)
899 return VA_RT_FORMAT_YUV444_12;
900 if (chroma_format_idc == 2)
901 return VA_RT_FORMAT_YUV422_12;
903 return VA_RT_FORMAT_YUV420_12;
907 if (chroma_format_idc == 3)
908 return VA_RT_FORMAT_YUV444_10;
909 if (chroma_format_idc == 2)
910 return VA_RT_FORMAT_YUV422_10;
912 return VA_RT_FORMAT_YUV420_10;
915 if (chroma_format_idc == 3)
916 return VA_RT_FORMAT_YUV444;
917 if (chroma_format_idc == 2)
918 return VA_RT_FORMAT_YUV422;
920 return VA_RT_FORMAT_YUV420;
923 GST_ERROR_OBJECT (self, "Unsupported chroma format: %d "
924 "(with depth luma: %d, with depth chroma: %d)",
925 chroma_format_idc, bit_depth_luma, bit_depth_chroma);
933 GstH265Profile profile;
934 VAProfile va_profile;
936 #define P(idc, va) { G_PASTE (GST_H265_PROFILE_, idc), G_PASTE (VAProfileHEVC, va) }
939 /*P (MAIN_STILL_PICTURE, ),
942 P (MONOCHROME_16, ),*/
944 P (MAIN_422_10, Main422_10),
945 P (MAIN_422_12, Main422_12),
946 P (MAIN_444, Main444),
947 P (MAIN_444_10, Main444_10),
948 P (MAIN_444_12, Main444_12),
952 P (MAIN_422_10_INTRA, ),
953 P (MAIN_422_12_INTRA, ),
954 P (MAIN_444_INTRA, ),
955 P (MAIN_444_10_INTRA, ),
956 P (MAIN_444_12_INTRA, ),
957 P (MAIN_444_16_INTRA, ),
958 P (MAIN_444_STILL_PICTURE, ),
959 P (MAIN_444_16_STILL_PICTURE, ),
961 P (HIGH_THROUGHPUT_444, ),
962 P (HIGH_THROUGHPUT_444_10, ),
963 P (HIGH_THROUGHPUT_444_14, ),
964 P (HIGH_THROUGHPUT_444_16_INTRA, ),*/
965 P (SCREEN_EXTENDED_MAIN, SccMain),
966 P (SCREEN_EXTENDED_MAIN_10, SccMain10),
967 P (SCREEN_EXTENDED_MAIN_444, SccMain444),
968 #if VA_CHECK_VERSION(1, 8, 0)
969 P (SCREEN_EXTENDED_MAIN_444_10, SccMain444_10),
971 /*P (SCREEN_EXTENDED_HIGH_THROUGHPUT_444, ),
972 P (SCREEN_EXTENDED_HIGH_THROUGHPUT_444_10, ),
973 P (SCREEN_EXTENDED_HIGH_THROUGHPUT_444_14, ),
974 P (MULTIVIEW_MAIN, ),
976 P (SCALABLE_MAIN_10, ),
977 P (SCALABLE_MONOCHROME, ),
978 P (SCALABLE_MONOCHROME_12, ),
979 P (SCALABLE_MONOCHROME_16, ),
980 P (SCALABLE_MAIN_444, ),
987 _get_profile (GstVaH265Dec * self, const GstH265SPS * sps, gint max_dpb_size)
989 GstH265Decoder *h265_decoder = GST_H265_DECODER (self);
990 GstVaBaseDec *base = GST_VA_BASE_DEC (self);
991 GstH265Profile profile = gst_h265_get_profile_from_sps ((GstH265SPS *) sps);
992 VAProfile profiles[4];
995 /* 1. The profile directly specified by the SPS should always be the
996 first choice. It is the exact one.
997 2. The profile in the input caps may contain the compatible profile
998 chosen by the upstream element. Upstream element such as the parse
999 may already decide the best compatible profile for us. We also need
1000 to consider it as a choice. */
1002 for (j = 0; j < G_N_ELEMENTS (profile_map); j++) {
1003 if (profile_map[j].profile == profile) {
1004 profiles[i++] = profile_map[j].va_profile;
1009 if (h265_decoder->input_state->caps
1010 && gst_caps_is_fixed (h265_decoder->input_state->caps)) {
1011 GstH265Profile compatible_profile = GST_H265_PROFILE_INVALID;
1012 GstStructure *structure;
1013 const gchar *profile_str;
1015 structure = gst_caps_get_structure (h265_decoder->input_state->caps, 0);
1017 profile_str = gst_structure_get_string (structure, "profile");
1019 compatible_profile = gst_h265_profile_from_string (profile_str);
1021 if (compatible_profile != profile) {
1022 GST_INFO_OBJECT (self, "The upstream set the compatible profile %s, "
1023 "also consider it as a candidate.", profile_str);
1025 for (j = 0; j < G_N_ELEMENTS (profile_map); j++) {
1026 if (profile_map[j].profile == compatible_profile) {
1027 profiles[i++] = profile_map[j].va_profile;
1034 for (j = 0; j < i && j < G_N_ELEMENTS (profiles); j++) {
1035 if (gst_va_decoder_has_profile (base->decoder, profiles[j]))
1039 GST_ERROR_OBJECT (self, "Unsupported profile: %d", profile);
1041 return VAProfileNone;
1044 static GstFlowReturn
1045 gst_va_h265_dec_new_sequence (GstH265Decoder * decoder, const GstH265SPS * sps,
1048 GstVaBaseDec *base = GST_VA_BASE_DEC (decoder);
1049 GstVaH265Dec *self = GST_VA_H265_DEC (decoder);
1052 gint display_height;
1053 gint padding_left, padding_right, padding_top, padding_bottom;
1055 gboolean negotiation_needed = FALSE;
1057 if (self->dpb_size < max_dpb_size)
1058 self->dpb_size = max_dpb_size;
1060 if (sps->conformance_window_flag) {
1061 display_width = sps->crop_rect_width;
1062 display_height = sps->crop_rect_height;
1063 padding_left = sps->crop_rect_x;
1064 padding_right = sps->width - sps->crop_rect_x - display_width;
1065 padding_top = sps->crop_rect_y;
1066 padding_bottom = sps->height - sps->crop_rect_y - display_height;
1068 display_width = sps->width;
1069 display_height = sps->height;
1070 padding_left = padding_right = padding_top = padding_bottom = 0;
1073 profile = _get_profile (self, sps, max_dpb_size);
1074 if (profile == VAProfileNone)
1075 return GST_FLOW_NOT_NEGOTIATED;
1077 rt_format = _get_rtformat (self, sps->bit_depth_luma_minus8 + 8,
1078 sps->bit_depth_chroma_minus8 + 8, sps->chroma_format_idc);
1080 return GST_FLOW_NOT_NEGOTIATED;
1082 if (!gst_va_decoder_config_is_equal (base->decoder, profile,
1083 rt_format, sps->width, sps->height)) {
1084 base->profile = profile;
1085 base->rt_format = rt_format;
1086 self->coded_width = sps->width;
1087 self->coded_height = sps->height;
1089 negotiation_needed = TRUE;
1090 GST_INFO_OBJECT (self, "Format changed to %s [%x] (%dx%d)",
1091 gst_va_profile_name (profile), rt_format, self->coded_width,
1092 self->coded_height);
1095 if (base->width != display_width || base->height != display_height) {
1096 base->width = display_width;
1097 base->height = display_height;
1099 negotiation_needed = TRUE;
1100 GST_INFO_OBJECT (self, "Resolution changed to %dx%d", base->width,
1104 base->need_valign = base->width < self->coded_width
1105 || base->height < self->coded_height;
1106 if (base->need_valign) {
1108 if (base->valign.padding_left != padding_left ||
1109 base->valign.padding_right != padding_right ||
1110 base->valign.padding_top != padding_top ||
1111 base->valign.padding_bottom != padding_bottom) {
1112 negotiation_needed = TRUE;
1113 GST_INFO_OBJECT (self, "crop rect changed to (%d,%d)-->(%d,%d)",
1114 padding_left, padding_top, padding_right, padding_bottom);
1116 base->valign = (GstVideoAlignment) {
1117 .padding_left = padding_left,
1118 .padding_right = padding_right,
1119 .padding_top = padding_top,
1120 .padding_bottom = padding_bottom,
1125 base->min_buffers = self->dpb_size + 4; /* dpb size + scratch surfaces */
1127 base->need_negotiation = negotiation_needed;
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_negotiate (GstVideoDecoder * decoder)
1202 GstVaBaseDec *base = GST_VA_BASE_DEC (decoder);
1203 GstVaH265Dec *self = GST_VA_H265_DEC (decoder);
1204 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
1205 GstCapsFeatures *capsfeatures = NULL;
1206 GstH265Decoder *h265dec = GST_H265_DECODER (decoder);
1208 /* Ignore downstream renegotiation request. */
1209 if (!base->need_negotiation)
1212 base->need_negotiation = FALSE;
1214 if (gst_va_decoder_is_open (base->decoder)
1215 && !gst_va_decoder_close (base->decoder))
1218 if (!gst_va_decoder_open (base->decoder, base->profile, base->rt_format))
1221 if (!gst_va_decoder_set_frame_size (base->decoder, self->coded_width,
1222 self->coded_height))
1225 if (base->output_state)
1226 gst_video_codec_state_unref (base->output_state);
1228 gst_va_base_dec_get_preferred_format_and_caps_features (base, &format,
1230 if (format == GST_VIDEO_FORMAT_UNKNOWN)
1233 base->output_state =
1234 gst_video_decoder_set_output_state (decoder, format,
1235 base->width, base->height, h265dec->input_state);
1237 base->output_state->caps = gst_video_info_to_caps (&base->output_state->info);
1239 gst_caps_set_features_simple (base->output_state->caps, capsfeatures);
1241 GST_INFO_OBJECT (self, "Negotiated caps %" GST_PTR_FORMAT,
1242 base->output_state->caps);
1244 return GST_VIDEO_DECODER_CLASS (parent_class)->negotiate (decoder);
1248 gst_va_h265_dec_dispose (GObject * object)
1250 g_free (GST_VA_H265_DEC (object)->prev_slice.data);
1252 gst_va_base_dec_close (GST_VIDEO_DECODER (object));
1254 G_OBJECT_CLASS (parent_class)->dispose (object);
1258 gst_va_h265_dec_class_init (gpointer g_class, gpointer class_data)
1260 GstCaps *src_doc_caps, *sink_doc_caps;
1261 GObjectClass *gobject_class = G_OBJECT_CLASS (g_class);
1262 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
1263 GstH265DecoderClass *h265decoder_class = GST_H265_DECODER_CLASS (g_class);
1264 GstVideoDecoderClass *decoder_class = GST_VIDEO_DECODER_CLASS (g_class);
1265 struct CData *cdata = class_data;
1268 if (cdata->description) {
1269 long_name = g_strdup_printf ("VA-API H.265 Decoder in %s",
1270 cdata->description);
1272 long_name = g_strdup ("VA-API H.265 Decoder");
1275 gst_element_class_set_metadata (element_class, long_name,
1276 "Codec/Decoder/Video/Hardware",
1277 "VA-API based H.265 video decoder",
1278 "Nicolas Dufresne <nicolas.dufresne@collabora.com>");
1280 sink_doc_caps = gst_caps_from_string (sink_caps_str);
1281 src_doc_caps = gst_caps_from_string (src_caps_str);
1283 parent_class = g_type_class_peek_parent (g_class);
1286 * GstVaH265Dec:device-path:
1288 * It shows the DRM device path used for the VA operation, if any.
1292 gst_va_base_dec_class_init (GST_VA_BASE_DEC_CLASS (g_class), HEVC,
1293 cdata->render_device_path, cdata->sink_caps, cdata->src_caps,
1294 src_doc_caps, sink_doc_caps);
1296 gobject_class->dispose = gst_va_h265_dec_dispose;
1298 decoder_class->getcaps = GST_DEBUG_FUNCPTR (gst_va_h265_dec_getcaps);
1299 decoder_class->negotiate = GST_DEBUG_FUNCPTR (gst_va_h265_dec_negotiate);
1301 h265decoder_class->new_sequence =
1302 GST_DEBUG_FUNCPTR (gst_va_h265_dec_new_sequence);
1303 h265decoder_class->decode_slice =
1304 GST_DEBUG_FUNCPTR (gst_va_h265_dec_decode_slice);
1306 h265decoder_class->new_picture =
1307 GST_DEBUG_FUNCPTR (gst_va_h265_dec_new_picture);
1308 h265decoder_class->output_picture =
1309 GST_DEBUG_FUNCPTR (gst_va_h265_dec_output_picture);
1310 h265decoder_class->start_picture =
1311 GST_DEBUG_FUNCPTR (gst_va_h265_dec_start_picture);
1312 h265decoder_class->end_picture =
1313 GST_DEBUG_FUNCPTR (gst_va_h265_dec_end_picture);
1316 g_free (cdata->description);
1317 g_free (cdata->render_device_path);
1318 gst_caps_unref (cdata->src_caps);
1319 gst_caps_unref (cdata->sink_caps);
1324 gst_va_h265_dec_init (GTypeInstance * instance, gpointer g_class)
1326 gst_va_base_dec_init (GST_VA_BASE_DEC (instance), GST_CAT_DEFAULT);
1327 gst_h265_decoder_set_process_ref_pic_lists (GST_H265_DECODER (instance),
1332 _register_debug_category (gpointer data)
1334 GST_DEBUG_CATEGORY_INIT (gst_va_h265dec_debug, "vah265dec", 0,
1341 gst_va_h265_dec_register (GstPlugin * plugin, GstVaDevice * device,
1342 GstCaps * sink_caps, GstCaps * src_caps, guint rank)
1344 static GOnce debug_once = G_ONCE_INIT;
1346 GTypeInfo type_info = {
1347 .class_size = sizeof (GstVaH265DecClass),
1348 .class_init = gst_va_h265_dec_class_init,
1349 .instance_size = sizeof (GstVaH265Dec),
1350 .instance_init = gst_va_h265_dec_init,
1352 struct CData *cdata;
1354 gchar *type_name, *feature_name;
1356 g_return_val_if_fail (GST_IS_PLUGIN (plugin), FALSE);
1357 g_return_val_if_fail (GST_IS_VA_DEVICE (device), FALSE);
1358 g_return_val_if_fail (GST_IS_CAPS (sink_caps), FALSE);
1359 g_return_val_if_fail (GST_IS_CAPS (src_caps), FALSE);
1361 cdata = g_new (struct CData, 1);
1362 cdata->description = NULL;
1363 cdata->render_device_path = g_strdup (device->render_device_path);
1364 cdata->sink_caps = _complete_sink_caps (sink_caps);
1365 cdata->src_caps = gst_caps_ref (src_caps);
1367 /* class data will be leaked if the element never gets instantiated */
1368 GST_MINI_OBJECT_FLAG_SET (cdata->sink_caps,
1369 GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
1370 GST_MINI_OBJECT_FLAG_SET (src_caps, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
1372 type_info.class_data = cdata;
1374 /* The first decoder to be registered should use a constant name,
1375 * like vah265dec, for any additional decoders, we create unique
1376 * names, using inserting the render device name. */
1377 if (device->index == 0) {
1378 type_name = g_strdup ("GstVaH265Dec");
1379 feature_name = g_strdup ("vah265dec");
1381 gchar *basename = g_path_get_basename (device->render_device_path);
1382 type_name = g_strdup_printf ("GstVa%sH265Dec", basename);
1383 feature_name = g_strdup_printf ("va%sh265dec", basename);
1384 cdata->description = basename;
1386 /* lower rank for non-first device */
1391 g_once (&debug_once, _register_debug_category, NULL);
1393 type = g_type_register_static (GST_TYPE_H265_DECODER,
1394 type_name, &type_info, 0);
1396 ret = gst_element_register (plugin, feature_name, rank, type);
1399 g_free (feature_name);