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