nihed-cros-libva: update test to the current interface
[nihav-player.git] / nihed-cros-libva / src / lib.rs
CommitLineData
68362724
KS
1// Copyright 2022 The ChromiumOS Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! Implements a lightweight and safe interface over `libva`.
6//!
7//! The starting point to using this crate is to open a [`Display`], from which a [`Context`] and
8//! [`Surface`]s can be allocated and used for doing actual work.
9
10#![deny(missing_docs)]
11
12mod bindings;
13pub mod buffer;
14mod config;
15mod context;
16mod display;
0f2fb233 17mod formats;
68362724
KS
18mod generic_value;
19mod image;
20mod picture;
21mod status;
22mod surface;
23mod usage_hint;
24
25pub use bindings::constants;
26pub use bindings::VAConfigAttrib;
27pub use bindings::VAConfigAttribType;
28pub use bindings::VAEntrypoint;
29pub use bindings::VAImageFormat;
30pub use bindings::VAProfile;
31pub use bindings::VASurfaceAttribType;
32pub use bindings::VASurfaceID;
68362724
KS
33pub use buffer::*;
34pub use config::*;
35pub use context::*;
36pub use display::*;
0f2fb233 37pub use formats::*;
68362724
KS
38pub use generic_value::*;
39pub use image::*;
40pub use picture::*;
69e6ce02 41pub use status::*;
68362724
KS
42pub use surface::*;
43pub use usage_hint::*;
44
49bf1d79
KS
45pub use bindings::constants::VA_INVALID_ID;
46
68362724
KS
47#[cfg(test)]
48mod tests {
49 use std::rc::Rc;
50
51 use super::*;
52
53 /// Returns a 32-bit CRC for the visible part of `image`, which must be in NV12 format.
54 fn crc_nv12_image(image: &Image) -> u32 {
55 let data = image.as_ref();
56 let va_image = image.image();
57 let offsets = &va_image.offsets;
58 let pitches = &va_image.pitches;
59 let width = va_image.width as usize;
60 let height = va_image.height as usize;
61
62 // We only support NV12 images
359f4b2f 63 assert_eq!(va_image.format.fourcc(), Ok(VAFourcc::NV12));
68362724
KS
64 // Consistency check
65 assert_eq!(va_image.num_planes, 2);
66
67 let mut hasher = crc32fast::Hasher::new();
68
69 let offset = offsets[0] as usize;
70 let pitch = pitches[0] as usize;
71 let y_plane = data[offset..(offset + pitch * height)]
72 .chunks(pitch)
73 .map(|line| &line[0..width]);
74
75 let offset = offsets[1] as usize;
76 let pitch = pitches[1] as usize;
77 let uv_plane = data[offset..(offset + pitch * ((height + 1) / 2))]
78 .chunks(pitch)
79 .map(|line| &line[0..width]);
80
81 for line in y_plane.chain(uv_plane) {
82 hasher.update(line);
83 }
84
85 hasher.finalize()
86 }
87
88 #[test]
89 // Ignore this test by default as it requires libva-compatible hardware.
90 #[ignore]
91 fn libva_utils_mpeg2vldemo() {
92 // Adapted from <https://github.com/intel/libva-utils/blob/master/decode/mpeg2vldemo.cpp>
93 let display = Display::open().unwrap();
94
95 assert!(!display.query_vendor_string().unwrap().is_empty());
96 let profiles = display.query_config_profiles().unwrap();
97 assert!(!profiles.is_empty());
98
99 let profile = bindings::VAProfile::VAProfileMPEG2Main;
100 let entrypoints = display.query_config_entrypoints(profile).unwrap();
101 assert!(!entrypoints.is_empty());
102 assert!(entrypoints
103 .iter()
104 .any(|e| *e == bindings::VAEntrypoint::VAEntrypointVLD));
105
359f4b2f 106 let format = RTFormat::YUV420;
68362724
KS
107 let width = 16;
108 let height = 16;
109
110 let mut attrs = vec![bindings::VAConfigAttrib {
111 type_: bindings::VAConfigAttribType::VAConfigAttribRTFormat,
112 value: 0,
113 }];
114
115 let entrypoint = bindings::VAEntrypoint::VAEntrypointVLD;
116 display
117 .get_config_attributes(profile, entrypoint, &mut attrs)
118 .unwrap();
119 assert!(attrs[0].value != bindings::constants::VA_ATTRIB_NOT_SUPPORTED);
120 assert!(attrs[0].value & bindings::constants::VA_RT_FORMAT_YUV420 != 0);
121
122 let config = display.create_config(attrs, profile, entrypoint).unwrap();
123
124 let mut surfaces = display
125 .create_surfaces(
126 format,
127 None,
128 width,
129 height,
359f4b2f 130 Some(UsageHint::Decoder.into()),
68362724
KS
131 1,
132 )
133 .unwrap();
134 let context = display
135 .create_context(
136 &config,
137 width as i32,
138 (((height + 15) / 16) * 16) as i32,
139 Some(&surfaces),
140 true,
141 )
142 .unwrap();
143
144 // The picture data is adapted from libva-utils at decode/mpeg2vldemo.cpp
145 // Data dump of a 16x16 MPEG2 video clip,it has one I frame
146 let mut mpeg2_clip: Vec<u8> = vec![
147 0x00, 0x00, 0x01, 0xb3, 0x01, 0x00, 0x10, 0x13, 0xff, 0xff, 0xe0, 0x18, 0x00, 0x00,
148 0x01, 0xb5, 0x14, 0x8a, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0xb8, 0x00, 0x08,
149 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0f, 0xff, 0xf8, 0x00, 0x00, 0x01, 0xb5,
150 0x8f, 0xff, 0xf3, 0x41, 0x80, 0x00, 0x00, 0x01, 0x01, 0x13, 0xe1, 0x00, 0x15, 0x81,
151 0x54, 0xe0, 0x2a, 0x05, 0x43, 0x00, 0x2d, 0x60, 0x18, 0x01, 0x4e, 0x82, 0xb9, 0x58,
152 0xb1, 0x83, 0x49, 0xa4, 0xa0, 0x2e, 0x05, 0x80, 0x4b, 0x7a, 0x00, 0x01, 0x38, 0x20,
153 0x80, 0xe8, 0x05, 0xff, 0x60, 0x18, 0xe0, 0x1d, 0x80, 0x98, 0x01, 0xf8, 0x06, 0x00,
154 0x54, 0x02, 0xc0, 0x18, 0x14, 0x03, 0xb2, 0x92, 0x80, 0xc0, 0x18, 0x94, 0x42, 0x2c,
155 0xb2, 0x11, 0x64, 0xa0, 0x12, 0x5e, 0x78, 0x03, 0x3c, 0x01, 0x80, 0x0e, 0x80, 0x18,
156 0x80, 0x6b, 0xca, 0x4e, 0x01, 0x0f, 0xe4, 0x32, 0xc9, 0xbf, 0x01, 0x42, 0x69, 0x43,
157 0x50, 0x4b, 0x01, 0xc9, 0x45, 0x80, 0x50, 0x01, 0x38, 0x65, 0xe8, 0x01, 0x03, 0xf3,
158 0xc0, 0x76, 0x00, 0xe0, 0x03, 0x20, 0x28, 0x18, 0x01, 0xa9, 0x34, 0x04, 0xc5, 0xe0,
159 0x0b, 0x0b, 0x04, 0x20, 0x06, 0xc0, 0x89, 0xff, 0x60, 0x12, 0x12, 0x8a, 0x2c, 0x34,
160 0x11, 0xff, 0xf6, 0xe2, 0x40, 0xc0, 0x30, 0x1b, 0x7a, 0x01, 0xa9, 0x0d, 0x00, 0xac,
161 0x64,
162 ];
163
164 let picture_coding_extension =
165 MPEG2PictureCodingExtension::new(0, 3, 0, 1, 0, 0, 0, 0, 0, 1, 1);
166 let pic_param = PictureParameterBufferMPEG2::new(
167 16,
168 16,
169 0xffffffff,
170 0xffffffff,
171 1,
172 0xffff,
173 &picture_coding_extension,
174 );
175
176 let pic_param = BufferType::PictureParameter(PictureParameter::MPEG2(pic_param));
177
178 let iq_matrix = IQMatrixBufferMPEG2::new(
179 1,
180 1,
181 0,
182 0,
183 [
184 8, 16, 16, 19, 16, 19, 22, 22, 22, 22, 22, 22, 26, 24, 26, 27, 27, 27, 26, 26, 26,
185 26, 27, 27, 27, 29, 29, 29, 34, 34, 34, 29, 29, 29, 27, 27, 29, 29, 32, 32, 34, 34,
186 37, 38, 37, 35, 35, 34, 35, 38, 38, 40, 40, 40, 48, 48, 46, 46, 56, 56, 58, 69, 69,
187 83,
188 ],
189 [
190 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
191 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
192 0, 0, 0, 0, 0, 0, 0, 0, 0,
193 ],
194 [0; 64],
195 [0; 64],
196 );
197
198 let iq_matrix = BufferType::IQMatrix(IQMatrix::MPEG2(iq_matrix));
199
200 let slice_param = SliceParameterBufferMPEG2::new(150, 0, 0, 38, 0, 0, 2, 0);
201
202 let slice_param = BufferType::SliceParameter(SliceParameter::MPEG2(slice_param));
203
204 let test_data_offset = 47;
205 let slice_data = BufferType::SliceData(mpeg2_clip.drain(test_data_offset..).collect());
206
207 let buffers = vec![
208 context.create_buffer(pic_param).unwrap(),
209 context.create_buffer(slice_param).unwrap(),
210 context.create_buffer(iq_matrix).unwrap(),
211 context.create_buffer(slice_data).unwrap(),
212 ];
213
214 let mut picture = Picture::new(0, Rc::clone(&context), surfaces.remove(0));
215 for buffer in buffers {
216 picture.add_buffer(buffer);
217 }
218
219 // Actual client code can just chain the calls.
220 let picture = picture.begin().unwrap();
221 let picture = picture.render().unwrap();
222 let picture = picture.end().unwrap();
223 let picture = picture.sync().map_err(|(e, _)| e).unwrap();
224
225 // Test whether we can map the resulting surface to obtain the raw yuv
226 // data
227 let image_fmts = display.query_image_formats().unwrap();
228 let image_fmt = image_fmts
229 .into_iter()
230 .find(|f| f.fourcc == bindings::constants::VA_FOURCC_NV12)
231 .expect("No valid VAImageFormat found for NV12");
232
233 let image = Image::new(&picture, image_fmt, width, height, false).unwrap();
234
235 assert_eq!(crc_nv12_image(&image), 0xa5713e52);
236 }
237}