• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GStreamer
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>
6  *
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.
11  *
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.
16  *
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.
21  */
22 
23 /**
24  * SECTION:element-vah265dec
25  * @title: vah265dec
26  * @short_description: A VA-API based H265 video decoder
27  *
28  * vah265dec decodes H265 bitstreams to VA surfaces using the
29  * installed and chosen [VA-API](https://01.org/linuxmedia/vaapi)
30  * driver.
31  *
32  * The decoding surfaces can be mapped onto main memory as video
33  * frames.
34  *
35  * ## Example launch line
36  * ```
37  * gst-launch-1.0 filesrc location=big_buck_bunny.mov ! parsebin ! vah265dec ! autovideosink
38  * ```
39  *
40  * Since: 1.20
41  *
42  */
43 
44 /* ToDo:
45  *
46  * + interlaced streams
47  * + mutiview and stereo profiles
48  * + SCC extension buffer
49  * + Add 10bit support
50  */
51 
52 #ifdef HAVE_CONFIG_H
53 #include "config.h"
54 #endif
55 
56 #include "gstvah265dec.h"
57 
58 #include "gstvabasedec.h"
59 
60 GST_DEBUG_CATEGORY_STATIC (gst_va_h265dec_debug);
61 #ifndef GST_DISABLE_GST_DEBUG
62 #define GST_CAT_DEFAULT gst_va_h265dec_debug
63 #else
64 #define GST_CAT_DEFAULT NULL
65 #endif
66 
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)
70 
71 struct slice
72 {
73   guint8 *data;
74   guint size;
75 
76   VASliceParameterBufferHEVCExtension param;
77 };
78 
79 typedef struct _GstVaH265Dec GstVaH265Dec;
80 typedef struct _GstVaH265DecClass GstVaH265DecClass;
81 
82 struct _GstVaH265DecClass
83 {
84   GstVaBaseDecClass parent_class;
85 };
86 
87 struct _GstVaH265Dec
88 {
89   GstVaBaseDec parent;
90 
91   GstFlowReturn last_ret;
92 
93   gint coded_width;
94   gint coded_height;
95   gint dpb_size;
96 
97   VAPictureParameterBufferHEVCExtension pic_param;
98 
99   gint32 WpOffsetHalfRangeC;
100 
101   struct slice prev_slice;
102 };
103 
104 static GstElementClass *parent_class = NULL;
105 
106 /* *INDENT-OFF* */
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 }");
111 /* *INDENT-ON* */
112 
113 static const gchar *sink_caps_str = "video/x-h265";
114 
115 static gboolean
_is_range_extension_profile(VAProfile profile)116 _is_range_extension_profile (VAProfile profile)
117 {
118   if (profile == VAProfileHEVCMain422_10
119       || profile == VAProfileHEVCMain444
120       || profile == VAProfileHEVCMain444_10
121       || profile == VAProfileHEVCMain12
122       || profile == VAProfileHEVCMain444_12
123       || profile == VAProfileHEVCMain422_12)
124     return TRUE;
125   return FALSE;
126 }
127 
128 static gboolean
_is_screen_content_ext_profile(VAProfile profile)129 _is_screen_content_ext_profile (VAProfile profile)
130 {
131   if (profile == VAProfileHEVCSccMain
132       || profile == VAProfileHEVCSccMain10
133       || profile == VAProfileHEVCSccMain444)
134     return TRUE;
135 
136   return FALSE;
137 }
138 
139 static inline void
_set_last_slice_flag(GstVaH265Dec * self)140 _set_last_slice_flag (GstVaH265Dec * self)
141 {
142   self->prev_slice.param.base.LongSliceFlags.fields.LastSliceOfPic = 1;
143 }
144 
145 static void
_replace_previous_slice(GstVaH265Dec * self,guint8 * data,guint size)146 _replace_previous_slice (GstVaH265Dec * self, guint8 * data, guint size)
147 {
148   struct slice *slice = &self->prev_slice;
149   gboolean do_reset = (slice->size < size);
150 
151   if (!data || do_reset) {
152     g_clear_pointer (&slice->data, g_free);
153     slice->size = 0;
154   }
155 
156   if (!data)
157     return;
158 
159   if (do_reset) {
160     GST_LOG_OBJECT (self, "allocating slice data %u", size);
161     slice->data = g_malloc (size);
162   }
163 
164   memcpy (slice->data, data, size);
165   slice->size = size;
166 }
167 
168 static gboolean
_submit_previous_slice(GstVaBaseDec * base,GstVaDecodePicture * va_pic)169 _submit_previous_slice (GstVaBaseDec * base, GstVaDecodePicture * va_pic)
170 {
171   GstVaH265Dec *self = GST_VA_H265_DEC (base);
172   struct slice *slice;
173   gboolean ret;
174   gsize param_size;
175 
176   slice = &self->prev_slice;
177   if (!slice->data && slice->size == 0)
178     return TRUE;
179   if (!slice->data || slice->size == 0)
180     return FALSE;
181 
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);
187 
188   return ret;
189 }
190 
191 static GstFlowReturn
gst_va_h265_dec_end_picture(GstH265Decoder * decoder,GstH265Picture * picture)192 gst_va_h265_dec_end_picture (GstH265Decoder * decoder, GstH265Picture * picture)
193 {
194   GstVaBaseDec *base = GST_VA_BASE_DEC (decoder);
195   GstVaH265Dec *self = GST_VA_H265_DEC (decoder);
196   GstVaDecodePicture *va_pic;
197   gboolean ret;
198 
199   GST_LOG_OBJECT (base, "end picture %p, (poc %d)",
200       picture, picture->pic_order_cnt);
201 
202   va_pic = gst_h265_picture_get_user_data (picture);
203 
204   _set_last_slice_flag (self);
205   ret = _submit_previous_slice (base, va_pic);
206 
207   /* TODO(victor): optimization: this could be done at decoder's
208    * stop() vmethod */
209   _replace_previous_slice (self, NULL, 0);
210 
211   if (!ret) {
212     GST_ERROR_OBJECT (self, "Failed to submit the previous slice");
213     return GST_FLOW_ERROR;
214   }
215 
216   ret = gst_va_decoder_decode (base->decoder, va_pic);
217   if (!ret) {
218     GST_ERROR_OBJECT (self, "Failed at end picture %p, (poc %d)",
219         picture, picture->pic_order_cnt);
220     return GST_FLOW_ERROR;
221   }
222 
223   return GST_FLOW_OK;
224 }
225 
226 static GstFlowReturn
gst_va_h265_dec_output_picture(GstH265Decoder * decoder,GstVideoCodecFrame * frame,GstH265Picture * picture)227 gst_va_h265_dec_output_picture (GstH265Decoder * decoder,
228     GstVideoCodecFrame * frame, GstH265Picture * picture)
229 {
230   GstVaBaseDec *base = GST_VA_BASE_DEC (decoder);
231   GstVaH265Dec *self = GST_VA_H265_DEC (decoder);
232   GstVaDecodePicture *va_pic;
233 
234   va_pic = gst_h265_picture_get_user_data (picture);
235   g_assert (va_pic->gstbuffer);
236 
237   GST_LOG_OBJECT (self,
238       "Outputting picture %p (poc %d)", picture, picture->pic_order_cnt);
239 
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;
245   }
246 
247   gst_buffer_replace (&frame->output_buffer, va_pic->gstbuffer);
248 
249   if (base->copy_frames)
250     gst_va_base_dec_copy_output_buffer (base, frame);
251 
252   gst_h265_picture_unref (picture);
253 
254   return gst_video_decoder_finish_frame (GST_VIDEO_DECODER (self), frame);
255 }
256 
257 static void
_init_vaapi_pic(VAPictureHEVC * va_picture)258 _init_vaapi_pic (VAPictureHEVC * va_picture)
259 {
260   va_picture->picture_id = VA_INVALID_ID;
261   va_picture->flags = VA_PICTURE_HEVC_INVALID;
262   va_picture->pic_order_cnt = 0;
263 }
264 
265 static gint
_find_frame_rps_type(GstH265Decoder * decoder,GstH265Picture * ref_pic)266 _find_frame_rps_type (GstH265Decoder * decoder, GstH265Picture * ref_pic)
267 {
268   gint i;
269 
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;
273   }
274 
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;
278   }
279 
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;
283   }
284 
285   return 0;
286 }
287 
288 
289 static void
_fill_vaapi_pic(GstH265Decoder * decoder,VAPictureHEVC * va_picture,GstH265Picture * picture)290 _fill_vaapi_pic (GstH265Decoder * decoder, VAPictureHEVC * va_picture,
291     GstH265Picture * picture)
292 {
293   GstVaDecodePicture *va_pic;
294 
295   va_pic = gst_h265_picture_get_user_data (picture);
296 
297   if (!va_pic) {
298     _init_vaapi_pic (va_picture);
299     return;
300   }
301 
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;
305 
306   if (picture->ref && picture->long_term)
307     va_picture->flags |= VA_PICTURE_HEVC_LONG_TERM_REFERENCE;
308 
309   va_picture->flags |= _find_frame_rps_type (decoder, picture);
310 }
311 
312 static guint8
_get_reference_index(GstH265Decoder * decoder,GstH265Picture * picture)313 _get_reference_index (GstH265Decoder * decoder, GstH265Picture * picture)
314 {
315   GstVaH265Dec *self = GST_VA_H265_DEC (decoder);
316   guint8 i;
317 
318   for (i = 0; i < 15; i++) {
319     VAPictureHEVC *ref_va_pic = &self->pic_param.base.ReferenceFrames[i];
320 
321     if (ref_va_pic->picture_id == VA_INVALID_ID)
322       break;
323 
324     if (ref_va_pic->pic_order_cnt == picture->pic_order_cnt)
325       return i;
326   }
327 
328   return 0xFF;
329 }
330 
331 /* fill the VA API reference picture lists from the GstCodec reference
332  * picture list */
333 static void
_fill_ref_pic_list(GstH265Decoder * decoder,GstH265Picture * cur_pic,guint8 va_reflist[15],GArray * reflist)334 _fill_ref_pic_list (GstH265Decoder * decoder, GstH265Picture * cur_pic,
335     guint8 va_reflist[15], GArray * reflist)
336 {
337   guint i;
338 
339   for (i = 0; i < reflist->len && i < 15; i++) {
340     GstH265Picture *picture = g_array_index (reflist, GstH265Picture *, i);
341     va_reflist[i] = _get_reference_index (decoder, picture);
342   }
343 
344   for (; i < 15; i++)
345     va_reflist[i] = 0xFF;
346 }
347 
348 static void
_fill_pred_weight_table(GstVaH265Dec * self,GstH265SliceHdr * header,VASliceParameterBufferHEVCExtension * slice_param)349 _fill_pred_weight_table (GstVaH265Dec * self, GstH265SliceHdr * header,
350     VASliceParameterBufferHEVCExtension * slice_param)
351 {
352   gint chroma_weight, chroma_log2_weight_denom;
353   gint i, j;
354   GstH265PPS *pps = header->pps;
355   gboolean is_rext = _is_range_extension_profile (self->parent.profile);
356 
357   if (GST_H265_IS_I_SLICE (header) ||
358       (!pps->weighted_pred_flag && GST_H265_IS_P_SLICE (header)) ||
359       (!pps->weighted_bipred_flag && GST_H265_IS_B_SLICE (header)))
360     return;
361 
362   slice_param->base.luma_log2_weight_denom =
363       header->pred_weight_table.luma_log2_weight_denom;
364 
365   if (pps->sps->chroma_array_type != 0)
366     slice_param->base.delta_chroma_log2_weight_denom =
367         header->pred_weight_table.delta_chroma_log2_weight_denom;
368 
369   for (i = 0; i <= header->num_ref_idx_l0_active_minus1; i++) {
370     if (!header->pred_weight_table.luma_weight_l0_flag[i])
371       continue;
372 
373     slice_param->base.delta_luma_weight_l0[i] =
374         header->pred_weight_table.delta_luma_weight_l0[i];
375     slice_param->base.luma_offset_l0[i] =
376         header->pred_weight_table.luma_offset_l0[i];
377 
378     if (is_rext) {
379       slice_param->rext.luma_offset_l0[i] =
380           header->pred_weight_table.luma_offset_l0[i];
381     }
382   }
383 
384   chroma_log2_weight_denom = slice_param->base.luma_log2_weight_denom +
385       slice_param->base.delta_chroma_log2_weight_denom;
386 
387   for (i = 0; i <= header->num_ref_idx_l0_active_minus1; i++) {
388     if (!header->pred_weight_table.chroma_weight_l0_flag[i])
389       continue;
390 
391     for (j = 0; j < 2; j++) {
392       gint16 delta_chroma_offset_l0 =
393           header->pred_weight_table.delta_chroma_offset_l0[i][j];
394       gint chroma_offset;
395 
396       slice_param->base.delta_chroma_weight_l0[i][j] =
397           header->pred_weight_table.delta_chroma_weight_l0[i][j];
398 
399       /* Find  ChromaWeightL0 */
400       chroma_weight = (1 << chroma_log2_weight_denom) +
401           header->pred_weight_table.delta_chroma_weight_l0[i][j];
402       chroma_offset = self->WpOffsetHalfRangeC + delta_chroma_offset_l0
403           - ((self->WpOffsetHalfRangeC * chroma_weight)
404           >> chroma_log2_weight_denom);
405 
406       /* 7-56 */
407       slice_param->base.ChromaOffsetL0[i][j] = CLAMP (chroma_offset,
408           -self->WpOffsetHalfRangeC, self->WpOffsetHalfRangeC - 1);
409 
410       if (is_rext) {
411         slice_param->rext.ChromaOffsetL0[i][j] =
412             slice_param->base.ChromaOffsetL0[i][j];
413       }
414     }
415   }
416 
417   /* Skip l1 if this is not a B-Frame. */
418   if (!GST_H265_IS_B_SLICE (header))
419     return;
420 
421   for (i = 0; i <= header->num_ref_idx_l1_active_minus1; i++) {
422     if (!header->pred_weight_table.luma_weight_l1_flag[i])
423       continue;
424 
425     slice_param->base.delta_luma_weight_l1[i] =
426         header->pred_weight_table.delta_luma_weight_l1[i];
427     slice_param->base.luma_offset_l1[i] =
428         header->pred_weight_table.luma_offset_l1[i];
429 
430     if (is_rext) {
431       slice_param->rext.luma_offset_l1[i] =
432           header->pred_weight_table.luma_offset_l1[i];
433     }
434   }
435 
436   for (i = 0; i <= header->num_ref_idx_l1_active_minus1; i++) {
437     if (!header->pred_weight_table.chroma_weight_l1_flag[i])
438       continue;
439 
440     for (j = 0; j < 2; j++) {
441       gint16 delta_chroma_offset_l1 =
442           header->pred_weight_table.delta_chroma_offset_l1[i][j];
443       gint chroma_offset;
444 
445       slice_param->base.delta_chroma_weight_l1[i][j] =
446           header->pred_weight_table.delta_chroma_weight_l1[i][j];
447 
448       /* Find  ChromaWeightL1 */
449       chroma_weight = (1 << chroma_log2_weight_denom) +
450           header->pred_weight_table.delta_chroma_weight_l1[i][j];
451 
452       chroma_offset = self->WpOffsetHalfRangeC + delta_chroma_offset_l1
453           - ((self->WpOffsetHalfRangeC * chroma_weight)
454           >> chroma_log2_weight_denom);
455 
456       /* 7-56 */
457       slice_param->base.ChromaOffsetL1[i][j] = CLAMP (chroma_offset,
458           -self->WpOffsetHalfRangeC, self->WpOffsetHalfRangeC - 1);
459 
460       if (is_rext) {
461         slice_param->rext.ChromaOffsetL1[i][j] =
462             slice_param->base.ChromaOffsetL1[i][j];
463       }
464     }
465   }
466 }
467 
468 static inline guint
_get_slice_data_byte_offset(GstH265SliceHdr * slice_hdr,guint nal_header_bytes)469 _get_slice_data_byte_offset (GstH265SliceHdr * slice_hdr,
470     guint nal_header_bytes)
471 {
472   guint epb_count;
473 
474   epb_count = slice_hdr->n_emulation_prevention_bytes;
475   return nal_header_bytes + (slice_hdr->header_size + 7) / 8 - epb_count;
476 }
477 
478 static GstFlowReturn
gst_va_h265_dec_decode_slice(GstH265Decoder * decoder,GstH265Picture * picture,GstH265Slice * slice,GArray * ref_pic_list0,GArray * ref_pic_list1)479 gst_va_h265_dec_decode_slice (GstH265Decoder * decoder,
480     GstH265Picture * picture, GstH265Slice * slice, GArray * ref_pic_list0,
481     GArray * ref_pic_list1)
482 {
483   GstH265SliceHdr *header = &slice->header;
484   GstH265NalUnit *nalu = &slice->nalu;
485   GstVaBaseDec *base = GST_VA_BASE_DEC (decoder);
486   GstVaH265Dec *self = GST_VA_H265_DEC (decoder);
487   GstVaDecodePicture *va_pic;
488   VASliceParameterBufferHEVCExtension *slice_param;
489 
490   va_pic = gst_h265_picture_get_user_data (picture);
491   if (!_submit_previous_slice (base, va_pic)) {
492     _replace_previous_slice (self, NULL, 0);
493     GST_ERROR_OBJECT (base, "Failed to submit previous slice buffers");
494     return GST_FLOW_ERROR;
495   }
496 
497   slice_param = &self->prev_slice.param;
498 
499   /* *INDENT-OFF* */
500   slice_param->base = (VASliceParameterBufferHEVC) {
501     .slice_data_size = nalu->size,
502     .slice_data_offset = 0,
503     .slice_data_flag = VA_SLICE_DATA_FLAG_ALL,
504     .slice_data_byte_offset = _get_slice_data_byte_offset (header, nalu->header_bytes),
505     .slice_segment_address = header->segment_address,
506     .collocated_ref_idx = header->temporal_mvp_enabled_flag ? header->collocated_ref_idx : 0xFF,
507     .num_ref_idx_l0_active_minus1 = header->num_ref_idx_l0_active_minus1,
508     .num_ref_idx_l1_active_minus1 = header->num_ref_idx_l1_active_minus1,
509     .slice_qp_delta = header->qp_delta,
510     .slice_cb_qp_offset = header->cb_qp_offset,
511     .slice_cr_qp_offset = header->cr_qp_offset,
512     .slice_beta_offset_div2 = header->beta_offset_div2,
513     .slice_tc_offset_div2 = header->tc_offset_div2,
514     .five_minus_max_num_merge_cand = header->five_minus_max_num_merge_cand,
515     .num_entry_point_offsets = header->num_entry_point_offsets,
516     .entry_offset_to_subset_array = 0, /* does not exist in spec */
517     .slice_data_num_emu_prevn_bytes = header->n_emulation_prevention_bytes,
518     .LongSliceFlags.fields = {
519       .LastSliceOfPic = 0, /* the last one will be set on end_picture() */
520       .dependent_slice_segment_flag = header->dependent_slice_segment_flag,
521       .slice_type = header->type,
522       .color_plane_id = header->colour_plane_id,
523       .slice_sao_luma_flag = header->sao_luma_flag,
524       .slice_sao_chroma_flag = header->sao_chroma_flag,
525       .mvd_l1_zero_flag = header->mvd_l1_zero_flag,
526       .cabac_init_flag = header->cabac_init_flag,
527       .slice_temporal_mvp_enabled_flag = header->temporal_mvp_enabled_flag,
528       .slice_deblocking_filter_disabled_flag =
529           header->deblocking_filter_disabled_flag,
530       .collocated_from_l0_flag = header->collocated_from_l0_flag,
531       .slice_loop_filter_across_slices_enabled_flag =
532           header->loop_filter_across_slices_enabled_flag,
533     },
534   };
535   /* *INDENT-ON* */
536 
537   if (_is_range_extension_profile (base->profile)
538       || _is_screen_content_ext_profile (base->profile)) {
539     /* *INDENT-OFF* */
540     slice_param->rext = (VASliceParameterBufferHEVCRext) {
541       .slice_ext_flags.bits = {
542         .cu_chroma_qp_offset_enabled_flag = header->cu_chroma_qp_offset_enabled_flag,
543         .use_integer_mv_flag = header->use_integer_mv_flag,
544       },
545       .slice_act_y_qp_offset = header->slice_act_y_qp_offset,
546       .slice_act_cb_qp_offset = header->slice_act_cb_qp_offset,
547       .slice_act_cr_qp_offset = header->slice_act_cr_qp_offset,
548     };
549     /* *INDENT-ON* */
550   }
551 
552   _fill_ref_pic_list (decoder, picture, slice_param->base.RefPicList[0],
553       ref_pic_list0);
554   _fill_ref_pic_list (decoder, picture, slice_param->base.RefPicList[1],
555       ref_pic_list1);
556 
557   _fill_pred_weight_table (GST_VA_H265_DEC (decoder), header, slice_param);
558 
559   _replace_previous_slice (self, slice->nalu.data + slice->nalu.offset,
560       slice->nalu.size);
561 
562   return GST_FLOW_OK;
563 }
564 
565 static void
_fill_picture_range_ext_parameter(GstVaH265Dec * decoder,GstH265SPS * sps,GstH265PPS * pps)566 _fill_picture_range_ext_parameter (GstVaH265Dec * decoder,
567     GstH265SPS * sps, GstH265PPS * pps)
568 {
569   VAPictureParameterBufferHEVCRext *pic_param = &decoder->pic_param.rext;
570 
571   GstH265SPSExtensionParams *sps_ext = &sps->sps_extnsion_params;
572   GstH265PPSExtensionParams *pps_ext = &pps->pps_extension_params;
573 
574   /* *INDENT-OFF* */
575   *pic_param = (VAPictureParameterBufferHEVCRext) {
576     .range_extension_pic_fields.bits = {
577       .transform_skip_rotation_enabled_flag = sps_ext->transform_skip_rotation_enabled_flag,
578       .transform_skip_context_enabled_flag = sps_ext->transform_skip_context_enabled_flag,
579       .implicit_rdpcm_enabled_flag = sps_ext->implicit_rdpcm_enabled_flag,
580       .explicit_rdpcm_enabled_flag = sps_ext->explicit_rdpcm_enabled_flag,
581       .extended_precision_processing_flag = sps_ext->extended_precision_processing_flag,
582       .intra_smoothing_disabled_flag = sps_ext->intra_smoothing_disabled_flag,
583       .high_precision_offsets_enabled_flag = sps_ext->high_precision_offsets_enabled_flag,
584       .persistent_rice_adaptation_enabled_flag = sps_ext->persistent_rice_adaptation_enabled_flag,
585       .cabac_bypass_alignment_enabled_flag = sps_ext->cabac_bypass_alignment_enabled_flag,
586       .cross_component_prediction_enabled_flag = pps_ext->cross_component_prediction_enabled_flag,
587       .chroma_qp_offset_list_enabled_flag = pps_ext->chroma_qp_offset_list_enabled_flag,
588     },
589     .diff_cu_chroma_qp_offset_depth = pps_ext->diff_cu_chroma_qp_offset_depth,
590     .chroma_qp_offset_list_len_minus1 = pps_ext->chroma_qp_offset_list_len_minus1,
591     .log2_sao_offset_scale_luma = pps_ext->log2_sao_offset_scale_luma,
592     .log2_sao_offset_scale_chroma = pps_ext->log2_sao_offset_scale_chroma,
593     .log2_max_transform_skip_block_size_minus2 = pps_ext->log2_max_transform_skip_block_size_minus2,
594   };
595   /* *INDENT-ON* */
596 
597   memcpy (pic_param->cb_qp_offset_list, pps_ext->cb_qp_offset_list,
598       sizeof (pic_param->cb_qp_offset_list));
599   memcpy (pic_param->cr_qp_offset_list, pps_ext->cr_qp_offset_list,
600       sizeof (pic_param->cr_qp_offset_list));
601 }
602 
603 static void
_fill_screen_content_ext_parameter(GstVaH265Dec * decoder,GstH265SPS * sps,GstH265PPS * pps)604 _fill_screen_content_ext_parameter (GstVaH265Dec * decoder,
605     GstH265SPS * sps, GstH265PPS * pps)
606 {
607   VAPictureParameterBufferHEVCScc *pic_param = &decoder->pic_param.scc;
608   const GstH265PPSSccExtensionParams *pps_scc = &pps->pps_scc_extension_params;
609   const GstH265SPSSccExtensionParams *sps_scc = &sps->sps_scc_extension_params;
610   guint32 num_comps;
611   guint i, n;
612 
613   /* *INDENT-OFF* */
614   *pic_param = (VAPictureParameterBufferHEVCScc) {
615     .screen_content_pic_fields.bits = {
616       .pps_curr_pic_ref_enabled_flag = pps_scc->pps_curr_pic_ref_enabled_flag,
617       .palette_mode_enabled_flag = sps_scc->palette_mode_enabled_flag,
618       .motion_vector_resolution_control_idc = sps_scc->motion_vector_resolution_control_idc,
619       .intra_boundary_filtering_disabled_flag = sps_scc->intra_boundary_filtering_disabled_flag,
620       .residual_adaptive_colour_transform_enabled_flag = pps_scc->residual_adaptive_colour_transform_enabled_flag,
621       .pps_slice_act_qp_offsets_present_flag = pps_scc->pps_slice_act_qp_offsets_present_flag,
622     },
623     .palette_max_size = sps_scc->palette_max_size,
624     .delta_palette_max_predictor_size = sps_scc->delta_palette_max_predictor_size,
625     .pps_act_y_qp_offset_plus5 = pps_scc->pps_act_y_qp_offset_plus5,
626     .pps_act_cb_qp_offset_plus5 = pps_scc->pps_act_cb_qp_offset_plus5,
627     .pps_act_cr_qp_offset_plus3 = pps_scc->pps_act_cr_qp_offset_plus3,
628   };
629   /* *INDENT-ON* */
630 
631   /* firstly use the pps, then sps */
632   num_comps = sps->chroma_format_idc ? 3 : 1;
633 
634   if (pps_scc->pps_palette_predictor_initializers_present_flag) {
635     pic_param->predictor_palette_size =
636         pps_scc->pps_num_palette_predictor_initializer;
637     for (n = 0; n < num_comps; n++)
638       for (i = 0; i < pps_scc->pps_num_palette_predictor_initializer; i++)
639         pic_param->predictor_palette_entries[n][i] =
640             (uint16_t) pps_scc->pps_palette_predictor_initializer[n][i];
641   } else if (sps_scc->sps_palette_predictor_initializers_present_flag) {
642     pic_param->predictor_palette_size =
643         sps_scc->sps_num_palette_predictor_initializer_minus1 + 1;
644     for (n = 0; n < num_comps; n++)
645       for (i = 0;
646           i < sps_scc->sps_num_palette_predictor_initializer_minus1 + 1; i++)
647         pic_param->predictor_palette_entries[n][i] =
648             (uint16_t) sps_scc->sps_palette_predictor_initializer[n][i];
649   }
650 }
651 
652 static GstFlowReturn
gst_va_h265_dec_start_picture(GstH265Decoder * decoder,GstH265Picture * picture,GstH265Slice * slice,GstH265Dpb * dpb)653 gst_va_h265_dec_start_picture (GstH265Decoder * decoder,
654     GstH265Picture * picture, GstH265Slice * slice, GstH265Dpb * dpb)
655 {
656   GstH265PPS *pps;
657   GstH265SPS *sps;
658   GstVaH265Dec *self = GST_VA_H265_DEC (decoder);
659   GstVaBaseDec *base = &self->parent;
660   GstVaDecodePicture *va_pic;
661   GstH265ScalingList *scaling_list = NULL;
662   VAIQMatrixBufferHEVC iq_matrix = { 0, };
663   VAPictureParameterBufferHEVCExtension *pic_param = &self->pic_param;
664   gsize pic_param_size;
665   guint i;
666 
667   va_pic = gst_h265_picture_get_user_data (picture);
668 
669   pps = slice->header.pps;
670   sps = pps->sps;
671 
672   /* *INDENT-OFF* */
673   pic_param->base = (VAPictureParameterBufferHEVC) {
674     .pic_width_in_luma_samples = sps->pic_width_in_luma_samples,
675     .pic_height_in_luma_samples = sps->pic_height_in_luma_samples,
676     .sps_max_dec_pic_buffering_minus1 = sps->max_dec_pic_buffering_minus1[sps->max_sub_layers_minus1],
677     .bit_depth_luma_minus8 = sps->bit_depth_luma_minus8,
678     .bit_depth_chroma_minus8 = sps->bit_depth_chroma_minus8,
679     .pcm_sample_bit_depth_luma_minus1 = sps->pcm_sample_bit_depth_luma_minus1,
680     .pcm_sample_bit_depth_chroma_minus1 = sps->pcm_sample_bit_depth_chroma_minus1,
681     .log2_min_luma_coding_block_size_minus3 = sps->log2_min_luma_coding_block_size_minus3,
682     .log2_diff_max_min_luma_coding_block_size = sps->log2_diff_max_min_luma_coding_block_size,
683     .log2_min_transform_block_size_minus2 = sps->log2_min_transform_block_size_minus2,
684     .log2_diff_max_min_transform_block_size = sps->log2_diff_max_min_transform_block_size,
685     .log2_min_pcm_luma_coding_block_size_minus3 = sps->log2_min_pcm_luma_coding_block_size_minus3,
686     .log2_diff_max_min_pcm_luma_coding_block_size = sps->log2_diff_max_min_pcm_luma_coding_block_size,
687     .max_transform_hierarchy_depth_intra = sps->max_transform_hierarchy_depth_intra,
688     .max_transform_hierarchy_depth_inter = sps->max_transform_hierarchy_depth_inter,
689     .init_qp_minus26 = pps->init_qp_minus26,
690     .diff_cu_qp_delta_depth = pps->diff_cu_qp_delta_depth,
691     .pps_cb_qp_offset = pps->cb_qp_offset,
692     .pps_cr_qp_offset = pps->cr_qp_offset,
693     .log2_parallel_merge_level_minus2 = pps->log2_parallel_merge_level_minus2,
694     .num_tile_columns_minus1 = pps->num_tile_columns_minus1,
695     .num_tile_rows_minus1 = pps->num_tile_rows_minus1,
696     .log2_max_pic_order_cnt_lsb_minus4 = sps->log2_max_pic_order_cnt_lsb_minus4,
697     .num_short_term_ref_pic_sets = sps->num_short_term_ref_pic_sets,
698     .num_long_term_ref_pic_sps = sps->num_long_term_ref_pics_sps,
699     .num_ref_idx_l0_default_active_minus1 = pps->num_ref_idx_l0_default_active_minus1,
700     .num_ref_idx_l1_default_active_minus1 = pps->num_ref_idx_l1_default_active_minus1,
701     .pps_beta_offset_div2 = pps->beta_offset_div2,
702     .pps_tc_offset_div2 = pps->tc_offset_div2,
703     .num_extra_slice_header_bits = pps->num_extra_slice_header_bits,
704     .st_rps_bits = slice->header.short_term_ref_pic_set_size, /* FIXME missing emulation bits removal */
705     .pic_fields.bits = {
706       .chroma_format_idc = sps->chroma_format_idc,
707       .separate_colour_plane_flag = sps->separate_colour_plane_flag,
708       .pcm_enabled_flag = sps->pcm_enabled_flag,
709       .scaling_list_enabled_flag = sps->scaling_list_enabled_flag,
710       .transform_skip_enabled_flag = pps->transform_skip_enabled_flag,
711       .amp_enabled_flag = sps->amp_enabled_flag,
712       .strong_intra_smoothing_enabled_flag = sps->strong_intra_smoothing_enabled_flag,
713       .sign_data_hiding_enabled_flag = pps->sign_data_hiding_enabled_flag,
714       .constrained_intra_pred_flag = pps->constrained_intra_pred_flag,
715       .cu_qp_delta_enabled_flag = pps->cu_qp_delta_enabled_flag,
716       .weighted_pred_flag = pps->weighted_pred_flag,
717       .weighted_bipred_flag = pps->weighted_bipred_flag,
718       .transquant_bypass_enabled_flag = pps->transquant_bypass_enabled_flag,
719       .tiles_enabled_flag = pps->tiles_enabled_flag,
720       .entropy_coding_sync_enabled_flag = pps->entropy_coding_sync_enabled_flag,
721       .pps_loop_filter_across_slices_enabled_flag = pps->loop_filter_across_slices_enabled_flag,
722       .loop_filter_across_tiles_enabled_flag = pps->loop_filter_across_tiles_enabled_flag,
723       .pcm_loop_filter_disabled_flag = sps->pcm_loop_filter_disabled_flag,
724       /* Not set by FFMPEG either */
725       .NoPicReorderingFlag = 0,
726       .NoBiPredFlag = 0,
727     },
728     .slice_parsing_fields.bits = {
729       .lists_modification_present_flag = pps->lists_modification_present_flag,
730       .long_term_ref_pics_present_flag = sps->long_term_ref_pics_present_flag,
731       .sps_temporal_mvp_enabled_flag = sps->temporal_mvp_enabled_flag,
732       .cabac_init_present_flag = pps->cabac_init_present_flag,
733       .output_flag_present_flag = pps->output_flag_present_flag,
734       .dependent_slice_segments_enabled_flag = pps->dependent_slice_segments_enabled_flag,
735       .pps_slice_chroma_qp_offsets_present_flag = pps->slice_chroma_qp_offsets_present_flag,
736       .sample_adaptive_offset_enabled_flag = sps->sample_adaptive_offset_enabled_flag,
737       .deblocking_filter_override_enabled_flag = pps->deblocking_filter_override_enabled_flag,
738       .pps_disable_deblocking_filter_flag = pps->deblocking_filter_disabled_flag,
739       .slice_segment_header_extension_present_flag = pps->slice_segment_header_extension_present_flag,
740       .RapPicFlag = picture->RapPicFlag,
741       .IdrPicFlag = GST_H265_IS_NAL_TYPE_IDR (slice->nalu.type),
742       .IntraPicFlag = GST_H265_IS_NAL_TYPE_IRAP (slice->nalu.type),
743     },
744   };
745   /* *INDENT-ON* */
746 
747   if (_is_range_extension_profile (self->parent.profile)
748       || _is_screen_content_ext_profile (self->parent.profile)) {
749     _fill_picture_range_ext_parameter (self, sps, pps);
750     if (_is_screen_content_ext_profile (self->parent.profile))
751       _fill_screen_content_ext_parameter (self, sps, pps);
752   }
753 
754   for (i = 0; i <= pps->num_tile_columns_minus1; i++)
755     pic_param->base.column_width_minus1[i] = pps->column_width_minus1[i];
756 
757   for (i = 0; i <= pps->num_tile_rows_minus1; i++)
758     pic_param->base.row_height_minus1[i] = pps->row_height_minus1[i];
759 
760   _fill_vaapi_pic (decoder, &pic_param->base.CurrPic, picture);
761 
762   /* reference frames */
763   {
764     GArray *ref_list = gst_h265_dpb_get_pictures_all (dpb);
765     guint j;
766 
767     i = 0;
768     for (j = 0; j < 15 && j < ref_list->len; j++) {
769       GstH265Picture *pic = g_array_index (ref_list, GstH265Picture *, j);
770 
771       if (pic->ref) {
772         _fill_vaapi_pic (decoder, &pic_param->base.ReferenceFrames[i], pic);
773         i++;
774       }
775     }
776     g_array_unref (ref_list);
777 
778     /* 7.4.3.3.3, the current decoded picture is marked as "used for
779        long-term reference". Current picture is not in the DPB now. */
780     if (pps->pps_scc_extension_params.pps_curr_pic_ref_enabled_flag && i < 15) {
781       pic_param->base.ReferenceFrames[i].picture_id =
782           gst_va_decode_picture_get_surface (gst_h265_picture_get_user_data
783           (picture));
784       pic_param->base.ReferenceFrames[i].pic_order_cnt = picture->pic_order_cnt;
785       pic_param->base.ReferenceFrames[i].flags |=
786           VA_PICTURE_HEVC_LONG_TERM_REFERENCE;
787       pic_param->base.ReferenceFrames[i].flags |=
788           _find_frame_rps_type (decoder, picture);
789       i++;
790     }
791 
792     for (; i < 15; i++)
793       _init_vaapi_pic (&pic_param->base.ReferenceFrames[i]);
794   }
795 
796   pic_param_size = _is_range_extension_profile (self->parent.profile)
797       || _is_screen_content_ext_profile (self->parent.profile) ?
798       sizeof (*pic_param) : sizeof (pic_param->base);
799   if (!gst_va_decoder_add_param_buffer (base->decoder, va_pic,
800           VAPictureParameterBufferType, pic_param, pic_param_size))
801     return GST_FLOW_ERROR;
802 
803   if (pps->scaling_list_data_present_flag ||
804       (sps->scaling_list_enabled_flag
805           && !sps->scaling_list_data_present_flag)) {
806     scaling_list = &pps->scaling_list;
807     GST_DEBUG_OBJECT (decoder, "Passing scaling list from PPS");
808   } else if (sps->scaling_list_enabled_flag &&
809       sps->scaling_list_data_present_flag) {
810     scaling_list = &sps->scaling_list;
811     GST_DEBUG_OBJECT (decoder, "Passing scaling list from SPS");
812   }
813 
814   if (scaling_list) {
815     for (i = 0; i < G_N_ELEMENTS (iq_matrix.ScalingList4x4); i++)
816       gst_h265_quant_matrix_4x4_get_raster_from_uprightdiagonal
817           (iq_matrix.ScalingList4x4[i], scaling_list->scaling_lists_4x4[i]);
818 
819     for (i = 0; i < G_N_ELEMENTS (iq_matrix.ScalingList8x8); i++)
820       gst_h265_quant_matrix_8x8_get_raster_from_uprightdiagonal
821           (iq_matrix.ScalingList8x8[i], scaling_list->scaling_lists_8x8[i]);
822 
823     for (i = 0; i < G_N_ELEMENTS (iq_matrix.ScalingList16x16); i++)
824       gst_h265_quant_matrix_16x16_get_raster_from_uprightdiagonal
825           (iq_matrix.ScalingList16x16[i], scaling_list->scaling_lists_16x16[i]);
826 
827     for (i = 0; i < G_N_ELEMENTS (iq_matrix.ScalingList32x32); i++)
828       gst_h265_quant_matrix_32x32_get_raster_from_uprightdiagonal
829           (iq_matrix.ScalingList32x32[i], scaling_list->scaling_lists_32x32[i]);
830 
831     for (i = 0; i < 6; i++)
832       iq_matrix.ScalingListDC16x16[i] =
833           scaling_list->scaling_list_dc_coef_minus8_16x16[i] + 8;
834 
835     for (i = 0; i < 2; i++)
836       iq_matrix.ScalingListDC32x32[i] =
837           scaling_list->scaling_list_dc_coef_minus8_32x32[i] + 8;
838 
839     if (!gst_va_decoder_add_param_buffer (base->decoder, va_pic,
840             VAIQMatrixBufferType, &iq_matrix, sizeof (iq_matrix))) {
841       return GST_FLOW_ERROR;
842     }
843   }
844 
845   return GST_FLOW_OK;
846 }
847 
848 static GstFlowReturn
gst_va_h265_dec_new_picture(GstH265Decoder * decoder,GstVideoCodecFrame * frame,GstH265Picture * picture)849 gst_va_h265_dec_new_picture (GstH265Decoder * decoder,
850     GstVideoCodecFrame * frame, GstH265Picture * picture)
851 {
852   GstVaBaseDec *base = GST_VA_BASE_DEC (decoder);
853   GstVaH265Dec *self = GST_VA_H265_DEC (decoder);
854   GstVaDecodePicture *pic;
855   GstBuffer *output_buffer;
856   GstVideoDecoder *vdec = GST_VIDEO_DECODER (decoder);
857 
858   if (base->need_negotiation) {
859     if (!gst_video_decoder_negotiate (vdec)) {
860       GST_ERROR_OBJECT (self, "Failed to negotiate with downstream");
861       return GST_FLOW_NOT_NEGOTIATED;
862     }
863   }
864 
865   output_buffer = gst_video_decoder_allocate_output_buffer (vdec);
866   if (!output_buffer) {
867     self->last_ret = GST_FLOW_ERROR;
868     goto error;
869   }
870   self->last_ret = GST_FLOW_OK;
871 
872   pic = gst_va_decode_picture_new (base->decoder, output_buffer);
873   gst_buffer_unref (output_buffer);
874 
875   gst_h265_picture_set_user_data (picture, pic,
876       (GDestroyNotify) gst_va_decode_picture_free);
877 
878   GST_LOG_OBJECT (self, "New va decode picture %p - %#x", pic,
879       gst_va_decode_picture_get_surface (pic));
880 
881   return GST_FLOW_OK;
882 
883 error:
884   {
885     GST_WARNING_OBJECT (self,
886         "Failed to allocated output buffer, return %s",
887         gst_flow_get_name (self->last_ret));
888     return self->last_ret;
889   }
890 }
891 
892 static guint
_get_rtformat(GstVaH265Dec * self,guint8 bit_depth_luma,guint8 bit_depth_chroma,guint8 chroma_format_idc)893 _get_rtformat (GstVaH265Dec * self, guint8 bit_depth_luma,
894     guint8 bit_depth_chroma, guint8 chroma_format_idc)
895 {
896   guint8 bit_num = MAX (bit_depth_luma, bit_depth_chroma);
897 
898   switch (bit_num) {
899     case 11:
900     case 12:
901       if (chroma_format_idc == 3)
902         return VA_RT_FORMAT_YUV444_12;
903       if (chroma_format_idc == 2)
904         return VA_RT_FORMAT_YUV422_12;
905       else
906         return VA_RT_FORMAT_YUV420_12;
907       break;
908     case 9:
909     case 10:
910       if (chroma_format_idc == 3)
911         return VA_RT_FORMAT_YUV444_10;
912       if (chroma_format_idc == 2)
913         return VA_RT_FORMAT_YUV422_10;
914       else
915         return VA_RT_FORMAT_YUV420_10;
916       break;
917     case 8:
918       if (chroma_format_idc == 3)
919         return VA_RT_FORMAT_YUV444;
920       if (chroma_format_idc == 2)
921         return VA_RT_FORMAT_YUV422;
922       else
923         return VA_RT_FORMAT_YUV420;
924       break;
925     default:
926       GST_ERROR_OBJECT (self, "Unsupported chroma format: %d "
927           "(with depth luma: %d, with depth chroma: %d)",
928           chroma_format_idc, bit_depth_luma, bit_depth_chroma);
929       return 0;
930   }
931 }
932 
933 /* *INDENT-OFF* */
934 static const struct
935 {
936   GstH265Profile profile;
937   VAProfile va_profile;
938 } profile_map[] = {
939 #define P(idc, va) { G_PASTE (GST_H265_PROFILE_, idc), G_PASTE (VAProfileHEVC, va) }
940   P (MAIN, Main),
941   P (MAIN_10, Main10),
942   /*P (MAIN_STILL_PICTURE, ),
943   P (MONOCHROME, ),
944   P (MONOCHROME_12, ),
945   P (MONOCHROME_16, ),*/
946   P (MAIN_12, Main12),
947   P (MAIN_422_10, Main422_10),
948   P (MAIN_422_12, Main422_12),
949   P (MAIN_444, Main444),
950   P (MAIN_444_10, Main444_10),
951   P (MAIN_444_12, Main444_12),
952   /*P (MAIN_INTRA, ),
953   P (MAIN_10_INTRA, ),
954   P (MAIN_12_INTRA, ),
955   P (MAIN_422_10_INTRA, ),
956   P (MAIN_422_12_INTRA, ),
957   P (MAIN_444_INTRA, ),
958   P (MAIN_444_10_INTRA, ),
959   P (MAIN_444_12_INTRA, ),
960   P (MAIN_444_16_INTRA, ),
961   P (MAIN_444_STILL_PICTURE, ),
962   P (MAIN_444_16_STILL_PICTURE, ),
963   P (MONOCHROME_10, ),
964   P (HIGH_THROUGHPUT_444, ),
965   P (HIGH_THROUGHPUT_444_10, ),
966   P (HIGH_THROUGHPUT_444_14, ),
967   P (HIGH_THROUGHPUT_444_16_INTRA, ),*/
968   P (SCREEN_EXTENDED_MAIN, SccMain),
969   P (SCREEN_EXTENDED_MAIN_10, SccMain10),
970   P (SCREEN_EXTENDED_MAIN_444, SccMain444),
971   /*P (SCREEN_EXTENDED_MAIN_444_10, ),
972   P (SCREEN_EXTENDED_HIGH_THROUGHPUT_444, ),
973   P (SCREEN_EXTENDED_HIGH_THROUGHPUT_444_10, ),
974   P (SCREEN_EXTENDED_HIGH_THROUGHPUT_444_14, ),
975   P (MULTIVIEW_MAIN, ),
976   P (SCALABLE_MAIN, ),
977   P (SCALABLE_MAIN_10, ),
978   P (SCALABLE_MONOCHROME, ),
979   P (SCALABLE_MONOCHROME_12, ),
980   P (SCALABLE_MONOCHROME_16, ),
981   P (SCALABLE_MAIN_444, ),
982   P (3D_MAIN, ),*/
983 #undef P
984 };
985 /* *INDENT-ON* */
986 
987 static VAProfile
_get_profile(GstVaH265Dec * self,const GstH265SPS * sps,gint max_dpb_size)988 _get_profile (GstVaH265Dec * self, const GstH265SPS * sps, gint max_dpb_size)
989 {
990   GstH265Decoder *h265_decoder = GST_H265_DECODER (self);
991   GstVaBaseDec *base = GST_VA_BASE_DEC (self);
992   GstH265Profile profile = gst_h265_get_profile_from_sps ((GstH265SPS *) sps);
993   VAProfile profiles[4];
994   gint i = 0, j;
995 
996   /* 1. The profile directly specified by the SPS should always be the
997      first choice. It is the exact one.
998      2. The profile in the input caps may contain the compatible profile
999      chosen by the upstream element. Upstream element such as the parse
1000      may already decide the best compatible profile for us. We also need
1001      to consider it as a choice. */
1002 
1003   for (j = 0; j < G_N_ELEMENTS (profile_map); j++) {
1004     if (profile_map[j].profile == profile) {
1005       profiles[i++] = profile_map[j].va_profile;
1006       break;
1007     }
1008   }
1009 
1010   if (h265_decoder->input_state->caps
1011       && gst_caps_is_fixed (h265_decoder->input_state->caps)) {
1012     GstH265Profile compatible_profile = GST_H265_PROFILE_INVALID;
1013     GstStructure *structure;
1014     const gchar *profile_str;
1015 
1016     structure = gst_caps_get_structure (h265_decoder->input_state->caps, 0);
1017 
1018     profile_str = gst_structure_get_string (structure, "profile");
1019     if (profile_str)
1020       compatible_profile = gst_h265_profile_from_string (profile_str);
1021 
1022     if (compatible_profile != profile) {
1023       GST_INFO_OBJECT (self, "The upstream set the compatible profile %s, "
1024           "also consider it as a candidate.", profile_str);
1025 
1026       for (j = 0; j < G_N_ELEMENTS (profile_map); j++) {
1027         if (profile_map[j].profile == compatible_profile) {
1028           profiles[i++] = profile_map[j].va_profile;
1029           break;
1030         }
1031       }
1032     }
1033   }
1034 
1035   for (j = 0; j < i && j < G_N_ELEMENTS (profiles); j++) {
1036     if (gst_va_decoder_has_profile (base->decoder, profiles[j]))
1037       return profiles[j];
1038   }
1039 
1040   GST_ERROR_OBJECT (self, "Unsupported profile: %d", profile);
1041 
1042   return VAProfileNone;
1043 }
1044 
1045 static GstFlowReturn
gst_va_h265_dec_new_sequence(GstH265Decoder * decoder,const GstH265SPS * sps,gint max_dpb_size)1046 gst_va_h265_dec_new_sequence (GstH265Decoder * decoder, const GstH265SPS * sps,
1047     gint max_dpb_size)
1048 {
1049   GstVaBaseDec *base = GST_VA_BASE_DEC (decoder);
1050   GstVaH265Dec *self = GST_VA_H265_DEC (decoder);
1051   VAProfile profile;
1052   gint display_width;
1053   gint display_height;
1054   gint padding_left, padding_right, padding_top, padding_bottom;
1055   guint rt_format;
1056   gboolean negotiation_needed = FALSE;
1057 
1058   if (self->dpb_size < max_dpb_size)
1059     self->dpb_size = max_dpb_size;
1060 
1061   if (sps->conformance_window_flag) {
1062     display_width = sps->crop_rect_width;
1063     display_height = sps->crop_rect_height;
1064     padding_left = sps->crop_rect_x;
1065     padding_right = sps->width - sps->crop_rect_x - display_width;
1066     padding_top = sps->crop_rect_y;
1067     padding_bottom = sps->height - sps->crop_rect_y - display_height;
1068   } else {
1069     display_width = sps->width;
1070     display_height = sps->height;
1071     padding_left = padding_right = padding_top = padding_bottom = 0;
1072   }
1073 
1074   profile = _get_profile (self, sps, max_dpb_size);
1075   if (profile == VAProfileNone)
1076     return GST_FLOW_NOT_NEGOTIATED;
1077 
1078   rt_format = _get_rtformat (self, sps->bit_depth_luma_minus8 + 8,
1079       sps->bit_depth_chroma_minus8 + 8, sps->chroma_format_idc);
1080   if (rt_format == 0)
1081     return GST_FLOW_NOT_NEGOTIATED;
1082 
1083   if (!gst_va_decoder_config_is_equal (base->decoder, profile,
1084           rt_format, sps->width, sps->height)) {
1085     base->profile = profile;
1086     base->rt_format = rt_format;
1087     self->coded_width = sps->width;
1088     self->coded_height = sps->height;
1089 
1090     negotiation_needed = TRUE;
1091     GST_INFO_OBJECT (self, "Format changed to %s [%x] (%dx%d)",
1092         gst_va_profile_name (profile), rt_format, self->coded_width,
1093         self->coded_height);
1094   }
1095 
1096   if (base->width != display_width || base->height != display_height) {
1097     base->width = display_width;
1098     base->height = display_height;
1099 
1100     negotiation_needed = TRUE;
1101     GST_INFO_OBJECT (self, "Resolution changed to %dx%d", base->width,
1102         base->height);
1103   }
1104 
1105   base->need_valign = base->width < self->coded_width
1106       || base->height < self->coded_height;
1107   if (base->need_valign) {
1108     /* *INDENT-OFF* */
1109     if (base->valign.padding_left != padding_left ||
1110         base->valign.padding_right != padding_right ||
1111         base->valign.padding_top != padding_top ||
1112         base->valign.padding_bottom != padding_bottom) {
1113       negotiation_needed = TRUE;
1114       GST_INFO_OBJECT (self, "crop rect changed to (%d,%d)-->(%d,%d)",
1115           padding_left, padding_top, padding_right, padding_bottom);
1116     }
1117     base->valign = (GstVideoAlignment) {
1118       .padding_left = padding_left,
1119       .padding_right = padding_right,
1120       .padding_top = padding_top,
1121       .padding_bottom = padding_bottom,
1122     };
1123     /* *INDENT-ON* */
1124   }
1125 
1126   base->min_buffers = self->dpb_size + 4;       /* dpb size + scratch surfaces */
1127 
1128   base->need_negotiation = negotiation_needed;
1129 
1130   {
1131     /* FIXME: We don't have parser API for sps_range_extension, so
1132      * assuming high_precision_offsets_enabled_flag as zero */
1133     guint high_precision_offsets_enabled_flag = 0, bitdepthC = 0;
1134 
1135     /* Calculate WpOffsetHalfRangeC: (7-34) */
1136     bitdepthC = sps->bit_depth_chroma_minus8 + 8;
1137     self->WpOffsetHalfRangeC =
1138         1 << (high_precision_offsets_enabled_flag ? (bitdepthC - 1) : 7);
1139   }
1140 
1141   return GST_FLOW_OK;
1142 }
1143 
1144 static GstCaps *
_complete_sink_caps(GstCaps * sinkcaps)1145 _complete_sink_caps (GstCaps * sinkcaps)
1146 {
1147   GstCaps *caps = gst_caps_copy (sinkcaps);
1148   GValue val = G_VALUE_INIT;
1149   const gchar *streamformat[] = { "hvc1", "hev1", "byte-stream" };
1150   gint i;
1151 
1152   g_value_init (&val, G_TYPE_STRING);
1153   g_value_set_string (&val, "au");
1154   gst_caps_set_value (caps, "alignment", &val);
1155   g_value_unset (&val);
1156 
1157   gst_value_list_init (&val, G_N_ELEMENTS (streamformat));
1158   for (i = 0; i < G_N_ELEMENTS (streamformat); i++) {
1159     GValue v = G_VALUE_INIT;
1160 
1161     g_value_init (&v, G_TYPE_STRING);
1162     g_value_set_string (&v, streamformat[i]);
1163     gst_value_list_append_value (&val, &v);
1164     g_value_unset (&v);
1165   }
1166   gst_caps_set_value (caps, "stream-format", &val);
1167   g_value_unset (&val);
1168 
1169   return caps;
1170 }
1171 
1172 static GstCaps *
gst_va_h265_dec_getcaps(GstVideoDecoder * decoder,GstCaps * filter)1173 gst_va_h265_dec_getcaps (GstVideoDecoder * decoder, GstCaps * filter)
1174 {
1175   GstCaps *sinkcaps, *caps = NULL, *tmp;
1176   GstVaBaseDec *base = GST_VA_BASE_DEC (decoder);
1177 
1178   if (base->decoder)
1179     caps = gst_va_decoder_get_sinkpad_caps (base->decoder);
1180 
1181   if (caps) {
1182     sinkcaps = _complete_sink_caps (caps);
1183     gst_caps_unref (caps);
1184     if (filter) {
1185       tmp = gst_caps_intersect_full (filter, sinkcaps,
1186           GST_CAPS_INTERSECT_FIRST);
1187       gst_caps_unref (sinkcaps);
1188       caps = tmp;
1189     } else {
1190       caps = sinkcaps;
1191     }
1192     GST_LOG_OBJECT (base, "Returning caps %" GST_PTR_FORMAT, caps);
1193   } else if (!caps) {
1194     caps = gst_video_decoder_proxy_getcaps (decoder, NULL, filter);
1195   }
1196 
1197   return caps;
1198 }
1199 
1200 static gboolean
gst_va_h265_dec_negotiate(GstVideoDecoder * decoder)1201 gst_va_h265_dec_negotiate (GstVideoDecoder * decoder)
1202 {
1203   GstVaBaseDec *base = GST_VA_BASE_DEC (decoder);
1204   GstVaH265Dec *self = GST_VA_H265_DEC (decoder);
1205   GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
1206   GstCapsFeatures *capsfeatures = NULL;
1207   GstH265Decoder *h265dec = GST_H265_DECODER (decoder);
1208 
1209   /* Ignore downstream renegotiation request. */
1210   if (!base->need_negotiation)
1211     return TRUE;
1212 
1213   base->need_negotiation = FALSE;
1214 
1215   if (gst_va_decoder_is_open (base->decoder)
1216       && !gst_va_decoder_close (base->decoder))
1217     return FALSE;
1218 
1219   if (!gst_va_decoder_open (base->decoder, base->profile, base->rt_format))
1220     return FALSE;
1221 
1222   if (!gst_va_decoder_set_frame_size (base->decoder, self->coded_width,
1223           self->coded_height))
1224     return FALSE;
1225 
1226   if (base->output_state)
1227     gst_video_codec_state_unref (base->output_state);
1228 
1229   gst_va_base_dec_get_preferred_format_and_caps_features (base, &format,
1230       &capsfeatures);
1231 
1232   base->output_state =
1233       gst_video_decoder_set_output_state (decoder, format,
1234       base->width, base->height, h265dec->input_state);
1235 
1236   base->output_state->caps = gst_video_info_to_caps (&base->output_state->info);
1237   if (capsfeatures)
1238     gst_caps_set_features_simple (base->output_state->caps, capsfeatures);
1239 
1240   GST_INFO_OBJECT (self, "Negotiated caps %" GST_PTR_FORMAT,
1241       base->output_state->caps);
1242 
1243   return GST_VIDEO_DECODER_CLASS (parent_class)->negotiate (decoder);
1244 }
1245 
1246 static void
gst_va_h265_dec_dispose(GObject * object)1247 gst_va_h265_dec_dispose (GObject * object)
1248 {
1249   g_free (GST_VA_H265_DEC (object)->prev_slice.data);
1250 
1251   gst_va_base_dec_close (GST_VIDEO_DECODER (object));
1252 
1253   G_OBJECT_CLASS (parent_class)->dispose (object);
1254 }
1255 
1256 static void
gst_va_h265_dec_class_init(gpointer g_class,gpointer class_data)1257 gst_va_h265_dec_class_init (gpointer g_class, gpointer class_data)
1258 {
1259   GstCaps *src_doc_caps, *sink_doc_caps;
1260   GObjectClass *gobject_class = G_OBJECT_CLASS (g_class);
1261   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
1262   GstH265DecoderClass *h265decoder_class = GST_H265_DECODER_CLASS (g_class);
1263   GstVideoDecoderClass *decoder_class = GST_VIDEO_DECODER_CLASS (g_class);
1264   struct CData *cdata = class_data;
1265   gchar *long_name;
1266 
1267   if (cdata->description) {
1268     long_name = g_strdup_printf ("VA-API H.265 Decoder in %s",
1269         cdata->description);
1270   } else {
1271     long_name = g_strdup ("VA-API H.265 Decoder");
1272   }
1273 
1274   gst_element_class_set_metadata (element_class, long_name,
1275       "Codec/Decoder/Video/Hardware",
1276       "VA-API based H.265 video decoder",
1277       "Nicolas Dufresne <nicolas.dufresne@collabora.com>");
1278 
1279   sink_doc_caps = gst_caps_from_string (sink_caps_str);
1280   src_doc_caps = gst_caps_from_string (src_caps_str);
1281 
1282   parent_class = g_type_class_peek_parent (g_class);
1283 
1284   gst_va_base_dec_class_init (GST_VA_BASE_DEC_CLASS (g_class), HEVC,
1285       cdata->render_device_path, cdata->sink_caps, cdata->src_caps,
1286       src_doc_caps, sink_doc_caps);
1287 
1288   gobject_class->dispose = gst_va_h265_dec_dispose;
1289 
1290   decoder_class->getcaps = GST_DEBUG_FUNCPTR (gst_va_h265_dec_getcaps);
1291   decoder_class->negotiate = GST_DEBUG_FUNCPTR (gst_va_h265_dec_negotiate);
1292 
1293   h265decoder_class->new_sequence =
1294       GST_DEBUG_FUNCPTR (gst_va_h265_dec_new_sequence);
1295   h265decoder_class->decode_slice =
1296       GST_DEBUG_FUNCPTR (gst_va_h265_dec_decode_slice);
1297 
1298   h265decoder_class->new_picture =
1299       GST_DEBUG_FUNCPTR (gst_va_h265_dec_new_picture);
1300   h265decoder_class->output_picture =
1301       GST_DEBUG_FUNCPTR (gst_va_h265_dec_output_picture);
1302   h265decoder_class->start_picture =
1303       GST_DEBUG_FUNCPTR (gst_va_h265_dec_start_picture);
1304   h265decoder_class->end_picture =
1305       GST_DEBUG_FUNCPTR (gst_va_h265_dec_end_picture);
1306 
1307   g_free (long_name);
1308   g_free (cdata->description);
1309   g_free (cdata->render_device_path);
1310   gst_caps_unref (cdata->src_caps);
1311   gst_caps_unref (cdata->sink_caps);
1312   g_free (cdata);
1313 }
1314 
1315 static void
gst_va_h265_dec_init(GTypeInstance * instance,gpointer g_class)1316 gst_va_h265_dec_init (GTypeInstance * instance, gpointer g_class)
1317 {
1318   gst_va_base_dec_init (GST_VA_BASE_DEC (instance), GST_CAT_DEFAULT);
1319   gst_h265_decoder_set_process_ref_pic_lists (GST_H265_DECODER (instance),
1320       TRUE);
1321 }
1322 
1323 static gpointer
_register_debug_category(gpointer data)1324 _register_debug_category (gpointer data)
1325 {
1326   GST_DEBUG_CATEGORY_INIT (gst_va_h265dec_debug, "vah265dec", 0,
1327       "VA H265 decoder");
1328 
1329   return NULL;
1330 }
1331 
1332 gboolean
gst_va_h265_dec_register(GstPlugin * plugin,GstVaDevice * device,GstCaps * sink_caps,GstCaps * src_caps,guint rank)1333 gst_va_h265_dec_register (GstPlugin * plugin, GstVaDevice * device,
1334     GstCaps * sink_caps, GstCaps * src_caps, guint rank)
1335 {
1336   static GOnce debug_once = G_ONCE_INIT;
1337   GType type;
1338   GTypeInfo type_info = {
1339     .class_size = sizeof (GstVaH265DecClass),
1340     .class_init = gst_va_h265_dec_class_init,
1341     .instance_size = sizeof (GstVaH265Dec),
1342     .instance_init = gst_va_h265_dec_init,
1343   };
1344   struct CData *cdata;
1345   gboolean ret;
1346   gchar *type_name, *feature_name;
1347 
1348   g_return_val_if_fail (GST_IS_PLUGIN (plugin), FALSE);
1349   g_return_val_if_fail (GST_IS_VA_DEVICE (device), FALSE);
1350   g_return_val_if_fail (GST_IS_CAPS (sink_caps), FALSE);
1351   g_return_val_if_fail (GST_IS_CAPS (src_caps), FALSE);
1352 
1353   cdata = g_new (struct CData, 1);
1354   cdata->description = NULL;
1355   cdata->render_device_path = g_strdup (device->render_device_path);
1356   cdata->sink_caps = _complete_sink_caps (sink_caps);
1357   cdata->src_caps = gst_caps_ref (src_caps);
1358 
1359   /* class data will be leaked if the element never gets instantiated */
1360   GST_MINI_OBJECT_FLAG_SET (cdata->sink_caps,
1361       GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
1362   GST_MINI_OBJECT_FLAG_SET (src_caps, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
1363 
1364   type_info.class_data = cdata;
1365 
1366   type_name = g_strdup ("GstVaH265Dec");
1367   feature_name = g_strdup ("vah265dec");
1368 
1369   /* The first decoder to be registered should use a constant name,
1370    * like vah265dec, for any additional decoders, we create unique
1371    * names, using inserting the render device name. */
1372   if (g_type_from_name (type_name)) {
1373     gchar *basename = g_path_get_basename (device->render_device_path);
1374     g_free (type_name);
1375     g_free (feature_name);
1376     type_name = g_strdup_printf ("GstVa%sH265Dec", basename);
1377     feature_name = g_strdup_printf ("va%sh265dec", basename);
1378     cdata->description = basename;
1379 
1380     /* lower rank for non-first device */
1381     if (rank > 0)
1382       rank--;
1383   }
1384 
1385   g_once (&debug_once, _register_debug_category, NULL);
1386 
1387   type = g_type_register_static (GST_TYPE_H265_DECODER,
1388       type_name, &type_info, 0);
1389 
1390   ret = gst_element_register (plugin, feature_name, rank, type);
1391 
1392   g_free (type_name);
1393   g_free (feature_name);
1394 
1395   return ret;
1396 }
1397