1use crate::{VideoFormat, ffi};
4use glib::translate::*;
5
6use crate::video_vbi::line_buffer_len;
7use crate::{VBI_HD_MIN_PIXEL_WIDTH, VideoAncillaryDID, VideoAncillaryDID16, VideoVBIError};
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")]
191 pub fn write_line(&mut self, data: &mut [u8]) -> Result<usize, VideoVBIError> {
192 if data.len() < self.line_buffer_len {
193 return Err(VideoVBIError::InsufficientLineBufLen {
194 found: data.len(),
195 expected: self.line_buffer_len,
196 });
197 }
198
199 unsafe {
200 let dest = data.as_mut_ptr();
201 ffi::gst_video_vbi_encoder_write_line(self.inner.to_glib_none_mut().0, dest);
202 }
203
204 let mut anc_len = std::mem::take(&mut self.anc_len);
205 match self.format {
206 VideoFormat::V210 => {
207 let word_count = anc_len / 2;
209
210 if self.pixel_width < VBI_HD_MIN_PIXEL_WIDTH {
211 anc_len = 4 * 4 * word_count.div_ceil(12);
213 } else {
214 let pair_count = usize::min(word_count, self.pixel_width as usize);
218 anc_len = 4 * 4 * pair_count.div_ceil(6);
219 }
220 }
221 VideoFormat::Uyvy => {
222 if self.pixel_width < VBI_HD_MIN_PIXEL_WIDTH {
225 anc_len = 4 * anc_len.div_ceil(4);
227 } else {
228 let pair_count = usize::min(anc_len, self.pixel_width as usize);
233 anc_len = 4 * pair_count.div_ceil(2);
234 }
235 }
236 _ => unreachable!(),
237 }
238
239 assert!(anc_len < self.line_buffer_len);
240
241 Ok(anc_len)
242 }
243}
244
245impl<'a> TryFrom<&'a crate::VideoInfo> for VideoVBIEncoder {
246 type Error = VideoVBIError;
247
248 fn try_from(info: &'a crate::VideoInfo) -> Result<VideoVBIEncoder, VideoVBIError> {
249 skip_assert_initialized!();
250 VideoVBIEncoder::try_new(info.format(), info.width())
251 }
252}
253
254#[cfg(test)]
255mod tests {
256 use super::*;
257
258 #[test]
259 fn cea608_component() {
260 let mut encoder =
261 VideoVBIEncoder::try_new(VideoFormat::V210, VBI_HD_MIN_PIXEL_WIDTH).unwrap();
262 encoder
263 .add_did16_ancillary(
264 VideoAFDDescriptionMode::Component,
265 VideoAncillaryDID16::S334Eia608,
266 &[0x80, 0x94, 0x2c],
267 )
268 .unwrap();
269
270 let mut buf = vec![0; encoder.line_buffer_len()];
271 let anc_len = encoder.write_line(buf.as_mut_slice()).unwrap();
272 assert_eq!(32, anc_len);
273 assert_eq!(
274 buf[0..anc_len],
275 [
276 0x00, 0x00, 0x00, 0x00, 0xff, 0x03, 0xf0, 0x3f, 0x00, 0x84, 0x05, 0x00, 0x02, 0x01,
277 0x30, 0x20, 0x00, 0x00, 0x06, 0x00, 0x94, 0x01, 0xc0, 0x12, 0x00, 0x98, 0x0a, 0x00,
278 0x00, 0x00, 0x00, 0x00
279 ]
280 );
281 }
282
283 #[test]
284 fn cea608_component_sd() {
285 let mut encoder = VideoVBIEncoder::try_new(VideoFormat::V210, 768).unwrap();
286 encoder
287 .add_did16_ancillary(
288 VideoAFDDescriptionMode::Component,
289 VideoAncillaryDID16::S334Eia608,
290 &[0x80, 0x94, 0x2c],
291 )
292 .unwrap();
293
294 let mut buf = vec![0; encoder.line_buffer_len()];
295 let anc_len = encoder.write_line(buf.as_mut_slice()).unwrap();
296 assert_eq!(16, anc_len);
297 assert_eq!(
298 buf[0..anc_len],
299 [
300 0x00, 0xfc, 0xff, 0x3f, 0x61, 0x09, 0x34, 0x20, 0x80, 0x51, 0xc6, 0x12, 0xa6, 0x02,
301 0x00, 0x00
302 ]
303 );
304 }
305
306 #[test]
307 fn cea608_composite() {
308 let mut encoder =
309 VideoVBIEncoder::try_new(VideoFormat::V210, VBI_HD_MIN_PIXEL_WIDTH).unwrap();
310 encoder
311 .add_did16_ancillary(
312 VideoAFDDescriptionMode::Composite,
313 VideoAncillaryDID16::S334Eia608,
314 &[0x15, 0x94, 0x2c],
315 )
316 .unwrap();
317
318 let mut buf = vec![0; encoder.line_buffer_len()];
319 let anc_len = encoder.write_line(buf.as_mut_slice()).unwrap();
320 assert_eq!(32, anc_len);
321 assert_eq!(
322 buf[0..anc_len],
323 [
324 0x00, 0xf0, 0x0f, 0x00, 0x61, 0x01, 0x20, 0x10, 0x00, 0x0c, 0x08, 0x00, 0x15, 0x01,
325 0x40, 0x19, 0x00, 0xb0, 0x04, 0x00, 0x3b, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
326 0x00, 0x00, 0x00, 0x00
327 ]
328 );
329 }
330
331 #[test]
332 fn cea608_composite_sd() {
333 let mut encoder = VideoVBIEncoder::try_new(VideoFormat::V210, 768).unwrap();
334 encoder
335 .add_did16_ancillary(
336 VideoAFDDescriptionMode::Composite,
337 VideoAncillaryDID16::S334Eia608,
338 &[0x15, 0x94, 0x2c],
339 )
340 .unwrap();
341
342 let mut buf = vec![0; encoder.line_buffer_len()];
343 let anc_len = encoder.write_line(buf.as_mut_slice()).unwrap();
344 assert_eq!(16, anc_len);
345 assert_eq!(
346 buf[0..anc_len],
347 [
348 0xfc, 0x87, 0x25, 0x10, 0x03, 0x56, 0x44, 0x19, 0x2c, 0xed, 0x08, 0x00, 0x00, 0x00,
349 0x00, 0x00
350 ]
351 );
352 }
353
354 #[test]
355 fn cea608_component_uyvy() {
356 let mut encoder =
357 VideoVBIEncoder::try_new(VideoFormat::Uyvy, VBI_HD_MIN_PIXEL_WIDTH).unwrap();
358 encoder
359 .add_did16_ancillary(
360 VideoAFDDescriptionMode::Component,
361 VideoAncillaryDID16::S334Eia608,
362 &[0x80, 0x94, 0x2c],
363 )
364 .unwrap();
365
366 let mut buf = vec![0; encoder.line_buffer_len()];
367 let anc_len = encoder.write_line(buf.as_mut_slice()).unwrap();
368 assert_eq!(20, anc_len);
369 assert_eq!(
370 buf[0..anc_len],
371 [
372 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x61, 0x00, 0x02, 0x00, 0x03, 0x00, 0x80,
373 0x00, 0x94, 0x00, 0x2c, 0x00, 0xa6
374 ]
375 );
376 }
377
378 #[test]
379 fn cea608_component_sd_uyvy() {
380 let mut encoder = VideoVBIEncoder::try_new(VideoFormat::Uyvy, 768).unwrap();
381 encoder
382 .add_did16_ancillary(
383 VideoAFDDescriptionMode::Component,
384 VideoAncillaryDID16::S334Eia608,
385 &[0x80, 0x94, 0x2c],
386 )
387 .unwrap();
388
389 let mut buf = vec![0; encoder.line_buffer_len()];
390 let anc_len = encoder.write_line(buf.as_mut_slice()).unwrap();
391 assert_eq!(12, anc_len);
392 assert_eq!(
393 buf[0..anc_len],
394 [
395 0x00, 0xff, 0xff, 0x61, 0x02, 0x03, 0x80, 0x94, 0x2c, 0xa6, 0x00, 0x00
396 ]
397 );
398 }
399
400 #[test]
401 fn cea608_composite_uyvy() {
402 let mut encoder =
403 VideoVBIEncoder::try_new(VideoFormat::Uyvy, VBI_HD_MIN_PIXEL_WIDTH).unwrap();
404 encoder
405 .add_did16_ancillary(
406 VideoAFDDescriptionMode::Composite,
407 VideoAncillaryDID16::S334Eia608,
408 &[0x15, 0x94, 0x2c],
409 )
410 .unwrap();
411
412 let mut buf = vec![0; encoder.line_buffer_len()];
413 let anc_len = encoder.write_line(buf.as_mut_slice()).unwrap();
414 assert_eq!(16, anc_len);
415 assert_eq!(
416 buf[0..anc_len],
417 [
418 0x00, 0xfc, 0x00, 0x61, 0x00, 0x02, 0x00, 0x03, 0x00, 0x15, 0x00, 0x94, 0x00, 0x2c,
419 0x00, 0x3b
420 ]
421 );
422 }
423
424 #[test]
425 fn cea608_composite_sd_uyvy() {
426 let mut encoder = VideoVBIEncoder::try_new(VideoFormat::Uyvy, 768).unwrap();
427 encoder
428 .add_did16_ancillary(
429 VideoAFDDescriptionMode::Composite,
430 VideoAncillaryDID16::S334Eia608,
431 &[0x15, 0x94, 0x2c],
432 )
433 .unwrap();
434
435 let mut buf = vec![0; encoder.line_buffer_len()];
436 let anc_len = encoder.write_line(buf.as_mut_slice()).unwrap();
437 assert_eq!(8, anc_len);
438 assert_eq!(
439 buf[0..anc_len],
440 [0xfc, 0x61, 0x02, 0x03, 0x15, 0x94, 0x2c, 0x3b]
441 );
442 }
443
444 #[test]
445 fn insufficient_line_buf_len() {
446 let mut encoder =
447 VideoVBIEncoder::try_new(VideoFormat::V210, VBI_HD_MIN_PIXEL_WIDTH).unwrap();
448 encoder
449 .add_did16_ancillary(
450 VideoAFDDescriptionMode::Component,
451 VideoAncillaryDID16::S334Eia608,
452 &[0x80, 0x94, 0x2c],
453 )
454 .unwrap();
455 let mut buf = vec![0; 10];
456 assert_eq!(
457 encoder.write_line(buf.as_mut_slice()).unwrap_err(),
458 VideoVBIError::InsufficientLineBufLen {
459 found: 10,
460 expected: encoder.line_buffer_len()
461 },
462 );
463 }
464
465 #[test]
466 fn cea708_component() {
467 let mut encoder =
468 VideoVBIEncoder::try_new(VideoFormat::V210, VBI_HD_MIN_PIXEL_WIDTH).unwrap();
469 encoder
470 .add_did16_ancillary(
471 VideoAFDDescriptionMode::Component,
472 VideoAncillaryDID16::S334Eia708,
473 &[
474 0x96, 0x69, 0x55, 0x3f, 0x43, 0x00, 0x00, 0x72, 0xf8, 0xfc, 0x94, 0x2c, 0xf9,
475 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00,
476 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00,
477 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa,
478 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00,
479 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00,
480 0xfa, 0x00, 0x00, 0x74, 0x00, 0x00, 0x1b,
481 ],
482 )
483 .unwrap();
484
485 let mut buf = vec![0; encoder.line_buffer_len()];
486 let anc_len = encoder.write_line(buf.as_mut_slice()).unwrap();
487 assert_eq!(256, anc_len);
488 assert_eq!(
489 buf[0..anc_len],
490 [
491 0x00, 0x00, 0x00, 0x00, 0xff, 0x03, 0xf0, 0x3f, 0x00, 0x84, 0x05, 0x00, 0x01, 0x01,
492 0x50, 0x25, 0x00, 0x58, 0x0a, 0x00, 0x69, 0x02, 0x50, 0x25, 0x00, 0xfc, 0x08, 0x00,
493 0x43, 0x01, 0x00, 0x20, 0x00, 0x00, 0x08, 0x00, 0x72, 0x02, 0x80, 0x1f, 0x00, 0xf0,
494 0x0b, 0x00, 0x94, 0x01, 0xc0, 0x12, 0x00, 0xe4, 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, 0xe8, 0x0b, 0x00, 0x00, 0x02,
504 0x00, 0x20, 0x00, 0xe8, 0x0b, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, 0xe8, 0x0b, 0x00,
505 0x00, 0x02, 0x00, 0x20, 0x00, 0xe8, 0x0b, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, 0xe8,
506 0x0b, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, 0xe8, 0x0b, 0x00, 0x00, 0x02, 0x00, 0x20,
507 0x00, 0xe8, 0x0b, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, 0xd0, 0x09, 0x00, 0x00, 0x02,
508 0x00, 0x20, 0x00, 0x6c, 0x08, 0x00, 0xb7, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
509 0x00, 0x00, 0x00, 0x00
510 ]
511 );
512 }
513
514 #[test]
515 fn cea608_and_cea708_component() {
516 let mut encoder =
517 VideoVBIEncoder::try_new(VideoFormat::V210, VBI_HD_MIN_PIXEL_WIDTH).unwrap();
518 encoder
519 .add_did16_ancillary(
520 VideoAFDDescriptionMode::Component,
521 VideoAncillaryDID16::S334Eia608,
522 &[0x80, 0x94, 0x2c],
523 )
524 .unwrap();
525
526 encoder
527 .add_did16_ancillary(
528 VideoAFDDescriptionMode::Component,
529 VideoAncillaryDID16::S334Eia708,
530 &[
531 0x96, 0x69, 0x55, 0x3f, 0x43, 0x00, 0x00, 0x72, 0xf8, 0xfc, 0x94, 0x2c, 0xf9,
532 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00,
533 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00,
534 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa,
535 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00,
536 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00,
537 0xfa, 0x00, 0x00, 0x74, 0x00, 0x00, 0x1b,
538 ],
539 )
540 .unwrap();
541
542 let mut buf = vec![0; encoder.line_buffer_len()];
543 let anc_len = encoder.write_line(buf.as_mut_slice()).unwrap();
544 assert_eq!(272, anc_len);
545 assert_eq!(
546 buf[0..anc_len],
547 [
548 0x00, 0x00, 0x00, 0x00, 0xff, 0x03, 0xf0, 0x3f, 0x00, 0x84, 0x05, 0x00, 0x02, 0x01,
549 0x30, 0x20, 0x00, 0x00, 0x06, 0x00, 0x94, 0x01, 0xc0, 0x12, 0x00, 0x98, 0x0a, 0x00,
550 0x00, 0x00, 0xf0, 0x3f, 0x00, 0xfc, 0x0f, 0x00, 0x61, 0x01, 0x10, 0x10, 0x00, 0x54,
551 0x09, 0x00, 0x96, 0x02, 0x90, 0x26, 0x00, 0x54, 0x09, 0x00, 0x3f, 0x02, 0x30, 0x14,
552 0x00, 0x00, 0x08, 0x00, 0x00, 0x02, 0x20, 0x27, 0x00, 0xe0, 0x07, 0x00, 0xfc, 0x02,
553 0x40, 0x19, 0x00, 0xb0, 0x04, 0x00, 0xf9, 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, 0xfa, 0x02, 0x00, 0x20, 0x00, 0x00,
563 0x08, 0x00, 0xfa, 0x02, 0x00, 0x20, 0x00, 0x00, 0x08, 0x00, 0xfa, 0x02, 0x00, 0x20,
564 0x00, 0x00, 0x08, 0x00, 0xfa, 0x02, 0x00, 0x20, 0x00, 0x00, 0x08, 0x00, 0xfa, 0x02,
565 0x00, 0x20, 0x00, 0x00, 0x08, 0x00, 0xfa, 0x02, 0x00, 0x20, 0x00, 0x00, 0x08, 0x00,
566 0xfa, 0x02, 0x00, 0x20, 0x00, 0x00, 0x08, 0x00, 0x74, 0x02, 0x00, 0x20, 0x00, 0x00,
567 0x08, 0x00, 0x1b, 0x02, 0x70, 0x2b
568 ]
569 );
570 }
571}