1use std::rc::Rc;
6
7use anyhow::anyhow;
8use anyhow::Context;
9use libva::BufferType;
10use libva::Display;
11use libva::HevcSliceExtFlags;
12use libva::IQMatrix;
13use libva::IQMatrixBufferHEVC;
14use libva::Picture as VaPicture;
15use libva::PictureHEVC;
16use libva::PictureParameterBufferHEVC;
17use libva::SliceParameter;
18use libva::SliceParameterBufferHEVC;
19use libva::SliceParameterBufferHEVCRext;
20use libva::SurfaceMemoryDescriptor;
21
22use crate::backend::vaapi::decoder::DecodedHandle as VADecodedHandle;
23use crate::backend::vaapi::decoder::PoolCreationMode;
24use crate::backend::vaapi::decoder::VaStreamInfo;
25use crate::backend::vaapi::decoder::VaapiBackend;
26use crate::backend::vaapi::decoder::VaapiPicture;
27use crate::codec::h265::dpb::Dpb;
28use crate::codec::h265::parser::NaluType;
29use crate::codec::h265::parser::Pps;
30use crate::codec::h265::parser::Profile;
31use crate::codec::h265::parser::Slice;
32use crate::codec::h265::parser::Sps;
33use crate::codec::h265::picture::PictureData;
34use crate::codec::h265::picture::Reference;
35use crate::decoder::stateless::h265::clip3;
36use crate::decoder::stateless::h265::RefPicListEntry;
37use crate::decoder::stateless::h265::RefPicSet;
38use crate::decoder::stateless::h265::StatelessH265DecoderBackend;
39use crate::decoder::stateless::h265::H265;
40use crate::decoder::stateless::NewPictureError;
41use crate::decoder::stateless::NewPictureResult;
42use crate::decoder::stateless::NewStatelessDecoderError;
43use crate::decoder::stateless::PoolLayer;
44use crate::decoder::stateless::StatelessBackendResult;
45use crate::decoder::stateless::StatelessDecoder;
46use crate::decoder::stateless::StatelessDecoderBackend;
47use crate::decoder::stateless::StatelessDecoderBackendPicture;
48use crate::decoder::BlockingMode;
49use crate::Resolution;
50
51enum ScalingListType {
52 Sps,
53 Pps,
54 None,
55}
56
57impl VaStreamInfo for &Sps {
58 fn va_profile(&self) -> anyhow::Result<i32> {
59 let profile_idc = self.profile_tier_level.general_profile_idc;
60 let profile = Profile::n(profile_idc)
61 .with_context(|| format!("Invalid profile_idc {:?}", profile_idc))?;
62
63 let bit_depth = std::cmp::max(
64 self.bit_depth_luma_minus8 + 8,
65 self.bit_depth_chroma_minus8 + 8,
66 );
67
68 let chroma_format_idc = self.chroma_format_idc;
69 let err = Err(anyhow!(
70 "Invalid combination of profile, bit depth an chroma_format_idc: ({:?}, {}, {}",
71 profile,
72 bit_depth,
73 chroma_format_idc
74 ));
75
76 match profile {
78 Profile::Main | Profile::MainStill | Profile::Main10 => {
79 match (bit_depth, chroma_format_idc) {
80 (8, 0) | (8, 1) => Ok(libva::VAProfile::VAProfileHEVCMain),
81 (8, 3) => Ok(libva::VAProfile::VAProfileHEVCMain444),
82 (10, 0) | (10, 1) => Ok(libva::VAProfile::VAProfileHEVCMain10),
83 (10, 2) => Ok(libva::VAProfile::VAProfileHEVCMain422_10),
84 (12, 1) => Ok(libva::VAProfile::VAProfileHEVCMain12),
85 (12, 2) => Ok(libva::VAProfile::VAProfileHEVCMain422_12),
86 (12, 3) => Ok(libva::VAProfile::VAProfileHEVCMain444_12),
87 _ => err,
88 }
89 }
90
91 Profile::ScalableMain => match (bit_depth, chroma_format_idc) {
93 (8, 1) => Ok(libva::VAProfile::VAProfileHEVCSccMain),
94 (8, 3) => Ok(libva::VAProfile::VAProfileHEVCSccMain444),
95 (10, 1) => Ok(libva::VAProfile::VAProfileHEVCSccMain10),
96 (10, 3) => Ok(libva::VAProfile::VAProfileHEVCSccMain444_10),
97 _ => err,
98 },
99
100 _ => unimplemented!("Adding more profile support based on A.3. is still TODO"),
101 }
102 }
103
104 fn rt_format(&self) -> anyhow::Result<u32> {
105 let bit_depth = std::cmp::max(
106 self.bit_depth_luma_minus8 + 8,
107 self.bit_depth_chroma_minus8 + 8,
108 );
109
110 let chroma_format_idc = self.chroma_format_idc;
111
112 match (bit_depth, chroma_format_idc) {
113 (8, 0) | (8, 1) => Ok(libva::constants::VA_RT_FORMAT_YUV420),
114 (8, 2) => Ok(libva::constants::VA_RT_FORMAT_YUV422),
115 (8, 3) => Ok(libva::constants::VA_RT_FORMAT_YUV444),
116 (9, 0) | (9, 1) | (10, 0) | (10, 1) => Ok(libva::constants::VA_RT_FORMAT_YUV420_10),
117 (9, 2) | (10, 2) => Ok(libva::constants::VA_RT_FORMAT_YUV422_10),
118 (9, 3) | (10, 3) => Ok(libva::constants::VA_RT_FORMAT_YUV444_10),
119 (11, 0) | (11, 1) | (12, 0) | (12, 1) => Ok(libva::constants::VA_RT_FORMAT_YUV420_12),
120 (11, 2) | (12, 2) => Ok(libva::constants::VA_RT_FORMAT_YUV422_12),
121 (11, 3) | (12, 3) => Ok(libva::constants::VA_RT_FORMAT_YUV444_12),
122 _ => Err(anyhow!(
123 "unsupported bit depth/chroma format pair {}, {}",
124 bit_depth,
125 chroma_format_idc
126 )),
127 }
128 }
129
130 fn min_num_surfaces(&self) -> usize {
131 self.max_dpb_size() + 4
132 }
133
134 fn coded_size(&self) -> (u32, u32) {
135 (self.width().into(), self.height().into())
136 }
137
138 fn visible_rect(&self) -> ((u32, u32), (u32, u32)) {
139 let rect = self.visible_rectangle();
140
141 ((rect.min.x, rect.min.y), (rect.max.x, rect.max.y))
142 }
143}
144
145fn build_slice_ref_pic_list<M: SurfaceMemoryDescriptor>(
146 ref_pic_list: &[Option<RefPicListEntry<VADecodedHandle<M>>>; 16],
147 va_references: &[PictureHEVC; 15],
148) -> [u8; 15] {
149 let mut va_refs = [0xff; 15];
150
151 for (ref_pic_list_idx, ref_pic_list_entry) in ref_pic_list.iter().enumerate() {
152 if ref_pic_list_idx == 15 {
153 break;
154 }
155
156 if let Some(ref_pic_list_entry) = ref_pic_list_entry {
157 for (va_ref_idx, va_ref) in va_references.iter().enumerate() {
158 if va_ref.picture_id() == libva::constants::VA_INVALID_ID {
159 break;
160 }
161
162 let pic_order_cnt = match ref_pic_list_entry {
163 RefPicListEntry::CurrentPicture(p) => p.pic_order_cnt_val,
164 RefPicListEntry::DpbEntry(p) => p.0.borrow().pic_order_cnt_val,
165 };
166
167 if va_ref.pic_order_cnt() == pic_order_cnt {
168 va_refs[ref_pic_list_idx] = va_ref_idx as u8;
169 }
170 }
171 }
172 }
173
174 va_refs
175}
176
177fn va_rps_flag<M: SurfaceMemoryDescriptor>(
178 hevc_pic: &PictureData,
179 rps: &RefPicSet<VADecodedHandle<M>>,
180) -> u32 {
181 if rps
182 .ref_pic_set_st_curr_before
183 .iter()
184 .flatten()
185 .any(|dpb_entry| *dpb_entry.0.borrow() == *hevc_pic)
186 {
187 libva::constants::VA_PICTURE_HEVC_RPS_ST_CURR_BEFORE
188 } else if rps
189 .ref_pic_set_st_curr_after
190 .iter()
191 .flatten()
192 .any(|dpb_entry| *dpb_entry.0.borrow() == *hevc_pic)
193 {
194 libva::constants::VA_PICTURE_HEVC_RPS_ST_CURR_AFTER
195 } else if rps
196 .ref_pic_set_lt_curr
197 .iter()
198 .flatten()
199 .any(|dpb_entry| *dpb_entry.0.borrow() == *hevc_pic)
200 {
201 libva::constants::VA_PICTURE_HEVC_RPS_LT_CURR
202 } else {
203 0
204 }
205}
206
207fn build_invalid_va_hevc_pic() -> libva::PictureHEVC {
210 libva::PictureHEVC::new(
211 libva::constants::VA_INVALID_ID,
212 0,
213 libva::constants::VA_PICTURE_HEVC_INVALID,
214 )
215}
216
217fn fill_va_hevc_pic<M: SurfaceMemoryDescriptor>(
218 hevc_pic: &PictureData,
219 surface_id: libva::VASurfaceID,
220 rps: &RefPicSet<VADecodedHandle<M>>,
221) -> libva::PictureHEVC {
222 let mut flags = 0;
223
224 if matches!(hevc_pic.reference(), Reference::LongTerm) {
225 flags |= libva::constants::VA_PICTURE_HEVC_LONG_TERM_REFERENCE;
226 }
227
228 flags |= va_rps_flag(hevc_pic, rps);
229
230 libva::PictureHEVC::new(surface_id, hevc_pic.pic_order_cnt_val, flags)
231}
232
233fn is_range_extension_profile(va_profile: libva::VAProfile::Type) -> bool {
234 matches!(
235 va_profile,
236 libva::VAProfile::VAProfileHEVCMain422_10
237 | libva::VAProfile::VAProfileHEVCMain444
238 | libva::VAProfile::VAProfileHEVCMain444_10
239 | libva::VAProfile::VAProfileHEVCMain12
240 | libva::VAProfile::VAProfileHEVCMain422_12
241 | libva::VAProfile::VAProfileHEVCMain444_12
242 )
243}
244
245fn is_scc_ext_profile(va_profile: libva::VAProfile::Type) -> bool {
246 matches!(
247 va_profile,
248 libva::VAProfile::VAProfileHEVCSccMain
249 | libva::VAProfile::VAProfileHEVCSccMain10
250 | libva::VAProfile::VAProfileHEVCSccMain444
251 | libva::VAProfile::VAProfileHEVCMain444_10,
252 )
253}
254
255fn build_picture_rext(sps: &Sps, pps: &Pps) -> anyhow::Result<BufferType> {
256 let sps_rext = &sps.range_extension;
257 let pps_rext = &pps.range_extension;
258
259 let range_extension_pic_fields = libva::HevcRangeExtensionPicFields::new(
260 sps_rext.transform_skip_rotation_enabled_flag as u32,
261 sps_rext.transform_skip_context_enabled_flag as u32,
262 sps_rext.implicit_rdpcm_enabled_flag as u32,
263 sps_rext.explicit_rdpcm_enabled_flag as u32,
264 sps_rext.extended_precision_processing_flag as u32,
265 sps_rext.intra_smoothing_disabled_flag as u32,
266 sps_rext.high_precision_offsets_enabled_flag as u32,
267 sps_rext.persistent_rice_adaptation_enabled_flag as u32,
268 sps_rext.cabac_bypass_alignment_enabled_flag as u32,
269 pps_rext.cross_component_prediction_enabled_flag as u32,
270 pps_rext.chroma_qp_offset_list_enabled_flag as u32,
271 );
272
273 let rext = libva::PictureParameterBufferHEVCRext::new(
274 &range_extension_pic_fields,
275 pps_rext.diff_cu_chroma_qp_offset_depth as u8,
276 pps_rext.chroma_qp_offset_list_len_minus1 as u8,
277 pps_rext.log2_sao_offset_scale_luma as u8,
278 pps_rext.log2_sao_offset_scale_chroma as u8,
279 pps_rext.log2_max_transform_skip_block_size_minus2 as u8,
280 pps_rext.cb_qp_offset_list.map(|x| x as i8),
281 pps_rext.cr_qp_offset_list.map(|x| x as i8),
282 );
283
284 Ok(BufferType::PictureParameter(
285 libva::PictureParameter::HEVCRext(rext),
286 ))
287}
288
289fn build_picture_scc(sps: &Sps, pps: &Pps) -> anyhow::Result<BufferType> {
290 let sps_scc = &sps.scc_extension;
291 let pps_scc = &pps.scc_extension;
292
293 let scc_pic_fields = libva::HevcScreenContentPicFields::new(
294 pps_scc.curr_pic_ref_enabled_flag as u32,
295 sps_scc.palette_mode_enabled_flag as u32,
296 sps_scc.motion_vector_resolution_control_idc as u32,
297 sps_scc.intra_boundary_filtering_disabled_flag as u32,
298 pps_scc.residual_adaptive_colour_transform_enabled_flag as u32,
299 pps_scc.slice_act_qp_offsets_present_flag as u32,
300 );
301
302 let (predictor_palette_entries, predictor_palette_size) =
303 if pps_scc.palette_predictor_initializers_present_flag {
304 (
305 pps_scc
306 .palette_predictor_initializer
307 .map(|outer| outer.map(u16::from)),
308 pps_scc.num_palette_predictor_initializers,
309 )
310 } else if sps_scc.palette_predictor_initializers_present_flag {
311 (
312 sps_scc
313 .palette_predictor_initializer
314 .map(|outer| outer.map(|inner| inner as u16)),
315 sps_scc.num_palette_predictor_initializer_minus1 + 1,
316 )
317 } else {
318 ([[0; 128]; 3], 0)
319 };
320
321 let scc = libva::PictureParameterBufferHEVCScc::new(
322 &scc_pic_fields,
323 sps_scc.palette_max_size,
324 sps_scc.delta_palette_max_predictor_size,
325 predictor_palette_size,
326 predictor_palette_entries,
327 pps_scc.act_y_qp_offset_plus5,
328 pps_scc.act_cb_qp_offset_plus5,
329 pps_scc.act_cr_qp_offset_plus3,
330 );
331
332 Ok(BufferType::PictureParameter(
333 libva::PictureParameter::HEVCScc(scc),
334 ))
335}
336
337fn build_pic_param<M: SurfaceMemoryDescriptor>(
338 _: &Slice,
339 current_picture: &PictureData,
340 current_surface_id: libva::VASurfaceID,
341 dpb: &Dpb<VADecodedHandle<M>>,
342 rps: &RefPicSet<VADecodedHandle<M>>,
343 sps: &Sps,
344 pps: &Pps,
345) -> anyhow::Result<(BufferType, [PictureHEVC; 15])> {
346 let curr_pic = fill_va_hevc_pic(current_picture, current_surface_id, rps);
347
348 let mut reference_frames = vec![];
349
350 for ref_pic in dpb.get_all_references() {
351 let surface_id = ref_pic.1.borrow().surface().id();
352 let ref_pic = fill_va_hevc_pic(&ref_pic.0.borrow(), surface_id, rps);
353 reference_frames.push(ref_pic);
354 }
355
356 if pps.scc_extension.curr_pic_ref_enabled_flag {
360 if reference_frames.len() >= 15 {
361 log::warn!(
362 "Bug: Trying to set the current picture as a VA reference, but the VA DPB is full."
363 )
364 } else {
365 reference_frames.push(curr_pic);
366 }
367 }
368
369 for _ in reference_frames.len()..15 {
370 reference_frames.push(build_invalid_va_hevc_pic());
371 }
372
373 let reference_frames = reference_frames.try_into();
374 let reference_frames = match reference_frames {
375 Ok(va_refs) => va_refs,
376 Err(_) => {
377 panic!("Bug: wrong number of references, expected 15");
379 }
380 };
381
382 let pic_fields = libva::HevcPicFields::new(
383 sps.chroma_format_idc as u32,
384 sps.separate_colour_plane_flag as u32,
385 sps.pcm_enabled_flag as u32,
386 sps.scaling_list_enabled_flag as u32,
387 pps.transform_skip_enabled_flag as u32,
388 sps.amp_enabled_flag as u32,
389 sps.strong_intra_smoothing_enabled_flag as u32,
390 pps.sign_data_hiding_enabled_flag as u32,
391 pps.constrained_intra_pred_flag as u32,
392 pps.cu_qp_delta_enabled_flag as u32,
393 pps.weighted_pred_flag as u32,
394 pps.weighted_bipred_flag as u32,
395 pps.transquant_bypass_enabled_flag as u32,
396 pps.tiles_enabled_flag as u32,
397 pps.entropy_coding_sync_enabled_flag as u32,
398 pps.loop_filter_across_slices_enabled_flag as u32,
399 pps.loop_filter_across_tiles_enabled_flag as u32,
400 sps.pcm_loop_filter_disabled_flag as u32,
401 0,
403 0,
404 );
405
406 let rap_pic_flag = current_picture.nalu_type as u32 >= NaluType::BlaWLp as u32
407 && current_picture.nalu_type as u32 <= NaluType::CraNut as u32;
408
409 let slice_parsing_fields = libva::HevcSliceParsingFields::new(
410 pps.lists_modification_present_flag as u32,
411 sps.long_term_ref_pics_present_flag as u32,
412 sps.temporal_mvp_enabled_flag as u32,
413 pps.cabac_init_present_flag as u32,
414 pps.output_flag_present_flag as u32,
415 pps.dependent_slice_segments_enabled_flag as u32,
416 pps.slice_chroma_qp_offsets_present_flag as u32,
417 sps.sample_adaptive_offset_enabled_flag as u32,
418 pps.deblocking_filter_override_enabled_flag as u32,
419 pps.deblocking_filter_disabled_flag as u32,
420 pps.slice_segment_header_extension_present_flag as u32,
421 rap_pic_flag as u32,
422 current_picture.nalu_type.is_idr() as u32,
423 current_picture.nalu_type.is_irap() as u32,
424 );
425
426 let pic_param = PictureParameterBufferHEVC::new(
427 curr_pic,
428 reference_frames,
429 sps.pic_width_in_luma_samples,
430 sps.pic_height_in_luma_samples,
431 &pic_fields,
432 sps.max_dec_pic_buffering_minus1[usize::from(sps.max_sub_layers_minus1)],
433 sps.bit_depth_luma_minus8,
434 sps.bit_depth_chroma_minus8,
435 sps.pcm_sample_bit_depth_luma_minus1,
436 sps.pcm_sample_bit_depth_chroma_minus1,
437 sps.log2_min_luma_coding_block_size_minus3,
438 sps.log2_diff_max_min_luma_coding_block_size,
439 sps.log2_min_luma_transform_block_size_minus2,
440 sps.log2_diff_max_min_luma_transform_block_size,
441 sps.log2_min_pcm_luma_coding_block_size_minus3,
442 sps.log2_diff_max_min_pcm_luma_coding_block_size,
443 sps.max_transform_hierarchy_depth_intra,
444 sps.max_transform_hierarchy_depth_inter,
445 pps.init_qp_minus26,
446 pps.diff_cu_qp_delta_depth,
447 pps.cb_qp_offset,
448 pps.cr_qp_offset,
449 pps.log2_parallel_merge_level_minus2,
450 pps.num_tile_columns_minus1,
451 pps.num_tile_rows_minus1,
452 pps.column_width_minus1.map(|x| x as u16),
453 pps.row_height_minus1.map(|x| x as u16),
454 &slice_parsing_fields,
455 sps.log2_max_pic_order_cnt_lsb_minus4,
456 sps.num_short_term_ref_pic_sets,
457 sps.num_long_term_ref_pics_sps,
458 pps.num_ref_idx_l0_default_active_minus1,
459 pps.num_ref_idx_l1_default_active_minus1,
460 pps.beta_offset_div2,
461 pps.tc_offset_div2,
462 pps.num_extra_slice_header_bits,
463 current_picture.short_term_ref_pic_set_size_bits,
464 );
465
466 Ok((
467 BufferType::PictureParameter(libva::PictureParameter::HEVC(pic_param)),
468 reference_frames,
469 ))
470}
471
472fn find_scaling_list(sps: &Sps, pps: &Pps) -> ScalingListType {
473 if pps.scaling_list_data_present_flag
474 || (sps.scaling_list_enabled_flag && !sps.scaling_list_data_present_flag)
475 {
476 ScalingListType::Pps
477 } else if sps.scaling_list_enabled_flag && sps.scaling_list_data_present_flag {
478 ScalingListType::Sps
479 } else {
480 ScalingListType::None
481 }
482}
483
484fn build_iq_matrix(sps: &Sps, pps: &Pps) -> BufferType {
485 let scaling_lists = match find_scaling_list(sps, pps) {
486 ScalingListType::Sps => &sps.scaling_list,
487 ScalingListType::Pps => &pps.scaling_list,
488 ScalingListType::None => panic!("No scaling list data available"),
489 };
490
491 let mut scaling_list_32x32 = [[0; 64]; 2];
492
493 for i in (0..6).step_by(3) {
494 for j in 0..64 {
495 scaling_list_32x32[i / 3][j] = scaling_lists.scaling_list_32x32[i][j];
496 }
497 }
498
499 let mut scaling_list_dc_32x32 = [0; 2];
500 for i in (0..6).step_by(3) {
501 scaling_list_dc_32x32[i / 3] =
502 (scaling_lists.scaling_list_dc_coef_minus8_32x32[i] + 8) as u8;
503 }
504
505 let mut scaling_list_4x4 = [[0; 16]; 6];
506 let mut scaling_list_8x8 = [[0; 64]; 6];
507 let mut scaling_list_16x16 = [[0; 64]; 6];
508 let mut scaling_list_32x32_r = [[0; 64]; 2];
509
510 (0..6).for_each(|i| {
511 super::get_raster_from_up_right_diagonal_4x4(
512 scaling_lists.scaling_list_4x4[i],
513 &mut scaling_list_4x4[i],
514 );
515
516 super::get_raster_from_up_right_diagonal_8x8(
517 scaling_lists.scaling_list_8x8[i],
518 &mut scaling_list_8x8[i],
519 );
520
521 super::get_raster_from_up_right_diagonal_8x8(
522 scaling_lists.scaling_list_16x16[i],
523 &mut scaling_list_16x16[i],
524 );
525 });
526
527 (0..2).for_each(|i| {
528 super::get_raster_from_up_right_diagonal_8x8(
529 scaling_list_32x32[i],
530 &mut scaling_list_32x32_r[i],
531 );
532 });
533
534 BufferType::IQMatrix(IQMatrix::HEVC(IQMatrixBufferHEVC::new(
535 scaling_list_4x4,
536 scaling_list_8x8,
537 scaling_list_16x16,
538 scaling_list_32x32_r,
539 scaling_lists
540 .scaling_list_dc_coef_minus8_16x16
541 .map(|x| (x + 8) as u8),
542 scaling_list_dc_32x32,
543 )))
544}
545
546impl<M: SurfaceMemoryDescriptor + 'static> VaapiBackend<M> {
547 fn submit_last_slice(
548 &mut self,
549 picture: &mut <Self as StatelessDecoderBackendPicture<H265>>::Picture,
550 ) -> anyhow::Result<()> {
551 if let Some(last_slice) = picture.last_slice.take() {
552 let metadata = self.metadata_state.get_parsed()?;
553 let context = &metadata.context;
554 let picture = &mut picture.picture;
555
556 let slice_param = BufferType::SliceParameter(SliceParameter::HEVC(last_slice.0));
557 let slice_param = context.create_buffer(slice_param)?;
558 picture.add_buffer(slice_param);
559
560 if let Some(slice_param_rext) = last_slice.1 {
561 let slice_param_rext =
562 BufferType::SliceParameter(SliceParameter::HEVCRext(slice_param_rext));
563 let slice_param_rext = context.create_buffer(slice_param_rext)?;
564 picture.add_buffer(slice_param_rext);
565 }
566
567 let slice_data = BufferType::SliceData(last_slice.2);
568 let slice_data = context.create_buffer(slice_data)?;
569 picture.add_buffer(slice_data);
570 }
571
572 Ok(())
573 }
574}
575
576pub struct VaapiH265Picture<Picture> {
577 picture: Picture,
578
579 last_slice: Option<(
582 SliceParameterBufferHEVC,
583 Option<SliceParameterBufferHEVCRext>,
584 Vec<u8>,
585 )>,
586
587 va_references: [PictureHEVC; 15],
588}
589
590impl<M: SurfaceMemoryDescriptor + 'static> StatelessDecoderBackendPicture<H265>
591 for VaapiBackend<M>
592{
593 type Picture = VaapiH265Picture<VaapiPicture<M>>;
594}
595
596impl<M: SurfaceMemoryDescriptor + 'static> StatelessH265DecoderBackend for VaapiBackend<M> {
597 fn new_sequence(&mut self, sps: &Sps) -> StatelessBackendResult<()> {
598 self.new_sequence(sps, PoolCreationMode::Highest)
599 }
600
601 fn new_picture(
602 &mut self,
603 coded_resolution: Resolution,
604 timestamp: u64,
605 ) -> NewPictureResult<Self::Picture> {
606 let layer = PoolLayer::Layer(coded_resolution);
607 let pool = self
608 .frame_pool(layer)
609 .pop()
610 .ok_or(NewPictureError::NoFramePool(coded_resolution))?;
611 let surface = pool
612 .get_surface()
613 .ok_or(NewPictureError::OutOfOutputBuffers)?;
614 let metadata = self.metadata_state.get_parsed()?;
615
616 Ok(VaapiH265Picture {
617 picture: VaPicture::new(timestamp, Rc::clone(&metadata.context), surface),
618 last_slice: Default::default(),
619 va_references: Default::default(),
620 })
621 }
622
623 fn begin_picture(
624 &mut self,
625 picture: &mut Self::Picture,
626 picture_data: &PictureData,
627 sps: &Sps,
628 pps: &Pps,
629 dpb: &Dpb<Self::Handle>,
630 rps: &RefPicSet<Self::Handle>,
631 slice: &Slice,
632 ) -> crate::decoder::stateless::StatelessBackendResult<()> {
633 let metadata = self.metadata_state.get_parsed()?;
634 let context = &metadata.context;
635
636 let surface_id = picture.picture.surface().id();
637
638 let (pic_param, reference_frames) =
639 build_pic_param(slice, picture_data, surface_id, dpb, rps, sps, pps)?;
640
641 picture.va_references = reference_frames;
642
643 let picture = &mut picture.picture;
644
645 let pic_param = context
646 .create_buffer(pic_param)
647 .context("while creating picture parameter buffer")?;
648
649 picture.add_buffer(pic_param);
650
651 if !matches!(find_scaling_list(sps, pps), ScalingListType::None) {
652 let iq_matrix = build_iq_matrix(sps, pps);
653 let iq_matrix = context
654 .create_buffer(iq_matrix)
655 .context("while creating IQ matrix buffer")?;
656
657 picture.add_buffer(iq_matrix);
658 }
659
660 let va_profile = sps.va_profile()?;
661 if is_range_extension_profile(va_profile) || is_scc_ext_profile(va_profile) {
662 let rext = build_picture_rext(sps, pps)?;
663 let rext = context
664 .create_buffer(rext)
665 .context("while creating picture parameter range extension buffer")?;
666
667 picture.add_buffer(rext);
668
669 if is_scc_ext_profile(va_profile) {
670 let scc = build_picture_scc(sps, pps)?;
671 let scc = context
672 .create_buffer(scc)
673 .context("while creating picture screen content coding buffer")?;
674
675 picture.add_buffer(scc);
676 }
677 }
678
679 Ok(())
680 }
681
682 fn decode_slice(
683 &mut self,
684 picture: &mut Self::Picture,
685 slice: &Slice,
686 sps: &Sps,
687 _: &Pps,
688 ref_pic_list0: &[Option<RefPicListEntry<Self::Handle>>; 16],
689 ref_pic_list1: &[Option<RefPicListEntry<Self::Handle>>; 16],
690 ) -> crate::decoder::stateless::StatelessBackendResult<()> {
691 self.submit_last_slice(picture)?;
692 let hdr = &slice.header;
693
694 let va_references = &picture.va_references;
695 let ref_pic_list0 = build_slice_ref_pic_list(ref_pic_list0, va_references);
696 let ref_pic_list1 = build_slice_ref_pic_list(ref_pic_list1, va_references);
697
698 let long_slice_flags = libva::HevcLongSliceFlags::new(
699 0,
700 hdr.dependent_slice_segment_flag as u32,
701 hdr.type_ as u32,
702 hdr.colour_plane_id as u32,
703 hdr.sao_luma_flag as u32,
704 hdr.sao_chroma_flag as u32,
705 hdr.mvd_l1_zero_flag as u32,
706 hdr.cabac_init_flag as u32,
707 hdr.temporal_mvp_enabled_flag as u32,
708 hdr.deblocking_filter_disabled_flag as u32,
709 hdr.collocated_from_l0_flag as u32,
710 hdr.loop_filter_across_slices_enabled_flag as u32,
711 );
712
713 let collocated_ref_idx = if hdr.temporal_mvp_enabled_flag {
714 hdr.collocated_ref_idx
715 } else {
716 0xff
717 };
718
719 let pwt = &hdr.pred_weight_table;
720
721 let mut delta_luma_weight_l0: [i8; 15usize] = Default::default();
722 let mut luma_offset_l0: [i8; 15usize] = Default::default();
723 let mut delta_chroma_weight_l0: [[i8; 2usize]; 15usize] = Default::default();
724 let mut chroma_offset_l0: [[i8; 2usize]; 15usize] = Default::default();
725 let mut delta_luma_weight_l1: [i8; 15usize] = Default::default();
726 let mut luma_offset_l1: [i8; 15usize] = Default::default();
727 let mut delta_chroma_weight_l1: [[i8; 2usize]; 15usize] = Default::default();
728 let mut chroma_offset_l1: [[i8; 2usize]; 15usize] = Default::default();
729
730 for i in 0..15 {
731 delta_luma_weight_l0[i] = pwt.delta_luma_weight_l0[i];
732 luma_offset_l0[i] = pwt.luma_offset_l0[i];
733
734 if hdr.type_.is_b() {
735 delta_luma_weight_l1[i] = pwt.delta_luma_weight_l1[i];
736 luma_offset_l1[i] = pwt.luma_offset_l1[i];
737 }
738
739 for j in 0..2 {
740 delta_chroma_weight_l0[i][j] = pwt.delta_chroma_weight_l0[i][j];
741 let delta_chroma_offset = pwt.delta_chroma_offset_l0[i][j];
742
743 let chroma_weight_l0 = (1 << pwt.chroma_log2_weight_denom)
744 + i32::from(pwt.delta_chroma_weight_l0[i][j]);
745
746 let offset = sps.wp_offset_half_range_c as i32 + delta_chroma_offset as i32
747 - ((sps.wp_offset_half_range_c as i32 * chroma_weight_l0)
748 >> pwt.chroma_log2_weight_denom);
749
750 chroma_offset_l0[i][j] = clip3(
751 -(sps.wp_offset_half_range_c as i32),
752 (sps.wp_offset_half_range_c - 1) as i32,
753 offset,
754 ) as _;
755
756 if hdr.type_.is_b() {
757 delta_chroma_weight_l1[i][j] = pwt.delta_chroma_weight_l1[i][j];
758 let delta_chroma_offset = pwt.delta_chroma_offset_l1[i][j];
759
760 let chroma_weight_l1 = (1 << pwt.chroma_log2_weight_denom)
761 + i32::from(pwt.delta_chroma_weight_l1[i][j]);
762
763 let offset = sps.wp_offset_half_range_c as i32 + delta_chroma_offset as i32
764 - ((sps.wp_offset_half_range_c as i32 * chroma_weight_l1)
765 >> pwt.chroma_log2_weight_denom);
766
767 chroma_offset_l1[i][j] = clip3(
768 -(sps.wp_offset_half_range_c as i32),
769 (sps.wp_offset_half_range_c - 1) as i32,
770 offset,
771 ) as _;
772 }
773 }
774 }
775
776 let slice_param = SliceParameterBufferHEVC::new(
777 slice.nalu.size as u32,
778 0,
779 libva::constants::VA_SLICE_DATA_FLAG_ALL,
780 (hdr.header_bit_size / 8) as _,
781 hdr.segment_address,
782 [ref_pic_list0, ref_pic_list1],
783 &long_slice_flags,
784 collocated_ref_idx,
785 hdr.num_ref_idx_l0_active_minus1,
786 hdr.num_ref_idx_l1_active_minus1,
787 hdr.qp_delta,
788 hdr.cb_qp_offset,
789 hdr.cr_qp_offset,
790 hdr.beta_offset_div2,
791 hdr.tc_offset_div2,
792 pwt.luma_log2_weight_denom,
793 pwt.delta_chroma_log2_weight_denom,
794 delta_luma_weight_l0,
795 luma_offset_l0,
796 delta_chroma_weight_l0,
797 chroma_offset_l0,
798 delta_luma_weight_l1,
799 luma_offset_l1,
800 delta_chroma_weight_l1,
801 chroma_offset_l1,
802 hdr.five_minus_max_num_merge_cand,
803 hdr.num_entry_point_offsets as _,
804 0,
805 hdr.n_emulation_prevention_bytes as _,
806 );
807
808 let va_profile = sps.va_profile()?;
809
810 let slice_param_ext =
811 if is_range_extension_profile(va_profile) || is_scc_ext_profile(va_profile) {
812 let slice_ext_flags = HevcSliceExtFlags::new(
813 hdr.cu_chroma_qp_offset_enabled_flag as u32,
814 hdr.use_integer_mv_flag as u32,
815 );
816
817 let slice_param_ext = SliceParameterBufferHEVCRext::new(
818 luma_offset_l0.map(i16::from),
819 chroma_offset_l0.map(|outer| outer.map(i16::from)),
820 luma_offset_l1.map(i16::from),
821 chroma_offset_l1.map(|outer| outer.map(i16::from)),
822 &slice_ext_flags,
823 hdr.slice_act_y_qp_offset,
824 hdr.slice_act_cb_qp_offset,
825 hdr.slice_act_cr_qp_offset,
826 );
827
828 Some(slice_param_ext)
829 } else {
830 None
831 };
832
833 let slice_data = Vec::from(slice.nalu.as_ref());
834
835 picture.last_slice = Some((slice_param, slice_param_ext, slice_data));
836
837 Ok(())
838 }
839
840 fn submit_picture(
841 &mut self,
842 mut picture: Self::Picture,
843 ) -> StatelessBackendResult<Self::Handle> {
844 if let Some(last_slice) = &mut picture.last_slice {
845 last_slice.0.set_as_last();
846 }
847 self.submit_last_slice(&mut picture)?;
848 self.process_picture::<H265>(picture.picture)
849 }
850}
851
852impl<M: SurfaceMemoryDescriptor + 'static> StatelessDecoder<H265, VaapiBackend<M>> {
853 pub fn new_vaapi<S>(
855 display: Rc<Display>,
856 blocking_mode: BlockingMode,
857 ) -> Result<Self, NewStatelessDecoderError>
858 where
859 M: From<S>,
860 S: From<M>,
861 {
862 Self::new(VaapiBackend::new(display, false), blocking_mode)
863 }
864}
865
866#[cfg(test)]
867mod tests {
868 use libva::Display;
869
870 use crate::codec::h265::parser::Nalu;
871 use crate::decoder::stateless::h265::H265;
872 use crate::decoder::stateless::tests::test_decode_stream;
873 use crate::decoder::stateless::tests::TestStream;
874 use crate::decoder::stateless::StatelessDecoder;
875 use crate::decoder::BlockingMode;
876 use crate::utils::simple_playback_loop;
877 use crate::utils::simple_playback_loop_owned_frames;
878 use crate::utils::NalIterator;
879 use crate::DecodedFormat;
880
881 fn test_decoder_vaapi(
883 test: &TestStream,
884 output_format: DecodedFormat,
885 blocking_mode: BlockingMode,
886 ) {
887 let display = Display::open().unwrap();
888 let decoder = StatelessDecoder::<H265, _>::new_vaapi::<()>(display, blocking_mode).unwrap();
889
890 test_decode_stream(
891 |d, s, f| {
892 simple_playback_loop(
893 d,
894 NalIterator::<Nalu>::new(s),
895 f,
896 &mut simple_playback_loop_owned_frames,
897 output_format,
898 blocking_mode,
899 )
900 },
901 decoder,
902 test,
903 true,
904 false,
905 );
906 }
907
908 #[test]
909 #[ignore]
911 fn test_64x64_progressive_i_block() {
912 use crate::decoder::stateless::h265::tests::DECODE_64X64_PROGRESSIVE_I;
913 test_decoder_vaapi(
914 &DECODE_64X64_PROGRESSIVE_I,
915 DecodedFormat::NV12,
916 BlockingMode::Blocking,
917 );
918 }
919
920 #[test]
921 #[ignore]
923 fn test_64x64_progressive_i_nonblock() {
924 use crate::decoder::stateless::h265::tests::DECODE_64X64_PROGRESSIVE_I;
925 test_decoder_vaapi(
926 &DECODE_64X64_PROGRESSIVE_I,
927 DecodedFormat::NV12,
928 BlockingMode::NonBlocking,
929 );
930 }
931
932 #[test]
933 #[ignore]
935 fn test_64x64_progressive_i_p_block() {
936 use crate::decoder::stateless::h265::tests::DECODE_64X64_PROGRESSIVE_I_P;
937 test_decoder_vaapi(
938 &DECODE_64X64_PROGRESSIVE_I_P,
939 DecodedFormat::NV12,
940 BlockingMode::Blocking,
941 );
942 }
943
944 #[test]
945 #[ignore]
947 fn test_64x64_progressive_i_p_nonblock() {
948 use crate::decoder::stateless::h265::tests::DECODE_64X64_PROGRESSIVE_I_P;
949 test_decoder_vaapi(
950 &DECODE_64X64_PROGRESSIVE_I_P,
951 DecodedFormat::NV12,
952 BlockingMode::NonBlocking,
953 );
954 }
955
956 #[test]
957 #[ignore]
959 fn test_64x64_progressive_i_p_b_p_block() {
960 use crate::decoder::stateless::h265::tests::DECODE_64X64_PROGRESSIVE_I_P_B_P;
961 test_decoder_vaapi(
962 &DECODE_64X64_PROGRESSIVE_I_P_B_P,
963 DecodedFormat::NV12,
964 BlockingMode::Blocking,
965 );
966 }
967
968 #[test]
969 #[ignore]
971 fn test_64x64_progressive_i_p_b_p_nonblock() {
972 use crate::decoder::stateless::h265::tests::DECODE_64X64_PROGRESSIVE_I_P_B_P;
973 test_decoder_vaapi(
974 &DECODE_64X64_PROGRESSIVE_I_P_B_P,
975 DecodedFormat::NV12,
976 BlockingMode::NonBlocking,
977 );
978 }
979}