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
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);
321 for (i = 0; i < 15; i++) {
322 VAPictureHEVC *ref_va_pic = &self->pic_param.base.ReferenceFrames[i];
324 if (ref_va_pic->picture_id == VA_INVALID_ID)
327 if (ref_va_pic->pic_order_cnt == picture->pic_order_cnt)
334 /* fill the VA API reference picture lists from the GstCodec reference
337 _fill_ref_pic_list (GstH265Decoder * decoder, GstH265Picture * cur_pic,
338 guint8 va_reflist[15], GArray * reflist)
342 for (i = 0; i < reflist->len && i < 15; i++) {
343 GstH265Picture *picture = g_array_index (reflist, GstH265Picture *, i);
344 va_reflist[i] = _get_reference_index (decoder, picture);
348 va_reflist[i] = 0xFF;
352 _fill_pred_weight_table (GstVaH265Dec * self, GstH265SliceHdr * header,
353 VASliceParameterBufferHEVCExtension * slice_param)
355 gint chroma_weight, chroma_log2_weight_denom;
357 GstH265PPS *pps = header->pps;
358 gboolean is_rext = _is_range_extension_profile (self->parent.profile);
360 if (GST_H265_IS_I_SLICE (header) ||
361 (!pps->weighted_pred_flag && GST_H265_IS_P_SLICE (header)) ||
362 (!pps->weighted_bipred_flag && GST_H265_IS_B_SLICE (header)))
365 slice_param->base.luma_log2_weight_denom =
366 header->pred_weight_table.luma_log2_weight_denom;
368 if (pps->sps->chroma_array_type != 0)
369 slice_param->base.delta_chroma_log2_weight_denom =
370 header->pred_weight_table.delta_chroma_log2_weight_denom;
372 for (i = 0; i <= header->num_ref_idx_l0_active_minus1; i++) {
373 if (!header->pred_weight_table.luma_weight_l0_flag[i])
376 slice_param->base.delta_luma_weight_l0[i] =
377 header->pred_weight_table.delta_luma_weight_l0[i];
378 slice_param->base.luma_offset_l0[i] =
379 header->pred_weight_table.luma_offset_l0[i];
382 slice_param->rext.luma_offset_l0[i] =
383 header->pred_weight_table.luma_offset_l0[i];
387 chroma_log2_weight_denom = slice_param->base.luma_log2_weight_denom +
388 slice_param->base.delta_chroma_log2_weight_denom;
390 for (i = 0; i <= header->num_ref_idx_l0_active_minus1; i++) {
391 if (!header->pred_weight_table.chroma_weight_l0_flag[i])
394 for (j = 0; j < 2; j++) {
395 gint16 delta_chroma_offset_l0 =
396 header->pred_weight_table.delta_chroma_offset_l0[i][j];
399 slice_param->base.delta_chroma_weight_l0[i][j] =
400 header->pred_weight_table.delta_chroma_weight_l0[i][j];
402 /* Find ChromaWeightL0 */
403 chroma_weight = (1 << chroma_log2_weight_denom) +
404 header->pred_weight_table.delta_chroma_weight_l0[i][j];
405 chroma_offset = self->WpOffsetHalfRangeC + delta_chroma_offset_l0
406 - ((self->WpOffsetHalfRangeC * chroma_weight)
407 >> chroma_log2_weight_denom);
410 slice_param->base.ChromaOffsetL0[i][j] = CLAMP (chroma_offset,
411 -self->WpOffsetHalfRangeC, self->WpOffsetHalfRangeC - 1);
414 slice_param->rext.ChromaOffsetL0[i][j] =
415 slice_param->base.ChromaOffsetL0[i][j];
420 /* Skip l1 if this is not a B-Frame. */
421 if (!GST_H265_IS_B_SLICE (header))
424 for (i = 0; i <= header->num_ref_idx_l1_active_minus1; i++) {
425 if (!header->pred_weight_table.luma_weight_l1_flag[i])
428 slice_param->base.delta_luma_weight_l1[i] =
429 header->pred_weight_table.delta_luma_weight_l1[i];
430 slice_param->base.luma_offset_l1[i] =
431 header->pred_weight_table.luma_offset_l1[i];
434 slice_param->rext.luma_offset_l1[i] =
435 header->pred_weight_table.luma_offset_l1[i];
439 for (i = 0; i <= header->num_ref_idx_l1_active_minus1; i++) {
440 if (!header->pred_weight_table.chroma_weight_l1_flag[i])
443 for (j = 0; j < 2; j++) {
444 gint16 delta_chroma_offset_l1 =
445 header->pred_weight_table.delta_chroma_offset_l1[i][j];
448 slice_param->base.delta_chroma_weight_l1[i][j] =
449 header->pred_weight_table.delta_chroma_weight_l1[i][j];
451 /* Find ChromaWeightL1 */
452 chroma_weight = (1 << chroma_log2_weight_denom) +
453 header->pred_weight_table.delta_chroma_weight_l1[i][j];
455 chroma_offset = self->WpOffsetHalfRangeC + delta_chroma_offset_l1
456 - ((self->WpOffsetHalfRangeC * chroma_weight)
457 >> chroma_log2_weight_denom);
460 slice_param->base.ChromaOffsetL1[i][j] = CLAMP (chroma_offset,
461 -self->WpOffsetHalfRangeC, self->WpOffsetHalfRangeC - 1);
464 slice_param->rext.ChromaOffsetL1[i][j] =
465 slice_param->base.ChromaOffsetL1[i][j];
472 _get_slice_data_byte_offset (GstH265SliceHdr * slice_hdr,
473 guint nal_header_bytes)
477 epb_count = slice_hdr->n_emulation_prevention_bytes;
478 return nal_header_bytes + (slice_hdr->header_size + 7) / 8 - epb_count;
482 gst_va_h265_dec_decode_slice (GstH265Decoder * decoder,
483 GstH265Picture * picture, GstH265Slice * slice, GArray * ref_pic_list0,
484 GArray * ref_pic_list1)
486 GstH265SliceHdr *header = &slice->header;
487 GstH265NalUnit *nalu = &slice->nalu;
488 GstVaBaseDec *base = GST_VA_BASE_DEC (decoder);
489 GstVaH265Dec *self = GST_VA_H265_DEC (decoder);
490 GstVaDecodePicture *va_pic;
491 VASliceParameterBufferHEVCExtension *slice_param;
493 va_pic = gst_h265_picture_get_user_data (picture);
494 if (!_submit_previous_slice (base, va_pic)) {
495 _replace_previous_slice (self, NULL, 0);
496 GST_ERROR_OBJECT (base, "Failed to submit previous slice buffers");
497 return GST_FLOW_ERROR;
500 slice_param = &self->prev_slice.param;
503 slice_param->base = (VASliceParameterBufferHEVC) {
504 .slice_data_size = nalu->size,
505 .slice_data_offset = 0,
506 .slice_data_flag = VA_SLICE_DATA_FLAG_ALL,
507 .slice_data_byte_offset = _get_slice_data_byte_offset (header, nalu->header_bytes),
508 .slice_segment_address = header->segment_address,
509 .collocated_ref_idx = header->temporal_mvp_enabled_flag ? header->collocated_ref_idx : 0xFF,
510 .num_ref_idx_l0_active_minus1 = header->num_ref_idx_l0_active_minus1,
511 .num_ref_idx_l1_active_minus1 = header->num_ref_idx_l1_active_minus1,
512 .slice_qp_delta = header->qp_delta,
513 .slice_cb_qp_offset = header->cb_qp_offset,
514 .slice_cr_qp_offset = header->cr_qp_offset,
515 .slice_beta_offset_div2 = header->beta_offset_div2,
516 .slice_tc_offset_div2 = header->tc_offset_div2,
517 .five_minus_max_num_merge_cand = header->five_minus_max_num_merge_cand,
518 .num_entry_point_offsets = header->num_entry_point_offsets,
519 .entry_offset_to_subset_array = 0, /* does not exist in spec */
520 .slice_data_num_emu_prevn_bytes = header->n_emulation_prevention_bytes,
521 .LongSliceFlags.fields = {
522 .LastSliceOfPic = 0, /* the last one will be set on end_picture() */
523 .dependent_slice_segment_flag = header->dependent_slice_segment_flag,
524 .slice_type = header->type,
525 .color_plane_id = header->colour_plane_id,
526 .slice_sao_luma_flag = header->sao_luma_flag,
527 .slice_sao_chroma_flag = header->sao_chroma_flag,
528 .mvd_l1_zero_flag = header->mvd_l1_zero_flag,
529 .cabac_init_flag = header->cabac_init_flag,
530 .slice_temporal_mvp_enabled_flag = header->temporal_mvp_enabled_flag,
531 .slice_deblocking_filter_disabled_flag =
532 header->deblocking_filter_disabled_flag,
533 .collocated_from_l0_flag = header->collocated_from_l0_flag,
534 .slice_loop_filter_across_slices_enabled_flag =
535 header->loop_filter_across_slices_enabled_flag,
540 if (_is_range_extension_profile (base->profile)
541 || _is_screen_content_ext_profile (base->profile)) {
543 slice_param->rext = (VASliceParameterBufferHEVCRext) {
544 .slice_ext_flags.bits = {
545 .cu_chroma_qp_offset_enabled_flag = header->cu_chroma_qp_offset_enabled_flag,
546 .use_integer_mv_flag = header->use_integer_mv_flag,
548 .slice_act_y_qp_offset = header->slice_act_y_qp_offset,
549 .slice_act_cb_qp_offset = header->slice_act_cb_qp_offset,
550 .slice_act_cr_qp_offset = header->slice_act_cr_qp_offset,
555 _fill_ref_pic_list (decoder, picture, slice_param->base.RefPicList[0],
557 _fill_ref_pic_list (decoder, picture, slice_param->base.RefPicList[1],
560 _fill_pred_weight_table (GST_VA_H265_DEC (decoder), header, slice_param);
562 _replace_previous_slice (self, slice->nalu.data + slice->nalu.offset,
569 _fill_picture_range_ext_parameter (GstVaH265Dec * decoder,
570 GstH265SPS * sps, GstH265PPS * pps)
572 VAPictureParameterBufferHEVCRext *pic_param = &decoder->pic_param.rext;
574 GstH265SPSExtensionParams *sps_ext = &sps->sps_extnsion_params;
575 GstH265PPSExtensionParams *pps_ext = &pps->pps_extension_params;
578 *pic_param = (VAPictureParameterBufferHEVCRext) {
579 .range_extension_pic_fields.bits = {
580 .transform_skip_rotation_enabled_flag = sps_ext->transform_skip_rotation_enabled_flag,
581 .transform_skip_context_enabled_flag = sps_ext->transform_skip_context_enabled_flag,
582 .implicit_rdpcm_enabled_flag = sps_ext->implicit_rdpcm_enabled_flag,
583 .explicit_rdpcm_enabled_flag = sps_ext->explicit_rdpcm_enabled_flag,
584 .extended_precision_processing_flag = sps_ext->extended_precision_processing_flag,
585 .intra_smoothing_disabled_flag = sps_ext->intra_smoothing_disabled_flag,
586 .high_precision_offsets_enabled_flag = sps_ext->high_precision_offsets_enabled_flag,
587 .persistent_rice_adaptation_enabled_flag = sps_ext->persistent_rice_adaptation_enabled_flag,
588 .cabac_bypass_alignment_enabled_flag = sps_ext->cabac_bypass_alignment_enabled_flag,
589 .cross_component_prediction_enabled_flag = pps_ext->cross_component_prediction_enabled_flag,
590 .chroma_qp_offset_list_enabled_flag = pps_ext->chroma_qp_offset_list_enabled_flag,
592 .diff_cu_chroma_qp_offset_depth = pps_ext->diff_cu_chroma_qp_offset_depth,
593 .chroma_qp_offset_list_len_minus1 = pps_ext->chroma_qp_offset_list_len_minus1,
594 .log2_sao_offset_scale_luma = pps_ext->log2_sao_offset_scale_luma,
595 .log2_sao_offset_scale_chroma = pps_ext->log2_sao_offset_scale_chroma,
596 .log2_max_transform_skip_block_size_minus2 = pps_ext->log2_max_transform_skip_block_size_minus2,
600 memcpy (pic_param->cb_qp_offset_list, pps_ext->cb_qp_offset_list,
601 sizeof (pic_param->cb_qp_offset_list));
602 memcpy (pic_param->cr_qp_offset_list, pps_ext->cr_qp_offset_list,
603 sizeof (pic_param->cr_qp_offset_list));
607 _fill_screen_content_ext_parameter (GstVaH265Dec * decoder,
608 GstH265SPS * sps, GstH265PPS * pps)
610 VAPictureParameterBufferHEVCScc *pic_param = &decoder->pic_param.scc;
611 const GstH265PPSSccExtensionParams *pps_scc = &pps->pps_scc_extension_params;
612 const GstH265SPSSccExtensionParams *sps_scc = &sps->sps_scc_extension_params;
617 *pic_param = (VAPictureParameterBufferHEVCScc) {
618 .screen_content_pic_fields.bits = {
619 .pps_curr_pic_ref_enabled_flag = pps_scc->pps_curr_pic_ref_enabled_flag,
620 .palette_mode_enabled_flag = sps_scc->palette_mode_enabled_flag,
621 .motion_vector_resolution_control_idc = sps_scc->motion_vector_resolution_control_idc,
622 .intra_boundary_filtering_disabled_flag = sps_scc->intra_boundary_filtering_disabled_flag,
623 .residual_adaptive_colour_transform_enabled_flag = pps_scc->residual_adaptive_colour_transform_enabled_flag,
624 .pps_slice_act_qp_offsets_present_flag = pps_scc->pps_slice_act_qp_offsets_present_flag,
626 .palette_max_size = sps_scc->palette_max_size,
627 .delta_palette_max_predictor_size = sps_scc->delta_palette_max_predictor_size,
628 .pps_act_y_qp_offset_plus5 = pps_scc->pps_act_y_qp_offset_plus5,
629 .pps_act_cb_qp_offset_plus5 = pps_scc->pps_act_cb_qp_offset_plus5,
630 .pps_act_cr_qp_offset_plus3 = pps_scc->pps_act_cr_qp_offset_plus3,
634 /* firstly use the pps, then sps */
635 num_comps = sps->chroma_format_idc ? 3 : 1;
637 if (pps_scc->pps_palette_predictor_initializers_present_flag) {
638 pic_param->predictor_palette_size =
639 pps_scc->pps_num_palette_predictor_initializer;
640 for (n = 0; n < num_comps; n++)
641 for (i = 0; i < pps_scc->pps_num_palette_predictor_initializer; i++)
642 pic_param->predictor_palette_entries[n][i] =
643 (uint16_t) pps_scc->pps_palette_predictor_initializer[n][i];
644 } else if (sps_scc->sps_palette_predictor_initializers_present_flag) {
645 pic_param->predictor_palette_size =
646 sps_scc->sps_num_palette_predictor_initializer_minus1 + 1;
647 for (n = 0; n < num_comps; n++)
649 i < sps_scc->sps_num_palette_predictor_initializer_minus1 + 1; i++)
650 pic_param->predictor_palette_entries[n][i] =
651 (uint16_t) sps_scc->sps_palette_predictor_initializer[n][i];
656 gst_va_h265_dec_start_picture (GstH265Decoder * decoder,
657 GstH265Picture * picture, GstH265Slice * slice, GstH265Dpb * dpb)
661 GstVaH265Dec *self = GST_VA_H265_DEC (decoder);
662 GstVaBaseDec *base = &self->parent;
663 GstVaDecodePicture *va_pic;
664 GstH265ScalingList *scaling_list = NULL;
665 VAIQMatrixBufferHEVC iq_matrix = { 0, };
666 VAPictureParameterBufferHEVCExtension *pic_param = &self->pic_param;
667 gsize pic_param_size;
670 va_pic = gst_h265_picture_get_user_data (picture);
672 pps = slice->header.pps;
676 pic_param->base = (VAPictureParameterBufferHEVC) {
677 .pic_width_in_luma_samples = sps->pic_width_in_luma_samples,
678 .pic_height_in_luma_samples = sps->pic_height_in_luma_samples,
679 .sps_max_dec_pic_buffering_minus1 = sps->max_dec_pic_buffering_minus1[sps->max_sub_layers_minus1],
680 .bit_depth_luma_minus8 = sps->bit_depth_luma_minus8,
681 .bit_depth_chroma_minus8 = sps->bit_depth_chroma_minus8,
682 .pcm_sample_bit_depth_luma_minus1 = sps->pcm_sample_bit_depth_luma_minus1,
683 .pcm_sample_bit_depth_chroma_minus1 = sps->pcm_sample_bit_depth_chroma_minus1,
684 .log2_min_luma_coding_block_size_minus3 = sps->log2_min_luma_coding_block_size_minus3,
685 .log2_diff_max_min_luma_coding_block_size = sps->log2_diff_max_min_luma_coding_block_size,
686 .log2_min_transform_block_size_minus2 = sps->log2_min_transform_block_size_minus2,
687 .log2_diff_max_min_transform_block_size = sps->log2_diff_max_min_transform_block_size,
688 .log2_min_pcm_luma_coding_block_size_minus3 = sps->log2_min_pcm_luma_coding_block_size_minus3,
689 .log2_diff_max_min_pcm_luma_coding_block_size = sps->log2_diff_max_min_pcm_luma_coding_block_size,
690 .max_transform_hierarchy_depth_intra = sps->max_transform_hierarchy_depth_intra,
691 .max_transform_hierarchy_depth_inter = sps->max_transform_hierarchy_depth_inter,
692 .init_qp_minus26 = pps->init_qp_minus26,
693 .diff_cu_qp_delta_depth = pps->diff_cu_qp_delta_depth,
694 .pps_cb_qp_offset = pps->cb_qp_offset,
695 .pps_cr_qp_offset = pps->cr_qp_offset,
696 .log2_parallel_merge_level_minus2 = pps->log2_parallel_merge_level_minus2,
697 .num_tile_columns_minus1 = pps->num_tile_columns_minus1,
698 .num_tile_rows_minus1 = pps->num_tile_rows_minus1,
699 .log2_max_pic_order_cnt_lsb_minus4 = sps->log2_max_pic_order_cnt_lsb_minus4,
700 .num_short_term_ref_pic_sets = sps->num_short_term_ref_pic_sets,
701 .num_long_term_ref_pic_sps = sps->num_long_term_ref_pics_sps,
702 .num_ref_idx_l0_default_active_minus1 = pps->num_ref_idx_l0_default_active_minus1,
703 .num_ref_idx_l1_default_active_minus1 = pps->num_ref_idx_l1_default_active_minus1,
704 .pps_beta_offset_div2 = pps->beta_offset_div2,
705 .pps_tc_offset_div2 = pps->tc_offset_div2,
706 .num_extra_slice_header_bits = pps->num_extra_slice_header_bits,
707 .st_rps_bits = slice->header.short_term_ref_pic_set_size, /* FIXME missing emulation bits removal */
709 .chroma_format_idc = sps->chroma_format_idc,
710 .separate_colour_plane_flag = sps->separate_colour_plane_flag,
711 .pcm_enabled_flag = sps->pcm_enabled_flag,
712 .scaling_list_enabled_flag = sps->scaling_list_enabled_flag,
713 .transform_skip_enabled_flag = pps->transform_skip_enabled_flag,
714 .amp_enabled_flag = sps->amp_enabled_flag,
715 .strong_intra_smoothing_enabled_flag = sps->strong_intra_smoothing_enabled_flag,
716 .sign_data_hiding_enabled_flag = pps->sign_data_hiding_enabled_flag,
717 .constrained_intra_pred_flag = pps->constrained_intra_pred_flag,
718 .cu_qp_delta_enabled_flag = pps->cu_qp_delta_enabled_flag,
719 .weighted_pred_flag = pps->weighted_pred_flag,
720 .weighted_bipred_flag = pps->weighted_bipred_flag,
721 .transquant_bypass_enabled_flag = pps->transquant_bypass_enabled_flag,
722 .tiles_enabled_flag = pps->tiles_enabled_flag,
723 .entropy_coding_sync_enabled_flag = pps->entropy_coding_sync_enabled_flag,
724 .pps_loop_filter_across_slices_enabled_flag = pps->loop_filter_across_slices_enabled_flag,
725 .loop_filter_across_tiles_enabled_flag = pps->loop_filter_across_tiles_enabled_flag,
726 .pcm_loop_filter_disabled_flag = sps->pcm_loop_filter_disabled_flag,
727 /* Not set by FFMPEG either */
728 .NoPicReorderingFlag = 0,
731 .slice_parsing_fields.bits = {
732 .lists_modification_present_flag = pps->lists_modification_present_flag,
733 .long_term_ref_pics_present_flag = sps->long_term_ref_pics_present_flag,
734 .sps_temporal_mvp_enabled_flag = sps->temporal_mvp_enabled_flag,
735 .cabac_init_present_flag = pps->cabac_init_present_flag,
736 .output_flag_present_flag = pps->output_flag_present_flag,
737 .dependent_slice_segments_enabled_flag = pps->dependent_slice_segments_enabled_flag,
738 .pps_slice_chroma_qp_offsets_present_flag = pps->slice_chroma_qp_offsets_present_flag,
739 .sample_adaptive_offset_enabled_flag = sps->sample_adaptive_offset_enabled_flag,
740 .deblocking_filter_override_enabled_flag = pps->deblocking_filter_override_enabled_flag,
741 .pps_disable_deblocking_filter_flag = pps->deblocking_filter_disabled_flag,
742 .slice_segment_header_extension_present_flag = pps->slice_segment_header_extension_present_flag,
743 .RapPicFlag = picture->RapPicFlag,
744 .IdrPicFlag = GST_H265_IS_NAL_TYPE_IDR (slice->nalu.type),
745 .IntraPicFlag = GST_H265_IS_NAL_TYPE_IRAP (slice->nalu.type),
750 if (_is_range_extension_profile (self->parent.profile)
751 || _is_screen_content_ext_profile (self->parent.profile)) {
752 _fill_picture_range_ext_parameter (self, sps, pps);
753 if (_is_screen_content_ext_profile (self->parent.profile))
754 _fill_screen_content_ext_parameter (self, sps, pps);
757 for (i = 0; i <= pps->num_tile_columns_minus1; i++)
758 pic_param->base.column_width_minus1[i] = pps->column_width_minus1[i];
760 for (i = 0; i <= pps->num_tile_rows_minus1; i++)
761 pic_param->base.row_height_minus1[i] = pps->row_height_minus1[i];
763 _fill_vaapi_pic (decoder, &pic_param->base.CurrPic, picture);
765 /* reference frames */
767 GArray *ref_list = gst_h265_dpb_get_pictures_all (dpb);
771 for (j = 0; j < 15 && j < ref_list->len; j++) {
772 GstH265Picture *pic = g_array_index (ref_list, GstH265Picture *, j);
775 _fill_vaapi_pic (decoder, &pic_param->base.ReferenceFrames[i], pic);
779 g_array_unref (ref_list);
781 /* 7.4.3.3.3, the current decoded picture is marked as "used for
782 long-term reference". Current picture is not in the DPB now. */
783 if (pps->pps_scc_extension_params.pps_curr_pic_ref_enabled_flag && i < 15) {
784 pic_param->base.ReferenceFrames[i].picture_id =
785 gst_va_decode_picture_get_surface (gst_h265_picture_get_user_data
787 pic_param->base.ReferenceFrames[i].pic_order_cnt = picture->pic_order_cnt;
788 pic_param->base.ReferenceFrames[i].flags |=
789 VA_PICTURE_HEVC_LONG_TERM_REFERENCE;
790 pic_param->base.ReferenceFrames[i].flags |=
791 _find_frame_rps_type (decoder, picture);
796 _init_vaapi_pic (&pic_param->base.ReferenceFrames[i]);
799 pic_param_size = _is_range_extension_profile (self->parent.profile)
800 || _is_screen_content_ext_profile (self->parent.profile) ?
801 sizeof (*pic_param) : sizeof (pic_param->base);
802 if (!gst_va_decoder_add_param_buffer (base->decoder, va_pic,
803 VAPictureParameterBufferType, pic_param, pic_param_size))
804 return GST_FLOW_ERROR;
806 if (pps->scaling_list_data_present_flag ||
807 (sps->scaling_list_enabled_flag
808 && !sps->scaling_list_data_present_flag)) {
809 scaling_list = &pps->scaling_list;
810 GST_DEBUG_OBJECT (decoder, "Passing scaling list from PPS");
811 } else if (sps->scaling_list_enabled_flag &&
812 sps->scaling_list_data_present_flag) {
813 scaling_list = &sps->scaling_list;
814 GST_DEBUG_OBJECT (decoder, "Passing scaling list from SPS");
818 for (i = 0; i < G_N_ELEMENTS (iq_matrix.ScalingList4x4); i++)
819 gst_h265_quant_matrix_4x4_get_raster_from_uprightdiagonal
820 (iq_matrix.ScalingList4x4[i], scaling_list->scaling_lists_4x4[i]);
822 for (i = 0; i < G_N_ELEMENTS (iq_matrix.ScalingList8x8); i++)
823 gst_h265_quant_matrix_8x8_get_raster_from_uprightdiagonal
824 (iq_matrix.ScalingList8x8[i], scaling_list->scaling_lists_8x8[i]);
826 for (i = 0; i < G_N_ELEMENTS (iq_matrix.ScalingList16x16); i++)
827 gst_h265_quant_matrix_16x16_get_raster_from_uprightdiagonal
828 (iq_matrix.ScalingList16x16[i], scaling_list->scaling_lists_16x16[i]);
830 for (i = 0; i < G_N_ELEMENTS (iq_matrix.ScalingList32x32); i++)
831 gst_h265_quant_matrix_32x32_get_raster_from_uprightdiagonal
832 (iq_matrix.ScalingList32x32[i], scaling_list->scaling_lists_32x32[i]);
834 for (i = 0; i < 6; i++)
835 iq_matrix.ScalingListDC16x16[i] =
836 scaling_list->scaling_list_dc_coef_minus8_16x16[i] + 8;
838 for (i = 0; i < 2; i++)
839 iq_matrix.ScalingListDC32x32[i] =
840 scaling_list->scaling_list_dc_coef_minus8_32x32[i] + 8;
842 if (!gst_va_decoder_add_param_buffer (base->decoder, va_pic,
843 VAIQMatrixBufferType, &iq_matrix, sizeof (iq_matrix))) {
844 return GST_FLOW_ERROR;
852 gst_va_h265_dec_new_picture (GstH265Decoder * decoder,
853 GstVideoCodecFrame * frame, GstH265Picture * picture)
855 GstVaBaseDec *base = GST_VA_BASE_DEC (decoder);
856 GstVaH265Dec *self = GST_VA_H265_DEC (decoder);
857 GstVaDecodePicture *pic;
858 GstBuffer *output_buffer;
859 GstVideoDecoder *vdec = GST_VIDEO_DECODER (decoder);
861 if (base->need_negotiation) {
862 if (!gst_video_decoder_negotiate (vdec)) {
863 GST_ERROR_OBJECT (self, "Failed to negotiate with downstream");
864 return GST_FLOW_NOT_NEGOTIATED;
868 output_buffer = gst_video_decoder_allocate_output_buffer (vdec);
869 if (!output_buffer) {
870 self->last_ret = GST_FLOW_ERROR;
873 self->last_ret = GST_FLOW_OK;
875 pic = gst_va_decode_picture_new (base->decoder, output_buffer);
876 gst_buffer_unref (output_buffer);
878 gst_h265_picture_set_user_data (picture, pic,
879 (GDestroyNotify) gst_va_decode_picture_free);
881 GST_LOG_OBJECT (self, "New va decode picture %p - %#x", pic,
882 gst_va_decode_picture_get_surface (pic));
888 GST_WARNING_OBJECT (self,
889 "Failed to allocated output buffer, return %s",
890 gst_flow_get_name (self->last_ret));
891 return self->last_ret;
896 _get_rtformat (GstVaH265Dec * self, guint8 bit_depth_luma,
897 guint8 bit_depth_chroma, guint8 chroma_format_idc)
899 guint8 bit_num = MAX (bit_depth_luma, bit_depth_chroma);
904 if (chroma_format_idc == 3)
905 return VA_RT_FORMAT_YUV444_12;
906 if (chroma_format_idc == 2)
907 return VA_RT_FORMAT_YUV422_12;
909 return VA_RT_FORMAT_YUV420_12;
913 if (chroma_format_idc == 3)
914 return VA_RT_FORMAT_YUV444_10;
915 if (chroma_format_idc == 2)
916 return VA_RT_FORMAT_YUV422_10;
918 return VA_RT_FORMAT_YUV420_10;
921 if (chroma_format_idc == 3)
922 return VA_RT_FORMAT_YUV444;
923 if (chroma_format_idc == 2)
924 return VA_RT_FORMAT_YUV422;
926 return VA_RT_FORMAT_YUV420;
929 GST_ERROR_OBJECT (self, "Unsupported chroma format: %d "
930 "(with depth luma: %d, with depth chroma: %d)",
931 chroma_format_idc, bit_depth_luma, bit_depth_chroma);
939 GstH265Profile profile;
940 VAProfile va_profile;
942 #define P(idc, va) { G_PASTE (GST_H265_PROFILE_, idc), G_PASTE (VAProfileHEVC, va) }
945 /*P (MAIN_STILL_PICTURE, ),
948 P (MONOCHROME_16, ),*/
950 P (MAIN_422_10, Main422_10),
951 P (MAIN_422_12, Main422_12),
952 P (MAIN_444, Main444),
953 P (MAIN_444_10, Main444_10),
954 P (MAIN_444_12, Main444_12),
958 P (MAIN_422_10_INTRA, ),
959 P (MAIN_422_12_INTRA, ),
960 P (MAIN_444_INTRA, ),
961 P (MAIN_444_10_INTRA, ),
962 P (MAIN_444_12_INTRA, ),
963 P (MAIN_444_16_INTRA, ),
964 P (MAIN_444_STILL_PICTURE, ),
965 P (MAIN_444_16_STILL_PICTURE, ),
967 P (HIGH_THROUGHPUT_444, ),
968 P (HIGH_THROUGHPUT_444_10, ),
969 P (HIGH_THROUGHPUT_444_14, ),
970 P (HIGH_THROUGHPUT_444_16_INTRA, ),*/
971 P (SCREEN_EXTENDED_MAIN, SccMain),
972 P (SCREEN_EXTENDED_MAIN_10, SccMain10),
973 P (SCREEN_EXTENDED_MAIN_444, SccMain444),
974 /*P (SCREEN_EXTENDED_MAIN_444_10, ),
975 P (SCREEN_EXTENDED_HIGH_THROUGHPUT_444, ),
976 P (SCREEN_EXTENDED_HIGH_THROUGHPUT_444_10, ),
977 P (SCREEN_EXTENDED_HIGH_THROUGHPUT_444_14, ),
978 P (MULTIVIEW_MAIN, ),
980 P (SCALABLE_MAIN_10, ),
981 P (SCALABLE_MONOCHROME, ),
982 P (SCALABLE_MONOCHROME_12, ),
983 P (SCALABLE_MONOCHROME_16, ),
984 P (SCALABLE_MAIN_444, ),
991 _get_profile (GstVaH265Dec * self, const GstH265SPS * sps, gint max_dpb_size)
993 GstH265Decoder *h265_decoder = GST_H265_DECODER (self);
994 GstVaBaseDec *base = GST_VA_BASE_DEC (self);
995 GstH265Profile profile = gst_h265_get_profile_from_sps ((GstH265SPS *) sps);
996 VAProfile profiles[4];
999 /* 1. The profile directly specified by the SPS should always be the
1000 first choice. It is the exact one.
1001 2. The profile in the input caps may contain the compatible profile
1002 chosen by the upstream element. Upstream element such as the parse
1003 may already decide the best compatible profile for us. We also need
1004 to consider it as a choice. */
1006 for (j = 0; j < G_N_ELEMENTS (profile_map); j++) {
1007 if (profile_map[j].profile == profile) {
1008 profiles[i++] = profile_map[j].va_profile;
1013 if (h265_decoder->input_state->caps
1014 && gst_caps_is_fixed (h265_decoder->input_state->caps)) {
1015 GstH265Profile compatible_profile = GST_H265_PROFILE_INVALID;
1016 GstStructure *structure;
1017 const gchar *profile_str;
1019 structure = gst_caps_get_structure (h265_decoder->input_state->caps, 0);
1021 profile_str = gst_structure_get_string (structure, "profile");
1023 compatible_profile = gst_h265_profile_from_string (profile_str);
1025 if (compatible_profile != profile) {
1026 GST_INFO_OBJECT (self, "The upstream set the compatible profile %s, "
1027 "also consider it as a candidate.", profile_str);
1029 for (j = 0; j < G_N_ELEMENTS (profile_map); j++) {
1030 if (profile_map[j].profile == compatible_profile) {
1031 profiles[i++] = profile_map[j].va_profile;
1038 for (j = 0; j < i && j < G_N_ELEMENTS (profiles); j++) {
1039 if (gst_va_decoder_has_profile (base->decoder, profiles[j]))
1043 GST_ERROR_OBJECT (self, "Unsupported profile: %d", profile);
1045 return VAProfileNone;
1048 static GstFlowReturn
1049 gst_va_h265_dec_new_sequence (GstH265Decoder * decoder, const GstH265SPS * sps,
1052 GstVaBaseDec *base = GST_VA_BASE_DEC (decoder);
1053 GstVaH265Dec *self = GST_VA_H265_DEC (decoder);
1056 gint display_height;
1057 gint padding_left, padding_right, padding_top, padding_bottom;
1059 gboolean negotiation_needed = FALSE;
1061 if (self->dpb_size < max_dpb_size)
1062 self->dpb_size = max_dpb_size;
1064 if (sps->conformance_window_flag) {
1065 display_width = sps->crop_rect_width;
1066 display_height = sps->crop_rect_height;
1067 padding_left = sps->crop_rect_x;
1068 padding_right = sps->width - sps->crop_rect_x - display_width;
1069 padding_top = sps->crop_rect_y;
1070 padding_bottom = sps->height - sps->crop_rect_y - display_height;
1072 display_width = sps->width;
1073 display_height = sps->height;
1074 padding_left = padding_right = padding_top = padding_bottom = 0;
1077 profile = _get_profile (self, sps, max_dpb_size);
1078 if (profile == VAProfileNone)
1079 return GST_FLOW_NOT_NEGOTIATED;
1081 rt_format = _get_rtformat (self, sps->bit_depth_luma_minus8 + 8,
1082 sps->bit_depth_chroma_minus8 + 8, sps->chroma_format_idc);
1084 return GST_FLOW_NOT_NEGOTIATED;
1086 if (!gst_va_decoder_config_is_equal (base->decoder, profile,
1087 rt_format, sps->width, sps->height)) {
1088 base->profile = profile;
1089 base->rt_format = rt_format;
1090 self->coded_width = sps->width;
1091 self->coded_height = sps->height;
1093 negotiation_needed = TRUE;
1094 GST_INFO_OBJECT (self, "Format changed to %s [%x] (%dx%d)",
1095 gst_va_profile_name (profile), rt_format, self->coded_width,
1096 self->coded_height);
1099 if (base->width != display_width || base->height != display_height) {
1100 base->width = display_width;
1101 base->height = display_height;
1103 negotiation_needed = TRUE;
1104 GST_INFO_OBJECT (self, "Resolution changed to %dx%d", base->width,
1108 base->need_valign = base->width < self->coded_width
1109 || base->height < self->coded_height;
1110 if (base->need_valign) {
1112 if (base->valign.padding_left != padding_left ||
1113 base->valign.padding_right != padding_right ||
1114 base->valign.padding_top != padding_top ||
1115 base->valign.padding_bottom != padding_bottom) {
1116 negotiation_needed = TRUE;
1117 GST_INFO_OBJECT (self, "crop rect changed to (%d,%d)-->(%d,%d)",
1118 padding_left, padding_top, padding_right, padding_bottom);
1120 base->valign = (GstVideoAlignment) {
1121 .padding_left = padding_left,
1122 .padding_right = padding_right,
1123 .padding_top = padding_top,
1124 .padding_bottom = padding_bottom,
1129 base->min_buffers = self->dpb_size + 4; /* dpb size + scratch surfaces */
1131 base->need_negotiation = negotiation_needed;
1134 /* FIXME: We don't have parser API for sps_range_extension, so
1135 * assuming high_precision_offsets_enabled_flag as zero */
1136 guint high_precision_offsets_enabled_flag = 0, bitdepthC = 0;
1138 /* Calculate WpOffsetHalfRangeC: (7-34) */
1139 bitdepthC = sps->bit_depth_chroma_minus8 + 8;
1140 self->WpOffsetHalfRangeC =
1141 1 << (high_precision_offsets_enabled_flag ? (bitdepthC - 1) : 7);
1148 _complete_sink_caps (GstCaps * sinkcaps)
1150 GstCaps *caps = gst_caps_copy (sinkcaps);
1151 GValue val = G_VALUE_INIT;
1152 const gchar *streamformat[] = { "hvc1", "hev1", "byte-stream" };
1155 g_value_init (&val, G_TYPE_STRING);
1156 g_value_set_string (&val, "au");
1157 gst_caps_set_value (caps, "alignment", &val);
1158 g_value_unset (&val);
1160 gst_value_list_init (&val, G_N_ELEMENTS (streamformat));
1161 for (i = 0; i < G_N_ELEMENTS (streamformat); i++) {
1162 GValue v = G_VALUE_INIT;
1164 g_value_init (&v, G_TYPE_STRING);
1165 g_value_set_string (&v, streamformat[i]);
1166 gst_value_list_append_value (&val, &v);
1169 gst_caps_set_value (caps, "stream-format", &val);
1170 g_value_unset (&val);
1176 gst_va_h265_dec_getcaps (GstVideoDecoder * decoder, GstCaps * filter)
1178 GstCaps *sinkcaps, *caps = NULL, *tmp;
1179 GstVaBaseDec *base = GST_VA_BASE_DEC (decoder);
1182 caps = gst_va_decoder_get_sinkpad_caps (base->decoder);
1185 sinkcaps = _complete_sink_caps (caps);
1186 gst_caps_unref (caps);
1188 tmp = gst_caps_intersect_full (filter, sinkcaps,
1189 GST_CAPS_INTERSECT_FIRST);
1190 gst_caps_unref (sinkcaps);
1195 GST_LOG_OBJECT (base, "Returning caps %" GST_PTR_FORMAT, caps);
1197 caps = gst_video_decoder_proxy_getcaps (decoder, NULL, filter);
1204 gst_va_h265_dec_negotiate (GstVideoDecoder * decoder)
1206 GstVaBaseDec *base = GST_VA_BASE_DEC (decoder);
1207 GstVaH265Dec *self = GST_VA_H265_DEC (decoder);
1208 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
1209 GstCapsFeatures *capsfeatures = NULL;
1210 GstH265Decoder *h265dec = GST_H265_DECODER (decoder);
1212 /* Ignore downstream renegotiation request. */
1213 if (!base->need_negotiation)
1216 base->need_negotiation = FALSE;
1218 if (gst_va_decoder_is_open (base->decoder)
1219 && !gst_va_decoder_close (base->decoder))
1222 if (!gst_va_decoder_open (base->decoder, base->profile, base->rt_format))
1225 if (!gst_va_decoder_set_frame_size (base->decoder, self->coded_width,
1226 self->coded_height))
1229 if (base->output_state)
1230 gst_video_codec_state_unref (base->output_state);
1232 gst_va_base_dec_get_preferred_format_and_caps_features (base, &format,
1235 base->output_state =
1236 gst_video_decoder_set_output_state (decoder, format,
1237 base->width, base->height, h265dec->input_state);
1239 base->output_state->caps = gst_video_info_to_caps (&base->output_state->info);
1241 gst_caps_set_features_simple (base->output_state->caps, capsfeatures);
1243 GST_INFO_OBJECT (self, "Negotiated caps %" GST_PTR_FORMAT,
1244 base->output_state->caps);
1246 return GST_VIDEO_DECODER_CLASS (parent_class)->negotiate (decoder);
1250 gst_va_h265_dec_dispose (GObject * object)
1252 g_free (GST_VA_H265_DEC (object)->prev_slice.data);
1254 gst_va_base_dec_close (GST_VIDEO_DECODER (object));
1256 G_OBJECT_CLASS (parent_class)->dispose (object);
1260 gst_va_h265_dec_class_init (gpointer g_class, gpointer class_data)
1262 GstCaps *src_doc_caps, *sink_doc_caps;
1263 GObjectClass *gobject_class = G_OBJECT_CLASS (g_class);
1264 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
1265 GstH265DecoderClass *h265decoder_class = GST_H265_DECODER_CLASS (g_class);
1266 GstVideoDecoderClass *decoder_class = GST_VIDEO_DECODER_CLASS (g_class);
1267 struct CData *cdata = class_data;
1270 if (cdata->description) {
1271 long_name = g_strdup_printf ("VA-API H.265 Decoder in %s",
1272 cdata->description);
1274 long_name = g_strdup ("VA-API H.265 Decoder");
1277 gst_element_class_set_metadata (element_class, long_name,
1278 "Codec/Decoder/Video/Hardware",
1279 "VA-API based H.265 video decoder",
1280 "Nicolas Dufresne <nicolas.dufresne@collabora.com>");
1282 sink_doc_caps = gst_caps_from_string (sink_caps_str);
1283 src_doc_caps = gst_caps_from_string (src_caps_str);
1285 parent_class = g_type_class_peek_parent (g_class);
1287 gst_va_base_dec_class_init (GST_VA_BASE_DEC_CLASS (g_class), HEVC,
1288 cdata->render_device_path, cdata->sink_caps, cdata->src_caps,
1289 src_doc_caps, sink_doc_caps);
1291 gobject_class->dispose = gst_va_h265_dec_dispose;
1293 decoder_class->getcaps = GST_DEBUG_FUNCPTR (gst_va_h265_dec_getcaps);
1294 decoder_class->negotiate = GST_DEBUG_FUNCPTR (gst_va_h265_dec_negotiate);
1296 h265decoder_class->new_sequence =
1297 GST_DEBUG_FUNCPTR (gst_va_h265_dec_new_sequence);
1298 h265decoder_class->decode_slice =
1299 GST_DEBUG_FUNCPTR (gst_va_h265_dec_decode_slice);
1301 h265decoder_class->new_picture =
1302 GST_DEBUG_FUNCPTR (gst_va_h265_dec_new_picture);
1303 h265decoder_class->output_picture =
1304 GST_DEBUG_FUNCPTR (gst_va_h265_dec_output_picture);
1305 h265decoder_class->start_picture =
1306 GST_DEBUG_FUNCPTR (gst_va_h265_dec_start_picture);
1307 h265decoder_class->end_picture =
1308 GST_DEBUG_FUNCPTR (gst_va_h265_dec_end_picture);
1311 g_free (cdata->description);
1312 g_free (cdata->render_device_path);
1313 gst_caps_unref (cdata->src_caps);
1314 gst_caps_unref (cdata->sink_caps);
1319 gst_va_h265_dec_init (GTypeInstance * instance, gpointer g_class)
1321 gst_va_base_dec_init (GST_VA_BASE_DEC (instance), GST_CAT_DEFAULT);
1322 gst_h265_decoder_set_process_ref_pic_lists (GST_H265_DECODER (instance),
1327 _register_debug_category (gpointer data)
1329 GST_DEBUG_CATEGORY_INIT (gst_va_h265dec_debug, "vah265dec", 0,
1336 gst_va_h265_dec_register (GstPlugin * plugin, GstVaDevice * device,
1337 GstCaps * sink_caps, GstCaps * src_caps, guint rank)
1339 static GOnce debug_once = G_ONCE_INIT;
1341 GTypeInfo type_info = {
1342 .class_size = sizeof (GstVaH265DecClass),
1343 .class_init = gst_va_h265_dec_class_init,
1344 .instance_size = sizeof (GstVaH265Dec),
1345 .instance_init = gst_va_h265_dec_init,
1347 struct CData *cdata;
1349 gchar *type_name, *feature_name;
1351 g_return_val_if_fail (GST_IS_PLUGIN (plugin), FALSE);
1352 g_return_val_if_fail (GST_IS_VA_DEVICE (device), FALSE);
1353 g_return_val_if_fail (GST_IS_CAPS (sink_caps), FALSE);
1354 g_return_val_if_fail (GST_IS_CAPS (src_caps), FALSE);
1356 cdata = g_new (struct CData, 1);
1357 cdata->description = NULL;
1358 cdata->render_device_path = g_strdup (device->render_device_path);
1359 cdata->sink_caps = _complete_sink_caps (sink_caps);
1360 cdata->src_caps = gst_caps_ref (src_caps);
1362 /* class data will be leaked if the element never gets instantiated */
1363 GST_MINI_OBJECT_FLAG_SET (cdata->sink_caps,
1364 GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
1365 GST_MINI_OBJECT_FLAG_SET (src_caps, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
1367 type_info.class_data = cdata;
1369 type_name = g_strdup ("GstVaH265Dec");
1370 feature_name = g_strdup ("vah265dec");
1372 /* The first decoder to be registered should use a constant name,
1373 * like vah265dec, for any additional decoders, we create unique
1374 * names, using inserting the render device name. */
1375 if (g_type_from_name (type_name)) {
1376 gchar *basename = g_path_get_basename (device->render_device_path);
1378 g_free (feature_name);
1379 type_name = g_strdup_printf ("GstVa%sH265Dec", basename);
1380 feature_name = g_strdup_printf ("va%sh265dec", basename);
1381 cdata->description = basename;
1383 /* lower rank for non-first device */
1388 g_once (&debug_once, _register_debug_category, NULL);
1390 type = g_type_register_static (GST_TYPE_H265_DECODER,
1391 type_name, &type_info, 0);
1393 ret = gst_element_register (plugin, feature_name, rank, type);
1396 g_free (feature_name);