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;
106 static GstElementClass *parent_class = NULL;
109 static const gchar *src_caps_str =
110 GST_VIDEO_CAPS_MAKE_WITH_FEATURES (GST_CAPS_FEATURE_MEMORY_VA,
111 "{ NV12, P010_10LE }") " ;"
112 GST_VIDEO_CAPS_MAKE ("{ NV12, P010_10LE }");
115 static const gchar *sink_caps_str = "video/x-h265";
118 _is_range_extension_profile (VAProfile profile)
120 if (profile == VAProfileHEVCMain422_10
121 || profile == VAProfileHEVCMain444
122 || profile == VAProfileHEVCMain444_10
123 || profile == VAProfileHEVCMain12
124 || profile == VAProfileHEVCMain444_12
125 || profile == VAProfileHEVCMain422_12)
131 _is_screen_content_ext_profile (VAProfile profile)
133 if (profile == VAProfileHEVCSccMain
134 || profile == VAProfileHEVCSccMain10
135 || profile == VAProfileHEVCSccMain444)
142 _set_last_slice_flag (GstVaH265Dec * self)
144 self->prev_slice.param.base.LongSliceFlags.fields.LastSliceOfPic = 1;
148 _replace_previous_slice (GstVaH265Dec * self, guint8 * data, guint size)
150 struct slice *slice = &self->prev_slice;
151 gboolean do_reset = (slice->size < size);
153 if (!data || do_reset) {
154 g_clear_pointer (&slice->data, g_free);
162 GST_LOG_OBJECT (self, "allocating slice data %u", size);
163 slice->data = g_malloc (size);
166 memcpy (slice->data, data, size);
171 _submit_previous_slice (GstVaBaseDec * base, GstVaDecodePicture * va_pic)
173 GstVaH265Dec *self = GST_VA_H265_DEC (base);
178 slice = &self->prev_slice;
179 if (!slice->data && slice->size == 0)
181 if (!slice->data || slice->size == 0)
184 param_size = _is_range_extension_profile (self->parent.profile)
185 || _is_screen_content_ext_profile (self->parent.profile) ?
186 sizeof (slice->param) : sizeof (slice->param.base);
187 ret = gst_va_decoder_add_slice_buffer (base->decoder, va_pic, &slice->param,
188 param_size, slice->data, slice->size);
194 gst_va_h265_dec_end_picture (GstH265Decoder * decoder, GstH265Picture * picture)
196 GstVaBaseDec *base = GST_VA_BASE_DEC (decoder);
197 GstVaH265Dec *self = GST_VA_H265_DEC (decoder);
198 GstVaDecodePicture *va_pic;
201 GST_LOG_OBJECT (base, "end picture %p, (poc %d)",
202 picture, picture->pic_order_cnt);
204 va_pic = gst_h265_picture_get_user_data (picture);
206 _set_last_slice_flag (self);
207 ret = _submit_previous_slice (base, va_pic);
209 /* TODO(victor): optimization: this could be done at decoder's
211 _replace_previous_slice (self, NULL, 0);
214 GST_ERROR_OBJECT (self, "Failed to submit the previous slice");
215 return GST_FLOW_ERROR;
218 ret = gst_va_decoder_decode (base->decoder, va_pic);
220 GST_ERROR_OBJECT (self, "Failed at end picture %p, (poc %d)",
221 picture, picture->pic_order_cnt);
222 return GST_FLOW_ERROR;
229 gst_va_h265_dec_output_picture (GstH265Decoder * decoder,
230 GstVideoCodecFrame * frame, GstH265Picture * picture)
232 GstVaBaseDec *base = GST_VA_BASE_DEC (decoder);
233 GstVaH265Dec *self = GST_VA_H265_DEC (decoder);
234 GstVaDecodePicture *va_pic;
236 va_pic = gst_h265_picture_get_user_data (picture);
237 g_assert (va_pic->gstbuffer);
239 GST_LOG_OBJECT (self,
240 "Outputting picture %p (poc %d)", picture, picture->pic_order_cnt);
242 if (self->last_ret != GST_FLOW_OK) {
243 gst_h265_picture_unref (picture);
244 _replace_previous_slice (self, NULL, 0);
245 gst_video_decoder_drop_frame (GST_VIDEO_DECODER (self), frame);
246 return self->last_ret;
249 gst_buffer_replace (&frame->output_buffer, va_pic->gstbuffer);
251 if (base->copy_frames)
252 gst_va_base_dec_copy_output_buffer (base, frame);
254 gst_h265_picture_unref (picture);
256 return gst_video_decoder_finish_frame (GST_VIDEO_DECODER (self), frame);
260 _init_vaapi_pic (VAPictureHEVC * va_picture)
262 va_picture->picture_id = VA_INVALID_ID;
263 va_picture->flags = VA_PICTURE_HEVC_INVALID;
264 va_picture->pic_order_cnt = 0;
268 _find_frame_rps_type (GstH265Decoder * decoder, GstH265Picture * ref_pic)
272 for (i = 0; i < G_N_ELEMENTS (decoder->RefPicSetStCurrBefore); i++) {
273 if (ref_pic == decoder->RefPicSetStCurrBefore[i])
274 return VA_PICTURE_HEVC_RPS_ST_CURR_BEFORE;
277 for (i = 0; i < G_N_ELEMENTS (decoder->RefPicSetStCurrAfter); i++) {
278 if (ref_pic == decoder->RefPicSetStCurrAfter[i])
279 return VA_PICTURE_HEVC_RPS_ST_CURR_AFTER;
282 for (i = 0; i < G_N_ELEMENTS (decoder->RefPicSetLtCurr); i++) {
283 if (ref_pic == decoder->RefPicSetLtCurr[i])
284 return VA_PICTURE_HEVC_RPS_LT_CURR;
292 _fill_vaapi_pic (GstH265Decoder * decoder, VAPictureHEVC * va_picture,
293 GstH265Picture * picture)
295 GstVaDecodePicture *va_pic;
297 va_pic = gst_h265_picture_get_user_data (picture);
300 _init_vaapi_pic (va_picture);
304 va_picture->picture_id = gst_va_decode_picture_get_surface (va_pic);
305 va_picture->pic_order_cnt = picture->pic_order_cnt;
306 va_picture->flags = 0;
308 if (picture->ref && picture->long_term)
309 va_picture->flags |= VA_PICTURE_HEVC_LONG_TERM_REFERENCE;
311 va_picture->flags |= _find_frame_rps_type (decoder, picture);
315 _get_reference_index (GstH265Decoder * decoder, GstH265Picture * picture)
317 GstVaH265Dec *self = GST_VA_H265_DEC (decoder);
320 for (i = 0; i < 15; i++) {
321 VAPictureHEVC *ref_va_pic = &self->pic_param.base.ReferenceFrames[i];
323 if (ref_va_pic->picture_id == VA_INVALID_ID)
326 if (ref_va_pic->pic_order_cnt == picture->pic_order_cnt)
333 /* fill the VA API reference picture lists from the GstCodec reference
336 _fill_ref_pic_list (GstH265Decoder * decoder, GstH265Picture * cur_pic,
337 guint8 va_reflist[15], GArray * reflist)
341 for (i = 0; i < reflist->len && i < 15; i++) {
342 GstH265Picture *picture = g_array_index (reflist, GstH265Picture *, i);
343 va_reflist[i] = _get_reference_index (decoder, picture);
347 va_reflist[i] = 0xFF;
351 _fill_pred_weight_table (GstVaH265Dec * self, GstH265SliceHdr * header,
352 VASliceParameterBufferHEVCExtension * slice_param)
354 gint chroma_weight, chroma_log2_weight_denom;
356 GstH265PPS *pps = header->pps;
357 gboolean is_rext = _is_range_extension_profile (self->parent.profile);
359 if (GST_H265_IS_I_SLICE (header) ||
360 (!pps->weighted_pred_flag && GST_H265_IS_P_SLICE (header)) ||
361 (!pps->weighted_bipred_flag && GST_H265_IS_B_SLICE (header)))
364 slice_param->base.luma_log2_weight_denom =
365 header->pred_weight_table.luma_log2_weight_denom;
367 if (pps->sps->chroma_array_type != 0)
368 slice_param->base.delta_chroma_log2_weight_denom =
369 header->pred_weight_table.delta_chroma_log2_weight_denom;
371 for (i = 0; i <= header->num_ref_idx_l0_active_minus1; i++) {
372 if (!header->pred_weight_table.luma_weight_l0_flag[i])
375 slice_param->base.delta_luma_weight_l0[i] =
376 header->pred_weight_table.delta_luma_weight_l0[i];
377 slice_param->base.luma_offset_l0[i] =
378 header->pred_weight_table.luma_offset_l0[i];
381 slice_param->rext.luma_offset_l0[i] =
382 header->pred_weight_table.luma_offset_l0[i];
386 chroma_log2_weight_denom = slice_param->base.luma_log2_weight_denom +
387 slice_param->base.delta_chroma_log2_weight_denom;
389 for (i = 0; i <= header->num_ref_idx_l0_active_minus1; i++) {
390 if (!header->pred_weight_table.chroma_weight_l0_flag[i])
393 for (j = 0; j < 2; j++) {
394 gint16 delta_chroma_offset_l0 =
395 header->pred_weight_table.delta_chroma_offset_l0[i][j];
398 slice_param->base.delta_chroma_weight_l0[i][j] =
399 header->pred_weight_table.delta_chroma_weight_l0[i][j];
401 /* Find ChromaWeightL0 */
402 chroma_weight = (1 << chroma_log2_weight_denom) +
403 header->pred_weight_table.delta_chroma_weight_l0[i][j];
404 chroma_offset = self->WpOffsetHalfRangeC + delta_chroma_offset_l0
405 - ((self->WpOffsetHalfRangeC * chroma_weight)
406 >> chroma_log2_weight_denom);
409 slice_param->base.ChromaOffsetL0[i][j] = CLAMP (chroma_offset,
410 -self->WpOffsetHalfRangeC, self->WpOffsetHalfRangeC - 1);
413 slice_param->rext.ChromaOffsetL0[i][j] =
414 slice_param->base.ChromaOffsetL0[i][j];
419 /* Skip l1 if this is not a B-Frame. */
420 if (!GST_H265_IS_B_SLICE (header))
423 for (i = 0; i <= header->num_ref_idx_l1_active_minus1; i++) {
424 if (!header->pred_weight_table.luma_weight_l1_flag[i])
427 slice_param->base.delta_luma_weight_l1[i] =
428 header->pred_weight_table.delta_luma_weight_l1[i];
429 slice_param->base.luma_offset_l1[i] =
430 header->pred_weight_table.luma_offset_l1[i];
433 slice_param->rext.luma_offset_l1[i] =
434 header->pred_weight_table.luma_offset_l1[i];
438 for (i = 0; i <= header->num_ref_idx_l1_active_minus1; i++) {
439 if (!header->pred_weight_table.chroma_weight_l1_flag[i])
442 for (j = 0; j < 2; j++) {
443 gint16 delta_chroma_offset_l1 =
444 header->pred_weight_table.delta_chroma_offset_l1[i][j];
447 slice_param->base.delta_chroma_weight_l1[i][j] =
448 header->pred_weight_table.delta_chroma_weight_l1[i][j];
450 /* Find ChromaWeightL1 */
451 chroma_weight = (1 << chroma_log2_weight_denom) +
452 header->pred_weight_table.delta_chroma_weight_l1[i][j];
454 chroma_offset = self->WpOffsetHalfRangeC + delta_chroma_offset_l1
455 - ((self->WpOffsetHalfRangeC * chroma_weight)
456 >> chroma_log2_weight_denom);
459 slice_param->base.ChromaOffsetL1[i][j] = CLAMP (chroma_offset,
460 -self->WpOffsetHalfRangeC, self->WpOffsetHalfRangeC - 1);
463 slice_param->rext.ChromaOffsetL1[i][j] =
464 slice_param->base.ChromaOffsetL1[i][j];
471 _get_slice_data_byte_offset (GstH265SliceHdr * slice_hdr,
472 guint nal_header_bytes)
476 epb_count = slice_hdr->n_emulation_prevention_bytes;
477 return nal_header_bytes + (slice_hdr->header_size + 7) / 8 - epb_count;
481 gst_va_h265_dec_decode_slice (GstH265Decoder * decoder,
482 GstH265Picture * picture, GstH265Slice * slice, GArray * ref_pic_list0,
483 GArray * ref_pic_list1)
485 GstH265SliceHdr *header = &slice->header;
486 GstH265NalUnit *nalu = &slice->nalu;
487 GstVaBaseDec *base = GST_VA_BASE_DEC (decoder);
488 GstVaH265Dec *self = GST_VA_H265_DEC (decoder);
489 GstVaDecodePicture *va_pic;
490 VASliceParameterBufferHEVCExtension *slice_param;
492 va_pic = gst_h265_picture_get_user_data (picture);
493 if (!_submit_previous_slice (base, va_pic)) {
494 _replace_previous_slice (self, NULL, 0);
495 GST_ERROR_OBJECT (base, "Failed to submit previous slice buffers");
496 return GST_FLOW_ERROR;
499 slice_param = &self->prev_slice.param;
502 slice_param->base = (VASliceParameterBufferHEVC) {
503 .slice_data_size = nalu->size,
504 .slice_data_offset = 0,
505 .slice_data_flag = VA_SLICE_DATA_FLAG_ALL,
506 .slice_data_byte_offset = _get_slice_data_byte_offset (header, nalu->header_bytes),
507 .slice_segment_address = header->segment_address,
508 .collocated_ref_idx = header->temporal_mvp_enabled_flag ? header->collocated_ref_idx : 0xFF,
509 .num_ref_idx_l0_active_minus1 = header->num_ref_idx_l0_active_minus1,
510 .num_ref_idx_l1_active_minus1 = header->num_ref_idx_l1_active_minus1,
511 .slice_qp_delta = header->qp_delta,
512 .slice_cb_qp_offset = header->cb_qp_offset,
513 .slice_cr_qp_offset = header->cr_qp_offset,
514 .slice_beta_offset_div2 = header->beta_offset_div2,
515 .slice_tc_offset_div2 = header->tc_offset_div2,
516 .five_minus_max_num_merge_cand = header->five_minus_max_num_merge_cand,
517 .num_entry_point_offsets = header->num_entry_point_offsets,
518 .entry_offset_to_subset_array = 0, /* does not exist in spec */
519 .slice_data_num_emu_prevn_bytes = header->n_emulation_prevention_bytes,
520 .LongSliceFlags.fields = {
521 .LastSliceOfPic = 0, /* the last one will be set on end_picture() */
522 .dependent_slice_segment_flag = header->dependent_slice_segment_flag,
523 .slice_type = header->type,
524 .color_plane_id = header->colour_plane_id,
525 .slice_sao_luma_flag = header->sao_luma_flag,
526 .slice_sao_chroma_flag = header->sao_chroma_flag,
527 .mvd_l1_zero_flag = header->mvd_l1_zero_flag,
528 .cabac_init_flag = header->cabac_init_flag,
529 .slice_temporal_mvp_enabled_flag = header->temporal_mvp_enabled_flag,
530 .slice_deblocking_filter_disabled_flag =
531 header->deblocking_filter_disabled_flag,
532 .collocated_from_l0_flag = header->collocated_from_l0_flag,
533 .slice_loop_filter_across_slices_enabled_flag =
534 header->loop_filter_across_slices_enabled_flag,
539 if (_is_range_extension_profile (base->profile)
540 || _is_screen_content_ext_profile (base->profile)) {
542 slice_param->rext = (VASliceParameterBufferHEVCRext) {
543 .slice_ext_flags.bits = {
544 .cu_chroma_qp_offset_enabled_flag = header->cu_chroma_qp_offset_enabled_flag,
545 .use_integer_mv_flag = header->use_integer_mv_flag,
547 .slice_act_y_qp_offset = header->slice_act_y_qp_offset,
548 .slice_act_cb_qp_offset = header->slice_act_cb_qp_offset,
549 .slice_act_cr_qp_offset = header->slice_act_cr_qp_offset,
554 _fill_ref_pic_list (decoder, picture, slice_param->base.RefPicList[0],
556 _fill_ref_pic_list (decoder, picture, slice_param->base.RefPicList[1],
559 _fill_pred_weight_table (GST_VA_H265_DEC (decoder), header, slice_param);
561 _replace_previous_slice (self, slice->nalu.data + slice->nalu.offset,
568 _fill_picture_range_ext_parameter (GstVaH265Dec * decoder,
569 GstH265SPS * sps, GstH265PPS * pps)
571 VAPictureParameterBufferHEVCRext *pic_param = &decoder->pic_param.rext;
573 GstH265SPSExtensionParams *sps_ext = &sps->sps_extnsion_params;
574 GstH265PPSExtensionParams *pps_ext = &pps->pps_extension_params;
577 *pic_param = (VAPictureParameterBufferHEVCRext) {
578 .range_extension_pic_fields.bits = {
579 .transform_skip_rotation_enabled_flag = sps_ext->transform_skip_rotation_enabled_flag,
580 .transform_skip_context_enabled_flag = sps_ext->transform_skip_context_enabled_flag,
581 .implicit_rdpcm_enabled_flag = sps_ext->implicit_rdpcm_enabled_flag,
582 .explicit_rdpcm_enabled_flag = sps_ext->explicit_rdpcm_enabled_flag,
583 .extended_precision_processing_flag = sps_ext->extended_precision_processing_flag,
584 .intra_smoothing_disabled_flag = sps_ext->intra_smoothing_disabled_flag,
585 .high_precision_offsets_enabled_flag = sps_ext->high_precision_offsets_enabled_flag,
586 .persistent_rice_adaptation_enabled_flag = sps_ext->persistent_rice_adaptation_enabled_flag,
587 .cabac_bypass_alignment_enabled_flag = sps_ext->cabac_bypass_alignment_enabled_flag,
588 .cross_component_prediction_enabled_flag = pps_ext->cross_component_prediction_enabled_flag,
589 .chroma_qp_offset_list_enabled_flag = pps_ext->chroma_qp_offset_list_enabled_flag,
591 .diff_cu_chroma_qp_offset_depth = pps_ext->diff_cu_chroma_qp_offset_depth,
592 .chroma_qp_offset_list_len_minus1 = pps_ext->chroma_qp_offset_list_len_minus1,
593 .log2_sao_offset_scale_luma = pps_ext->log2_sao_offset_scale_luma,
594 .log2_sao_offset_scale_chroma = pps_ext->log2_sao_offset_scale_chroma,
595 .log2_max_transform_skip_block_size_minus2 = pps_ext->log2_max_transform_skip_block_size_minus2,
599 memcpy (pic_param->cb_qp_offset_list, pps_ext->cb_qp_offset_list,
600 sizeof (pic_param->cb_qp_offset_list));
601 memcpy (pic_param->cr_qp_offset_list, pps_ext->cr_qp_offset_list,
602 sizeof (pic_param->cr_qp_offset_list));
606 _fill_screen_content_ext_parameter (GstVaH265Dec * decoder,
607 GstH265SPS * sps, GstH265PPS * pps)
609 VAPictureParameterBufferHEVCScc *pic_param = &decoder->pic_param.scc;
610 const GstH265PPSSccExtensionParams *pps_scc = &pps->pps_scc_extension_params;
611 const GstH265SPSSccExtensionParams *sps_scc = &sps->sps_scc_extension_params;
616 *pic_param = (VAPictureParameterBufferHEVCScc) {
617 .screen_content_pic_fields.bits = {
618 .pps_curr_pic_ref_enabled_flag = pps_scc->pps_curr_pic_ref_enabled_flag,
619 .palette_mode_enabled_flag = sps_scc->palette_mode_enabled_flag,
620 .motion_vector_resolution_control_idc = sps_scc->motion_vector_resolution_control_idc,
621 .intra_boundary_filtering_disabled_flag = sps_scc->intra_boundary_filtering_disabled_flag,
622 .residual_adaptive_colour_transform_enabled_flag = pps_scc->residual_adaptive_colour_transform_enabled_flag,
623 .pps_slice_act_qp_offsets_present_flag = pps_scc->pps_slice_act_qp_offsets_present_flag,
625 .palette_max_size = sps_scc->palette_max_size,
626 .delta_palette_max_predictor_size = sps_scc->delta_palette_max_predictor_size,
627 .pps_act_y_qp_offset_plus5 = pps_scc->pps_act_y_qp_offset_plus5,
628 .pps_act_cb_qp_offset_plus5 = pps_scc->pps_act_cb_qp_offset_plus5,
629 .pps_act_cr_qp_offset_plus3 = pps_scc->pps_act_cr_qp_offset_plus3,
633 /* firstly use the pps, then sps */
634 num_comps = sps->chroma_format_idc ? 3 : 1;
636 if (pps_scc->pps_palette_predictor_initializers_present_flag) {
637 pic_param->predictor_palette_size =
638 pps_scc->pps_num_palette_predictor_initializer;
639 for (n = 0; n < num_comps; n++)
640 for (i = 0; i < pps_scc->pps_num_palette_predictor_initializer; i++)
641 pic_param->predictor_palette_entries[n][i] =
642 (uint16_t) pps_scc->pps_palette_predictor_initializer[n][i];
643 } else if (sps_scc->sps_palette_predictor_initializers_present_flag) {
644 pic_param->predictor_palette_size =
645 sps_scc->sps_num_palette_predictor_initializer_minus1 + 1;
646 for (n = 0; n < num_comps; n++)
648 i < sps_scc->sps_num_palette_predictor_initializer_minus1 + 1; i++)
649 pic_param->predictor_palette_entries[n][i] =
650 (uint16_t) sps_scc->sps_palette_predictor_initializer[n][i];
655 gst_va_h265_dec_start_picture (GstH265Decoder * decoder,
656 GstH265Picture * picture, GstH265Slice * slice, GstH265Dpb * dpb)
660 GstVaH265Dec *self = GST_VA_H265_DEC (decoder);
661 GstVaBaseDec *base = &self->parent;
662 GstVaDecodePicture *va_pic;
663 GstH265ScalingList *scaling_list = NULL;
664 VAIQMatrixBufferHEVC iq_matrix = { 0, };
665 VAPictureParameterBufferHEVCExtension *pic_param = &self->pic_param;
666 gsize pic_param_size;
669 va_pic = gst_h265_picture_get_user_data (picture);
671 pps = slice->header.pps;
675 pic_param->base = (VAPictureParameterBufferHEVC) {
676 .pic_width_in_luma_samples = sps->pic_width_in_luma_samples,
677 .pic_height_in_luma_samples = sps->pic_height_in_luma_samples,
678 .sps_max_dec_pic_buffering_minus1 = sps->max_dec_pic_buffering_minus1[sps->max_sub_layers_minus1],
679 .bit_depth_luma_minus8 = sps->bit_depth_luma_minus8,
680 .bit_depth_chroma_minus8 = sps->bit_depth_chroma_minus8,
681 .pcm_sample_bit_depth_luma_minus1 = sps->pcm_sample_bit_depth_luma_minus1,
682 .pcm_sample_bit_depth_chroma_minus1 = sps->pcm_sample_bit_depth_chroma_minus1,
683 .log2_min_luma_coding_block_size_minus3 = sps->log2_min_luma_coding_block_size_minus3,
684 .log2_diff_max_min_luma_coding_block_size = sps->log2_diff_max_min_luma_coding_block_size,
685 .log2_min_transform_block_size_minus2 = sps->log2_min_transform_block_size_minus2,
686 .log2_diff_max_min_transform_block_size = sps->log2_diff_max_min_transform_block_size,
687 .log2_min_pcm_luma_coding_block_size_minus3 = sps->log2_min_pcm_luma_coding_block_size_minus3,
688 .log2_diff_max_min_pcm_luma_coding_block_size = sps->log2_diff_max_min_pcm_luma_coding_block_size,
689 .max_transform_hierarchy_depth_intra = sps->max_transform_hierarchy_depth_intra,
690 .max_transform_hierarchy_depth_inter = sps->max_transform_hierarchy_depth_inter,
691 .init_qp_minus26 = pps->init_qp_minus26,
692 .diff_cu_qp_delta_depth = pps->diff_cu_qp_delta_depth,
693 .pps_cb_qp_offset = pps->cb_qp_offset,
694 .pps_cr_qp_offset = pps->cr_qp_offset,
695 .log2_parallel_merge_level_minus2 = pps->log2_parallel_merge_level_minus2,
696 .num_tile_columns_minus1 = pps->num_tile_columns_minus1,
697 .num_tile_rows_minus1 = pps->num_tile_rows_minus1,
698 .log2_max_pic_order_cnt_lsb_minus4 = sps->log2_max_pic_order_cnt_lsb_minus4,
699 .num_short_term_ref_pic_sets = sps->num_short_term_ref_pic_sets,
700 .num_long_term_ref_pic_sps = sps->num_long_term_ref_pics_sps,
701 .num_ref_idx_l0_default_active_minus1 = pps->num_ref_idx_l0_default_active_minus1,
702 .num_ref_idx_l1_default_active_minus1 = pps->num_ref_idx_l1_default_active_minus1,
703 .pps_beta_offset_div2 = pps->beta_offset_div2,
704 .pps_tc_offset_div2 = pps->tc_offset_div2,
705 .num_extra_slice_header_bits = pps->num_extra_slice_header_bits,
706 .st_rps_bits = slice->header.short_term_ref_pic_set_size, /* FIXME missing emulation bits removal */
708 .chroma_format_idc = sps->chroma_format_idc,
709 .separate_colour_plane_flag = sps->separate_colour_plane_flag,
710 .pcm_enabled_flag = sps->pcm_enabled_flag,
711 .scaling_list_enabled_flag = sps->scaling_list_enabled_flag,
712 .transform_skip_enabled_flag = pps->transform_skip_enabled_flag,
713 .amp_enabled_flag = sps->amp_enabled_flag,
714 .strong_intra_smoothing_enabled_flag = sps->strong_intra_smoothing_enabled_flag,
715 .sign_data_hiding_enabled_flag = pps->sign_data_hiding_enabled_flag,
716 .constrained_intra_pred_flag = pps->constrained_intra_pred_flag,
717 .cu_qp_delta_enabled_flag = pps->cu_qp_delta_enabled_flag,
718 .weighted_pred_flag = pps->weighted_pred_flag,
719 .weighted_bipred_flag = pps->weighted_bipred_flag,
720 .transquant_bypass_enabled_flag = pps->transquant_bypass_enabled_flag,
721 .tiles_enabled_flag = pps->tiles_enabled_flag,
722 .entropy_coding_sync_enabled_flag = pps->entropy_coding_sync_enabled_flag,
723 .pps_loop_filter_across_slices_enabled_flag = pps->loop_filter_across_slices_enabled_flag,
724 .loop_filter_across_tiles_enabled_flag = pps->loop_filter_across_tiles_enabled_flag,
725 .pcm_loop_filter_disabled_flag = sps->pcm_loop_filter_disabled_flag,
726 /* Not set by FFMPEG either */
727 .NoPicReorderingFlag = 0,
730 .slice_parsing_fields.bits = {
731 .lists_modification_present_flag = pps->lists_modification_present_flag,
732 .long_term_ref_pics_present_flag = sps->long_term_ref_pics_present_flag,
733 .sps_temporal_mvp_enabled_flag = sps->temporal_mvp_enabled_flag,
734 .cabac_init_present_flag = pps->cabac_init_present_flag,
735 .output_flag_present_flag = pps->output_flag_present_flag,
736 .dependent_slice_segments_enabled_flag = pps->dependent_slice_segments_enabled_flag,
737 .pps_slice_chroma_qp_offsets_present_flag = pps->slice_chroma_qp_offsets_present_flag,
738 .sample_adaptive_offset_enabled_flag = sps->sample_adaptive_offset_enabled_flag,
739 .deblocking_filter_override_enabled_flag = pps->deblocking_filter_override_enabled_flag,
740 .pps_disable_deblocking_filter_flag = pps->deblocking_filter_disabled_flag,
741 .slice_segment_header_extension_present_flag = pps->slice_segment_header_extension_present_flag,
742 .RapPicFlag = picture->RapPicFlag,
743 .IdrPicFlag = GST_H265_IS_NAL_TYPE_IDR (slice->nalu.type),
744 .IntraPicFlag = GST_H265_IS_NAL_TYPE_IRAP (slice->nalu.type),
749 if (_is_range_extension_profile (self->parent.profile)
750 || _is_screen_content_ext_profile (self->parent.profile)) {
751 _fill_picture_range_ext_parameter (self, sps, pps);
752 if (_is_screen_content_ext_profile (self->parent.profile))
753 _fill_screen_content_ext_parameter (self, sps, pps);
756 for (i = 0; i <= pps->num_tile_columns_minus1; i++)
757 pic_param->base.column_width_minus1[i] = pps->column_width_minus1[i];
759 for (i = 0; i <= pps->num_tile_rows_minus1; i++)
760 pic_param->base.row_height_minus1[i] = pps->row_height_minus1[i];
762 _fill_vaapi_pic (decoder, &pic_param->base.CurrPic, picture);
764 /* reference frames */
766 GArray *ref_list = gst_h265_dpb_get_pictures_all (dpb);
770 for (j = 0; j < 15 && j < ref_list->len; j++) {
771 GstH265Picture *pic = g_array_index (ref_list, GstH265Picture *, j);
774 _fill_vaapi_pic (decoder, &pic_param->base.ReferenceFrames[i], pic);
778 g_array_unref (ref_list);
780 /* 7.4.3.3.3, the current decoded picture is marked as "used for
781 long-term reference". Current picture is not in the DPB now. */
782 if (pps->pps_scc_extension_params.pps_curr_pic_ref_enabled_flag && i < 15) {
783 pic_param->base.ReferenceFrames[i].picture_id =
784 gst_va_decode_picture_get_surface (gst_h265_picture_get_user_data
786 pic_param->base.ReferenceFrames[i].pic_order_cnt = picture->pic_order_cnt;
787 pic_param->base.ReferenceFrames[i].flags |=
788 VA_PICTURE_HEVC_LONG_TERM_REFERENCE;
789 pic_param->base.ReferenceFrames[i].flags |=
790 _find_frame_rps_type (decoder, picture);
795 _init_vaapi_pic (&pic_param->base.ReferenceFrames[i]);
798 pic_param_size = _is_range_extension_profile (self->parent.profile)
799 || _is_screen_content_ext_profile (self->parent.profile) ?
800 sizeof (*pic_param) : sizeof (pic_param->base);
801 if (!gst_va_decoder_add_param_buffer (base->decoder, va_pic,
802 VAPictureParameterBufferType, pic_param, pic_param_size))
803 return GST_FLOW_ERROR;
805 if (pps->scaling_list_data_present_flag ||
806 (sps->scaling_list_enabled_flag
807 && !sps->scaling_list_data_present_flag)) {
808 scaling_list = &pps->scaling_list;
809 GST_DEBUG_OBJECT (decoder, "Passing scaling list from PPS");
810 } else if (sps->scaling_list_enabled_flag &&
811 sps->scaling_list_data_present_flag) {
812 scaling_list = &sps->scaling_list;
813 GST_DEBUG_OBJECT (decoder, "Passing scaling list from SPS");
817 for (i = 0; i < G_N_ELEMENTS (iq_matrix.ScalingList4x4); i++)
818 gst_h265_quant_matrix_4x4_get_raster_from_uprightdiagonal
819 (iq_matrix.ScalingList4x4[i], scaling_list->scaling_lists_4x4[i]);
821 for (i = 0; i < G_N_ELEMENTS (iq_matrix.ScalingList8x8); i++)
822 gst_h265_quant_matrix_8x8_get_raster_from_uprightdiagonal
823 (iq_matrix.ScalingList8x8[i], scaling_list->scaling_lists_8x8[i]);
825 for (i = 0; i < G_N_ELEMENTS (iq_matrix.ScalingList16x16); i++)
826 gst_h265_quant_matrix_16x16_get_raster_from_uprightdiagonal
827 (iq_matrix.ScalingList16x16[i], scaling_list->scaling_lists_16x16[i]);
829 for (i = 0; i < G_N_ELEMENTS (iq_matrix.ScalingList32x32); i++)
830 gst_h265_quant_matrix_32x32_get_raster_from_uprightdiagonal
831 (iq_matrix.ScalingList32x32[i], scaling_list->scaling_lists_32x32[i]);
833 for (i = 0; i < 6; i++)
834 iq_matrix.ScalingListDC16x16[i] =
835 scaling_list->scaling_list_dc_coef_minus8_16x16[i] + 8;
837 for (i = 0; i < 2; i++)
838 iq_matrix.ScalingListDC32x32[i] =
839 scaling_list->scaling_list_dc_coef_minus8_32x32[i] + 8;
841 if (!gst_va_decoder_add_param_buffer (base->decoder, va_pic,
842 VAIQMatrixBufferType, &iq_matrix, sizeof (iq_matrix))) {
843 return GST_FLOW_ERROR;
851 gst_va_h265_dec_new_picture (GstH265Decoder * decoder,
852 GstVideoCodecFrame * frame, GstH265Picture * picture)
854 GstVaBaseDec *base = GST_VA_BASE_DEC (decoder);
855 GstVaH265Dec *self = GST_VA_H265_DEC (decoder);
856 GstVaDecodePicture *pic;
857 GstBuffer *output_buffer;
858 GstVideoDecoder *vdec = GST_VIDEO_DECODER (decoder);
860 output_buffer = gst_video_decoder_allocate_output_buffer (vdec);
861 if (!output_buffer) {
862 self->last_ret = GST_FLOW_ERROR;
865 self->last_ret = GST_FLOW_OK;
867 pic = gst_va_decode_picture_new (base->decoder, output_buffer);
868 gst_buffer_unref (output_buffer);
870 gst_h265_picture_set_user_data (picture, pic,
871 (GDestroyNotify) gst_va_decode_picture_free);
873 GST_LOG_OBJECT (self, "New va decode picture %p - %#x", pic,
874 gst_va_decode_picture_get_surface (pic));
880 GST_WARNING_OBJECT (self,
881 "Failed to allocated output buffer, return %s",
882 gst_flow_get_name (self->last_ret));
883 return self->last_ret;
888 _get_rtformat (GstVaH265Dec * self, guint8 bit_depth_luma,
889 guint8 bit_depth_chroma, guint8 chroma_format_idc)
891 guint8 bit_num = MAX (bit_depth_luma, bit_depth_chroma);
896 if (chroma_format_idc == 3)
897 return VA_RT_FORMAT_YUV444_12;
898 if (chroma_format_idc == 2)
899 return VA_RT_FORMAT_YUV422_12;
901 return VA_RT_FORMAT_YUV420_12;
905 if (chroma_format_idc == 3)
906 return VA_RT_FORMAT_YUV444_10;
907 if (chroma_format_idc == 2)
908 return VA_RT_FORMAT_YUV422_10;
910 return VA_RT_FORMAT_YUV420_10;
913 if (chroma_format_idc == 3)
914 return VA_RT_FORMAT_YUV444;
915 if (chroma_format_idc == 2)
916 return VA_RT_FORMAT_YUV422;
918 return VA_RT_FORMAT_YUV420;
921 GST_ERROR_OBJECT (self, "Unsupported chroma format: %d "
922 "(with depth luma: %d, with depth chroma: %d)",
923 chroma_format_idc, bit_depth_luma, bit_depth_chroma);
931 GstH265Profile profile;
932 VAProfile va_profile;
934 #define P(idc, va) { G_PASTE (GST_H265_PROFILE_, idc), G_PASTE (VAProfileHEVC, va) }
937 /*P (MAIN_STILL_PICTURE, ),
940 P (MONOCHROME_16, ),*/
942 P (MAIN_422_10, Main422_10),
943 P (MAIN_422_12, Main422_12),
944 P (MAIN_444, Main444),
945 P (MAIN_444_10, Main444_10),
946 P (MAIN_444_12, Main444_12),
950 P (MAIN_422_10_INTRA, ),
951 P (MAIN_422_12_INTRA, ),
952 P (MAIN_444_INTRA, ),
953 P (MAIN_444_10_INTRA, ),
954 P (MAIN_444_12_INTRA, ),
955 P (MAIN_444_16_INTRA, ),
956 P (MAIN_444_STILL_PICTURE, ),
957 P (MAIN_444_16_STILL_PICTURE, ),
959 P (HIGH_THROUGHPUT_444, ),
960 P (HIGH_THROUGHPUT_444_10, ),
961 P (HIGH_THROUGHPUT_444_14, ),
962 P (HIGH_THROUGHPUT_444_16_INTRA, ),*/
963 P (SCREEN_EXTENDED_MAIN, SccMain),
964 P (SCREEN_EXTENDED_MAIN_10, SccMain10),
965 P (SCREEN_EXTENDED_MAIN_444, SccMain444),
966 /*P (SCREEN_EXTENDED_MAIN_444_10, ),
967 P (SCREEN_EXTENDED_HIGH_THROUGHPUT_444, ),
968 P (SCREEN_EXTENDED_HIGH_THROUGHPUT_444_10, ),
969 P (SCREEN_EXTENDED_HIGH_THROUGHPUT_444_14, ),
970 P (MULTIVIEW_MAIN, ),
972 P (SCALABLE_MAIN_10, ),
973 P (SCALABLE_MONOCHROME, ),
974 P (SCALABLE_MONOCHROME_12, ),
975 P (SCALABLE_MONOCHROME_16, ),
976 P (SCALABLE_MAIN_444, ),
983 _get_profile (GstVaH265Dec * self, const GstH265SPS * sps, gint max_dpb_size)
985 GstH265Decoder *h265_decoder = GST_H265_DECODER (self);
986 GstVaBaseDec *base = GST_VA_BASE_DEC (self);
987 GstH265Profile profile = gst_h265_get_profile_from_sps ((GstH265SPS *) sps);
988 VAProfile profiles[4];
991 /* 1. The profile directly specified by the SPS should always be the
992 first choice. It is the exact one.
993 2. The profile in the input caps may contain the compatible profile
994 chosen by the upstream element. Upstream element such as the parse
995 may already decide the best compatible profile for us. We also need
996 to consider it as a choice. */
998 for (j = 0; j < G_N_ELEMENTS (profile_map); j++) {
999 if (profile_map[j].profile == profile) {
1000 profiles[i++] = profile_map[j].va_profile;
1005 if (h265_decoder->input_state->caps
1006 && gst_caps_is_fixed (h265_decoder->input_state->caps)) {
1007 GstH265Profile compatible_profile = GST_H265_PROFILE_INVALID;
1008 GstStructure *structure;
1009 const gchar *profile_str;
1011 structure = gst_caps_get_structure (h265_decoder->input_state->caps, 0);
1013 profile_str = gst_structure_get_string (structure, "profile");
1015 compatible_profile = gst_h265_profile_from_string (profile_str);
1017 if (compatible_profile != profile) {
1018 GST_INFO_OBJECT (self, "The upstream set the compatible profile %s, "
1019 "also consider it as a candidate.", profile_str);
1021 for (j = 0; j < G_N_ELEMENTS (profile_map); j++) {
1022 if (profile_map[j].profile == compatible_profile) {
1023 profiles[i++] = profile_map[j].va_profile;
1030 for (j = 0; j < i && j < G_N_ELEMENTS (profiles); j++) {
1031 if (gst_va_decoder_has_profile (base->decoder, profiles[j]))
1035 GST_ERROR_OBJECT (self, "Unsupported profile: %d", profile);
1037 return VAProfileNone;
1040 static GstFlowReturn
1041 gst_va_h265_dec_new_sequence (GstH265Decoder * decoder, const GstH265SPS * sps,
1044 GstVaBaseDec *base = GST_VA_BASE_DEC (decoder);
1045 GstVaH265Dec *self = GST_VA_H265_DEC (decoder);
1048 gint display_height;
1049 gint padding_left, padding_right, padding_top, padding_bottom;
1051 gboolean negotiation_needed = FALSE;
1053 if (self->dpb_size < max_dpb_size)
1054 self->dpb_size = max_dpb_size;
1056 if (sps->conformance_window_flag) {
1057 display_width = sps->crop_rect_width;
1058 display_height = sps->crop_rect_height;
1059 padding_left = sps->crop_rect_x;
1060 padding_right = sps->width - sps->crop_rect_x - display_width;
1061 padding_top = sps->crop_rect_y;
1062 padding_bottom = sps->height - sps->crop_rect_y - display_height;
1064 display_width = sps->width;
1065 display_height = sps->height;
1066 padding_left = padding_right = padding_top = padding_bottom = 0;
1069 profile = _get_profile (self, sps, max_dpb_size);
1070 if (profile == VAProfileNone)
1071 return GST_FLOW_NOT_NEGOTIATED;
1073 rt_format = _get_rtformat (self, sps->bit_depth_luma_minus8 + 8,
1074 sps->bit_depth_chroma_minus8 + 8, sps->chroma_format_idc);
1076 return GST_FLOW_NOT_NEGOTIATED;
1078 if (!gst_va_decoder_config_is_equal (base->decoder, profile,
1079 rt_format, sps->width, sps->height)) {
1080 base->profile = profile;
1081 base->rt_format = rt_format;
1082 self->coded_width = sps->width;
1083 self->coded_height = sps->height;
1085 negotiation_needed = TRUE;
1086 GST_INFO_OBJECT (self, "Format changed to %s [%x] (%dx%d)",
1087 gst_va_profile_name (profile), rt_format, self->coded_width,
1088 self->coded_height);
1091 if (base->width != display_width || base->height != display_height) {
1092 base->width = display_width;
1093 base->height = display_height;
1095 negotiation_needed = TRUE;
1096 GST_INFO_OBJECT (self, "Resolution changed to %dx%d", base->width,
1100 base->need_valign = base->width < self->coded_width
1101 || base->height < self->coded_height;
1102 if (base->need_valign) {
1104 if (base->valign.padding_left != padding_left ||
1105 base->valign.padding_right != padding_right ||
1106 base->valign.padding_top != padding_top ||
1107 base->valign.padding_bottom != padding_bottom) {
1108 negotiation_needed = TRUE;
1109 GST_INFO_OBJECT (self, "crop rect changed to (%d,%d)-->(%d,%d)",
1110 padding_left, padding_top, padding_right, padding_bottom);
1112 base->valign = (GstVideoAlignment) {
1113 .padding_left = padding_left,
1114 .padding_right = padding_right,
1115 .padding_top = padding_top,
1116 .padding_bottom = padding_bottom,
1121 base->min_buffers = self->dpb_size + 4; /* dpb size + scratch surfaces */
1123 if (negotiation_needed) {
1124 self->need_negotiation = TRUE;
1125 if (!gst_video_decoder_negotiate (GST_VIDEO_DECODER (self))) {
1126 GST_ERROR_OBJECT (self, "Failed to negotiate with downstream");
1127 return GST_FLOW_NOT_NEGOTIATED;
1132 /* FIXME: We don't have parser API for sps_range_extension, so
1133 * assuming high_precision_offsets_enabled_flag as zero */
1134 guint high_precision_offsets_enabled_flag = 0, bitdepthC = 0;
1136 /* Calculate WpOffsetHalfRangeC: (7-34) */
1137 bitdepthC = sps->bit_depth_chroma_minus8 + 8;
1138 self->WpOffsetHalfRangeC =
1139 1 << (high_precision_offsets_enabled_flag ? (bitdepthC - 1) : 7);
1146 _complete_sink_caps (GstCaps * sinkcaps)
1148 GstCaps *caps = gst_caps_copy (sinkcaps);
1149 GValue val = G_VALUE_INIT;
1150 const gchar *streamformat[] = { "hvc1", "hev1", "byte-stream" };
1153 g_value_init (&val, G_TYPE_STRING);
1154 g_value_set_string (&val, "au");
1155 gst_caps_set_value (caps, "alignment", &val);
1156 g_value_unset (&val);
1158 gst_value_list_init (&val, G_N_ELEMENTS (streamformat));
1159 for (i = 0; i < G_N_ELEMENTS (streamformat); i++) {
1160 GValue v = G_VALUE_INIT;
1162 g_value_init (&v, G_TYPE_STRING);
1163 g_value_set_string (&v, streamformat[i]);
1164 gst_value_list_append_value (&val, &v);
1167 gst_caps_set_value (caps, "stream-format", &val);
1168 g_value_unset (&val);
1174 gst_va_h265_dec_getcaps (GstVideoDecoder * decoder, GstCaps * filter)
1176 GstCaps *sinkcaps, *caps = NULL, *tmp;
1177 GstVaBaseDec *base = GST_VA_BASE_DEC (decoder);
1180 caps = gst_va_decoder_get_sinkpad_caps (base->decoder);
1183 sinkcaps = _complete_sink_caps (caps);
1184 gst_caps_unref (caps);
1186 tmp = gst_caps_intersect_full (filter, sinkcaps,
1187 GST_CAPS_INTERSECT_FIRST);
1188 gst_caps_unref (sinkcaps);
1193 GST_LOG_OBJECT (base, "Returning caps %" GST_PTR_FORMAT, caps);
1195 caps = gst_video_decoder_proxy_getcaps (decoder, NULL, filter);
1202 gst_va_h265_dec_negotiate (GstVideoDecoder * decoder)
1204 GstVaBaseDec *base = GST_VA_BASE_DEC (decoder);
1205 GstVaH265Dec *self = GST_VA_H265_DEC (decoder);
1206 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
1207 GstCapsFeatures *capsfeatures = NULL;
1208 GstH265Decoder *h265dec = GST_H265_DECODER (decoder);
1210 /* Ignore downstream renegotiation request. */
1211 if (!self->need_negotiation)
1214 self->need_negotiation = FALSE;
1216 if (gst_va_decoder_is_open (base->decoder)
1217 && !gst_va_decoder_close (base->decoder))
1220 if (!gst_va_decoder_open (base->decoder, base->profile, base->rt_format))
1223 if (!gst_va_decoder_set_frame_size (base->decoder, self->coded_width,
1224 self->coded_height))
1227 if (base->output_state)
1228 gst_video_codec_state_unref (base->output_state);
1230 gst_va_base_dec_get_preferred_format_and_caps_features (base, &format,
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);
1285 gst_va_base_dec_class_init (GST_VA_BASE_DEC_CLASS (g_class), HEVC,
1286 cdata->render_device_path, cdata->sink_caps, cdata->src_caps,
1287 src_doc_caps, sink_doc_caps);
1289 gobject_class->dispose = gst_va_h265_dec_dispose;
1291 decoder_class->getcaps = GST_DEBUG_FUNCPTR (gst_va_h265_dec_getcaps);
1292 decoder_class->negotiate = GST_DEBUG_FUNCPTR (gst_va_h265_dec_negotiate);
1294 h265decoder_class->new_sequence =
1295 GST_DEBUG_FUNCPTR (gst_va_h265_dec_new_sequence);
1296 h265decoder_class->decode_slice =
1297 GST_DEBUG_FUNCPTR (gst_va_h265_dec_decode_slice);
1299 h265decoder_class->new_picture =
1300 GST_DEBUG_FUNCPTR (gst_va_h265_dec_new_picture);
1301 h265decoder_class->output_picture =
1302 GST_DEBUG_FUNCPTR (gst_va_h265_dec_output_picture);
1303 h265decoder_class->start_picture =
1304 GST_DEBUG_FUNCPTR (gst_va_h265_dec_start_picture);
1305 h265decoder_class->end_picture =
1306 GST_DEBUG_FUNCPTR (gst_va_h265_dec_end_picture);
1309 g_free (cdata->description);
1310 g_free (cdata->render_device_path);
1311 gst_caps_unref (cdata->src_caps);
1312 gst_caps_unref (cdata->sink_caps);
1317 gst_va_h265_dec_init (GTypeInstance * instance, gpointer g_class)
1319 gst_va_base_dec_init (GST_VA_BASE_DEC (instance), GST_CAT_DEFAULT);
1320 gst_h265_decoder_set_process_ref_pic_lists (GST_H265_DECODER (instance),
1325 _register_debug_category (gpointer data)
1327 GST_DEBUG_CATEGORY_INIT (gst_va_h265dec_debug, "vah265dec", 0,
1334 gst_va_h265_dec_register (GstPlugin * plugin, GstVaDevice * device,
1335 GstCaps * sink_caps, GstCaps * src_caps, guint rank)
1337 static GOnce debug_once = G_ONCE_INIT;
1339 GTypeInfo type_info = {
1340 .class_size = sizeof (GstVaH265DecClass),
1341 .class_init = gst_va_h265_dec_class_init,
1342 .instance_size = sizeof (GstVaH265Dec),
1343 .instance_init = gst_va_h265_dec_init,
1345 struct CData *cdata;
1347 gchar *type_name, *feature_name;
1349 g_return_val_if_fail (GST_IS_PLUGIN (plugin), FALSE);
1350 g_return_val_if_fail (GST_IS_VA_DEVICE (device), FALSE);
1351 g_return_val_if_fail (GST_IS_CAPS (sink_caps), FALSE);
1352 g_return_val_if_fail (GST_IS_CAPS (src_caps), FALSE);
1354 cdata = g_new (struct CData, 1);
1355 cdata->description = NULL;
1356 cdata->render_device_path = g_strdup (device->render_device_path);
1357 cdata->sink_caps = _complete_sink_caps (sink_caps);
1358 cdata->src_caps = gst_caps_ref (src_caps);
1360 /* class data will be leaked if the element never gets instantiated */
1361 GST_MINI_OBJECT_FLAG_SET (cdata->sink_caps,
1362 GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
1363 GST_MINI_OBJECT_FLAG_SET (src_caps, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
1365 type_info.class_data = cdata;
1367 type_name = g_strdup ("GstVaH265Dec");
1368 feature_name = g_strdup ("vah265dec");
1370 /* The first decoder to be registered should use a constant name,
1371 * like vah265dec, for any additional decoders, we create unique
1372 * names, using inserting the render device name. */
1373 if (g_type_from_name (type_name)) {
1374 gchar *basename = g_path_get_basename (device->render_device_path);
1376 g_free (feature_name);
1377 type_name = g_strdup_printf ("GstVa%sH265Dec", basename);
1378 feature_name = g_strdup_printf ("va%sh265dec", basename);
1379 cdata->description = basename;
1381 /* lower rank for non-first device */
1386 g_once (&debug_once, _register_debug_category, NULL);
1388 type = g_type_register_static (GST_TYPE_H265_DECODER,
1389 type_name, &type_info, 0);
1391 ret = gst_element_register (plugin, feature_name, rank, type);
1394 g_free (feature_name);