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)]
21pub struct VideoVBIEncoder {
22 inner: VideoVBIEncoderInner,
23 format: VideoFormat,
24 pixel_width: u32,
25 line_buffer_len: usize,
26 anc_len: usize,
27}
28
29unsafe impl Send for VideoVBIEncoder {}
30unsafe impl Sync for VideoVBIEncoder {}
31
32#[derive(Clone, Copy, Debug, Eq, PartialEq)]
33pub enum VideoAFDDescriptionMode {
34 Composite,
35 Component,
36}
37
38impl VideoAFDDescriptionMode {
39 pub fn is_composite(&self) -> bool {
40 matches!(self, VideoAFDDescriptionMode::Composite)
41 }
42
43 pub fn is_component(&self) -> bool {
44 matches!(self, VideoAFDDescriptionMode::Component)
45 }
46}
47
48impl VideoVBIEncoder {
49 #[doc(alias = "gst_video_vbi_encoder_new")]
50 pub fn try_new(
51 format: VideoFormat,
52 pixel_width: u32,
53 ) -> Result<VideoVBIEncoder, VideoVBIError> {
54 skip_assert_initialized!();
55 let res: Option<VideoVBIEncoderInner> = unsafe {
56 from_glib_full(ffi::gst_video_vbi_encoder_new(
57 format.into_glib(),
58 pixel_width,
59 ))
60 };
61
62 Ok(VideoVBIEncoder {
63 inner: res.ok_or(VideoVBIError::Unsupported)?,
64 format,
65 pixel_width,
66 line_buffer_len: line_buffer_len(format, pixel_width),
67 anc_len: 0,
68 })
69 }
70
71 pub fn add_did_ancillary(
74 &mut self,
75 adf_mode: VideoAFDDescriptionMode,
76 did: VideoAncillaryDID,
77 block_number: u8,
78 data: &[u8],
79 ) -> Result<(), VideoVBIError> {
80 self.add_ancillary(adf_mode, did.into_glib() as u8, block_number, data)
81 }
82
83 pub fn add_did16_ancillary(
86 &mut self,
87 adf_mode: VideoAFDDescriptionMode,
88 did16: VideoAncillaryDID16,
89 data: &[u8],
90 ) -> Result<(), VideoVBIError> {
91 let did16 = did16.into_glib();
92
93 self.add_ancillary(
94 adf_mode,
95 ((did16 & 0xff00) >> 8) as u8,
96 (did16 & 0xff) as u8,
97 data,
98 )
99 }
100
101 #[doc(alias = "gst_video_vbi_encoder_add_ancillary")]
102 pub fn add_ancillary(
103 &mut self,
104 adf_mode: VideoAFDDescriptionMode,
105 did: u8,
106 sdid_block_number: u8,
107 data: &[u8],
108 ) -> Result<(), VideoVBIError> {
109 let data_count = data.len() as _;
110 let res: bool = unsafe {
111 from_glib(ffi::gst_video_vbi_encoder_add_ancillary(
112 self.inner.to_glib_none_mut().0,
113 adf_mode.is_composite().into_glib(),
114 did,
115 sdid_block_number,
116 data.to_glib_none().0,
117 data_count,
118 ))
119 };
120
121 if !res {
122 return Err(VideoVBIError::NotEnoughSpace);
123 }
124
125 let mut len = 1 + 3 + (data_count as usize) + 1;
130 if adf_mode.is_component() {
131 len += 2;
132 }
133
134 if matches!(self.format, VideoFormat::V210) {
135 len *= 2;
137 }
138
139 self.anc_len += len;
140
141 Ok(())
142 }
143
144 pub fn line_buffer_len(&self) -> usize {
147 self.line_buffer_len
148 }
149
150 #[doc(alias = "gst_video_vbi_encoder_write_line")]
165 pub fn write_line(&mut self, data: &mut [u8]) -> Result<usize, VideoVBIError> {
166 if data.len() < self.line_buffer_len {
167 return Err(VideoVBIError::InsufficientLineBufLen {
168 found: data.len(),
169 expected: self.line_buffer_len,
170 });
171 }
172
173 unsafe {
174 let dest = data.as_mut_ptr();
175 ffi::gst_video_vbi_encoder_write_line(self.inner.to_glib_none_mut().0, dest);
176 }
177
178 let mut anc_len = std::mem::take(&mut self.anc_len);
179 match self.format {
180 VideoFormat::V210 => {
181 let word_count = anc_len / 2;
183
184 if self.pixel_width < VBI_HD_MIN_PIXEL_WIDTH {
185 anc_len = 4 * 4 * word_count.div_ceil(12);
187 } else {
188 let pair_count = usize::min(word_count, self.pixel_width as usize);
192 anc_len = 4 * 4 * pair_count.div_ceil(6);
193 }
194 }
195 VideoFormat::Uyvy => {
196 if self.pixel_width < VBI_HD_MIN_PIXEL_WIDTH {
199 anc_len = 4 * anc_len.div_ceil(4);
201 } else {
202 let pair_count = usize::min(anc_len, self.pixel_width as usize);
207 anc_len = 4 * pair_count.div_ceil(2);
208 }
209 }
210 _ => unreachable!(),
211 }
212
213 assert!(anc_len < self.line_buffer_len);
214
215 Ok(anc_len)
216 }
217}
218
219impl<'a> TryFrom<&'a crate::VideoInfo> for VideoVBIEncoder {
220 type Error = VideoVBIError;
221
222 fn try_from(info: &'a crate::VideoInfo) -> Result<VideoVBIEncoder, VideoVBIError> {
223 skip_assert_initialized!();
224 VideoVBIEncoder::try_new(info.format(), info.width())
225 }
226}
227
228#[cfg(test)]
229mod tests {
230 use super::*;
231
232 #[test]
233 fn cea608_component() {
234 let mut encoder =
235 VideoVBIEncoder::try_new(VideoFormat::V210, VBI_HD_MIN_PIXEL_WIDTH).unwrap();
236 encoder
237 .add_did16_ancillary(
238 VideoAFDDescriptionMode::Component,
239 VideoAncillaryDID16::S334Eia608,
240 &[0x80, 0x94, 0x2c],
241 )
242 .unwrap();
243
244 let mut buf = vec![0; encoder.line_buffer_len()];
245 let anc_len = encoder.write_line(buf.as_mut_slice()).unwrap();
246 assert_eq!(32, anc_len);
247 assert_eq!(
248 buf[0..anc_len],
249 [
250 0x00, 0x00, 0x00, 0x00, 0xff, 0x03, 0xf0, 0x3f, 0x00, 0x84, 0x05, 0x00, 0x02, 0x01,
251 0x30, 0x20, 0x00, 0x00, 0x06, 0x00, 0x94, 0x01, 0xc0, 0x12, 0x00, 0x98, 0x0a, 0x00,
252 0x00, 0x00, 0x00, 0x00
253 ]
254 );
255 }
256
257 #[test]
258 fn cea608_component_sd() {
259 let mut encoder = VideoVBIEncoder::try_new(VideoFormat::V210, 768).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!(16, anc_len);
271 assert_eq!(
272 buf[0..anc_len],
273 [
274 0x00, 0xfc, 0xff, 0x3f, 0x61, 0x09, 0x34, 0x20, 0x80, 0x51, 0xc6, 0x12, 0xa6, 0x02,
275 0x00, 0x00
276 ]
277 );
278 }
279
280 #[test]
281 fn cea608_composite() {
282 let mut encoder =
283 VideoVBIEncoder::try_new(VideoFormat::V210, VBI_HD_MIN_PIXEL_WIDTH).unwrap();
284 encoder
285 .add_did16_ancillary(
286 VideoAFDDescriptionMode::Composite,
287 VideoAncillaryDID16::S334Eia608,
288 &[0x15, 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!(32, anc_len);
295 assert_eq!(
296 buf[0..anc_len],
297 [
298 0x00, 0xf0, 0x0f, 0x00, 0x61, 0x01, 0x20, 0x10, 0x00, 0x0c, 0x08, 0x00, 0x15, 0x01,
299 0x40, 0x19, 0x00, 0xb0, 0x04, 0x00, 0x3b, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
300 0x00, 0x00, 0x00, 0x00
301 ]
302 );
303 }
304
305 #[test]
306 fn cea608_composite_sd() {
307 let mut encoder = VideoVBIEncoder::try_new(VideoFormat::V210, 768).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!(16, anc_len);
319 assert_eq!(
320 buf[0..anc_len],
321 [
322 0xfc, 0x87, 0x25, 0x10, 0x03, 0x56, 0x44, 0x19, 0x2c, 0xed, 0x08, 0x00, 0x00, 0x00,
323 0x00, 0x00
324 ]
325 );
326 }
327
328 #[test]
329 fn cea608_component_uyvy() {
330 let mut encoder =
331 VideoVBIEncoder::try_new(VideoFormat::Uyvy, VBI_HD_MIN_PIXEL_WIDTH).unwrap();
332 encoder
333 .add_did16_ancillary(
334 VideoAFDDescriptionMode::Component,
335 VideoAncillaryDID16::S334Eia608,
336 &[0x80, 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!(20, anc_len);
343 assert_eq!(
344 buf[0..anc_len],
345 [
346 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x61, 0x00, 0x02, 0x00, 0x03, 0x00, 0x80,
347 0x00, 0x94, 0x00, 0x2c, 0x00, 0xa6
348 ]
349 );
350 }
351
352 #[test]
353 fn cea608_component_sd_uyvy() {
354 let mut encoder = VideoVBIEncoder::try_new(VideoFormat::Uyvy, 768).unwrap();
355 encoder
356 .add_did16_ancillary(
357 VideoAFDDescriptionMode::Component,
358 VideoAncillaryDID16::S334Eia608,
359 &[0x80, 0x94, 0x2c],
360 )
361 .unwrap();
362
363 let mut buf = vec![0; encoder.line_buffer_len()];
364 let anc_len = encoder.write_line(buf.as_mut_slice()).unwrap();
365 assert_eq!(12, anc_len);
366 assert_eq!(
367 buf[0..anc_len],
368 [
369 0x00, 0xff, 0xff, 0x61, 0x02, 0x03, 0x80, 0x94, 0x2c, 0xa6, 0x00, 0x00
370 ]
371 );
372 }
373
374 #[test]
375 fn cea608_composite_uyvy() {
376 let mut encoder =
377 VideoVBIEncoder::try_new(VideoFormat::Uyvy, VBI_HD_MIN_PIXEL_WIDTH).unwrap();
378 encoder
379 .add_did16_ancillary(
380 VideoAFDDescriptionMode::Composite,
381 VideoAncillaryDID16::S334Eia608,
382 &[0x15, 0x94, 0x2c],
383 )
384 .unwrap();
385
386 let mut buf = vec![0; encoder.line_buffer_len()];
387 let anc_len = encoder.write_line(buf.as_mut_slice()).unwrap();
388 assert_eq!(16, anc_len);
389 assert_eq!(
390 buf[0..anc_len],
391 [
392 0x00, 0xfc, 0x00, 0x61, 0x00, 0x02, 0x00, 0x03, 0x00, 0x15, 0x00, 0x94, 0x00, 0x2c,
393 0x00, 0x3b
394 ]
395 );
396 }
397
398 #[test]
399 fn cea608_composite_sd_uyvy() {
400 let mut encoder = VideoVBIEncoder::try_new(VideoFormat::Uyvy, 768).unwrap();
401 encoder
402 .add_did16_ancillary(
403 VideoAFDDescriptionMode::Composite,
404 VideoAncillaryDID16::S334Eia608,
405 &[0x15, 0x94, 0x2c],
406 )
407 .unwrap();
408
409 let mut buf = vec![0; encoder.line_buffer_len()];
410 let anc_len = encoder.write_line(buf.as_mut_slice()).unwrap();
411 assert_eq!(8, anc_len);
412 assert_eq!(
413 buf[0..anc_len],
414 [0xfc, 0x61, 0x02, 0x03, 0x15, 0x94, 0x2c, 0x3b]
415 );
416 }
417
418 #[test]
419 fn insufficient_line_buf_len() {
420 let mut encoder =
421 VideoVBIEncoder::try_new(VideoFormat::V210, VBI_HD_MIN_PIXEL_WIDTH).unwrap();
422 encoder
423 .add_did16_ancillary(
424 VideoAFDDescriptionMode::Component,
425 VideoAncillaryDID16::S334Eia608,
426 &[0x80, 0x94, 0x2c],
427 )
428 .unwrap();
429 let mut buf = vec![0; 10];
430 assert_eq!(
431 encoder.write_line(buf.as_mut_slice()).unwrap_err(),
432 VideoVBIError::InsufficientLineBufLen {
433 found: 10,
434 expected: encoder.line_buffer_len()
435 },
436 );
437 }
438
439 #[test]
440 fn cea708_component() {
441 let mut encoder =
442 VideoVBIEncoder::try_new(VideoFormat::V210, VBI_HD_MIN_PIXEL_WIDTH).unwrap();
443 encoder
444 .add_did16_ancillary(
445 VideoAFDDescriptionMode::Component,
446 VideoAncillaryDID16::S334Eia708,
447 &[
448 0x96, 0x69, 0x55, 0x3f, 0x43, 0x00, 0x00, 0x72, 0xf8, 0xfc, 0x94, 0x2c, 0xf9,
449 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00,
450 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00,
451 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa,
452 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00,
453 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00,
454 0xfa, 0x00, 0x00, 0x74, 0x00, 0x00, 0x1b,
455 ],
456 )
457 .unwrap();
458
459 let mut buf = vec![0; encoder.line_buffer_len()];
460 let anc_len = encoder.write_line(buf.as_mut_slice()).unwrap();
461 assert_eq!(256, anc_len);
462 assert_eq!(
463 buf[0..anc_len],
464 [
465 0x00, 0x00, 0x00, 0x00, 0xff, 0x03, 0xf0, 0x3f, 0x00, 0x84, 0x05, 0x00, 0x01, 0x01,
466 0x50, 0x25, 0x00, 0x58, 0x0a, 0x00, 0x69, 0x02, 0x50, 0x25, 0x00, 0xfc, 0x08, 0x00,
467 0x43, 0x01, 0x00, 0x20, 0x00, 0x00, 0x08, 0x00, 0x72, 0x02, 0x80, 0x1f, 0x00, 0xf0,
468 0x0b, 0x00, 0x94, 0x01, 0xc0, 0x12, 0x00, 0xe4, 0x0b, 0x00, 0x00, 0x02, 0x00, 0x20,
469 0x00, 0xe8, 0x0b, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, 0xe8, 0x0b, 0x00, 0x00, 0x02,
470 0x00, 0x20, 0x00, 0xe8, 0x0b, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, 0xe8, 0x0b, 0x00,
471 0x00, 0x02, 0x00, 0x20, 0x00, 0xe8, 0x0b, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, 0xe8,
472 0x0b, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, 0xe8, 0x0b, 0x00, 0x00, 0x02, 0x00, 0x20,
473 0x00, 0xe8, 0x0b, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, 0xe8, 0x0b, 0x00, 0x00, 0x02,
474 0x00, 0x20, 0x00, 0xe8, 0x0b, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, 0xe8, 0x0b, 0x00,
475 0x00, 0x02, 0x00, 0x20, 0x00, 0xe8, 0x0b, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, 0xe8,
476 0x0b, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, 0xe8, 0x0b, 0x00, 0x00, 0x02, 0x00, 0x20,
477 0x00, 0xe8, 0x0b, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, 0xe8, 0x0b, 0x00, 0x00, 0x02,
478 0x00, 0x20, 0x00, 0xe8, 0x0b, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, 0xe8, 0x0b, 0x00,
479 0x00, 0x02, 0x00, 0x20, 0x00, 0xe8, 0x0b, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, 0xe8,
480 0x0b, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, 0xe8, 0x0b, 0x00, 0x00, 0x02, 0x00, 0x20,
481 0x00, 0xe8, 0x0b, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, 0xd0, 0x09, 0x00, 0x00, 0x02,
482 0x00, 0x20, 0x00, 0x6c, 0x08, 0x00, 0xb7, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
483 0x00, 0x00, 0x00, 0x00
484 ]
485 );
486 }
487
488 #[test]
489 fn cea608_and_cea708_component() {
490 let mut encoder =
491 VideoVBIEncoder::try_new(VideoFormat::V210, VBI_HD_MIN_PIXEL_WIDTH).unwrap();
492 encoder
493 .add_did16_ancillary(
494 VideoAFDDescriptionMode::Component,
495 VideoAncillaryDID16::S334Eia608,
496 &[0x80, 0x94, 0x2c],
497 )
498 .unwrap();
499
500 encoder
501 .add_did16_ancillary(
502 VideoAFDDescriptionMode::Component,
503 VideoAncillaryDID16::S334Eia708,
504 &[
505 0x96, 0x69, 0x55, 0x3f, 0x43, 0x00, 0x00, 0x72, 0xf8, 0xfc, 0x94, 0x2c, 0xf9,
506 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00,
507 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00,
508 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa,
509 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00,
510 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00,
511 0xfa, 0x00, 0x00, 0x74, 0x00, 0x00, 0x1b,
512 ],
513 )
514 .unwrap();
515
516 let mut buf = vec![0; encoder.line_buffer_len()];
517 let anc_len = encoder.write_line(buf.as_mut_slice()).unwrap();
518 assert_eq!(272, anc_len);
519 assert_eq!(
520 buf[0..anc_len],
521 [
522 0x00, 0x00, 0x00, 0x00, 0xff, 0x03, 0xf0, 0x3f, 0x00, 0x84, 0x05, 0x00, 0x02, 0x01,
523 0x30, 0x20, 0x00, 0x00, 0x06, 0x00, 0x94, 0x01, 0xc0, 0x12, 0x00, 0x98, 0x0a, 0x00,
524 0x00, 0x00, 0xf0, 0x3f, 0x00, 0xfc, 0x0f, 0x00, 0x61, 0x01, 0x10, 0x10, 0x00, 0x54,
525 0x09, 0x00, 0x96, 0x02, 0x90, 0x26, 0x00, 0x54, 0x09, 0x00, 0x3f, 0x02, 0x30, 0x14,
526 0x00, 0x00, 0x08, 0x00, 0x00, 0x02, 0x20, 0x27, 0x00, 0xe0, 0x07, 0x00, 0xfc, 0x02,
527 0x40, 0x19, 0x00, 0xb0, 0x04, 0x00, 0xf9, 0x02, 0x00, 0x20, 0x00, 0x00, 0x08, 0x00,
528 0xfa, 0x02, 0x00, 0x20, 0x00, 0x00, 0x08, 0x00, 0xfa, 0x02, 0x00, 0x20, 0x00, 0x00,
529 0x08, 0x00, 0xfa, 0x02, 0x00, 0x20, 0x00, 0x00, 0x08, 0x00, 0xfa, 0x02, 0x00, 0x20,
530 0x00, 0x00, 0x08, 0x00, 0xfa, 0x02, 0x00, 0x20, 0x00, 0x00, 0x08, 0x00, 0xfa, 0x02,
531 0x00, 0x20, 0x00, 0x00, 0x08, 0x00, 0xfa, 0x02, 0x00, 0x20, 0x00, 0x00, 0x08, 0x00,
532 0xfa, 0x02, 0x00, 0x20, 0x00, 0x00, 0x08, 0x00, 0xfa, 0x02, 0x00, 0x20, 0x00, 0x00,
533 0x08, 0x00, 0xfa, 0x02, 0x00, 0x20, 0x00, 0x00, 0x08, 0x00, 0xfa, 0x02, 0x00, 0x20,
534 0x00, 0x00, 0x08, 0x00, 0xfa, 0x02, 0x00, 0x20, 0x00, 0x00, 0x08, 0x00, 0xfa, 0x02,
535 0x00, 0x20, 0x00, 0x00, 0x08, 0x00, 0xfa, 0x02, 0x00, 0x20, 0x00, 0x00, 0x08, 0x00,
536 0xfa, 0x02, 0x00, 0x20, 0x00, 0x00, 0x08, 0x00, 0xfa, 0x02, 0x00, 0x20, 0x00, 0x00,
537 0x08, 0x00, 0xfa, 0x02, 0x00, 0x20, 0x00, 0x00, 0x08, 0x00, 0xfa, 0x02, 0x00, 0x20,
538 0x00, 0x00, 0x08, 0x00, 0xfa, 0x02, 0x00, 0x20, 0x00, 0x00, 0x08, 0x00, 0xfa, 0x02,
539 0x00, 0x20, 0x00, 0x00, 0x08, 0x00, 0xfa, 0x02, 0x00, 0x20, 0x00, 0x00, 0x08, 0x00,
540 0xfa, 0x02, 0x00, 0x20, 0x00, 0x00, 0x08, 0x00, 0x74, 0x02, 0x00, 0x20, 0x00, 0x00,
541 0x08, 0x00, 0x1b, 0x02, 0x70, 0x2b
542 ]
543 );
544 }
545}