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");
213 return GST_FLOW_ERROR;
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);
220 return GST_FLOW_ERROR;
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");
494 return GST_FLOW_ERROR;
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))
801 return GST_FLOW_ERROR;
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 if (!gst_va_decoder_add_param_buffer (base->decoder, va_pic,
840 VAIQMatrixBufferType, &iq_matrix, sizeof (iq_matrix))) {
841 return GST_FLOW_ERROR;
849 gst_va_h265_dec_new_picture (GstH265Decoder * decoder,
850 GstVideoCodecFrame * frame, GstH265Picture * picture)
852 GstVaBaseDec *base = GST_VA_BASE_DEC (decoder);
853 GstVaH265Dec *self = GST_VA_H265_DEC (decoder);
854 GstVaDecodePicture *pic;
855 GstBuffer *output_buffer;
856 GstVideoDecoder *vdec = GST_VIDEO_DECODER (decoder);
858 output_buffer = gst_video_decoder_allocate_output_buffer (vdec);
859 if (!output_buffer) {
860 self->last_ret = GST_FLOW_ERROR;
863 self->last_ret = GST_FLOW_OK;
865 pic = gst_va_decode_picture_new (base->decoder, output_buffer);
866 gst_buffer_unref (output_buffer);
868 gst_h265_picture_set_user_data (picture, pic,
869 (GDestroyNotify) gst_va_decode_picture_free);
871 GST_LOG_OBJECT (self, "New va decode picture %p - %#x", pic,
872 gst_va_decode_picture_get_surface (pic));
878 GST_WARNING_OBJECT (self,
879 "Failed to allocated output buffer, return %s",
880 gst_flow_get_name (self->last_ret));
881 return self->last_ret;
886 _get_rtformat (GstVaH265Dec * self, guint8 bit_depth_luma,
887 guint8 bit_depth_chroma, guint8 chroma_format_idc)
889 guint8 bit_num = MAX (bit_depth_luma, bit_depth_chroma);
894 if (chroma_format_idc == 3)
895 return VA_RT_FORMAT_YUV444_12;
896 if (chroma_format_idc == 2)
897 return VA_RT_FORMAT_YUV422_12;
899 return VA_RT_FORMAT_YUV420_12;
903 if (chroma_format_idc == 3)
904 return VA_RT_FORMAT_YUV444_10;
905 if (chroma_format_idc == 2)
906 return VA_RT_FORMAT_YUV422_10;
908 return VA_RT_FORMAT_YUV420_10;
911 if (chroma_format_idc == 3)
912 return VA_RT_FORMAT_YUV444;
913 if (chroma_format_idc == 2)
914 return VA_RT_FORMAT_YUV422;
916 return VA_RT_FORMAT_YUV420;
919 GST_ERROR_OBJECT (self, "Unsupported chroma format: %d "
920 "(with depth luma: %d, with depth chroma: %d)",
921 chroma_format_idc, bit_depth_luma, bit_depth_chroma);
929 GstH265Profile profile;
930 VAProfile va_profile;
932 #define P(idc, va) { G_PASTE (GST_H265_PROFILE_, idc), G_PASTE (VAProfileHEVC, va) }
935 /*P (MAIN_STILL_PICTURE, ),
938 P (MONOCHROME_16, ),*/
940 P (MAIN_422_10, Main422_10),
941 P (MAIN_422_12, Main422_12),
942 P (MAIN_444, Main444),
943 P (MAIN_444_10, Main444_10),
944 P (MAIN_444_12, Main444_12),
948 P (MAIN_422_10_INTRA, ),
949 P (MAIN_422_12_INTRA, ),
950 P (MAIN_444_INTRA, ),
951 P (MAIN_444_10_INTRA, ),
952 P (MAIN_444_12_INTRA, ),
953 P (MAIN_444_16_INTRA, ),
954 P (MAIN_444_STILL_PICTURE, ),
955 P (MAIN_444_16_STILL_PICTURE, ),
957 P (HIGH_THROUGHPUT_444, ),
958 P (HIGH_THROUGHPUT_444_10, ),
959 P (HIGH_THROUGHPUT_444_14, ),
960 P (HIGH_THROUGHPUT_444_16_INTRA, ),*/
961 P (SCREEN_EXTENDED_MAIN, SccMain),
962 P (SCREEN_EXTENDED_MAIN_10, SccMain10),
963 P (SCREEN_EXTENDED_MAIN_444, SccMain444),
964 /*P (SCREEN_EXTENDED_MAIN_444_10, ),
965 P (SCREEN_EXTENDED_HIGH_THROUGHPUT_444, ),
966 P (SCREEN_EXTENDED_HIGH_THROUGHPUT_444_10, ),
967 P (SCREEN_EXTENDED_HIGH_THROUGHPUT_444_14, ),
968 P (MULTIVIEW_MAIN, ),
970 P (SCALABLE_MAIN_10, ),
971 P (SCALABLE_MONOCHROME, ),
972 P (SCALABLE_MONOCHROME_12, ),
973 P (SCALABLE_MONOCHROME_16, ),
974 P (SCALABLE_MAIN_444, ),
981 _get_profile (GstVaH265Dec * self, const GstH265SPS * sps, gint max_dpb_size)
983 GstH265Decoder *h265_decoder = GST_H265_DECODER (self);
984 GstVaBaseDec *base = GST_VA_BASE_DEC (self);
985 GstH265Profile profile = gst_h265_get_profile_from_sps ((GstH265SPS *) sps);
986 VAProfile profiles[4];
989 /* 1. The profile directly specified by the SPS should always be the
990 first choice. It is the exact one.
991 2. The profile in the input caps may contain the compatible profile
992 chosen by the upstream element. Upstream element such as the parse
993 may already decide the best compatible profile for us. We also need
994 to consider it as a choice. */
996 for (j = 0; j < G_N_ELEMENTS (profile_map); j++) {
997 if (profile_map[j].profile == profile) {
998 profiles[i++] = profile_map[j].va_profile;
1003 if (h265_decoder->input_state->caps
1004 && gst_caps_is_fixed (h265_decoder->input_state->caps)) {
1005 GstH265Profile compatible_profile = GST_H265_PROFILE_INVALID;
1006 GstStructure *structure;
1007 const gchar *profile_str;
1009 structure = gst_caps_get_structure (h265_decoder->input_state->caps, 0);
1011 profile_str = gst_structure_get_string (structure, "profile");
1013 compatible_profile = gst_h265_profile_from_string (profile_str);
1015 if (compatible_profile != profile) {
1016 GST_INFO_OBJECT (self, "The upstream set the compatible profile %s, "
1017 "also consider it as a candidate.", profile_str);
1019 for (j = 0; j < G_N_ELEMENTS (profile_map); j++) {
1020 if (profile_map[j].profile == compatible_profile) {
1021 profiles[i++] = profile_map[j].va_profile;
1028 for (j = 0; j < i && j < G_N_ELEMENTS (profiles); j++) {
1029 if (gst_va_decoder_has_profile (base->decoder, profiles[j]))
1033 GST_ERROR_OBJECT (self, "Unsupported profile: %d", profile);
1035 return VAProfileNone;
1038 static GstFlowReturn
1039 gst_va_h265_dec_new_sequence (GstH265Decoder * decoder, const GstH265SPS * sps,
1042 GstVaBaseDec *base = GST_VA_BASE_DEC (decoder);
1043 GstVaH265Dec *self = GST_VA_H265_DEC (decoder);
1046 gint display_height;
1047 gint padding_left, padding_right, padding_top, padding_bottom;
1049 gboolean negotiation_needed = FALSE;
1051 if (self->dpb_size < max_dpb_size)
1052 self->dpb_size = max_dpb_size;
1054 if (sps->conformance_window_flag) {
1055 display_width = sps->crop_rect_width;
1056 display_height = sps->crop_rect_height;
1057 padding_left = sps->crop_rect_x;
1058 padding_right = sps->width - sps->crop_rect_x - display_width;
1059 padding_top = sps->crop_rect_y;
1060 padding_bottom = sps->height - sps->crop_rect_y - display_height;
1062 display_width = sps->width;
1063 display_height = sps->height;
1064 padding_left = padding_right = padding_top = padding_bottom = 0;
1067 profile = _get_profile (self, sps, max_dpb_size);
1068 if (profile == VAProfileNone)
1069 return GST_FLOW_NOT_NEGOTIATED;
1071 rt_format = _get_rtformat (self, sps->bit_depth_luma_minus8 + 8,
1072 sps->bit_depth_chroma_minus8 + 8, sps->chroma_format_idc);
1074 return GST_FLOW_NOT_NEGOTIATED;
1076 if (!gst_va_decoder_config_is_equal (base->decoder, profile,
1077 rt_format, sps->width, sps->height)) {
1078 base->profile = profile;
1079 base->rt_format = rt_format;
1080 self->coded_width = sps->width;
1081 self->coded_height = sps->height;
1083 negotiation_needed = TRUE;
1084 GST_INFO_OBJECT (self, "Format changed to %s [%x] (%dx%d)",
1085 gst_va_profile_name (profile), rt_format, self->coded_width,
1086 self->coded_height);
1089 if (base->width != display_width || base->height != display_height) {
1090 base->width = display_width;
1091 base->height = display_height;
1093 negotiation_needed = TRUE;
1094 GST_INFO_OBJECT (self, "Resolution changed to %dx%d", base->width,
1098 base->need_valign = base->width < self->coded_width
1099 || base->height < self->coded_height;
1100 if (base->need_valign) {
1102 if (base->valign.padding_left != padding_left ||
1103 base->valign.padding_right != padding_right ||
1104 base->valign.padding_top != padding_top ||
1105 base->valign.padding_bottom != padding_bottom) {
1106 negotiation_needed = TRUE;
1107 GST_INFO_OBJECT (self, "crop rect changed to (%d,%d)-->(%d,%d)",
1108 padding_left, padding_top, padding_right, padding_bottom);
1110 base->valign = (GstVideoAlignment) {
1111 .padding_left = padding_left,
1112 .padding_right = padding_right,
1113 .padding_top = padding_top,
1114 .padding_bottom = padding_bottom,
1119 base->min_buffers = self->dpb_size + 4; /* dpb size + scratch surfaces */
1121 if (negotiation_needed) {
1122 self->need_negotiation = TRUE;
1123 if (!gst_video_decoder_negotiate (GST_VIDEO_DECODER (self))) {
1124 GST_ERROR_OBJECT (self, "Failed to negotiate with downstream");
1125 return GST_FLOW_NOT_NEGOTIATED;
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 (!self->need_negotiation)
1212 self->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,
1231 base->output_state =
1232 gst_video_decoder_set_output_state (decoder, format,
1233 base->width, base->height, h265dec->input_state);
1235 base->output_state->caps = gst_video_info_to_caps (&base->output_state->info);
1237 gst_caps_set_features_simple (base->output_state->caps, capsfeatures);
1239 GST_INFO_OBJECT (self, "Negotiated caps %" GST_PTR_FORMAT,
1240 base->output_state->caps);
1242 return GST_VIDEO_DECODER_CLASS (GST_VA_BASE_DEC_GET_PARENT_CLASS
1243 (decoder))->negotiate (decoder);
1247 gst_va_h265_dec_dispose (GObject * object)
1249 g_free (GST_VA_H265_DEC (object)->prev_slice.data);
1251 gst_va_base_dec_close (GST_VIDEO_DECODER (object));
1253 G_OBJECT_CLASS (GST_VA_BASE_DEC_GET_PARENT_CLASS (object))->dispose (object);
1257 gst_va_h265_dec_class_init (gpointer g_class, gpointer class_data)
1259 GstCaps *src_doc_caps, *sink_doc_caps;
1260 GObjectClass *gobject_class = G_OBJECT_CLASS (g_class);
1261 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
1262 GstH265DecoderClass *h265decoder_class = GST_H265_DECODER_CLASS (g_class);
1263 GstVideoDecoderClass *decoder_class = GST_VIDEO_DECODER_CLASS (g_class);
1264 struct CData *cdata = class_data;
1267 if (cdata->description) {
1268 long_name = g_strdup_printf ("VA-API H.265 Decoder in %s",
1269 cdata->description);
1271 long_name = g_strdup ("VA-API H.265 Decoder");
1274 gst_element_class_set_metadata (element_class, long_name,
1275 "Codec/Decoder/Video/Hardware",
1276 "VA-API based H.265 video decoder",
1277 "Nicolas Dufresne <nicolas.dufresne@collabora.com>");
1279 sink_doc_caps = gst_caps_from_string (sink_caps_str);
1280 src_doc_caps = gst_caps_from_string (src_caps_str);
1282 gst_va_base_dec_class_init (GST_VA_BASE_DEC_CLASS (g_class), HEVC,
1283 cdata->render_device_path, cdata->sink_caps, cdata->src_caps,
1284 src_doc_caps, sink_doc_caps);
1286 gobject_class->dispose = gst_va_h265_dec_dispose;
1288 decoder_class->getcaps = GST_DEBUG_FUNCPTR (gst_va_h265_dec_getcaps);
1289 decoder_class->negotiate = GST_DEBUG_FUNCPTR (gst_va_h265_dec_negotiate);
1291 h265decoder_class->new_sequence =
1292 GST_DEBUG_FUNCPTR (gst_va_h265_dec_new_sequence);
1293 h265decoder_class->decode_slice =
1294 GST_DEBUG_FUNCPTR (gst_va_h265_dec_decode_slice);
1296 h265decoder_class->new_picture =
1297 GST_DEBUG_FUNCPTR (gst_va_h265_dec_new_picture);
1298 h265decoder_class->output_picture =
1299 GST_DEBUG_FUNCPTR (gst_va_h265_dec_output_picture);
1300 h265decoder_class->start_picture =
1301 GST_DEBUG_FUNCPTR (gst_va_h265_dec_start_picture);
1302 h265decoder_class->end_picture =
1303 GST_DEBUG_FUNCPTR (gst_va_h265_dec_end_picture);
1306 g_free (cdata->description);
1307 g_free (cdata->render_device_path);
1308 gst_caps_unref (cdata->src_caps);
1309 gst_caps_unref (cdata->sink_caps);
1314 gst_va_h265_dec_init (GTypeInstance * instance, gpointer g_class)
1316 gst_va_base_dec_init (GST_VA_BASE_DEC (instance), GST_CAT_DEFAULT);
1317 gst_h265_decoder_set_process_ref_pic_lists (GST_H265_DECODER (instance),
1322 _register_debug_category (gpointer data)
1324 GST_DEBUG_CATEGORY_INIT (gst_va_h265dec_debug, "vah265dec", 0,
1331 gst_va_h265_dec_register (GstPlugin * plugin, GstVaDevice * device,
1332 GstCaps * sink_caps, GstCaps * src_caps, guint rank)
1334 static GOnce debug_once = G_ONCE_INIT;
1336 GTypeInfo type_info = {
1337 .class_size = sizeof (GstVaH265DecClass),
1338 .class_init = gst_va_h265_dec_class_init,
1339 .instance_size = sizeof (GstVaH265Dec),
1340 .instance_init = gst_va_h265_dec_init,
1342 struct CData *cdata;
1344 gchar *type_name, *feature_name;
1346 g_return_val_if_fail (GST_IS_PLUGIN (plugin), FALSE);
1347 g_return_val_if_fail (GST_IS_VA_DEVICE (device), FALSE);
1348 g_return_val_if_fail (GST_IS_CAPS (sink_caps), FALSE);
1349 g_return_val_if_fail (GST_IS_CAPS (src_caps), FALSE);
1351 cdata = g_new (struct CData, 1);
1352 cdata->description = NULL;
1353 cdata->render_device_path = g_strdup (device->render_device_path);
1354 cdata->sink_caps = _complete_sink_caps (sink_caps);
1355 cdata->src_caps = gst_caps_ref (src_caps);
1357 /* class data will be leaked if the element never gets instantiated */
1358 GST_MINI_OBJECT_FLAG_SET (cdata->sink_caps,
1359 GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
1360 GST_MINI_OBJECT_FLAG_SET (src_caps, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
1362 type_info.class_data = cdata;
1364 type_name = g_strdup ("GstVaH265Dec");
1365 feature_name = g_strdup ("vah265dec");
1367 /* The first decoder to be registered should use a constant name,
1368 * like vah265dec, for any additional decoders, we create unique
1369 * names, using inserting the render device name. */
1370 if (g_type_from_name (type_name)) {
1371 gchar *basename = g_path_get_basename (device->render_device_path);
1373 g_free (feature_name);
1374 type_name = g_strdup_printf ("GstVa%sH265Dec", basename);
1375 feature_name = g_strdup_printf ("va%sh265dec", basename);
1376 cdata->description = basename;
1378 /* lower rank for non-first device */
1383 g_once (&debug_once, _register_debug_category, NULL);
1385 type = g_type_register_static (GST_TYPE_H265_DECODER,
1386 type_name, &type_info, 0);
1388 ret = gst_element_register (plugin, feature_name, rank, type);
1391 g_free (feature_name);