1use crate::{ffi, VideoFormat};
4use glib::translate::*;
5
6use crate::video_vbi::line_buffer_len;
7use crate::{VideoAncillaryDID, VideoAncillaryDID16, VideoVBIError, VBI_HD_MIN_PIXEL_WIDTH};
8
9glib::wrapper! {
10 #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
11 struct VideoVBIEncoderInner(Boxed<ffi::GstVideoVBIEncoder>);
12
13 match fn {
14 copy => |ptr| ffi::gst_video_vbi_encoder_copy(ptr),
15 free => |ptr| ffi::gst_video_vbi_encoder_free(ptr),
16 type_ => || ffi::gst_video_vbi_encoder_get_type(),
17 }
18}
19
20#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
23pub struct VideoVBIEncoder {
24 inner: VideoVBIEncoderInner,
25 format: VideoFormat,
26 pixel_width: u32,
27 line_buffer_len: usize,
28 anc_len: usize,
29}
30
31unsafe impl Send for VideoVBIEncoder {}
32unsafe impl Sync for VideoVBIEncoder {}
33
34#[derive(Clone, Copy, Debug, Eq, PartialEq)]
35pub enum VideoAFDDescriptionMode {
36 Composite,
37 Component,
38}
39
40impl VideoAFDDescriptionMode {
41 pub fn is_composite(&self) -> bool {
42 matches!(self, VideoAFDDescriptionMode::Composite)
43 }
44
45 pub fn is_component(&self) -> bool {
46 matches!(self, VideoAFDDescriptionMode::Component)
47 }
48}
49
50impl VideoVBIEncoder {
51 #[doc(alias = "gst_video_vbi_encoder_new")]
52 pub fn try_new(
53 format: VideoFormat,
54 pixel_width: u32,
55 ) -> Result<VideoVBIEncoder, VideoVBIError> {
56 skip_assert_initialized!();
57 let res: Option<VideoVBIEncoderInner> = unsafe {
58 from_glib_full(ffi::gst_video_vbi_encoder_new(
59 format.into_glib(),
60 pixel_width,
61 ))
62 };
63
64 Ok(VideoVBIEncoder {
65 inner: res.ok_or(VideoVBIError::Unsupported)?,
66 format,
67 pixel_width,
68 line_buffer_len: line_buffer_len(format, pixel_width),
69 anc_len: 0,
70 })
71 }
72
73 pub fn add_did_ancillary(
76 &mut self,
77 adf_mode: VideoAFDDescriptionMode,
78 did: VideoAncillaryDID,
79 block_number: u8,
80 data: &[u8],
81 ) -> Result<(), VideoVBIError> {
82 self.add_ancillary(adf_mode, did.into_glib() as u8, block_number, data)
83 }
84
85 pub fn add_did16_ancillary(
88 &mut self,
89 adf_mode: VideoAFDDescriptionMode,
90 did16: VideoAncillaryDID16,
91 data: &[u8],
92 ) -> Result<(), VideoVBIError> {
93 let did16 = did16.into_glib();
94
95 self.add_ancillary(
96 adf_mode,
97 ((did16 & 0xff00) >> 8) as u8,
98 (did16 & 0xff) as u8,
99 data,
100 )
101 }
102
103 #[doc(alias = "gst_video_vbi_encoder_add_ancillary")]
123 pub fn add_ancillary(
124 &mut self,
125 adf_mode: VideoAFDDescriptionMode,
126 did: u8,
127 sdid_block_number: u8,
128 data: &[u8],
129 ) -> Result<(), VideoVBIError> {
130 let data_count = data.len() as _;
131 let res: bool = unsafe {
132 from_glib(ffi::gst_video_vbi_encoder_add_ancillary(
133 self.inner.to_glib_none_mut().0,
134 adf_mode.is_composite().into_glib(),
135 did,
136 sdid_block_number,
137 data.to_glib_none().0,
138 data_count,
139 ))
140 };
141
142 if !res {
143 return Err(VideoVBIError::NotEnoughSpace);
144 }
145
146 let mut len = 1 + 3 + (data_count as usize) + 1;
151 if adf_mode.is_component() {
152 len += 2;
153 }
154
155 if matches!(self.format, VideoFormat::V210) {
156 len *= 2;
158 }
159
160 self.anc_len += len;
161
162 Ok(())
163 }
164
165 pub fn line_buffer_len(&self) -> usize {
168 self.line_buffer_len
169 }
170
171 #[doc(alias = "gst_video_vbi_encoder_write_line")]
186 pub fn write_line(&mut self, data: &mut [u8]) -> Result<usize, VideoVBIError> {
187 if data.len() < self.line_buffer_len {
188 return Err(VideoVBIError::InsufficientLineBufLen {
189 found: data.len(),
190 expected: self.line_buffer_len,
191 });
192 }
193
194 unsafe {
195 let dest = data.as_mut_ptr();
196 ffi::gst_video_vbi_encoder_write_line(self.inner.to_glib_none_mut().0, dest);
197 }
198
199 let mut anc_len = std::mem::take(&mut self.anc_len);
200 match self.format {
201 VideoFormat::V210 => {
202 let word_count = anc_len / 2;
204
205 if self.pixel_width < VBI_HD_MIN_PIXEL_WIDTH {
206 anc_len =
208 4 * 4 * ((word_count / 12) + if word_count % 12 == 0 { 0 } else { 1 });
209 } else {
210 let pair_count = usize::min(word_count, self.pixel_width as usize);
215 anc_len = 4 * 4 * ((pair_count / 6) + if pair_count % 6 == 0 { 0 } else { 1 });
216 }
217 }
218 VideoFormat::Uyvy => {
219 if self.pixel_width < VBI_HD_MIN_PIXEL_WIDTH {
222 anc_len = 4 * ((anc_len / 4) + if anc_len % 4 == 0 { 0 } else { 1 });
224 } else {
225 let pair_count = usize::min(anc_len, self.pixel_width as usize);
231 anc_len = 4 * ((pair_count / 2) + if pair_count % 2 == 0 { 0 } else { 1 });
232 }
233 }
234 _ => unreachable!(),
235 }
236
237 assert!(anc_len < self.line_buffer_len);
238
239 Ok(anc_len)
240 }
241}
242
243impl<'a> TryFrom<&'a crate::VideoInfo> for VideoVBIEncoder {
244 type Error = VideoVBIError;
245
246 fn try_from(info: &'a crate::VideoInfo) -> Result<VideoVBIEncoder, VideoVBIError> {
247 skip_assert_initialized!();
248 VideoVBIEncoder::try_new(info.format(), info.width())
249 }
250}
251
252#[cfg(test)]
253mod tests {
254 use super::*;
255
256 #[test]
257 fn cea608_component() {
258 let mut encoder =
259 VideoVBIEncoder::try_new(VideoFormat::V210, VBI_HD_MIN_PIXEL_WIDTH).unwrap();
260 encoder
261 .add_did16_ancillary(
262 VideoAFDDescriptionMode::Component,
263 VideoAncillaryDID16::S334Eia608,
264 &[0x80, 0x94, 0x2c],
265 )
266 .unwrap();
267
268 let mut buf = vec![0; encoder.line_buffer_len()];
269 let anc_len = encoder.write_line(buf.as_mut_slice()).unwrap();
270 assert_eq!(32, anc_len);
271 assert_eq!(
272 buf[0..anc_len],
273 [
274 0x00, 0x00, 0x00, 0x00, 0xff, 0x03, 0xf0, 0x3f, 0x00, 0x84, 0x05, 0x00, 0x02, 0x01,
275 0x30, 0x20, 0x00, 0x00, 0x06, 0x00, 0x94, 0x01, 0xc0, 0x12, 0x00, 0x98, 0x0a, 0x00,
276 0x00, 0x00, 0x00, 0x00
277 ]
278 );
279 }
280
281 #[test]
282 fn cea608_component_sd() {
283 let mut encoder = VideoVBIEncoder::try_new(VideoFormat::V210, 768).unwrap();
284 encoder
285 .add_did16_ancillary(
286 VideoAFDDescriptionMode::Component,
287 VideoAncillaryDID16::S334Eia608,
288 &[0x80, 0x94, 0x2c],
289 )
290 .unwrap();
291
292 let mut buf = vec![0; encoder.line_buffer_len()];
293 let anc_len = encoder.write_line(buf.as_mut_slice()).unwrap();
294 assert_eq!(16, anc_len);
295 assert_eq!(
296 buf[0..anc_len],
297 [
298 0x00, 0xfc, 0xff, 0x3f, 0x61, 0x09, 0x34, 0x20, 0x80, 0x51, 0xc6, 0x12, 0xa6, 0x02,
299 0x00, 0x00
300 ]
301 );
302 }
303
304 #[test]
305 fn cea608_composite() {
306 let mut encoder =
307 VideoVBIEncoder::try_new(VideoFormat::V210, VBI_HD_MIN_PIXEL_WIDTH).unwrap();
308 encoder
309 .add_did16_ancillary(
310 VideoAFDDescriptionMode::Composite,
311 VideoAncillaryDID16::S334Eia608,
312 &[0x15, 0x94, 0x2c],
313 )
314 .unwrap();
315
316 let mut buf = vec![0; encoder.line_buffer_len()];
317 let anc_len = encoder.write_line(buf.as_mut_slice()).unwrap();
318 assert_eq!(32, anc_len);
319 assert_eq!(
320 buf[0..anc_len],
321 [
322 0x00, 0xf0, 0x0f, 0x00, 0x61, 0x01, 0x20, 0x10, 0x00, 0x0c, 0x08, 0x00, 0x15, 0x01,
323 0x40, 0x19, 0x00, 0xb0, 0x04, 0x00, 0x3b, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
324 0x00, 0x00, 0x00, 0x00
325 ]
326 );
327 }
328
329 #[test]
330 fn cea608_composite_sd() {
331 let mut encoder = VideoVBIEncoder::try_new(VideoFormat::V210, 768).unwrap();
332 encoder
333 .add_did16_ancillary(
334 VideoAFDDescriptionMode::Composite,
335 VideoAncillaryDID16::S334Eia608,
336 &[0x15, 0x94, 0x2c],
337 )
338 .unwrap();
339
340 let mut buf = vec![0; encoder.line_buffer_len()];
341 let anc_len = encoder.write_line(buf.as_mut_slice()).unwrap();
342 assert_eq!(16, anc_len);
343 assert_eq!(
344 buf[0..anc_len],
345 [
346 0xfc, 0x87, 0x25, 0x10, 0x03, 0x56, 0x44, 0x19, 0x2c, 0xed, 0x08, 0x00, 0x00, 0x00,
347 0x00, 0x00
348 ]
349 );
350 }
351
352 #[test]
353 fn cea608_component_uyvy() {
354 let mut encoder =
355 VideoVBIEncoder::try_new(VideoFormat::Uyvy, VBI_HD_MIN_PIXEL_WIDTH).unwrap();
356 encoder
357 .add_did16_ancillary(
358 VideoAFDDescriptionMode::Component,
359 VideoAncillaryDID16::S334Eia608,
360 &[0x80, 0x94, 0x2c],
361 )
362 .unwrap();
363
364 let mut buf = vec![0; encoder.line_buffer_len()];
365 let anc_len = encoder.write_line(buf.as_mut_slice()).unwrap();
366 assert_eq!(20, anc_len);
367 assert_eq!(
368 buf[0..anc_len],
369 [
370 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x61, 0x00, 0x02, 0x00, 0x03, 0x00, 0x80,
371 0x00, 0x94, 0x00, 0x2c, 0x00, 0xa6
372 ]
373 );
374 }
375
376 #[test]
377 fn cea608_component_sd_uyvy() {
378 let mut encoder = VideoVBIEncoder::try_new(VideoFormat::Uyvy, 768).unwrap();
379 encoder
380 .add_did16_ancillary(
381 VideoAFDDescriptionMode::Component,
382 VideoAncillaryDID16::S334Eia608,
383 &[0x80, 0x94, 0x2c],
384 )
385 .unwrap();
386
387 let mut buf = vec![0; encoder.line_buffer_len()];
388 let anc_len = encoder.write_line(buf.as_mut_slice()).unwrap();
389 assert_eq!(12, anc_len);
390 assert_eq!(
391 buf[0..anc_len],
392 [0x00, 0xff, 0xff, 0x61, 0x02, 0x03, 0x80, 0x94, 0x2c, 0xa6, 0x00, 0x00]
393 );
394 }
395
396 #[test]
397 fn cea608_composite_uyvy() {
398 let mut encoder =
399 VideoVBIEncoder::try_new(VideoFormat::Uyvy, VBI_HD_MIN_PIXEL_WIDTH).unwrap();
400 encoder
401 .add_did16_ancillary(
402 VideoAFDDescriptionMode::Composite,
403 VideoAncillaryDID16::S334Eia608,
404 &[0x15, 0x94, 0x2c],
405 )
406 .unwrap();
407
408 let mut buf = vec![0; encoder.line_buffer_len()];
409 let anc_len = encoder.write_line(buf.as_mut_slice()).unwrap();
410 assert_eq!(16, anc_len);
411 assert_eq!(
412 buf[0..anc_len],
413 [
414 0x00, 0xfc, 0x00, 0x61, 0x00, 0x02, 0x00, 0x03, 0x00, 0x15, 0x00, 0x94, 0x00, 0x2c,
415 0x00, 0x3b
416 ]
417 );
418 }
419
420 #[test]
421 fn cea608_composite_sd_uyvy() {
422 let mut encoder = VideoVBIEncoder::try_new(VideoFormat::Uyvy, 768).unwrap();
423 encoder
424 .add_did16_ancillary(
425 VideoAFDDescriptionMode::Composite,
426 VideoAncillaryDID16::S334Eia608,
427 &[0x15, 0x94, 0x2c],
428 )
429 .unwrap();
430
431 let mut buf = vec![0; encoder.line_buffer_len()];
432 let anc_len = encoder.write_line(buf.as_mut_slice()).unwrap();
433 assert_eq!(8, anc_len);
434 assert_eq!(
435 buf[0..anc_len],
436 [0xfc, 0x61, 0x02, 0x03, 0x15, 0x94, 0x2c, 0x3b]
437 );
438 }
439
440 #[test]
441 fn insufficient_line_buf_len() {
442 let mut encoder =
443 VideoVBIEncoder::try_new(VideoFormat::V210, VBI_HD_MIN_PIXEL_WIDTH).unwrap();
444 encoder
445 .add_did16_ancillary(
446 VideoAFDDescriptionMode::Component,
447 VideoAncillaryDID16::S334Eia608,
448 &[0x80, 0x94, 0x2c],
449 )
450 .unwrap();
451 let mut buf = vec![0; 10];
452 assert_eq!(
453 encoder.write_line(buf.as_mut_slice()).unwrap_err(),
454 VideoVBIError::InsufficientLineBufLen {
455 found: 10,
456 expected: encoder.line_buffer_len()
457 },
458 );
459 }
460
461 #[test]
462 fn cea708_component() {
463 let mut encoder =
464 VideoVBIEncoder::try_new(VideoFormat::V210, VBI_HD_MIN_PIXEL_WIDTH).unwrap();
465 encoder
466 .add_did16_ancillary(
467 VideoAFDDescriptionMode::Component,
468 VideoAncillaryDID16::S334Eia708,
469 &[
470 0x96, 0x69, 0x55, 0x3f, 0x43, 0x00, 0x00, 0x72, 0xf8, 0xfc, 0x94, 0x2c, 0xf9,
471 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00,
472 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00,
473 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa,
474 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00,
475 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00,
476 0xfa, 0x00, 0x00, 0x74, 0x00, 0x00, 0x1b,
477 ],
478 )
479 .unwrap();
480
481 let mut buf = vec![0; encoder.line_buffer_len()];
482 let anc_len = encoder.write_line(buf.as_mut_slice()).unwrap();
483 assert_eq!(256, anc_len);
484 assert_eq!(
485 buf[0..anc_len],
486 [
487 0x00, 0x00, 0x00, 0x00, 0xff, 0x03, 0xf0, 0x3f, 0x00, 0x84, 0x05, 0x00, 0x01, 0x01,
488 0x50, 0x25, 0x00, 0x58, 0x0a, 0x00, 0x69, 0x02, 0x50, 0x25, 0x00, 0xfc, 0x08, 0x00,
489 0x43, 0x01, 0x00, 0x20, 0x00, 0x00, 0x08, 0x00, 0x72, 0x02, 0x80, 0x1f, 0x00, 0xf0,
490 0x0b, 0x00, 0x94, 0x01, 0xc0, 0x12, 0x00, 0xe4, 0x0b, 0x00, 0x00, 0x02, 0x00, 0x20,
491 0x00, 0xe8, 0x0b, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, 0xe8, 0x0b, 0x00, 0x00, 0x02,
492 0x00, 0x20, 0x00, 0xe8, 0x0b, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, 0xe8, 0x0b, 0x00,
493 0x00, 0x02, 0x00, 0x20, 0x00, 0xe8, 0x0b, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, 0xe8,
494 0x0b, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, 0xe8, 0x0b, 0x00, 0x00, 0x02, 0x00, 0x20,
495 0x00, 0xe8, 0x0b, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, 0xe8, 0x0b, 0x00, 0x00, 0x02,
496 0x00, 0x20, 0x00, 0xe8, 0x0b, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, 0xe8, 0x0b, 0x00,
497 0x00, 0x02, 0x00, 0x20, 0x00, 0xe8, 0x0b, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, 0xe8,
498 0x0b, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, 0xe8, 0x0b, 0x00, 0x00, 0x02, 0x00, 0x20,
499 0x00, 0xe8, 0x0b, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, 0xe8, 0x0b, 0x00, 0x00, 0x02,
500 0x00, 0x20, 0x00, 0xe8, 0x0b, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, 0xe8, 0x0b, 0x00,
501 0x00, 0x02, 0x00, 0x20, 0x00, 0xe8, 0x0b, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, 0xe8,
502 0x0b, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, 0xe8, 0x0b, 0x00, 0x00, 0x02, 0x00, 0x20,
503 0x00, 0xe8, 0x0b, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, 0xd0, 0x09, 0x00, 0x00, 0x02,
504 0x00, 0x20, 0x00, 0x6c, 0x08, 0x00, 0xb7, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
505 0x00, 0x00, 0x00, 0x00
506 ]
507 );
508 }
509
510 #[test]
511 fn cea608_and_cea708_component() {
512 let mut encoder =
513 VideoVBIEncoder::try_new(VideoFormat::V210, VBI_HD_MIN_PIXEL_WIDTH).unwrap();
514 encoder
515 .add_did16_ancillary(
516 VideoAFDDescriptionMode::Component,
517 VideoAncillaryDID16::S334Eia608,
518 &[0x80, 0x94, 0x2c],
519 )
520 .unwrap();
521
522 encoder
523 .add_did16_ancillary(
524 VideoAFDDescriptionMode::Component,
525 VideoAncillaryDID16::S334Eia708,
526 &[
527 0x96, 0x69, 0x55, 0x3f, 0x43, 0x00, 0x00, 0x72, 0xf8, 0xfc, 0x94, 0x2c, 0xf9,
528 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00,
529 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00,
530 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa,
531 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00,
532 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00,
533 0xfa, 0x00, 0x00, 0x74, 0x00, 0x00, 0x1b,
534 ],
535 )
536 .unwrap();
537
538 let mut buf = vec![0; encoder.line_buffer_len()];
539 let anc_len = encoder.write_line(buf.as_mut_slice()).unwrap();
540 assert_eq!(272, anc_len);
541 assert_eq!(
542 buf[0..anc_len],
543 [
544 0x00, 0x00, 0x00, 0x00, 0xff, 0x03, 0xf0, 0x3f, 0x00, 0x84, 0x05, 0x00, 0x02, 0x01,
545 0x30, 0x20, 0x00, 0x00, 0x06, 0x00, 0x94, 0x01, 0xc0, 0x12, 0x00, 0x98, 0x0a, 0x00,
546 0x00, 0x00, 0xf0, 0x3f, 0x00, 0xfc, 0x0f, 0x00, 0x61, 0x01, 0x10, 0x10, 0x00, 0x54,
547 0x09, 0x00, 0x96, 0x02, 0x90, 0x26, 0x00, 0x54, 0x09, 0x00, 0x3f, 0x02, 0x30, 0x14,
548 0x00, 0x00, 0x08, 0x00, 0x00, 0x02, 0x20, 0x27, 0x00, 0xe0, 0x07, 0x00, 0xfc, 0x02,
549 0x40, 0x19, 0x00, 0xb0, 0x04, 0x00, 0xf9, 0x02, 0x00, 0x20, 0x00, 0x00, 0x08, 0x00,
550 0xfa, 0x02, 0x00, 0x20, 0x00, 0x00, 0x08, 0x00, 0xfa, 0x02, 0x00, 0x20, 0x00, 0x00,
551 0x08, 0x00, 0xfa, 0x02, 0x00, 0x20, 0x00, 0x00, 0x08, 0x00, 0xfa, 0x02, 0x00, 0x20,
552 0x00, 0x00, 0x08, 0x00, 0xfa, 0x02, 0x00, 0x20, 0x00, 0x00, 0x08, 0x00, 0xfa, 0x02,
553 0x00, 0x20, 0x00, 0x00, 0x08, 0x00, 0xfa, 0x02, 0x00, 0x20, 0x00, 0x00, 0x08, 0x00,
554 0xfa, 0x02, 0x00, 0x20, 0x00, 0x00, 0x08, 0x00, 0xfa, 0x02, 0x00, 0x20, 0x00, 0x00,
555 0x08, 0x00, 0xfa, 0x02, 0x00, 0x20, 0x00, 0x00, 0x08, 0x00, 0xfa, 0x02, 0x00, 0x20,
556 0x00, 0x00, 0x08, 0x00, 0xfa, 0x02, 0x00, 0x20, 0x00, 0x00, 0x08, 0x00, 0xfa, 0x02,
557 0x00, 0x20, 0x00, 0x00, 0x08, 0x00, 0xfa, 0x02, 0x00, 0x20, 0x00, 0x00, 0x08, 0x00,
558 0xfa, 0x02, 0x00, 0x20, 0x00, 0x00, 0x08, 0x00, 0xfa, 0x02, 0x00, 0x20, 0x00, 0x00,
559 0x08, 0x00, 0xfa, 0x02, 0x00, 0x20, 0x00, 0x00, 0x08, 0x00, 0xfa, 0x02, 0x00, 0x20,
560 0x00, 0x00, 0x08, 0x00, 0xfa, 0x02, 0x00, 0x20, 0x00, 0x00, 0x08, 0x00, 0xfa, 0x02,
561 0x00, 0x20, 0x00, 0x00, 0x08, 0x00, 0xfa, 0x02, 0x00, 0x20, 0x00, 0x00, 0x08, 0x00,
562 0xfa, 0x02, 0x00, 0x20, 0x00, 0x00, 0x08, 0x00, 0x74, 0x02, 0x00, 0x20, 0x00, 0x00,
563 0x08, 0x00, 0x1b, 0x02, 0x70, 0x2b
564 ]
565 );
566 }
567}