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;
91 GstFlowReturn last_ret;
97 VAPictureParameterBufferHEVCExtension pic_param;
99 gint32 WpOffsetHalfRangeC;
101 struct slice prev_slice;
103 gboolean need_negotiation;
107 static const gchar *src_caps_str =
108 GST_VIDEO_CAPS_MAKE_WITH_FEATURES (GST_CAPS_FEATURE_MEMORY_VA,
109 "{ NV12, P010_10LE }") " ;"
110 GST_VIDEO_CAPS_MAKE ("{ NV12, P010_10LE }");
113 static const gchar *sink_caps_str = "video/x-h265";
116 _is_range_extension_profile (VAProfile profile)
118 if (profile == VAProfileHEVCMain422_10
119 || profile == VAProfileHEVCMain444
120 || profile == VAProfileHEVCMain444_10
121 || profile == VAProfileHEVCMain12
122 || profile == VAProfileHEVCMain444_12
123 || profile == VAProfileHEVCMain422_12)
129 _is_screen_content_ext_profile (VAProfile profile)
131 if (profile == VAProfileHEVCSccMain
132 || profile == VAProfileHEVCSccMain10
133 || profile == VAProfileHEVCSccMain444)
140 _set_last_slice_flag (GstVaH265Dec * self)
142 self->prev_slice.param.base.LongSliceFlags.fields.LastSliceOfPic = 1;
146 _replace_previous_slice (GstVaH265Dec * self, guint8 * data, guint size)
148 struct slice *slice = &self->prev_slice;
149 gboolean do_reset = (slice->size < size);
151 if (!data || do_reset) {
152 g_clear_pointer (&slice->data, g_free);
160 GST_LOG_OBJECT (self, "allocating slice data %u", size);
161 slice->data = g_malloc (size);
164 memcpy (slice->data, data, size);
169 _submit_previous_slice (GstVaBaseDec * base, GstVaDecodePicture * va_pic)
171 GstVaH265Dec *self = GST_VA_H265_DEC (base);
176 slice = &self->prev_slice;
177 if (!slice->data && slice->size == 0)
179 if (!slice->data || slice->size == 0)
182 param_size = _is_range_extension_profile (self->parent.profile)
183 || _is_screen_content_ext_profile (self->parent.profile) ?
184 sizeof (slice->param) : sizeof (slice->param.base);
185 ret = gst_va_decoder_add_slice_buffer (base->decoder, va_pic, &slice->param,
186 param_size, slice->data, slice->size);
192 gst_va_h265_dec_end_picture (GstH265Decoder * decoder, GstH265Picture * picture)
194 GstVaBaseDec *base = GST_VA_BASE_DEC (decoder);
195 GstVaH265Dec *self = GST_VA_H265_DEC (decoder);
196 GstVaDecodePicture *va_pic;
199 GST_LOG_OBJECT (base, "end picture %p, (poc %d)",
200 picture, picture->pic_order_cnt);
202 va_pic = gst_h265_picture_get_user_data (picture);
204 _set_last_slice_flag (self);
205 ret = _submit_previous_slice (base, va_pic);
207 /* TODO(victor): optimization: this could be done at decoder's
209 _replace_previous_slice (self, NULL, 0);
212 GST_ERROR_OBJECT (self, "Failed to submit the previous slice");
216 ret = gst_va_decoder_decode (base->decoder, va_pic);
218 GST_ERROR_OBJECT (self, "Failed at end picture %p, (poc %d)",
219 picture, picture->pic_order_cnt);
227 gst_va_h265_dec_output_picture (GstH265Decoder * decoder,
228 GstVideoCodecFrame * frame, GstH265Picture * picture)
230 GstVaBaseDec *base = GST_VA_BASE_DEC (decoder);
231 GstVaH265Dec *self = GST_VA_H265_DEC (decoder);
232 GstVaDecodePicture *va_pic;
234 va_pic = gst_h265_picture_get_user_data (picture);
235 g_assert (va_pic->gstbuffer);
237 GST_LOG_OBJECT (self,
238 "Outputting picture %p (poc %d)", picture, picture->pic_order_cnt);
240 if (self->last_ret != GST_FLOW_OK) {
241 gst_h265_picture_unref (picture);
242 _replace_previous_slice (self, NULL, 0);
243 gst_video_decoder_drop_frame (GST_VIDEO_DECODER (self), frame);
244 return self->last_ret;
247 gst_buffer_replace (&frame->output_buffer, va_pic->gstbuffer);
249 if (base->copy_frames)
250 gst_va_base_dec_copy_output_buffer (base, frame);
252 gst_h265_picture_unref (picture);
254 return gst_video_decoder_finish_frame (GST_VIDEO_DECODER (self), frame);
258 _init_vaapi_pic (VAPictureHEVC * va_picture)
260 va_picture->picture_id = VA_INVALID_ID;
261 va_picture->flags = VA_PICTURE_HEVC_INVALID;
262 va_picture->pic_order_cnt = 0;
266 _find_frame_rps_type (GstH265Decoder * decoder, GstH265Picture * ref_pic)
270 for (i = 0; i < G_N_ELEMENTS (decoder->RefPicSetStCurrBefore); i++) {
271 if (ref_pic == decoder->RefPicSetStCurrBefore[i])
272 return VA_PICTURE_HEVC_RPS_ST_CURR_BEFORE;
275 for (i = 0; i < G_N_ELEMENTS (decoder->RefPicSetStCurrAfter); i++) {
276 if (ref_pic == decoder->RefPicSetStCurrAfter[i])
277 return VA_PICTURE_HEVC_RPS_ST_CURR_AFTER;
280 for (i = 0; i < G_N_ELEMENTS (decoder->RefPicSetLtCurr); i++) {
281 if (ref_pic == decoder->RefPicSetLtCurr[i])
282 return VA_PICTURE_HEVC_RPS_LT_CURR;
290 _fill_vaapi_pic (GstH265Decoder * decoder, VAPictureHEVC * va_picture,
291 GstH265Picture * picture)
293 GstVaDecodePicture *va_pic;
295 va_pic = gst_h265_picture_get_user_data (picture);
298 _init_vaapi_pic (va_picture);
302 va_picture->picture_id = gst_va_decode_picture_get_surface (va_pic);
303 va_picture->pic_order_cnt = picture->pic_order_cnt;
304 va_picture->flags = 0;
306 if (picture->ref && picture->long_term)
307 va_picture->flags |= VA_PICTURE_HEVC_LONG_TERM_REFERENCE;
309 va_picture->flags |= _find_frame_rps_type (decoder, picture);
313 _get_reference_index (GstH265Decoder * decoder, GstH265Picture * picture)
315 GstVaH265Dec *self = GST_VA_H265_DEC (decoder);
318 for (i = 0; i < 15; i++) {
319 VAPictureHEVC *ref_va_pic = &self->pic_param.base.ReferenceFrames[i];
321 if (ref_va_pic->picture_id == VA_INVALID_ID)
324 if (ref_va_pic->pic_order_cnt == picture->pic_order_cnt)
331 /* fill the VA API reference picture lists from the GstCodec reference
334 _fill_ref_pic_list (GstH265Decoder * decoder, GstH265Picture * cur_pic,
335 guint8 va_reflist[15], GArray * reflist)
339 for (i = 0; i < reflist->len && i < 15; i++) {
340 GstH265Picture *picture = g_array_index (reflist, GstH265Picture *, i);
341 va_reflist[i] = _get_reference_index (decoder, picture);
345 va_reflist[i] = 0xFF;
349 _fill_pred_weight_table (GstVaH265Dec * self, GstH265SliceHdr * header,
350 VASliceParameterBufferHEVCExtension * slice_param)
352 gint chroma_weight, chroma_log2_weight_denom;
354 GstH265PPS *pps = header->pps;
355 gboolean is_rext = _is_range_extension_profile (self->parent.profile);
357 if (GST_H265_IS_I_SLICE (header) ||
358 (!pps->weighted_pred_flag && GST_H265_IS_P_SLICE (header)) ||
359 (!pps->weighted_bipred_flag && GST_H265_IS_B_SLICE (header)))
362 slice_param->base.luma_log2_weight_denom =
363 header->pred_weight_table.luma_log2_weight_denom;
365 if (pps->sps->chroma_array_type != 0)
366 slice_param->base.delta_chroma_log2_weight_denom =
367 header->pred_weight_table.delta_chroma_log2_weight_denom;
369 for (i = 0; i <= header->num_ref_idx_l0_active_minus1; i++) {
370 if (!header->pred_weight_table.luma_weight_l0_flag[i])
373 slice_param->base.delta_luma_weight_l0[i] =
374 header->pred_weight_table.delta_luma_weight_l0[i];
375 slice_param->base.luma_offset_l0[i] =
376 header->pred_weight_table.luma_offset_l0[i];
379 slice_param->rext.luma_offset_l0[i] =
380 header->pred_weight_table.luma_offset_l0[i];
384 chroma_log2_weight_denom = slice_param->base.luma_log2_weight_denom +
385 slice_param->base.delta_chroma_log2_weight_denom;
387 for (i = 0; i <= header->num_ref_idx_l0_active_minus1; i++) {
388 if (!header->pred_weight_table.chroma_weight_l0_flag[i])
391 for (j = 0; j < 2; j++) {
392 gint16 delta_chroma_offset_l0 =
393 header->pred_weight_table.delta_chroma_offset_l0[i][j];
396 slice_param->base.delta_chroma_weight_l0[i][j] =
397 header->pred_weight_table.delta_chroma_weight_l0[i][j];
399 /* Find ChromaWeightL0 */
400 chroma_weight = (1 << chroma_log2_weight_denom) +
401 header->pred_weight_table.delta_chroma_weight_l0[i][j];
402 chroma_offset = self->WpOffsetHalfRangeC + delta_chroma_offset_l0
403 - ((self->WpOffsetHalfRangeC * chroma_weight)
404 >> chroma_log2_weight_denom);
407 slice_param->base.ChromaOffsetL0[i][j] = CLAMP (chroma_offset,
408 -self->WpOffsetHalfRangeC, self->WpOffsetHalfRangeC - 1);
411 slice_param->rext.ChromaOffsetL0[i][j] =
412 slice_param->base.ChromaOffsetL0[i][j];
417 /* Skip l1 if this is not a B-Frame. */
418 if (!GST_H265_IS_B_SLICE (header))
421 for (i = 0; i <= header->num_ref_idx_l1_active_minus1; i++) {
422 if (!header->pred_weight_table.luma_weight_l1_flag[i])
425 slice_param->base.delta_luma_weight_l1[i] =
426 header->pred_weight_table.delta_luma_weight_l1[i];
427 slice_param->base.luma_offset_l1[i] =
428 header->pred_weight_table.luma_offset_l1[i];
431 slice_param->rext.luma_offset_l1[i] =
432 header->pred_weight_table.luma_offset_l1[i];
436 for (i = 0; i <= header->num_ref_idx_l1_active_minus1; i++) {
437 if (!header->pred_weight_table.chroma_weight_l1_flag[i])
440 for (j = 0; j < 2; j++) {
441 gint16 delta_chroma_offset_l1 =
442 header->pred_weight_table.delta_chroma_offset_l1[i][j];
445 slice_param->base.delta_chroma_weight_l1[i][j] =
446 header->pred_weight_table.delta_chroma_weight_l1[i][j];
448 /* Find ChromaWeightL1 */
449 chroma_weight = (1 << chroma_log2_weight_denom) +
450 header->pred_weight_table.delta_chroma_weight_l1[i][j];
452 chroma_offset = self->WpOffsetHalfRangeC + delta_chroma_offset_l1
453 - ((self->WpOffsetHalfRangeC * chroma_weight)
454 >> chroma_log2_weight_denom);
457 slice_param->base.ChromaOffsetL1[i][j] = CLAMP (chroma_offset,
458 -self->WpOffsetHalfRangeC, self->WpOffsetHalfRangeC - 1);
461 slice_param->rext.ChromaOffsetL1[i][j] =
462 slice_param->base.ChromaOffsetL1[i][j];
469 _get_slice_data_byte_offset (GstH265SliceHdr * slice_hdr,
470 guint nal_header_bytes)
474 epb_count = slice_hdr->n_emulation_prevention_bytes;
475 return nal_header_bytes + (slice_hdr->header_size + 7) / 8 - epb_count;
479 gst_va_h265_dec_decode_slice (GstH265Decoder * decoder,
480 GstH265Picture * picture, GstH265Slice * slice, GArray * ref_pic_list0,
481 GArray * ref_pic_list1)
483 GstH265SliceHdr *header = &slice->header;
484 GstH265NalUnit *nalu = &slice->nalu;
485 GstVaBaseDec *base = GST_VA_BASE_DEC (decoder);
486 GstVaH265Dec *self = GST_VA_H265_DEC (decoder);
487 GstVaDecodePicture *va_pic;
488 VASliceParameterBufferHEVCExtension *slice_param;
490 va_pic = gst_h265_picture_get_user_data (picture);
491 if (!_submit_previous_slice (base, va_pic)) {
492 _replace_previous_slice (self, NULL, 0);
493 GST_ERROR_OBJECT (base, "Failed to submit previous slice buffers");
497 slice_param = &self->prev_slice.param;
500 slice_param->base = (VASliceParameterBufferHEVC) {
501 .slice_data_size = nalu->size,
502 .slice_data_offset = 0,
503 .slice_data_flag = VA_SLICE_DATA_FLAG_ALL,
504 .slice_data_byte_offset = _get_slice_data_byte_offset (header, nalu->header_bytes),
505 .slice_segment_address = header->segment_address,
506 .collocated_ref_idx = header->temporal_mvp_enabled_flag ? header->collocated_ref_idx : 0xFF,
507 .num_ref_idx_l0_active_minus1 = header->num_ref_idx_l0_active_minus1,
508 .num_ref_idx_l1_active_minus1 = header->num_ref_idx_l1_active_minus1,
509 .slice_qp_delta = header->qp_delta,
510 .slice_cb_qp_offset = header->cb_qp_offset,
511 .slice_cr_qp_offset = header->cr_qp_offset,
512 .slice_beta_offset_div2 = header->beta_offset_div2,
513 .slice_tc_offset_div2 = header->tc_offset_div2,
514 .five_minus_max_num_merge_cand = header->five_minus_max_num_merge_cand,
515 .num_entry_point_offsets = header->num_entry_point_offsets,
516 .entry_offset_to_subset_array = 0, /* does not exist in spec */
517 .slice_data_num_emu_prevn_bytes = header->n_emulation_prevention_bytes,
518 .LongSliceFlags.fields = {
519 .LastSliceOfPic = 0, /* the last one will be set on end_picture() */
520 .dependent_slice_segment_flag = header->dependent_slice_segment_flag,
521 .slice_type = header->type,
522 .color_plane_id = header->colour_plane_id,
523 .slice_sao_luma_flag = header->sao_luma_flag,
524 .slice_sao_chroma_flag = header->sao_chroma_flag,
525 .mvd_l1_zero_flag = header->mvd_l1_zero_flag,
526 .cabac_init_flag = header->cabac_init_flag,
527 .slice_temporal_mvp_enabled_flag = header->temporal_mvp_enabled_flag,
528 .slice_deblocking_filter_disabled_flag =
529 header->deblocking_filter_disabled_flag,
530 .collocated_from_l0_flag = header->collocated_from_l0_flag,
531 .slice_loop_filter_across_slices_enabled_flag =
532 header->loop_filter_across_slices_enabled_flag,
537 if (_is_range_extension_profile (base->profile)
538 || _is_screen_content_ext_profile (base->profile)) {
540 slice_param->rext = (VASliceParameterBufferHEVCRext) {
541 .slice_ext_flags.bits = {
542 .cu_chroma_qp_offset_enabled_flag = header->cu_chroma_qp_offset_enabled_flag,
543 .use_integer_mv_flag = header->use_integer_mv_flag,
545 .slice_act_y_qp_offset = header->slice_act_y_qp_offset,
546 .slice_act_cb_qp_offset = header->slice_act_cb_qp_offset,
547 .slice_act_cr_qp_offset = header->slice_act_cr_qp_offset,
552 _fill_ref_pic_list (decoder, picture, slice_param->base.RefPicList[0],
554 _fill_ref_pic_list (decoder, picture, slice_param->base.RefPicList[1],
557 _fill_pred_weight_table (GST_VA_H265_DEC (decoder), header, slice_param);
559 _replace_previous_slice (self, slice->nalu.data + slice->nalu.offset,
566 _fill_picture_range_ext_parameter (GstVaH265Dec * decoder,
567 GstH265SPS * sps, GstH265PPS * pps)
569 VAPictureParameterBufferHEVCRext *pic_param = &decoder->pic_param.rext;
571 GstH265SPSExtensionParams *sps_ext = &sps->sps_extnsion_params;
572 GstH265PPSExtensionParams *pps_ext = &pps->pps_extension_params;
575 *pic_param = (VAPictureParameterBufferHEVCRext) {
576 .range_extension_pic_fields.bits = {
577 .transform_skip_rotation_enabled_flag = sps_ext->transform_skip_rotation_enabled_flag,
578 .transform_skip_context_enabled_flag = sps_ext->transform_skip_context_enabled_flag,
579 .implicit_rdpcm_enabled_flag = sps_ext->implicit_rdpcm_enabled_flag,
580 .explicit_rdpcm_enabled_flag = sps_ext->explicit_rdpcm_enabled_flag,
581 .extended_precision_processing_flag = sps_ext->extended_precision_processing_flag,
582 .intra_smoothing_disabled_flag = sps_ext->intra_smoothing_disabled_flag,
583 .high_precision_offsets_enabled_flag = sps_ext->high_precision_offsets_enabled_flag,
584 .persistent_rice_adaptation_enabled_flag = sps_ext->persistent_rice_adaptation_enabled_flag,
585 .cabac_bypass_alignment_enabled_flag = sps_ext->cabac_bypass_alignment_enabled_flag,
586 .cross_component_prediction_enabled_flag = pps_ext->cross_component_prediction_enabled_flag,
587 .chroma_qp_offset_list_enabled_flag = pps_ext->chroma_qp_offset_list_enabled_flag,
589 .diff_cu_chroma_qp_offset_depth = pps_ext->diff_cu_chroma_qp_offset_depth,
590 .chroma_qp_offset_list_len_minus1 = pps_ext->chroma_qp_offset_list_len_minus1,
591 .log2_sao_offset_scale_luma = pps_ext->log2_sao_offset_scale_luma,
592 .log2_sao_offset_scale_chroma = pps_ext->log2_sao_offset_scale_chroma,
593 .log2_max_transform_skip_block_size_minus2 = pps_ext->log2_max_transform_skip_block_size_minus2,
597 memcpy (pic_param->cb_qp_offset_list, pps_ext->cb_qp_offset_list,
598 sizeof (pic_param->cb_qp_offset_list));
599 memcpy (pic_param->cr_qp_offset_list, pps_ext->cr_qp_offset_list,
600 sizeof (pic_param->cr_qp_offset_list));
604 _fill_screen_content_ext_parameter (GstVaH265Dec * decoder,
605 GstH265SPS * sps, GstH265PPS * pps)
607 VAPictureParameterBufferHEVCScc *pic_param = &decoder->pic_param.scc;
608 const GstH265PPSSccExtensionParams *pps_scc = &pps->pps_scc_extension_params;
609 const GstH265SPSSccExtensionParams *sps_scc = &sps->sps_scc_extension_params;
614 *pic_param = (VAPictureParameterBufferHEVCScc) {
615 .screen_content_pic_fields.bits = {
616 .pps_curr_pic_ref_enabled_flag = pps_scc->pps_curr_pic_ref_enabled_flag,
617 .palette_mode_enabled_flag = sps_scc->palette_mode_enabled_flag,
618 .motion_vector_resolution_control_idc = sps_scc->motion_vector_resolution_control_idc,
619 .intra_boundary_filtering_disabled_flag = sps_scc->intra_boundary_filtering_disabled_flag,
620 .residual_adaptive_colour_transform_enabled_flag = pps_scc->residual_adaptive_colour_transform_enabled_flag,
621 .pps_slice_act_qp_offsets_present_flag = pps_scc->pps_slice_act_qp_offsets_present_flag,
623 .palette_max_size = sps_scc->palette_max_size,
624 .delta_palette_max_predictor_size = sps_scc->delta_palette_max_predictor_size,
625 .pps_act_y_qp_offset_plus5 = pps_scc->pps_act_y_qp_offset_plus5,
626 .pps_act_cb_qp_offset_plus5 = pps_scc->pps_act_cb_qp_offset_plus5,
627 .pps_act_cr_qp_offset_plus3 = pps_scc->pps_act_cr_qp_offset_plus3,
631 /* firstly use the pps, then sps */
632 num_comps = sps->chroma_format_idc ? 3 : 1;
634 if (pps_scc->pps_palette_predictor_initializers_present_flag) {
635 pic_param->predictor_palette_size =
636 pps_scc->pps_num_palette_predictor_initializer;
637 for (n = 0; n < num_comps; n++)
638 for (i = 0; i < pps_scc->pps_num_palette_predictor_initializer; i++)
639 pic_param->predictor_palette_entries[n][i] =
640 (uint16_t) pps_scc->pps_palette_predictor_initializer[n][i];
641 } else if (sps_scc->sps_palette_predictor_initializers_present_flag) {
642 pic_param->predictor_palette_size =
643 sps_scc->sps_num_palette_predictor_initializer_minus1 + 1;
644 for (n = 0; n < num_comps; n++)
646 i < sps_scc->sps_num_palette_predictor_initializer_minus1 + 1; i++)
647 pic_param->predictor_palette_entries[n][i] =
648 (uint16_t) sps_scc->sps_palette_predictor_initializer[n][i];
653 gst_va_h265_dec_start_picture (GstH265Decoder * decoder,
654 GstH265Picture * picture, GstH265Slice * slice, GstH265Dpb * dpb)
658 GstVaH265Dec *self = GST_VA_H265_DEC (decoder);
659 GstVaBaseDec *base = &self->parent;
660 GstVaDecodePicture *va_pic;
661 GstH265ScalingList *scaling_list = NULL;
662 VAIQMatrixBufferHEVC iq_matrix = { 0, };
663 VAPictureParameterBufferHEVCExtension *pic_param = &self->pic_param;
664 gsize pic_param_size;
667 va_pic = gst_h265_picture_get_user_data (picture);
669 pps = slice->header.pps;
673 pic_param->base = (VAPictureParameterBufferHEVC) {
674 .pic_width_in_luma_samples = sps->pic_width_in_luma_samples,
675 .pic_height_in_luma_samples = sps->pic_height_in_luma_samples,
676 .sps_max_dec_pic_buffering_minus1 = sps->max_dec_pic_buffering_minus1[sps->max_sub_layers_minus1],
677 .bit_depth_luma_minus8 = sps->bit_depth_luma_minus8,
678 .bit_depth_chroma_minus8 = sps->bit_depth_chroma_minus8,
679 .pcm_sample_bit_depth_luma_minus1 = sps->pcm_sample_bit_depth_luma_minus1,
680 .pcm_sample_bit_depth_chroma_minus1 = sps->pcm_sample_bit_depth_chroma_minus1,
681 .log2_min_luma_coding_block_size_minus3 = sps->log2_min_luma_coding_block_size_minus3,
682 .log2_diff_max_min_luma_coding_block_size = sps->log2_diff_max_min_luma_coding_block_size,
683 .log2_min_transform_block_size_minus2 = sps->log2_min_transform_block_size_minus2,
684 .log2_diff_max_min_transform_block_size = sps->log2_diff_max_min_transform_block_size,
685 .log2_min_pcm_luma_coding_block_size_minus3 = sps->log2_min_pcm_luma_coding_block_size_minus3,
686 .log2_diff_max_min_pcm_luma_coding_block_size = sps->log2_diff_max_min_pcm_luma_coding_block_size,
687 .max_transform_hierarchy_depth_intra = sps->max_transform_hierarchy_depth_intra,
688 .max_transform_hierarchy_depth_inter = sps->max_transform_hierarchy_depth_inter,
689 .init_qp_minus26 = pps->init_qp_minus26,
690 .diff_cu_qp_delta_depth = pps->diff_cu_qp_delta_depth,
691 .pps_cb_qp_offset = pps->cb_qp_offset,
692 .pps_cr_qp_offset = pps->cr_qp_offset,
693 .log2_parallel_merge_level_minus2 = pps->log2_parallel_merge_level_minus2,
694 .num_tile_columns_minus1 = pps->num_tile_columns_minus1,
695 .num_tile_rows_minus1 = pps->num_tile_rows_minus1,
696 .log2_max_pic_order_cnt_lsb_minus4 = sps->log2_max_pic_order_cnt_lsb_minus4,
697 .num_short_term_ref_pic_sets = sps->num_short_term_ref_pic_sets,
698 .num_long_term_ref_pic_sps = sps->num_long_term_ref_pics_sps,
699 .num_ref_idx_l0_default_active_minus1 = pps->num_ref_idx_l0_default_active_minus1,
700 .num_ref_idx_l1_default_active_minus1 = pps->num_ref_idx_l1_default_active_minus1,
701 .pps_beta_offset_div2 = pps->beta_offset_div2,
702 .pps_tc_offset_div2 = pps->tc_offset_div2,
703 .num_extra_slice_header_bits = pps->num_extra_slice_header_bits,
704 .st_rps_bits = slice->header.short_term_ref_pic_set_size, /* FIXME missing emulation bits removal */
706 .chroma_format_idc = sps->chroma_format_idc,
707 .separate_colour_plane_flag = sps->separate_colour_plane_flag,
708 .pcm_enabled_flag = sps->pcm_enabled_flag,
709 .scaling_list_enabled_flag = sps->scaling_list_enabled_flag,
710 .transform_skip_enabled_flag = pps->transform_skip_enabled_flag,
711 .amp_enabled_flag = sps->amp_enabled_flag,
712 .strong_intra_smoothing_enabled_flag = sps->strong_intra_smoothing_enabled_flag,
713 .sign_data_hiding_enabled_flag = pps->sign_data_hiding_enabled_flag,
714 .constrained_intra_pred_flag = pps->constrained_intra_pred_flag,
715 .cu_qp_delta_enabled_flag = pps->cu_qp_delta_enabled_flag,
716 .weighted_pred_flag = pps->weighted_pred_flag,
717 .weighted_bipred_flag = pps->weighted_bipred_flag,
718 .transquant_bypass_enabled_flag = pps->transquant_bypass_enabled_flag,
719 .tiles_enabled_flag = pps->tiles_enabled_flag,
720 .entropy_coding_sync_enabled_flag = pps->entropy_coding_sync_enabled_flag,
721 .pps_loop_filter_across_slices_enabled_flag = pps->loop_filter_across_slices_enabled_flag,
722 .loop_filter_across_tiles_enabled_flag = pps->loop_filter_across_tiles_enabled_flag,
723 .pcm_loop_filter_disabled_flag = sps->pcm_loop_filter_disabled_flag,
724 /* Not set by FFMPEG either */
725 .NoPicReorderingFlag = 0,
728 .slice_parsing_fields.bits = {
729 .lists_modification_present_flag = pps->lists_modification_present_flag,
730 .long_term_ref_pics_present_flag = sps->long_term_ref_pics_present_flag,
731 .sps_temporal_mvp_enabled_flag = sps->temporal_mvp_enabled_flag,
732 .cabac_init_present_flag = pps->cabac_init_present_flag,
733 .output_flag_present_flag = pps->output_flag_present_flag,
734 .dependent_slice_segments_enabled_flag = pps->dependent_slice_segments_enabled_flag,
735 .pps_slice_chroma_qp_offsets_present_flag = pps->slice_chroma_qp_offsets_present_flag,
736 .sample_adaptive_offset_enabled_flag = sps->sample_adaptive_offset_enabled_flag,
737 .deblocking_filter_override_enabled_flag = pps->deblocking_filter_override_enabled_flag,
738 .pps_disable_deblocking_filter_flag = pps->deblocking_filter_disabled_flag,
739 .slice_segment_header_extension_present_flag = pps->slice_segment_header_extension_present_flag,
740 .RapPicFlag = picture->RapPicFlag,
741 .IdrPicFlag = GST_H265_IS_NAL_TYPE_IDR (slice->nalu.type),
742 .IntraPicFlag = GST_H265_IS_NAL_TYPE_IRAP (slice->nalu.type),
747 if (_is_range_extension_profile (self->parent.profile)
748 || _is_screen_content_ext_profile (self->parent.profile)) {
749 _fill_picture_range_ext_parameter (self, sps, pps);
750 if (_is_screen_content_ext_profile (self->parent.profile))
751 _fill_screen_content_ext_parameter (self, sps, pps);
754 for (i = 0; i <= pps->num_tile_columns_minus1; i++)
755 pic_param->base.column_width_minus1[i] = pps->column_width_minus1[i];
757 for (i = 0; i <= pps->num_tile_rows_minus1; i++)
758 pic_param->base.row_height_minus1[i] = pps->row_height_minus1[i];
760 _fill_vaapi_pic (decoder, &pic_param->base.CurrPic, picture);
762 /* reference frames */
764 GArray *ref_list = gst_h265_dpb_get_pictures_all (dpb);
768 for (j = 0; j < 15 && j < ref_list->len; j++) {
769 GstH265Picture *pic = g_array_index (ref_list, GstH265Picture *, j);
772 _fill_vaapi_pic (decoder, &pic_param->base.ReferenceFrames[i], pic);
776 g_array_unref (ref_list);
778 /* 7.4.3.3.3, the current decoded picture is marked as "used for
779 long-term reference". Current picture is not in the DPB now. */
780 if (pps->pps_scc_extension_params.pps_curr_pic_ref_enabled_flag && i < 15) {
781 pic_param->base.ReferenceFrames[i].picture_id =
782 gst_va_decode_picture_get_surface (gst_h265_picture_get_user_data
784 pic_param->base.ReferenceFrames[i].pic_order_cnt = picture->pic_order_cnt;
785 pic_param->base.ReferenceFrames[i].flags |=
786 VA_PICTURE_HEVC_LONG_TERM_REFERENCE;
787 pic_param->base.ReferenceFrames[i].flags |=
788 _find_frame_rps_type (decoder, picture);
793 _init_vaapi_pic (&pic_param->base.ReferenceFrames[i]);
796 pic_param_size = _is_range_extension_profile (self->parent.profile)
797 || _is_screen_content_ext_profile (self->parent.profile) ?
798 sizeof (*pic_param) : sizeof (pic_param->base);
799 if (!gst_va_decoder_add_param_buffer (base->decoder, va_pic,
800 VAPictureParameterBufferType, pic_param, pic_param_size))
803 if (pps->scaling_list_data_present_flag ||
804 (sps->scaling_list_enabled_flag
805 && !sps->scaling_list_data_present_flag)) {
806 scaling_list = &pps->scaling_list;
807 GST_DEBUG_OBJECT (decoder, "Passing scaling list from PPS");
808 } else if (sps->scaling_list_enabled_flag &&
809 sps->scaling_list_data_present_flag) {
810 scaling_list = &sps->scaling_list;
811 GST_DEBUG_OBJECT (decoder, "Passing scaling list from SPS");
815 for (i = 0; i < G_N_ELEMENTS (iq_matrix.ScalingList4x4); i++)
816 gst_h265_quant_matrix_4x4_get_raster_from_uprightdiagonal
817 (iq_matrix.ScalingList4x4[i], scaling_list->scaling_lists_4x4[i]);
819 for (i = 0; i < G_N_ELEMENTS (iq_matrix.ScalingList8x8); i++)
820 gst_h265_quant_matrix_8x8_get_raster_from_uprightdiagonal
821 (iq_matrix.ScalingList8x8[i], scaling_list->scaling_lists_8x8[i]);
823 for (i = 0; i < G_N_ELEMENTS (iq_matrix.ScalingList16x16); i++)
824 gst_h265_quant_matrix_16x16_get_raster_from_uprightdiagonal
825 (iq_matrix.ScalingList16x16[i], scaling_list->scaling_lists_16x16[i]);
827 for (i = 0; i < G_N_ELEMENTS (iq_matrix.ScalingList32x32); i++)
828 gst_h265_quant_matrix_32x32_get_raster_from_uprightdiagonal
829 (iq_matrix.ScalingList32x32[i], scaling_list->scaling_lists_32x32[i]);
831 for (i = 0; i < 6; i++)
832 iq_matrix.ScalingListDC16x16[i] =
833 scaling_list->scaling_list_dc_coef_minus8_16x16[i] + 8;
835 for (i = 0; i < 2; i++)
836 iq_matrix.ScalingListDC32x32[i] =
837 scaling_list->scaling_list_dc_coef_minus8_32x32[i] + 8;
839 return gst_va_decoder_add_param_buffer (base->decoder, va_pic,
840 VAIQMatrixBufferType, &iq_matrix, sizeof (iq_matrix));
847 gst_va_h265_dec_new_picture (GstH265Decoder * decoder,
848 GstVideoCodecFrame * frame, GstH265Picture * picture)
850 GstVaBaseDec *base = GST_VA_BASE_DEC (decoder);
851 GstVaH265Dec *self = GST_VA_H265_DEC (decoder);
852 GstVaDecodePicture *pic;
853 GstBuffer *output_buffer;
854 GstVideoDecoder *vdec = GST_VIDEO_DECODER (decoder);
856 output_buffer = gst_video_decoder_allocate_output_buffer (vdec);
857 if (!output_buffer) {
858 self->last_ret = GST_FLOW_ERROR;
861 self->last_ret = GST_FLOW_OK;
863 pic = gst_va_decode_picture_new (base->decoder, output_buffer);
864 gst_buffer_unref (output_buffer);
866 gst_h265_picture_set_user_data (picture, pic,
867 (GDestroyNotify) gst_va_decode_picture_free);
869 GST_LOG_OBJECT (self, "New va decode picture %p - %#x", pic,
870 gst_va_decode_picture_get_surface (pic));
876 GST_WARNING_OBJECT (self,
877 "Failed to allocated output buffer, return %s",
878 gst_flow_get_name (self->last_ret));
884 _get_rtformat (GstVaH265Dec * self, guint8 bit_depth_luma,
885 guint8 bit_depth_chroma, guint8 chroma_format_idc)
887 guint8 bit_num = MAX (bit_depth_luma, bit_depth_chroma);
892 if (chroma_format_idc == 3)
893 return VA_RT_FORMAT_YUV444_12;
894 if (chroma_format_idc == 2)
895 return VA_RT_FORMAT_YUV422_12;
897 return VA_RT_FORMAT_YUV420_12;
901 if (chroma_format_idc == 3)
902 return VA_RT_FORMAT_YUV444_10;
903 if (chroma_format_idc == 2)
904 return VA_RT_FORMAT_YUV422_10;
906 return VA_RT_FORMAT_YUV420_10;
909 if (chroma_format_idc == 3)
910 return VA_RT_FORMAT_YUV444;
911 if (chroma_format_idc == 2)
912 return VA_RT_FORMAT_YUV422;
914 return VA_RT_FORMAT_YUV420;
917 GST_ERROR_OBJECT (self, "Unsupported chroma format: %d "
918 "(with depth luma: %d, with depth chroma: %d)",
919 chroma_format_idc, bit_depth_luma, bit_depth_chroma);
927 GstH265Profile profile;
928 VAProfile va_profile;
930 #define P(idc, va) { G_PASTE (GST_H265_PROFILE_, idc), G_PASTE (VAProfileHEVC, va) }
933 /*P (MAIN_STILL_PICTURE, ),
936 P (MONOCHROME_16, ),*/
938 P (MAIN_422_10, Main422_10),
939 P (MAIN_422_12, Main422_12),
940 P (MAIN_444, Main444),
941 P (MAIN_444_10, Main444_10),
942 P (MAIN_444_12, Main444_12),
946 P (MAIN_422_10_INTRA, ),
947 P (MAIN_422_12_INTRA, ),
948 P (MAIN_444_INTRA, ),
949 P (MAIN_444_10_INTRA, ),
950 P (MAIN_444_12_INTRA, ),
951 P (MAIN_444_16_INTRA, ),
952 P (MAIN_444_STILL_PICTURE, ),
953 P (MAIN_444_16_STILL_PICTURE, ),
955 P (HIGH_THROUGHPUT_444, ),
956 P (HIGH_THROUGHPUT_444_10, ),
957 P (HIGH_THROUGHPUT_444_14, ),
958 P (HIGH_THROUGHPUT_444_16_INTRA, ),*/
959 P (SCREEN_EXTENDED_MAIN, SccMain),
960 P (SCREEN_EXTENDED_MAIN_10, SccMain10),
961 P (SCREEN_EXTENDED_MAIN_444, SccMain444),
962 /*P (SCREEN_EXTENDED_MAIN_444_10, ),
963 P (SCREEN_EXTENDED_HIGH_THROUGHPUT_444, ),
964 P (SCREEN_EXTENDED_HIGH_THROUGHPUT_444_10, ),
965 P (SCREEN_EXTENDED_HIGH_THROUGHPUT_444_14, ),
966 P (MULTIVIEW_MAIN, ),
968 P (SCALABLE_MAIN_10, ),
969 P (SCALABLE_MONOCHROME, ),
970 P (SCALABLE_MONOCHROME_12, ),
971 P (SCALABLE_MONOCHROME_16, ),
972 P (SCALABLE_MAIN_444, ),
979 _get_profile (GstVaH265Dec * self, const GstH265SPS * sps, gint max_dpb_size)
981 GstH265Decoder *h265_decoder = GST_H265_DECODER (self);
982 GstVaBaseDec *base = GST_VA_BASE_DEC (self);
983 GstH265Profile profile = gst_h265_get_profile_from_sps ((GstH265SPS *) sps);
984 VAProfile profiles[4];
987 /* 1. The profile directly specified by the SPS should always be the
988 first choice. It is the exact one.
989 2. The profile in the input caps may contain the compatible profile
990 chosen by the upstream element. Upstream element such as the parse
991 may already decide the best compatible profile for us. We also need
992 to consider it as a choice. */
994 for (j = 0; j < G_N_ELEMENTS (profile_map); j++) {
995 if (profile_map[j].profile == profile) {
996 profiles[i++] = profile_map[j].va_profile;
1001 if (h265_decoder->input_state->caps
1002 && gst_caps_is_fixed (h265_decoder->input_state->caps)) {
1003 GstH265Profile compatible_profile = GST_H265_PROFILE_INVALID;
1004 GstStructure *structure;
1005 const gchar *profile_str;
1007 structure = gst_caps_get_structure (h265_decoder->input_state->caps, 0);
1009 profile_str = gst_structure_get_string (structure, "profile");
1011 compatible_profile = gst_h265_profile_from_string (profile_str);
1013 if (compatible_profile != profile) {
1014 GST_INFO_OBJECT (self, "The upstream set the compatible profile %s, "
1015 "also consider it as a candidate.", profile_str);
1017 for (j = 0; j < G_N_ELEMENTS (profile_map); j++) {
1018 if (profile_map[j].profile == compatible_profile) {
1019 profiles[i++] = profile_map[j].va_profile;
1026 for (j = 0; j < i && j < G_N_ELEMENTS (profiles); j++) {
1027 if (gst_va_decoder_has_profile (base->decoder, profiles[j]))
1031 GST_ERROR_OBJECT (self, "Unsupported profile: %d", profile);
1033 return VAProfileNone;
1037 gst_va_h265_dec_new_sequence (GstH265Decoder * decoder, const GstH265SPS * sps,
1040 GstVaBaseDec *base = GST_VA_BASE_DEC (decoder);
1041 GstVaH265Dec *self = GST_VA_H265_DEC (decoder);
1044 gint display_height;
1045 gint padding_left, padding_right, padding_top, padding_bottom;
1047 gboolean negotiation_needed = FALSE;
1049 if (self->dpb_size < max_dpb_size)
1050 self->dpb_size = max_dpb_size;
1052 if (sps->conformance_window_flag) {
1053 display_width = sps->crop_rect_width;
1054 display_height = sps->crop_rect_height;
1055 padding_left = sps->crop_rect_x;
1056 padding_right = sps->width - sps->crop_rect_x - display_width;
1057 padding_top = sps->crop_rect_y;
1058 padding_bottom = sps->height - sps->crop_rect_y - display_height;
1060 display_width = sps->width;
1061 display_height = sps->height;
1062 padding_left = padding_right = padding_top = padding_bottom = 0;
1065 profile = _get_profile (self, sps, max_dpb_size);
1066 if (profile == VAProfileNone)
1069 rt_format = _get_rtformat (self, sps->bit_depth_luma_minus8 + 8,
1070 sps->bit_depth_chroma_minus8 + 8, sps->chroma_format_idc);
1074 if (!gst_va_decoder_config_is_equal (base->decoder, profile,
1075 rt_format, sps->width, sps->height)) {
1076 base->profile = profile;
1077 base->rt_format = rt_format;
1078 self->coded_width = sps->width;
1079 self->coded_height = sps->height;
1081 negotiation_needed = TRUE;
1082 GST_INFO_OBJECT (self, "Format changed to %s [%x] (%dx%d)",
1083 gst_va_profile_name (profile), rt_format, self->coded_width,
1084 self->coded_height);
1087 if (base->width != display_width || base->height != display_height) {
1088 base->width = display_width;
1089 base->height = display_height;
1091 negotiation_needed = TRUE;
1092 GST_INFO_OBJECT (self, "Resolution changed to %dx%d", base->width,
1096 base->need_valign = base->width < self->coded_width
1097 || base->height < self->coded_height;
1098 if (base->need_valign) {
1100 if (base->valign.padding_left != padding_left ||
1101 base->valign.padding_right != padding_right ||
1102 base->valign.padding_top != padding_top ||
1103 base->valign.padding_bottom != padding_bottom) {
1104 negotiation_needed = TRUE;
1105 GST_INFO_OBJECT (self, "crop rect changed to (%d,%d)-->(%d,%d)",
1106 padding_left, padding_top, padding_right, padding_bottom);
1108 base->valign = (GstVideoAlignment) {
1109 .padding_left = padding_left,
1110 .padding_right = padding_right,
1111 .padding_top = padding_top,
1112 .padding_bottom = padding_bottom,
1117 base->min_buffers = self->dpb_size + 4; /* dpb size + scratch surfaces */
1119 if (negotiation_needed) {
1120 self->need_negotiation = TRUE;
1121 if (!gst_video_decoder_negotiate (GST_VIDEO_DECODER (self))) {
1122 GST_ERROR_OBJECT (self, "Failed to negotiate with downstream");
1128 /* FIXME: We don't have parser API for sps_range_extension, so
1129 * assuming high_precision_offsets_enabled_flag as zero */
1130 guint high_precision_offsets_enabled_flag = 0, bitdepthC = 0;
1132 /* Calculate WpOffsetHalfRangeC: (7-34) */
1133 bitdepthC = sps->bit_depth_chroma_minus8 + 8;
1134 self->WpOffsetHalfRangeC =
1135 1 << (high_precision_offsets_enabled_flag ? (bitdepthC - 1) : 7);
1142 _complete_sink_caps (GstCaps * sinkcaps)
1144 GstCaps *caps = gst_caps_copy (sinkcaps);
1145 GValue val = G_VALUE_INIT;
1146 const gchar *streamformat[] = { "hvc1", "hev1", "byte-stream" };
1149 g_value_init (&val, G_TYPE_STRING);
1150 g_value_set_string (&val, "au");
1151 gst_caps_set_value (caps, "alignment", &val);
1152 g_value_unset (&val);
1154 gst_value_list_init (&val, G_N_ELEMENTS (streamformat));
1155 for (i = 0; i < G_N_ELEMENTS (streamformat); i++) {
1156 GValue v = G_VALUE_INIT;
1158 g_value_init (&v, G_TYPE_STRING);
1159 g_value_set_string (&v, streamformat[i]);
1160 gst_value_list_append_value (&val, &v);
1163 gst_caps_set_value (caps, "stream-format", &val);
1164 g_value_unset (&val);
1170 gst_va_h265_dec_getcaps (GstVideoDecoder * decoder, GstCaps * filter)
1172 GstCaps *sinkcaps, *caps = NULL, *tmp;
1173 GstVaBaseDec *base = GST_VA_BASE_DEC (decoder);
1176 caps = gst_va_decoder_get_sinkpad_caps (base->decoder);
1179 sinkcaps = _complete_sink_caps (caps);
1180 gst_caps_unref (caps);
1182 tmp = gst_caps_intersect_full (filter, sinkcaps,
1183 GST_CAPS_INTERSECT_FIRST);
1184 gst_caps_unref (sinkcaps);
1189 GST_LOG_OBJECT (base, "Returning caps %" GST_PTR_FORMAT, caps);
1191 caps = gst_video_decoder_proxy_getcaps (decoder, NULL, filter);
1198 gst_va_h265_dec_negotiate (GstVideoDecoder * decoder)
1200 GstVaBaseDec *base = GST_VA_BASE_DEC (decoder);
1201 GstVaH265Dec *self = GST_VA_H265_DEC (decoder);
1202 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
1203 GstCapsFeatures *capsfeatures = NULL;
1204 GstH265Decoder *h265dec = GST_H265_DECODER (decoder);
1206 /* Ignore downstream renegotiation request. */
1207 if (!self->need_negotiation)
1210 self->need_negotiation = FALSE;
1212 if (gst_va_decoder_is_open (base->decoder)
1213 && !gst_va_decoder_close (base->decoder))
1216 if (!gst_va_decoder_open (base->decoder, base->profile, base->rt_format))
1219 if (!gst_va_decoder_set_frame_size (base->decoder, self->coded_width,
1220 self->coded_height))
1223 if (base->output_state)
1224 gst_video_codec_state_unref (base->output_state);
1226 gst_va_base_dec_get_preferred_format_and_caps_features (base, &format,
1229 base->output_state =
1230 gst_video_decoder_set_output_state (decoder, format,
1231 base->width, base->height, h265dec->input_state);
1233 base->output_state->caps = gst_video_info_to_caps (&base->output_state->info);
1235 gst_caps_set_features_simple (base->output_state->caps, capsfeatures);
1237 GST_INFO_OBJECT (self, "Negotiated caps %" GST_PTR_FORMAT,
1238 base->output_state->caps);
1240 return GST_VIDEO_DECODER_CLASS (GST_VA_BASE_DEC_GET_PARENT_CLASS
1241 (decoder))->negotiate (decoder);
1245 gst_va_h265_dec_dispose (GObject * object)
1247 g_free (GST_VA_H265_DEC (object)->prev_slice.data);
1249 gst_va_base_dec_close (GST_VIDEO_DECODER (object));
1251 G_OBJECT_CLASS (GST_VA_BASE_DEC_GET_PARENT_CLASS (object))->dispose (object);
1255 gst_va_h265_dec_class_init (gpointer g_class, gpointer class_data)
1257 GstCaps *src_doc_caps, *sink_doc_caps;
1258 GObjectClass *gobject_class = G_OBJECT_CLASS (g_class);
1259 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
1260 GstH265DecoderClass *h265decoder_class = GST_H265_DECODER_CLASS (g_class);
1261 GstVideoDecoderClass *decoder_class = GST_VIDEO_DECODER_CLASS (g_class);
1262 struct CData *cdata = class_data;
1265 if (cdata->description) {
1266 long_name = g_strdup_printf ("VA-API H.265 Decoder in %s",
1267 cdata->description);
1269 long_name = g_strdup ("VA-API H.265 Decoder");
1272 gst_element_class_set_metadata (element_class, long_name,
1273 "Codec/Decoder/Video/Hardware",
1274 "VA-API based H.265 video decoder",
1275 "Nicolas Dufresne <nicolas.dufresne@collabora.com>");
1277 sink_doc_caps = gst_caps_from_string (sink_caps_str);
1278 src_doc_caps = gst_caps_from_string (src_caps_str);
1280 gst_va_base_dec_class_init (GST_VA_BASE_DEC_CLASS (g_class), HEVC,
1281 cdata->render_device_path, cdata->sink_caps, cdata->src_caps,
1282 src_doc_caps, sink_doc_caps);
1284 gobject_class->dispose = gst_va_h265_dec_dispose;
1286 decoder_class->getcaps = GST_DEBUG_FUNCPTR (gst_va_h265_dec_getcaps);
1287 decoder_class->negotiate = GST_DEBUG_FUNCPTR (gst_va_h265_dec_negotiate);
1289 h265decoder_class->new_sequence =
1290 GST_DEBUG_FUNCPTR (gst_va_h265_dec_new_sequence);
1291 h265decoder_class->decode_slice =
1292 GST_DEBUG_FUNCPTR (gst_va_h265_dec_decode_slice);
1294 h265decoder_class->new_picture =
1295 GST_DEBUG_FUNCPTR (gst_va_h265_dec_new_picture);
1296 h265decoder_class->output_picture =
1297 GST_DEBUG_FUNCPTR (gst_va_h265_dec_output_picture);
1298 h265decoder_class->start_picture =
1299 GST_DEBUG_FUNCPTR (gst_va_h265_dec_start_picture);
1300 h265decoder_class->end_picture =
1301 GST_DEBUG_FUNCPTR (gst_va_h265_dec_end_picture);
1304 g_free (cdata->description);
1305 g_free (cdata->render_device_path);
1306 gst_caps_unref (cdata->src_caps);
1307 gst_caps_unref (cdata->sink_caps);
1312 gst_va_h265_dec_init (GTypeInstance * instance, gpointer g_class)
1314 gst_va_base_dec_init (GST_VA_BASE_DEC (instance), GST_CAT_DEFAULT);
1315 gst_h265_decoder_set_process_ref_pic_lists (GST_H265_DECODER (instance),
1320 _register_debug_category (gpointer data)
1322 GST_DEBUG_CATEGORY_INIT (gst_va_h265dec_debug, "vah265dec", 0,
1329 gst_va_h265_dec_register (GstPlugin * plugin, GstVaDevice * device,
1330 GstCaps * sink_caps, GstCaps * src_caps, guint rank)
1332 static GOnce debug_once = G_ONCE_INIT;
1334 GTypeInfo type_info = {
1335 .class_size = sizeof (GstVaH265DecClass),
1336 .class_init = gst_va_h265_dec_class_init,
1337 .instance_size = sizeof (GstVaH265Dec),
1338 .instance_init = gst_va_h265_dec_init,
1340 struct CData *cdata;
1342 gchar *type_name, *feature_name;
1344 g_return_val_if_fail (GST_IS_PLUGIN (plugin), FALSE);
1345 g_return_val_if_fail (GST_IS_VA_DEVICE (device), FALSE);
1346 g_return_val_if_fail (GST_IS_CAPS (sink_caps), FALSE);
1347 g_return_val_if_fail (GST_IS_CAPS (src_caps), FALSE);
1349 cdata = g_new (struct CData, 1);
1350 cdata->description = NULL;
1351 cdata->render_device_path = g_strdup (device->render_device_path);
1352 cdata->sink_caps = _complete_sink_caps (sink_caps);
1353 cdata->src_caps = gst_caps_ref (src_caps);
1355 /* class data will be leaked if the element never gets instantiated */
1356 GST_MINI_OBJECT_FLAG_SET (cdata->sink_caps,
1357 GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
1358 GST_MINI_OBJECT_FLAG_SET (src_caps, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
1360 type_info.class_data = cdata;
1362 type_name = g_strdup ("GstVaH265Dec");
1363 feature_name = g_strdup ("vah265dec");
1365 /* The first decoder to be registered should use a constant name,
1366 * like vah265dec, for any additional decoders, we create unique
1367 * names, using inserting the render device name. */
1368 if (g_type_from_name (type_name)) {
1369 gchar *basename = g_path_get_basename (device->render_device_path);
1371 g_free (feature_name);
1372 type_name = g_strdup_printf ("GstVa%sH265Dec", basename);
1373 feature_name = g_strdup_printf ("va%sh265dec", basename);
1374 cdata->description = basename;
1376 /* lower rank for non-first device */
1381 g_once (&debug_once, _register_debug_category, NULL);
1383 type = g_type_register_static (GST_TYPE_H265_DECODER,
1384 type_name, &type_info, 0);
1386 ret = gst_element_register (plugin, feature_name, rank, type);
1389 g_free (feature_name);