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;
104 static GstElementClass *parent_class = NULL;
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 || profile == VAProfileHEVCSccMain10
132 || profile == VAProfileHEVCSccMain444
133 #if VA_CHECK_VERSION(1, 8, 0)
134 || profile == VAProfileHEVCSccMain444_10
143 _set_last_slice_flag (GstVaH265Dec * self)
145 self->prev_slice.param.base.LongSliceFlags.fields.LastSliceOfPic = 1;
149 _replace_previous_slice (GstVaH265Dec * self, guint8 * data, guint size)
151 struct slice *slice = &self->prev_slice;
152 gboolean do_reset = (slice->size < size);
154 if (!data || do_reset) {
155 g_clear_pointer (&slice->data, g_free);
163 GST_LOG_OBJECT (self, "allocating slice data %u", size);
164 slice->data = g_malloc (size);
167 memcpy (slice->data, data, size);
172 _submit_previous_slice (GstVaBaseDec * base, GstVaDecodePicture * va_pic)
174 GstVaH265Dec *self = GST_VA_H265_DEC (base);
179 slice = &self->prev_slice;
180 if (!slice->data && slice->size == 0)
182 if (!slice->data || slice->size == 0)
185 param_size = _is_range_extension_profile (self->parent.profile)
186 || _is_screen_content_ext_profile (self->parent.profile) ?
187 sizeof (slice->param) : sizeof (slice->param.base);
188 ret = gst_va_decoder_add_slice_buffer (base->decoder, va_pic, &slice->param,
189 param_size, slice->data, slice->size);
195 gst_va_h265_dec_end_picture (GstH265Decoder * decoder, GstH265Picture * picture)
197 GstVaBaseDec *base = GST_VA_BASE_DEC (decoder);
198 GstVaH265Dec *self = GST_VA_H265_DEC (decoder);
199 GstVaDecodePicture *va_pic;
202 GST_LOG_OBJECT (base, "end picture %p, (poc %d)",
203 picture, picture->pic_order_cnt);
205 va_pic = gst_h265_picture_get_user_data (picture);
207 _set_last_slice_flag (self);
208 ret = _submit_previous_slice (base, va_pic);
210 /* TODO(victor): optimization: this could be done at decoder's
212 _replace_previous_slice (self, NULL, 0);
215 GST_ERROR_OBJECT (self, "Failed to submit the previous slice");
216 return GST_FLOW_ERROR;
219 ret = gst_va_decoder_decode (base->decoder, va_pic);
221 GST_ERROR_OBJECT (self, "Failed at end picture %p, (poc %d)",
222 picture, picture->pic_order_cnt);
223 return GST_FLOW_ERROR;
230 gst_va_h265_dec_output_picture (GstH265Decoder * decoder,
231 GstVideoCodecFrame * frame, GstH265Picture * picture)
233 GstVaBaseDec *base = GST_VA_BASE_DEC (decoder);
234 GstVaH265Dec *self = GST_VA_H265_DEC (decoder);
235 GstVaDecodePicture *va_pic;
237 va_pic = gst_h265_picture_get_user_data (picture);
238 g_assert (va_pic->gstbuffer);
240 GST_LOG_OBJECT (self,
241 "Outputting picture %p (poc %d)", picture, picture->pic_order_cnt);
243 if (self->last_ret != GST_FLOW_OK) {
244 gst_h265_picture_unref (picture);
245 _replace_previous_slice (self, NULL, 0);
246 gst_video_decoder_drop_frame (GST_VIDEO_DECODER (self), frame);
247 return self->last_ret;
250 gst_buffer_replace (&frame->output_buffer, va_pic->gstbuffer);
252 if (base->copy_frames)
253 gst_va_base_dec_copy_output_buffer (base, frame);
255 gst_h265_picture_unref (picture);
257 return gst_video_decoder_finish_frame (GST_VIDEO_DECODER (self), frame);
261 _init_vaapi_pic (VAPictureHEVC * va_picture)
263 va_picture->picture_id = VA_INVALID_ID;
264 va_picture->flags = VA_PICTURE_HEVC_INVALID;
265 va_picture->pic_order_cnt = 0;
269 _find_frame_rps_type (GstH265Decoder * decoder, GstH265Picture * ref_pic)
273 for (i = 0; i < G_N_ELEMENTS (decoder->RefPicSetStCurrBefore); i++) {
274 if (ref_pic == decoder->RefPicSetStCurrBefore[i])
275 return VA_PICTURE_HEVC_RPS_ST_CURR_BEFORE;
278 for (i = 0; i < G_N_ELEMENTS (decoder->RefPicSetStCurrAfter); i++) {
279 if (ref_pic == decoder->RefPicSetStCurrAfter[i])
280 return VA_PICTURE_HEVC_RPS_ST_CURR_AFTER;
283 for (i = 0; i < G_N_ELEMENTS (decoder->RefPicSetLtCurr); i++) {
284 if (ref_pic == decoder->RefPicSetLtCurr[i])
285 return VA_PICTURE_HEVC_RPS_LT_CURR;
293 _fill_vaapi_pic (GstH265Decoder * decoder, VAPictureHEVC * va_picture,
294 GstH265Picture * picture)
296 GstVaDecodePicture *va_pic;
298 va_pic = gst_h265_picture_get_user_data (picture);
301 _init_vaapi_pic (va_picture);
305 va_picture->picture_id = gst_va_decode_picture_get_surface (va_pic);
306 va_picture->pic_order_cnt = picture->pic_order_cnt;
307 va_picture->flags = 0;
309 if (picture->ref && picture->long_term)
310 va_picture->flags |= VA_PICTURE_HEVC_LONG_TERM_REFERENCE;
312 va_picture->flags |= _find_frame_rps_type (decoder, picture);
316 _get_reference_index (GstH265Decoder * decoder, GstH265Picture * picture)
318 GstVaH265Dec *self = GST_VA_H265_DEC (decoder);
324 for (i = 0; i < 15; i++) {
325 VAPictureHEVC *ref_va_pic = &self->pic_param.base.ReferenceFrames[i];
327 if (ref_va_pic->picture_id == VA_INVALID_ID)
330 if (ref_va_pic->pic_order_cnt == picture->pic_order_cnt)
337 /* fill the VA API reference picture lists from the GstCodec reference
340 _fill_ref_pic_list (GstH265Decoder * decoder, GstH265Picture * cur_pic,
341 guint8 va_reflist[15], GArray * reflist)
345 for (i = 0; i < reflist->len && i < 15; i++) {
346 GstH265Picture *picture = g_array_index (reflist, GstH265Picture *, i);
347 va_reflist[i] = _get_reference_index (decoder, picture);
351 va_reflist[i] = 0xFF;
355 _fill_pred_weight_table (GstVaH265Dec * self, GstH265SliceHdr * header,
356 VASliceParameterBufferHEVCExtension * slice_param)
358 gint chroma_weight, chroma_log2_weight_denom;
360 GstH265PPS *pps = header->pps;
361 gboolean is_rext = _is_range_extension_profile (self->parent.profile);
363 if (GST_H265_IS_I_SLICE (header) ||
364 (!pps->weighted_pred_flag && GST_H265_IS_P_SLICE (header)) ||
365 (!pps->weighted_bipred_flag && GST_H265_IS_B_SLICE (header)))
368 slice_param->base.luma_log2_weight_denom =
369 header->pred_weight_table.luma_log2_weight_denom;
371 if (pps->sps->chroma_array_type != 0)
372 slice_param->base.delta_chroma_log2_weight_denom =
373 header->pred_weight_table.delta_chroma_log2_weight_denom;
375 for (i = 0; i <= header->num_ref_idx_l0_active_minus1; i++) {
376 if (!header->pred_weight_table.luma_weight_l0_flag[i])
379 slice_param->base.delta_luma_weight_l0[i] =
380 header->pred_weight_table.delta_luma_weight_l0[i];
381 slice_param->base.luma_offset_l0[i] =
382 header->pred_weight_table.luma_offset_l0[i];
385 slice_param->rext.luma_offset_l0[i] =
386 header->pred_weight_table.luma_offset_l0[i];
390 chroma_log2_weight_denom = slice_param->base.luma_log2_weight_denom +
391 slice_param->base.delta_chroma_log2_weight_denom;
393 for (i = 0; i <= header->num_ref_idx_l0_active_minus1; i++) {
394 if (!header->pred_weight_table.chroma_weight_l0_flag[i])
397 for (j = 0; j < 2; j++) {
398 gint16 delta_chroma_offset_l0 =
399 header->pred_weight_table.delta_chroma_offset_l0[i][j];
402 slice_param->base.delta_chroma_weight_l0[i][j] =
403 header->pred_weight_table.delta_chroma_weight_l0[i][j];
405 /* Find ChromaWeightL0 */
406 chroma_weight = (1 << chroma_log2_weight_denom) +
407 header->pred_weight_table.delta_chroma_weight_l0[i][j];
408 chroma_offset = self->WpOffsetHalfRangeC + delta_chroma_offset_l0
409 - ((self->WpOffsetHalfRangeC * chroma_weight)
410 >> chroma_log2_weight_denom);
413 slice_param->base.ChromaOffsetL0[i][j] = CLAMP (chroma_offset,
414 -self->WpOffsetHalfRangeC, self->WpOffsetHalfRangeC - 1);
417 slice_param->rext.ChromaOffsetL0[i][j] =
418 slice_param->base.ChromaOffsetL0[i][j];
423 /* Skip l1 if this is not a B-Frame. */
424 if (!GST_H265_IS_B_SLICE (header))
427 for (i = 0; i <= header->num_ref_idx_l1_active_minus1; i++) {
428 if (!header->pred_weight_table.luma_weight_l1_flag[i])
431 slice_param->base.delta_luma_weight_l1[i] =
432 header->pred_weight_table.delta_luma_weight_l1[i];
433 slice_param->base.luma_offset_l1[i] =
434 header->pred_weight_table.luma_offset_l1[i];
437 slice_param->rext.luma_offset_l1[i] =
438 header->pred_weight_table.luma_offset_l1[i];
442 for (i = 0; i <= header->num_ref_idx_l1_active_minus1; i++) {
443 if (!header->pred_weight_table.chroma_weight_l1_flag[i])
446 for (j = 0; j < 2; j++) {
447 gint16 delta_chroma_offset_l1 =
448 header->pred_weight_table.delta_chroma_offset_l1[i][j];
451 slice_param->base.delta_chroma_weight_l1[i][j] =
452 header->pred_weight_table.delta_chroma_weight_l1[i][j];
454 /* Find ChromaWeightL1 */
455 chroma_weight = (1 << chroma_log2_weight_denom) +
456 header->pred_weight_table.delta_chroma_weight_l1[i][j];
458 chroma_offset = self->WpOffsetHalfRangeC + delta_chroma_offset_l1
459 - ((self->WpOffsetHalfRangeC * chroma_weight)
460 >> chroma_log2_weight_denom);
463 slice_param->base.ChromaOffsetL1[i][j] = CLAMP (chroma_offset,
464 -self->WpOffsetHalfRangeC, self->WpOffsetHalfRangeC - 1);
467 slice_param->rext.ChromaOffsetL1[i][j] =
468 slice_param->base.ChromaOffsetL1[i][j];
475 _get_slice_data_byte_offset (GstH265SliceHdr * slice_hdr,
476 guint nal_header_bytes)
480 epb_count = slice_hdr->n_emulation_prevention_bytes;
481 return nal_header_bytes + (slice_hdr->header_size + 7) / 8 - epb_count;
485 gst_va_h265_dec_decode_slice (GstH265Decoder * decoder,
486 GstH265Picture * picture, GstH265Slice * slice, GArray * ref_pic_list0,
487 GArray * ref_pic_list1)
489 GstH265SliceHdr *header = &slice->header;
490 GstH265NalUnit *nalu = &slice->nalu;
491 GstVaBaseDec *base = GST_VA_BASE_DEC (decoder);
492 GstVaH265Dec *self = GST_VA_H265_DEC (decoder);
493 GstVaDecodePicture *va_pic;
494 VASliceParameterBufferHEVCExtension *slice_param;
496 va_pic = gst_h265_picture_get_user_data (picture);
497 if (!_submit_previous_slice (base, va_pic)) {
498 _replace_previous_slice (self, NULL, 0);
499 GST_ERROR_OBJECT (base, "Failed to submit previous slice buffers");
500 return GST_FLOW_ERROR;
503 slice_param = &self->prev_slice.param;
506 slice_param->base = (VASliceParameterBufferHEVC) {
507 .slice_data_size = nalu->size,
508 .slice_data_offset = 0,
509 .slice_data_flag = VA_SLICE_DATA_FLAG_ALL,
510 .slice_data_byte_offset = _get_slice_data_byte_offset (header, nalu->header_bytes),
511 .slice_segment_address = header->segment_address,
512 .collocated_ref_idx = header->temporal_mvp_enabled_flag ? header->collocated_ref_idx : 0xFF,
513 .num_ref_idx_l0_active_minus1 = header->num_ref_idx_l0_active_minus1,
514 .num_ref_idx_l1_active_minus1 = header->num_ref_idx_l1_active_minus1,
515 .slice_qp_delta = header->qp_delta,
516 .slice_cb_qp_offset = header->cb_qp_offset,
517 .slice_cr_qp_offset = header->cr_qp_offset,
518 .slice_beta_offset_div2 = header->beta_offset_div2,
519 .slice_tc_offset_div2 = header->tc_offset_div2,
520 .five_minus_max_num_merge_cand = header->five_minus_max_num_merge_cand,
521 .num_entry_point_offsets = header->num_entry_point_offsets,
522 .entry_offset_to_subset_array = 0, /* does not exist in spec */
523 .slice_data_num_emu_prevn_bytes = header->n_emulation_prevention_bytes,
524 .LongSliceFlags.fields = {
525 .LastSliceOfPic = 0, /* the last one will be set on end_picture() */
526 .dependent_slice_segment_flag = header->dependent_slice_segment_flag,
527 .slice_type = header->type,
528 .color_plane_id = header->colour_plane_id,
529 .slice_sao_luma_flag = header->sao_luma_flag,
530 .slice_sao_chroma_flag = header->sao_chroma_flag,
531 .mvd_l1_zero_flag = header->mvd_l1_zero_flag,
532 .cabac_init_flag = header->cabac_init_flag,
533 .slice_temporal_mvp_enabled_flag = header->temporal_mvp_enabled_flag,
534 .slice_deblocking_filter_disabled_flag =
535 header->deblocking_filter_disabled_flag,
536 .collocated_from_l0_flag = header->collocated_from_l0_flag,
537 .slice_loop_filter_across_slices_enabled_flag =
538 header->loop_filter_across_slices_enabled_flag,
543 if (_is_range_extension_profile (base->profile)
544 || _is_screen_content_ext_profile (base->profile)) {
546 slice_param->rext = (VASliceParameterBufferHEVCRext) {
547 .slice_ext_flags.bits = {
548 .cu_chroma_qp_offset_enabled_flag = header->cu_chroma_qp_offset_enabled_flag,
549 .use_integer_mv_flag = header->use_integer_mv_flag,
551 .slice_act_y_qp_offset = header->slice_act_y_qp_offset,
552 .slice_act_cb_qp_offset = header->slice_act_cb_qp_offset,
553 .slice_act_cr_qp_offset = header->slice_act_cr_qp_offset,
558 _fill_ref_pic_list (decoder, picture, slice_param->base.RefPicList[0],
560 _fill_ref_pic_list (decoder, picture, slice_param->base.RefPicList[1],
563 _fill_pred_weight_table (GST_VA_H265_DEC (decoder), header, slice_param);
565 _replace_previous_slice (self, slice->nalu.data + slice->nalu.offset,
572 _fill_picture_range_ext_parameter (GstVaH265Dec * decoder,
573 GstH265SPS * sps, GstH265PPS * pps)
575 VAPictureParameterBufferHEVCRext *pic_param = &decoder->pic_param.rext;
577 GstH265SPSExtensionParams *sps_ext = &sps->sps_extension_params;
578 GstH265PPSExtensionParams *pps_ext = &pps->pps_extension_params;
581 *pic_param = (VAPictureParameterBufferHEVCRext) {
582 .range_extension_pic_fields.bits = {
583 .transform_skip_rotation_enabled_flag = sps_ext->transform_skip_rotation_enabled_flag,
584 .transform_skip_context_enabled_flag = sps_ext->transform_skip_context_enabled_flag,
585 .implicit_rdpcm_enabled_flag = sps_ext->implicit_rdpcm_enabled_flag,
586 .explicit_rdpcm_enabled_flag = sps_ext->explicit_rdpcm_enabled_flag,
587 .extended_precision_processing_flag = sps_ext->extended_precision_processing_flag,
588 .intra_smoothing_disabled_flag = sps_ext->intra_smoothing_disabled_flag,
589 .high_precision_offsets_enabled_flag = sps_ext->high_precision_offsets_enabled_flag,
590 .persistent_rice_adaptation_enabled_flag = sps_ext->persistent_rice_adaptation_enabled_flag,
591 .cabac_bypass_alignment_enabled_flag = sps_ext->cabac_bypass_alignment_enabled_flag,
592 .cross_component_prediction_enabled_flag = pps_ext->cross_component_prediction_enabled_flag,
593 .chroma_qp_offset_list_enabled_flag = pps_ext->chroma_qp_offset_list_enabled_flag,
595 .diff_cu_chroma_qp_offset_depth = pps_ext->diff_cu_chroma_qp_offset_depth,
596 .chroma_qp_offset_list_len_minus1 = pps_ext->chroma_qp_offset_list_len_minus1,
597 .log2_sao_offset_scale_luma = pps_ext->log2_sao_offset_scale_luma,
598 .log2_sao_offset_scale_chroma = pps_ext->log2_sao_offset_scale_chroma,
599 .log2_max_transform_skip_block_size_minus2 = pps_ext->log2_max_transform_skip_block_size_minus2,
603 memcpy (pic_param->cb_qp_offset_list, pps_ext->cb_qp_offset_list,
604 sizeof (pic_param->cb_qp_offset_list));
605 memcpy (pic_param->cr_qp_offset_list, pps_ext->cr_qp_offset_list,
606 sizeof (pic_param->cr_qp_offset_list));
610 _fill_screen_content_ext_parameter (GstVaH265Dec * decoder,
611 GstH265SPS * sps, GstH265PPS * pps)
613 VAPictureParameterBufferHEVCScc *pic_param = &decoder->pic_param.scc;
614 const GstH265PPSSccExtensionParams *pps_scc = &pps->pps_scc_extension_params;
615 const GstH265SPSSccExtensionParams *sps_scc = &sps->sps_scc_extension_params;
620 *pic_param = (VAPictureParameterBufferHEVCScc) {
621 .screen_content_pic_fields.bits = {
622 .pps_curr_pic_ref_enabled_flag = pps_scc->pps_curr_pic_ref_enabled_flag,
623 .palette_mode_enabled_flag = sps_scc->palette_mode_enabled_flag,
624 .motion_vector_resolution_control_idc = sps_scc->motion_vector_resolution_control_idc,
625 .intra_boundary_filtering_disabled_flag = sps_scc->intra_boundary_filtering_disabled_flag,
626 .residual_adaptive_colour_transform_enabled_flag = pps_scc->residual_adaptive_colour_transform_enabled_flag,
627 .pps_slice_act_qp_offsets_present_flag = pps_scc->pps_slice_act_qp_offsets_present_flag,
629 .palette_max_size = sps_scc->palette_max_size,
630 .delta_palette_max_predictor_size = sps_scc->delta_palette_max_predictor_size,
631 .pps_act_y_qp_offset_plus5 = pps_scc->pps_act_y_qp_offset_plus5,
632 .pps_act_cb_qp_offset_plus5 = pps_scc->pps_act_cb_qp_offset_plus5,
633 .pps_act_cr_qp_offset_plus3 = pps_scc->pps_act_cr_qp_offset_plus3,
637 /* firstly use the pps, then sps */
638 num_comps = sps->chroma_format_idc ? 3 : 1;
640 if (pps_scc->pps_palette_predictor_initializers_present_flag) {
641 pic_param->predictor_palette_size =
642 pps_scc->pps_num_palette_predictor_initializer;
643 for (n = 0; n < num_comps; n++)
644 for (i = 0; i < pps_scc->pps_num_palette_predictor_initializer; i++)
645 pic_param->predictor_palette_entries[n][i] =
646 (uint16_t) pps_scc->pps_palette_predictor_initializer[n][i];
647 } else if (sps_scc->sps_palette_predictor_initializers_present_flag) {
648 pic_param->predictor_palette_size =
649 sps_scc->sps_num_palette_predictor_initializer_minus1 + 1;
650 for (n = 0; n < num_comps; n++)
652 i < sps_scc->sps_num_palette_predictor_initializer_minus1 + 1; i++)
653 pic_param->predictor_palette_entries[n][i] =
654 (uint16_t) sps_scc->sps_palette_predictor_initializer[n][i];
659 gst_va_h265_dec_start_picture (GstH265Decoder * decoder,
660 GstH265Picture * picture, GstH265Slice * slice, GstH265Dpb * dpb)
664 GstVaH265Dec *self = GST_VA_H265_DEC (decoder);
665 GstVaBaseDec *base = &self->parent;
666 GstVaDecodePicture *va_pic;
667 GstH265ScalingList *scaling_list = NULL;
668 VAIQMatrixBufferHEVC iq_matrix = { 0, };
669 VAPictureParameterBufferHEVCExtension *pic_param = &self->pic_param;
670 gsize pic_param_size;
673 va_pic = gst_h265_picture_get_user_data (picture);
675 pps = slice->header.pps;
679 pic_param->base = (VAPictureParameterBufferHEVC) {
680 .pic_width_in_luma_samples = sps->pic_width_in_luma_samples,
681 .pic_height_in_luma_samples = sps->pic_height_in_luma_samples,
682 .sps_max_dec_pic_buffering_minus1 = sps->max_dec_pic_buffering_minus1[sps->max_sub_layers_minus1],
683 .bit_depth_luma_minus8 = sps->bit_depth_luma_minus8,
684 .bit_depth_chroma_minus8 = sps->bit_depth_chroma_minus8,
685 .pcm_sample_bit_depth_luma_minus1 = sps->pcm_sample_bit_depth_luma_minus1,
686 .pcm_sample_bit_depth_chroma_minus1 = sps->pcm_sample_bit_depth_chroma_minus1,
687 .log2_min_luma_coding_block_size_minus3 = sps->log2_min_luma_coding_block_size_minus3,
688 .log2_diff_max_min_luma_coding_block_size = sps->log2_diff_max_min_luma_coding_block_size,
689 .log2_min_transform_block_size_minus2 = sps->log2_min_transform_block_size_minus2,
690 .log2_diff_max_min_transform_block_size = sps->log2_diff_max_min_transform_block_size,
691 .log2_min_pcm_luma_coding_block_size_minus3 = sps->log2_min_pcm_luma_coding_block_size_minus3,
692 .log2_diff_max_min_pcm_luma_coding_block_size = sps->log2_diff_max_min_pcm_luma_coding_block_size,
693 .max_transform_hierarchy_depth_intra = sps->max_transform_hierarchy_depth_intra,
694 .max_transform_hierarchy_depth_inter = sps->max_transform_hierarchy_depth_inter,
695 .init_qp_minus26 = pps->init_qp_minus26,
696 .diff_cu_qp_delta_depth = pps->diff_cu_qp_delta_depth,
697 .pps_cb_qp_offset = pps->cb_qp_offset,
698 .pps_cr_qp_offset = pps->cr_qp_offset,
699 .log2_parallel_merge_level_minus2 = pps->log2_parallel_merge_level_minus2,
700 .num_tile_columns_minus1 = pps->num_tile_columns_minus1,
701 .num_tile_rows_minus1 = pps->num_tile_rows_minus1,
702 .log2_max_pic_order_cnt_lsb_minus4 = sps->log2_max_pic_order_cnt_lsb_minus4,
703 .num_short_term_ref_pic_sets = sps->num_short_term_ref_pic_sets,
704 .num_long_term_ref_pic_sps = sps->num_long_term_ref_pics_sps,
705 .num_ref_idx_l0_default_active_minus1 = pps->num_ref_idx_l0_default_active_minus1,
706 .num_ref_idx_l1_default_active_minus1 = pps->num_ref_idx_l1_default_active_minus1,
707 .pps_beta_offset_div2 = pps->beta_offset_div2,
708 .pps_tc_offset_div2 = pps->tc_offset_div2,
709 .num_extra_slice_header_bits = pps->num_extra_slice_header_bits,
710 .st_rps_bits = slice->header.short_term_ref_pic_set_size, /* FIXME missing emulation bits removal */
712 .chroma_format_idc = sps->chroma_format_idc,
713 .separate_colour_plane_flag = sps->separate_colour_plane_flag,
714 .pcm_enabled_flag = sps->pcm_enabled_flag,
715 .scaling_list_enabled_flag = sps->scaling_list_enabled_flag,
716 .transform_skip_enabled_flag = pps->transform_skip_enabled_flag,
717 .amp_enabled_flag = sps->amp_enabled_flag,
718 .strong_intra_smoothing_enabled_flag = sps->strong_intra_smoothing_enabled_flag,
719 .sign_data_hiding_enabled_flag = pps->sign_data_hiding_enabled_flag,
720 .constrained_intra_pred_flag = pps->constrained_intra_pred_flag,
721 .cu_qp_delta_enabled_flag = pps->cu_qp_delta_enabled_flag,
722 .weighted_pred_flag = pps->weighted_pred_flag,
723 .weighted_bipred_flag = pps->weighted_bipred_flag,
724 .transquant_bypass_enabled_flag = pps->transquant_bypass_enabled_flag,
725 .tiles_enabled_flag = pps->tiles_enabled_flag,
726 .entropy_coding_sync_enabled_flag = pps->entropy_coding_sync_enabled_flag,
727 .pps_loop_filter_across_slices_enabled_flag = pps->loop_filter_across_slices_enabled_flag,
728 .loop_filter_across_tiles_enabled_flag = pps->loop_filter_across_tiles_enabled_flag,
729 .pcm_loop_filter_disabled_flag = sps->pcm_loop_filter_disabled_flag,
730 /* Not set by FFMPEG either */
731 .NoPicReorderingFlag = 0,
734 .slice_parsing_fields.bits = {
735 .lists_modification_present_flag = pps->lists_modification_present_flag,
736 .long_term_ref_pics_present_flag = sps->long_term_ref_pics_present_flag,
737 .sps_temporal_mvp_enabled_flag = sps->temporal_mvp_enabled_flag,
738 .cabac_init_present_flag = pps->cabac_init_present_flag,
739 .output_flag_present_flag = pps->output_flag_present_flag,
740 .dependent_slice_segments_enabled_flag = pps->dependent_slice_segments_enabled_flag,
741 .pps_slice_chroma_qp_offsets_present_flag = pps->slice_chroma_qp_offsets_present_flag,
742 .sample_adaptive_offset_enabled_flag = sps->sample_adaptive_offset_enabled_flag,
743 .deblocking_filter_override_enabled_flag = pps->deblocking_filter_override_enabled_flag,
744 .pps_disable_deblocking_filter_flag = pps->deblocking_filter_disabled_flag,
745 .slice_segment_header_extension_present_flag = pps->slice_segment_header_extension_present_flag,
746 .RapPicFlag = picture->RapPicFlag,
747 .IdrPicFlag = GST_H265_IS_NAL_TYPE_IDR (slice->nalu.type),
748 .IntraPicFlag = GST_H265_IS_NAL_TYPE_IRAP (slice->nalu.type),
753 if (_is_range_extension_profile (self->parent.profile)
754 || _is_screen_content_ext_profile (self->parent.profile)) {
755 _fill_picture_range_ext_parameter (self, sps, pps);
756 if (_is_screen_content_ext_profile (self->parent.profile))
757 _fill_screen_content_ext_parameter (self, sps, pps);
760 for (i = 0; i <= pps->num_tile_columns_minus1; i++)
761 pic_param->base.column_width_minus1[i] = pps->column_width_minus1[i];
763 for (i = 0; i <= pps->num_tile_rows_minus1; i++)
764 pic_param->base.row_height_minus1[i] = pps->row_height_minus1[i];
766 _fill_vaapi_pic (decoder, &pic_param->base.CurrPic, picture);
768 /* reference frames */
770 GArray *ref_list = gst_h265_dpb_get_pictures_all (dpb);
774 for (j = 0; j < 15 && j < ref_list->len; j++) {
775 GstH265Picture *pic = g_array_index (ref_list, GstH265Picture *, j);
778 _fill_vaapi_pic (decoder, &pic_param->base.ReferenceFrames[i], pic);
782 g_array_unref (ref_list);
784 /* 7.4.3.3.3, the current decoded picture is marked as "used for
785 long-term reference". Current picture is not in the DPB now. */
786 if (pps->pps_scc_extension_params.pps_curr_pic_ref_enabled_flag && i < 15) {
787 pic_param->base.ReferenceFrames[i].picture_id =
788 gst_va_decode_picture_get_surface (gst_h265_picture_get_user_data
790 pic_param->base.ReferenceFrames[i].pic_order_cnt = picture->pic_order_cnt;
791 pic_param->base.ReferenceFrames[i].flags |=
792 VA_PICTURE_HEVC_LONG_TERM_REFERENCE;
793 pic_param->base.ReferenceFrames[i].flags |=
794 _find_frame_rps_type (decoder, picture);
799 _init_vaapi_pic (&pic_param->base.ReferenceFrames[i]);
802 pic_param_size = _is_range_extension_profile (self->parent.profile)
803 || _is_screen_content_ext_profile (self->parent.profile) ?
804 sizeof (*pic_param) : sizeof (pic_param->base);
805 if (!gst_va_decoder_add_param_buffer (base->decoder, va_pic,
806 VAPictureParameterBufferType, pic_param, pic_param_size))
807 return GST_FLOW_ERROR;
809 if (pps->scaling_list_data_present_flag ||
810 (sps->scaling_list_enabled_flag
811 && !sps->scaling_list_data_present_flag)) {
812 scaling_list = &pps->scaling_list;
813 GST_DEBUG_OBJECT (decoder, "Passing scaling list from PPS");
814 } else if (sps->scaling_list_enabled_flag &&
815 sps->scaling_list_data_present_flag) {
816 scaling_list = &sps->scaling_list;
817 GST_DEBUG_OBJECT (decoder, "Passing scaling list from SPS");
821 for (i = 0; i < G_N_ELEMENTS (iq_matrix.ScalingList4x4); i++)
822 gst_h265_quant_matrix_4x4_get_raster_from_uprightdiagonal
823 (iq_matrix.ScalingList4x4[i], scaling_list->scaling_lists_4x4[i]);
825 for (i = 0; i < G_N_ELEMENTS (iq_matrix.ScalingList8x8); i++)
826 gst_h265_quant_matrix_8x8_get_raster_from_uprightdiagonal
827 (iq_matrix.ScalingList8x8[i], scaling_list->scaling_lists_8x8[i]);
829 for (i = 0; i < G_N_ELEMENTS (iq_matrix.ScalingList16x16); i++)
830 gst_h265_quant_matrix_16x16_get_raster_from_uprightdiagonal
831 (iq_matrix.ScalingList16x16[i], scaling_list->scaling_lists_16x16[i]);
833 for (i = 0; i < G_N_ELEMENTS (iq_matrix.ScalingList32x32); i++)
834 gst_h265_quant_matrix_32x32_get_raster_from_uprightdiagonal
835 (iq_matrix.ScalingList32x32[i], scaling_list->scaling_lists_32x32[i]);
837 for (i = 0; i < 6; i++)
838 iq_matrix.ScalingListDC16x16[i] =
839 scaling_list->scaling_list_dc_coef_minus8_16x16[i] + 8;
841 for (i = 0; i < 2; i++)
842 iq_matrix.ScalingListDC32x32[i] =
843 scaling_list->scaling_list_dc_coef_minus8_32x32[i] + 8;
845 if (!gst_va_decoder_add_param_buffer (base->decoder, va_pic,
846 VAIQMatrixBufferType, &iq_matrix, sizeof (iq_matrix))) {
847 return GST_FLOW_ERROR;
855 gst_va_h265_dec_new_picture (GstH265Decoder * decoder,
856 GstVideoCodecFrame * frame, GstH265Picture * picture)
858 GstVaBaseDec *base = GST_VA_BASE_DEC (decoder);
859 GstVaH265Dec *self = GST_VA_H265_DEC (decoder);
860 GstVaDecodePicture *pic;
861 GstBuffer *output_buffer;
862 GstVideoDecoder *vdec = GST_VIDEO_DECODER (decoder);
864 if (base->need_negotiation) {
865 if (!gst_video_decoder_negotiate (vdec)) {
866 GST_ERROR_OBJECT (self, "Failed to negotiate with downstream");
867 return GST_FLOW_NOT_NEGOTIATED;
871 output_buffer = gst_video_decoder_allocate_output_buffer (vdec);
872 if (!output_buffer) {
873 self->last_ret = GST_FLOW_ERROR;
876 self->last_ret = GST_FLOW_OK;
878 pic = gst_va_decode_picture_new (base->decoder, output_buffer);
879 gst_buffer_unref (output_buffer);
881 gst_h265_picture_set_user_data (picture, pic,
882 (GDestroyNotify) gst_va_decode_picture_free);
884 GST_LOG_OBJECT (self, "New va decode picture %p - %#x", pic,
885 gst_va_decode_picture_get_surface (pic));
891 GST_WARNING_OBJECT (self,
892 "Failed to allocated output buffer, return %s",
893 gst_flow_get_name (self->last_ret));
894 return self->last_ret;
899 _get_rtformat (GstVaH265Dec * self, guint8 bit_depth_luma,
900 guint8 bit_depth_chroma, guint8 chroma_format_idc)
902 guint8 bit_num = MAX (bit_depth_luma, bit_depth_chroma);
907 if (chroma_format_idc == 3)
908 return VA_RT_FORMAT_YUV444_12;
909 if (chroma_format_idc == 2)
910 return VA_RT_FORMAT_YUV422_12;
912 return VA_RT_FORMAT_YUV420_12;
916 if (chroma_format_idc == 3)
917 return VA_RT_FORMAT_YUV444_10;
918 if (chroma_format_idc == 2)
919 return VA_RT_FORMAT_YUV422_10;
921 return VA_RT_FORMAT_YUV420_10;
924 if (chroma_format_idc == 3)
925 return VA_RT_FORMAT_YUV444;
926 if (chroma_format_idc == 2)
927 return VA_RT_FORMAT_YUV422;
929 return VA_RT_FORMAT_YUV420;
932 GST_ERROR_OBJECT (self, "Unsupported chroma format: %d "
933 "(with depth luma: %d, with depth chroma: %d)",
934 chroma_format_idc, bit_depth_luma, bit_depth_chroma);
942 GstH265Profile profile;
943 VAProfile va_profile;
945 #define P(idc, va) { G_PASTE (GST_H265_PROFILE_, idc), G_PASTE (VAProfileHEVC, va) }
948 /*P (MAIN_STILL_PICTURE, ),
951 P (MONOCHROME_16, ),*/
953 P (MAIN_422_10, Main422_10),
954 P (MAIN_422_12, Main422_12),
955 P (MAIN_444, Main444),
956 P (MAIN_444_10, Main444_10),
957 P (MAIN_444_12, Main444_12),
961 P (MAIN_422_10_INTRA, ),
962 P (MAIN_422_12_INTRA, ),
963 P (MAIN_444_INTRA, ),
964 P (MAIN_444_10_INTRA, ),
965 P (MAIN_444_12_INTRA, ),
966 P (MAIN_444_16_INTRA, ),
967 P (MAIN_444_STILL_PICTURE, ),
968 P (MAIN_444_16_STILL_PICTURE, ),
970 P (HIGH_THROUGHPUT_444, ),
971 P (HIGH_THROUGHPUT_444_10, ),
972 P (HIGH_THROUGHPUT_444_14, ),
973 P (HIGH_THROUGHPUT_444_16_INTRA, ),*/
974 P (SCREEN_EXTENDED_MAIN, SccMain),
975 P (SCREEN_EXTENDED_MAIN_10, SccMain10),
976 P (SCREEN_EXTENDED_MAIN_444, SccMain444),
977 #if VA_CHECK_VERSION(1, 8, 0)
978 P (SCREEN_EXTENDED_MAIN_444_10, SccMain444_10),
980 /*P (SCREEN_EXTENDED_HIGH_THROUGHPUT_444, ),
981 P (SCREEN_EXTENDED_HIGH_THROUGHPUT_444_10, ),
982 P (SCREEN_EXTENDED_HIGH_THROUGHPUT_444_14, ),
983 P (MULTIVIEW_MAIN, ),
985 P (SCALABLE_MAIN_10, ),
986 P (SCALABLE_MONOCHROME, ),
987 P (SCALABLE_MONOCHROME_12, ),
988 P (SCALABLE_MONOCHROME_16, ),
989 P (SCALABLE_MAIN_444, ),
996 _get_profile (GstVaH265Dec * self, const GstH265SPS * sps, gint max_dpb_size)
998 GstH265Decoder *h265_decoder = GST_H265_DECODER (self);
999 GstVaBaseDec *base = GST_VA_BASE_DEC (self);
1000 GstH265Profile profile = gst_h265_get_profile_from_sps ((GstH265SPS *) sps);
1001 VAProfile profiles[4];
1004 /* 1. The profile directly specified by the SPS should always be the
1005 first choice. It is the exact one.
1006 2. The profile in the input caps may contain the compatible profile
1007 chosen by the upstream element. Upstream element such as the parse
1008 may already decide the best compatible profile for us. We also need
1009 to consider it as a choice. */
1011 for (j = 0; j < G_N_ELEMENTS (profile_map); j++) {
1012 if (profile_map[j].profile == profile) {
1013 profiles[i++] = profile_map[j].va_profile;
1018 if (h265_decoder->input_state->caps
1019 && gst_caps_is_fixed (h265_decoder->input_state->caps)) {
1020 GstH265Profile compatible_profile = GST_H265_PROFILE_INVALID;
1021 GstStructure *structure;
1022 const gchar *profile_str;
1024 structure = gst_caps_get_structure (h265_decoder->input_state->caps, 0);
1026 profile_str = gst_structure_get_string (structure, "profile");
1028 compatible_profile = gst_h265_profile_from_string (profile_str);
1030 if (compatible_profile != profile) {
1031 GST_INFO_OBJECT (self, "The upstream set the compatible profile %s, "
1032 "also consider it as a candidate.", profile_str);
1034 for (j = 0; j < G_N_ELEMENTS (profile_map); j++) {
1035 if (profile_map[j].profile == compatible_profile) {
1036 profiles[i++] = profile_map[j].va_profile;
1043 for (j = 0; j < i && j < G_N_ELEMENTS (profiles); j++) {
1044 if (gst_va_decoder_has_profile (base->decoder, profiles[j]))
1048 GST_ERROR_OBJECT (self, "Unsupported profile: %d", profile);
1050 return VAProfileNone;
1053 static GstFlowReturn
1054 gst_va_h265_dec_new_sequence (GstH265Decoder * decoder, const GstH265SPS * sps,
1057 GstVaBaseDec *base = GST_VA_BASE_DEC (decoder);
1058 GstVaH265Dec *self = GST_VA_H265_DEC (decoder);
1061 gint display_height;
1062 gint padding_left, padding_right, padding_top, padding_bottom;
1064 gboolean negotiation_needed = FALSE;
1066 if (self->dpb_size < max_dpb_size)
1067 self->dpb_size = max_dpb_size;
1069 if (sps->conformance_window_flag) {
1070 display_width = sps->crop_rect_width;
1071 display_height = sps->crop_rect_height;
1072 padding_left = sps->crop_rect_x;
1073 padding_right = sps->width - sps->crop_rect_x - display_width;
1074 padding_top = sps->crop_rect_y;
1075 padding_bottom = sps->height - sps->crop_rect_y - display_height;
1077 display_width = sps->width;
1078 display_height = sps->height;
1079 padding_left = padding_right = padding_top = padding_bottom = 0;
1082 profile = _get_profile (self, sps, max_dpb_size);
1083 if (profile == VAProfileNone)
1084 return GST_FLOW_NOT_NEGOTIATED;
1086 rt_format = _get_rtformat (self, sps->bit_depth_luma_minus8 + 8,
1087 sps->bit_depth_chroma_minus8 + 8, sps->chroma_format_idc);
1089 return GST_FLOW_NOT_NEGOTIATED;
1091 if (!gst_va_decoder_config_is_equal (base->decoder, profile,
1092 rt_format, sps->width, sps->height)) {
1093 base->profile = profile;
1094 base->rt_format = rt_format;
1095 self->coded_width = sps->width;
1096 self->coded_height = sps->height;
1098 negotiation_needed = TRUE;
1099 GST_INFO_OBJECT (self, "Format changed to %s [%x] (%dx%d)",
1100 gst_va_profile_name (profile), rt_format, self->coded_width,
1101 self->coded_height);
1104 if (base->width != display_width || base->height != display_height) {
1105 base->width = display_width;
1106 base->height = display_height;
1108 negotiation_needed = TRUE;
1109 GST_INFO_OBJECT (self, "Resolution changed to %dx%d", base->width,
1113 base->need_valign = base->width < self->coded_width
1114 || base->height < self->coded_height;
1115 if (base->need_valign) {
1117 if (base->valign.padding_left != padding_left ||
1118 base->valign.padding_right != padding_right ||
1119 base->valign.padding_top != padding_top ||
1120 base->valign.padding_bottom != padding_bottom) {
1121 negotiation_needed = TRUE;
1122 GST_INFO_OBJECT (self, "crop rect changed to (%d,%d)-->(%d,%d)",
1123 padding_left, padding_top, padding_right, padding_bottom);
1125 base->valign = (GstVideoAlignment) {
1126 .padding_left = padding_left,
1127 .padding_right = padding_right,
1128 .padding_top = padding_top,
1129 .padding_bottom = padding_bottom,
1134 base->min_buffers = self->dpb_size + 4; /* dpb size + scratch surfaces */
1136 base->need_negotiation = negotiation_needed;
1139 /* FIXME: We don't have parser API for sps_range_extension, so
1140 * assuming high_precision_offsets_enabled_flag as zero */
1141 guint high_precision_offsets_enabled_flag = 0, bitdepthC = 0;
1143 /* Calculate WpOffsetHalfRangeC: (7-34) */
1144 bitdepthC = sps->bit_depth_chroma_minus8 + 8;
1145 self->WpOffsetHalfRangeC =
1146 1 << (high_precision_offsets_enabled_flag ? (bitdepthC - 1) : 7);
1153 _complete_sink_caps (GstCaps * sinkcaps)
1155 GstCaps *caps = gst_caps_copy (sinkcaps);
1156 GValue val = G_VALUE_INIT;
1157 const gchar *streamformat[] = { "hvc1", "hev1", "byte-stream" };
1160 g_value_init (&val, G_TYPE_STRING);
1161 g_value_set_string (&val, "au");
1162 gst_caps_set_value (caps, "alignment", &val);
1163 g_value_unset (&val);
1165 gst_value_list_init (&val, G_N_ELEMENTS (streamformat));
1166 for (i = 0; i < G_N_ELEMENTS (streamformat); i++) {
1167 GValue v = G_VALUE_INIT;
1169 g_value_init (&v, G_TYPE_STRING);
1170 g_value_set_string (&v, streamformat[i]);
1171 gst_value_list_append_value (&val, &v);
1174 gst_caps_set_value (caps, "stream-format", &val);
1175 g_value_unset (&val);
1181 gst_va_h265_dec_getcaps (GstVideoDecoder * decoder, GstCaps * filter)
1183 GstCaps *sinkcaps, *caps = NULL, *tmp;
1184 GstVaBaseDec *base = GST_VA_BASE_DEC (decoder);
1187 caps = gst_va_decoder_get_sinkpad_caps (base->decoder);
1190 sinkcaps = _complete_sink_caps (caps);
1191 gst_caps_unref (caps);
1193 tmp = gst_caps_intersect_full (filter, sinkcaps,
1194 GST_CAPS_INTERSECT_FIRST);
1195 gst_caps_unref (sinkcaps);
1200 GST_LOG_OBJECT (base, "Returning caps %" GST_PTR_FORMAT, caps);
1202 caps = gst_video_decoder_proxy_getcaps (decoder, NULL, filter);
1209 gst_va_h265_dec_negotiate (GstVideoDecoder * decoder)
1211 GstVaBaseDec *base = GST_VA_BASE_DEC (decoder);
1212 GstVaH265Dec *self = GST_VA_H265_DEC (decoder);
1213 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
1214 GstCapsFeatures *capsfeatures = NULL;
1215 GstH265Decoder *h265dec = GST_H265_DECODER (decoder);
1217 /* Ignore downstream renegotiation request. */
1218 if (!base->need_negotiation)
1221 base->need_negotiation = FALSE;
1223 if (gst_va_decoder_is_open (base->decoder)
1224 && !gst_va_decoder_close (base->decoder))
1227 if (!gst_va_decoder_open (base->decoder, base->profile, base->rt_format))
1230 if (!gst_va_decoder_set_frame_size (base->decoder, self->coded_width,
1231 self->coded_height))
1234 if (base->output_state)
1235 gst_video_codec_state_unref (base->output_state);
1237 gst_va_base_dec_get_preferred_format_and_caps_features (base, &format,
1239 if (format == GST_VIDEO_FORMAT_UNKNOWN)
1242 base->output_state =
1243 gst_video_decoder_set_output_state (decoder, format,
1244 base->width, base->height, h265dec->input_state);
1246 base->output_state->caps = gst_video_info_to_caps (&base->output_state->info);
1248 gst_caps_set_features_simple (base->output_state->caps, capsfeatures);
1250 GST_INFO_OBJECT (self, "Negotiated caps %" GST_PTR_FORMAT,
1251 base->output_state->caps);
1253 return GST_VIDEO_DECODER_CLASS (parent_class)->negotiate (decoder);
1257 gst_va_h265_dec_dispose (GObject * object)
1259 g_free (GST_VA_H265_DEC (object)->prev_slice.data);
1261 gst_va_base_dec_close (GST_VIDEO_DECODER (object));
1263 G_OBJECT_CLASS (parent_class)->dispose (object);
1267 gst_va_h265_dec_class_init (gpointer g_class, gpointer class_data)
1269 GstCaps *src_doc_caps, *sink_doc_caps;
1270 GObjectClass *gobject_class = G_OBJECT_CLASS (g_class);
1271 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
1272 GstH265DecoderClass *h265decoder_class = GST_H265_DECODER_CLASS (g_class);
1273 GstVideoDecoderClass *decoder_class = GST_VIDEO_DECODER_CLASS (g_class);
1274 struct CData *cdata = class_data;
1277 if (cdata->description) {
1278 long_name = g_strdup_printf ("VA-API H.265 Decoder in %s",
1279 cdata->description);
1281 long_name = g_strdup ("VA-API H.265 Decoder");
1284 gst_element_class_set_metadata (element_class, long_name,
1285 "Codec/Decoder/Video/Hardware",
1286 "VA-API based H.265 video decoder",
1287 "Nicolas Dufresne <nicolas.dufresne@collabora.com>");
1289 sink_doc_caps = gst_caps_from_string (sink_caps_str);
1290 src_doc_caps = gst_caps_from_string (src_caps_str);
1292 parent_class = g_type_class_peek_parent (g_class);
1295 * GstVaH265Dec:device-path:
1297 * It shows the DRM device path used for the VA operation, if any.
1301 gst_va_base_dec_class_init (GST_VA_BASE_DEC_CLASS (g_class), HEVC,
1302 cdata->render_device_path, cdata->sink_caps, cdata->src_caps,
1303 src_doc_caps, sink_doc_caps);
1305 gobject_class->dispose = gst_va_h265_dec_dispose;
1307 decoder_class->getcaps = GST_DEBUG_FUNCPTR (gst_va_h265_dec_getcaps);
1308 decoder_class->negotiate = GST_DEBUG_FUNCPTR (gst_va_h265_dec_negotiate);
1310 h265decoder_class->new_sequence =
1311 GST_DEBUG_FUNCPTR (gst_va_h265_dec_new_sequence);
1312 h265decoder_class->decode_slice =
1313 GST_DEBUG_FUNCPTR (gst_va_h265_dec_decode_slice);
1315 h265decoder_class->new_picture =
1316 GST_DEBUG_FUNCPTR (gst_va_h265_dec_new_picture);
1317 h265decoder_class->output_picture =
1318 GST_DEBUG_FUNCPTR (gst_va_h265_dec_output_picture);
1319 h265decoder_class->start_picture =
1320 GST_DEBUG_FUNCPTR (gst_va_h265_dec_start_picture);
1321 h265decoder_class->end_picture =
1322 GST_DEBUG_FUNCPTR (gst_va_h265_dec_end_picture);
1325 g_free (cdata->description);
1326 g_free (cdata->render_device_path);
1327 gst_caps_unref (cdata->src_caps);
1328 gst_caps_unref (cdata->sink_caps);
1333 gst_va_h265_dec_init (GTypeInstance * instance, gpointer g_class)
1335 gst_va_base_dec_init (GST_VA_BASE_DEC (instance), GST_CAT_DEFAULT);
1336 gst_h265_decoder_set_process_ref_pic_lists (GST_H265_DECODER (instance),
1341 _register_debug_category (gpointer data)
1343 GST_DEBUG_CATEGORY_INIT (gst_va_h265dec_debug, "vah265dec", 0,
1350 gst_va_h265_dec_register (GstPlugin * plugin, GstVaDevice * device,
1351 GstCaps * sink_caps, GstCaps * src_caps, guint rank)
1353 static GOnce debug_once = G_ONCE_INIT;
1355 GTypeInfo type_info = {
1356 .class_size = sizeof (GstVaH265DecClass),
1357 .class_init = gst_va_h265_dec_class_init,
1358 .instance_size = sizeof (GstVaH265Dec),
1359 .instance_init = gst_va_h265_dec_init,
1361 struct CData *cdata;
1363 gchar *type_name, *feature_name;
1365 g_return_val_if_fail (GST_IS_PLUGIN (plugin), FALSE);
1366 g_return_val_if_fail (GST_IS_VA_DEVICE (device), FALSE);
1367 g_return_val_if_fail (GST_IS_CAPS (sink_caps), FALSE);
1368 g_return_val_if_fail (GST_IS_CAPS (src_caps), FALSE);
1370 cdata = g_new (struct CData, 1);
1371 cdata->description = NULL;
1372 cdata->render_device_path = g_strdup (device->render_device_path);
1373 cdata->sink_caps = _complete_sink_caps (sink_caps);
1374 cdata->src_caps = gst_caps_ref (src_caps);
1376 /* class data will be leaked if the element never gets instantiated */
1377 GST_MINI_OBJECT_FLAG_SET (cdata->sink_caps,
1378 GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
1379 GST_MINI_OBJECT_FLAG_SET (src_caps, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
1381 type_info.class_data = cdata;
1383 type_name = g_strdup ("GstVaH265Dec");
1384 feature_name = g_strdup ("vah265dec");
1386 /* The first decoder to be registered should use a constant name,
1387 * like vah265dec, for any additional decoders, we create unique
1388 * names, using inserting the render device name. */
1389 if (g_type_from_name (type_name)) {
1390 gchar *basename = g_path_get_basename (device->render_device_path);
1392 g_free (feature_name);
1393 type_name = g_strdup_printf ("GstVa%sH265Dec", basename);
1394 feature_name = g_strdup_printf ("va%sh265dec", basename);
1395 cdata->description = basename;
1397 /* lower rank for non-first device */
1402 g_once (&debug_once, _register_debug_category, NULL);
1404 type = g_type_register_static (GST_TYPE_H265_DECODER,
1405 type_name, &type_info, 0);
1407 ret = gst_element_register (plugin, feature_name, rank, type);
1410 g_free (feature_name);