pixelflux/encoders/vaapi/
h264.rs1use va_sys::*;
15
16use super::super::bits::{BitWriter, nal_unit};
17use super::super::codec::h264_level;
18use super::{Buffers, Frame, Negotiated};
19
20const LOG2_MAX_FRAME_NUM_MINUS4: u32 = 12;
23const PIC_INIT_QP: u32 = 26;
25pub(super) const MIN_QP: u32 = 7;
28
29pub(super) struct Arm {
30 profile: VAProfile,
31 level_idc: u32,
32 mb_width: u32,
33 mb_height: u32,
34 slices: (u32, u32),
36 cabac: bool,
37 transform_8x8: bool,
38 dpb: u32,
39 sequence: VAEncSequenceParameterBufferH264,
40 sps: Vec<u8>,
41 pps: Vec<u8>,
42 idr_pic_id: u16,
43}
44
45impl Arm {
46 pub(super) fn new(profile: VAProfile) -> Self {
47 Self {
48 profile,
49 level_idc: 0,
50 mb_width: 0,
51 mb_height: 0,
52 slices: (1, 1),
53 cabac: profile != VAProfileH264ConstrainedBaseline,
54 transform_8x8: profile == VAProfileH264High,
55 dpb: 1,
56 sequence: unsafe { std::mem::zeroed() },
57 sps: Vec::new(),
58 pps: Vec::new(),
59 idr_pic_id: 0,
60 }
61 }
62
63 pub(super) fn frame_num_range(&self) -> u32 {
65 1 << (4 + LOG2_MAX_FRAME_NUM_MINUS4)
66 }
67
68 pub(super) fn slices(&self) -> (u32, u32) {
69 self.slices
70 }
71
72 pub(super) fn level(&self) -> u32 {
74 self.level_idc
75 }
76
77 pub(super) fn configure(
81 &mut self,
82 n: &Negotiated,
83 surface_width: u32,
84 surface_height: u32,
85 slices: (u32, u32),
86 ) {
87 self.mb_width = surface_width / 16;
88 self.mb_height = surface_height / 16;
89 self.slices = slices;
90 self.dpb = n.dpb;
91 self.level_idc = h264_level(
92 n.width,
93 n.height,
94 n.fps.ceil(),
95 u64::from(n.bits_per_second),
96 )
97 .max(n.dpb_level);
98 let profile_idc = if self.profile == VAProfileH264High {
99 100
100 } else if self.profile == VAProfileH264Main {
101 77
102 } else {
103 66
104 };
105 let crop = (self.mb_width * 16 != n.width) || (self.mb_height * 16 != n.height);
106
107 let mut w = BitWriter::new();
108 w.u(8, profile_idc);
109 let (set1, set3, set4, set5) = (
110 profile_idc != 100,
111 false,
112 profile_idc != 66,
113 profile_idc != 66,
114 );
115 w.flag(false);
116 w.flag(set1);
117 w.flag(false);
118 w.flag(set3);
119 w.flag(set4);
120 w.flag(set5);
121 w.u(2, 0);
122 w.u(8, u64::from(self.level_idc));
123 w.ue(0);
124 if profile_idc == 100 {
125 w.ue(1);
126 w.ue(0);
127 w.ue(0);
128 w.flag(false);
129 w.flag(false);
130 }
131 w.ue(LOG2_MAX_FRAME_NUM_MINUS4);
132 w.ue(2);
133 w.ue(self.dpb);
134 w.flag(false);
135 w.ue(self.mb_width - 1);
136 w.ue(self.mb_height - 1);
137 w.flag(true);
138 w.flag(true);
139 w.flag(crop);
140 if crop {
141 w.ue(0);
142 w.ue((self.mb_width * 16 - n.width) / 2);
143 w.ue(0);
144 w.ue((self.mb_height * 16 - n.height) / 2);
145 }
146 w.flag(true);
147 w.flag(false);
148 w.flag(false);
149 w.flag(true);
150 w.u(3, 5);
151 w.flag(false);
152 w.flag(true);
153 w.u(8, 1);
154 w.u(8, 1);
155 w.u(8, 1);
156 w.flag(false);
157 w.flag(true);
158 w.u(32, u64::from(n.fps.den));
159 w.u(32, 2 * u64::from(n.fps.num));
160 w.flag(true);
161 w.flag(false);
162 w.flag(false);
163 w.flag(false);
164 w.flag(true);
165 w.flag(true);
166 w.ue(0);
167 w.ue(0);
168 w.ue(15);
169 w.ue(15);
170 w.ue(0);
171 w.ue(self.dpb);
172 w.trailing_bits();
173 self.sps = nal_unit(&[0x67], w.as_bytes());
174
175 let mut w = BitWriter::new();
176 w.ue(0);
177 w.ue(0);
178 w.flag(self.cabac);
179 w.flag(false);
180 w.ue(0);
181 w.ue(0);
182 w.ue(0);
183 w.flag(false);
184 w.u(2, 0);
185 w.se(PIC_INIT_QP as i32 - 26);
186 w.se(0);
187 w.se(0);
188 w.flag(false);
189 w.flag(false);
190 w.flag(false);
191 if self.transform_8x8 {
192 w.flag(true);
193 w.flag(false);
194 w.se(0);
195 }
196 w.trailing_bits();
197 self.pps = nal_unit(&[0x68], w.as_bytes());
198
199 let s = &mut self.sequence;
200 *s = unsafe { std::mem::zeroed() };
201 s.seq_parameter_set_id = 0;
202 s.level_idc = self.level_idc.min(n.h264_driver_level) as u8;
203 s.intra_period = i32::MAX as u32;
204 s.intra_idr_period = i32::MAX as u32;
205 s.ip_period = 1;
206 s.bits_per_second = n.bits_per_second;
207 s.max_num_ref_frames = self.dpb;
208 s.picture_width_in_mbs = self.mb_width as u16;
209 s.picture_height_in_mbs = self.mb_height as u16;
210 unsafe {
211 let f = &mut s.seq_fields.bits;
212 f.set_chroma_format_idc(1);
213 f.set_frame_mbs_only_flag(1);
214 f.set_direct_8x8_inference_flag(1);
215 f.set_log2_max_frame_num_minus4(LOG2_MAX_FRAME_NUM_MINUS4);
216 f.set_pic_order_cnt_type(2);
217 let v = &mut s.vui_fields.bits;
218 v.set_timing_info_present_flag(1);
219 v.set_bitstream_restriction_flag(1);
220 v.set_log2_max_mv_length_horizontal(15);
221 v.set_log2_max_mv_length_vertical(15);
222 }
223 s.frame_cropping_flag = u8::from(crop);
224 if crop {
225 s.frame_crop_right_offset = (self.mb_width * 16 - n.width) / 2;
226 s.frame_crop_bottom_offset = (self.mb_height * 16 - n.height) / 2;
227 }
228 s.vui_parameters_present_flag = 1;
229 s.num_units_in_tick = n.fps.den;
230 s.time_scale = 2 * n.fps.num;
231 }
232
233 pub(super) fn sequence(&mut self, n: &Negotiated, out: &mut Buffers) {
234 out.push(VAEncSequenceParameterBufferType, &self.sequence);
235 if n.packed & VA_ENC_PACKED_HEADER_SEQUENCE != 0 {
236 let mut bytes = self.sps.clone();
237 bytes.extend_from_slice(&self.pps);
238 let bits = 8 * bytes.len() as u32;
239 out.push_packed(VAEncPackedHeaderSequence, &bytes, bits);
240 }
241 }
242
243 pub(super) fn picture(
251 &mut self,
252 n: &Negotiated,
253 frame: &Frame,
254 out: &mut Buffers,
255 ) -> Result<(), String> {
256 let frame_num = ((frame.pts - frame.key_pts) % u64::from(self.frame_num_range())) as u32;
257 let poc = 2 * (frame.pts - frame.key_pts) as i32;
258 if frame.key {
259 self.idr_pic_id = self
260 .idr_pic_id
261 .wrapping_add(if frame.pts == 0 { 0 } else { 1 });
262 }
263 let long_term = |pts: u64| frame.long_term.iter().find(|l| l.0 == pts).map(|l| l.1);
264 let picture = |pts: u64, surface: VASurfaceID| VAPictureH264 {
265 picture_id: surface,
266 frame_idx: long_term(pts).map_or(
267 ((pts - frame.key_pts) % u64::from(self.frame_num_range())) as u32,
268 u32::from,
269 ),
270 flags: if long_term(pts).is_some() {
271 VA_PICTURE_H264_LONG_TERM_REFERENCE
272 } else {
273 VA_PICTURE_H264_SHORT_TERM_REFERENCE
274 },
275 TopFieldOrderCnt: 2 * (pts - frame.key_pts) as i32,
276 BottomFieldOrderCnt: 2 * (pts - frame.key_pts) as i32,
277 va_reserved: [0; 4],
278 };
279 let invalid = VAPictureH264 {
280 picture_id: VA_INVALID_ID,
281 frame_idx: 0,
282 flags: VA_PICTURE_H264_INVALID,
283 TopFieldOrderCnt: 0,
284 BottomFieldOrderCnt: 0,
285 va_reserved: [0; 4],
286 };
287
288 let marked = if frame.key && frame.anchored {
289 Some(0)
290 } else {
291 frame.anchor
292 };
293 let mut pic: VAEncPictureParameterBufferH264 = unsafe { std::mem::zeroed() };
294 pic.CurrPic = VAPictureH264 {
295 picture_id: frame.recon,
296 frame_idx: marked.map_or(frame_num, u32::from),
297 flags: if marked.is_some() {
298 VA_PICTURE_H264_LONG_TERM_REFERENCE
299 } else {
300 0
301 },
302 TopFieldOrderCnt: poc,
303 BottomFieldOrderCnt: poc,
304 va_reserved: [0; 4],
305 };
306 pic.ReferenceFrames = [invalid; 16];
307 let mut held: Vec<(u64, VASurfaceID)> = frame
308 .held
309 .iter()
310 .filter(|h| !frame.key && h.0 >= frame.key_pts)
311 .map(|h| (h.0, h.1))
312 .collect();
313 held.sort_by_key(|h| std::cmp::Reverse(h.0));
314 for (i, &(pts, surface)) in held.iter().take(16).enumerate() {
315 pic.ReferenceFrames[i] = picture(pts, surface);
316 }
317 pic.coded_buf = frame.coded;
318 pic.frame_num = frame_num as u16;
319 pic.pic_init_qp = PIC_INIT_QP as u8;
320 unsafe {
321 let f = &mut pic.pic_fields.bits;
322 f.set_idr_pic_flag(u32::from(frame.key));
323 f.set_reference_pic_flag(1);
324 f.set_entropy_coding_mode_flag(u32::from(self.cabac));
325 f.set_transform_8x8_mode_flag(u32::from(self.transform_8x8));
326 }
327 out.push(VAEncPictureParameterBufferType, &pic);
328
329 let reference = frame.reference.map(|(pts, surface)| picture(pts, surface));
330 if !frame.key && reference.is_none() {
331 return Err("a predicted H.264 picture without a reference".into());
332 }
333 let slice_qp = if n.rc_mode == VA_RC_CQP {
334 frame.qp.clamp(MIN_QP, 51)
335 } else {
336 PIC_INIT_QP
337 };
338 let slice_qp_delta = slice_qp as i32 - PIC_INIT_QP as i32;
339 let (slice_count, slice_rows) = self.slices;
340 for i in 0..slice_count {
341 let first_row = i * slice_rows;
342 let rows = if i + 1 == slice_count {
343 self.mb_height - first_row
344 } else {
345 slice_rows
346 };
347 let first_mb = first_row * self.mb_width;
348 let mbs = rows * self.mb_width;
349 let slice_type = if frame.key { 7 } else { 5 };
350
351 if n.packed & VA_ENC_PACKED_HEADER_SLICE != 0 {
352 let mut w = BitWriter::new();
353 w.ue(first_mb);
354 w.ue(slice_type);
355 w.ue(0);
356 w.u(4 + LOG2_MAX_FRAME_NUM_MINUS4, u64::from(frame_num));
357 if frame.key {
358 w.ue(u32::from(self.idr_pic_id));
359 }
360 if !frame.key {
361 w.flag(false);
362 let (ref_pts, _) = frame.reference.unwrap();
363 if let Some(index) = long_term(ref_pts) {
364 w.flag(true);
365 w.ue(2);
366 w.ue(u32::from(index));
367 w.ue(3);
368 } else {
369 let ref_frame_num =
370 ((ref_pts - frame.key_pts) % u64::from(self.frame_num_range())) as u32;
371 let newest = held.iter().find(|h| long_term(h.0).is_none()).map(|h| h.0)
372 == Some(ref_pts);
373 w.flag(!newest);
374 if !newest {
375 let diff = (frame_num + self.frame_num_range() - ref_frame_num)
376 % self.frame_num_range();
377 w.ue(0);
378 w.ue(diff - 1);
379 w.ue(3);
380 }
381 }
382 }
383 if frame.key {
384 w.flag(false);
385 w.flag(frame.anchored);
386 } else if let Some(index) = frame.anchor {
387 w.flag(true);
388 w.ue(6);
389 w.ue(u32::from(index));
390 w.ue(0);
391 } else {
392 w.flag(false);
393 }
394 if self.cabac && !frame.key {
395 w.ue(0);
396 }
397 w.se(slice_qp_delta);
398 let header = nal_unit(if frame.key { &[0x65] } else { &[0x41] }, w.as_bytes());
399 let bits = 8 * (header.len() as u32 - w.as_bytes().len() as u32) + w.len() as u32;
400 out.push_packed(VAEncPackedHeaderSlice, &header, bits);
401 }
402
403 let mut slice: VAEncSliceParameterBufferH264 = unsafe { std::mem::zeroed() };
404 slice.macroblock_address = first_mb;
405 slice.num_macroblocks = mbs;
406 slice.macroblock_info = VA_INVALID_ID;
407 slice.slice_type = (slice_type % 5) as u8;
408 slice.pic_parameter_set_id = 0;
409 slice.idr_pic_id = self.idr_pic_id;
410 slice.pic_order_cnt_lsb = 0;
411 slice.direct_spatial_mv_pred_flag = 1;
412 slice.RefPicList0 = [invalid; 32];
413 slice.RefPicList1 = [invalid; 32];
414 if let Some(r) = reference {
415 slice.RefPicList0[0] = r;
416 }
417 slice.slice_qp_delta = slice_qp_delta as i8;
418 out.push(VAEncSliceParameterBufferType, &slice);
419 }
420 Ok(())
421 }
422}