gstreamer_video/
video_vbi_encoder.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use 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)]
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    // rustdoc-stripper-ignore-next
72    /// Adds the provided ancillary data as a DID and block number AFD.
73    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    // rustdoc-stripper-ignore-next
84    /// Adds the provided ancillary data as a DID16 (DID & SDID) AFD.
85    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        // AFD: 1 byte (+2 if component)
126        // DID + SDID_block_number + Data Count: 3 bytes
127        // DATA: data_count bytes
128        // Checksum: 1 byte
129        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            // 10bits payload on 16bits for now: will be packed when writing the line
136            len *= 2;
137        }
138
139        self.anc_len += len;
140
141        Ok(())
142    }
143
144    // rustdoc-stripper-ignore-next
145    /// Returns the buffer length needed to store the line.
146    pub fn line_buffer_len(&self) -> usize {
147        self.line_buffer_len
148    }
149
150    // rustdoc-stripper-ignore-next
151    /// Writes the ancillaries encoded for VBI to the provided buffer.
152    ///
153    /// Use [`Self::line_buffer_len`] to get the expected buffer length.
154    ///
155    /// Resets the internal state, so this [`VideoVBIEncoder`] can be reused for
156    /// subsequent VBI encodings.
157    ///
158    /// # Returns
159    ///
160    /// - `Ok` with the written length in bytes in the line buffer containing the encoded
161    ///   ancilliaries previously added using [`VideoVBIEncoder::add_ancillary`],
162    ///   [`VideoVBIEncoder::add_did_ancillary`] or [`VideoVBIEncoder::add_did16_ancillary`].
163    /// - `Err` if the ancillary could not be added.
164    #[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                // Anc data consists in 10bits stored in 16bits word
182                let word_count = anc_len / 2;
183
184                if self.pixel_width < VBI_HD_MIN_PIXEL_WIDTH {
185                    // SD: Packs 12x 10bits data in 4x 32bits word
186                    anc_len =
187                        4 * 4 * ((word_count / 12) + if word_count % 12 == 0 { 0 } else { 1 });
188                } else {
189                    // HD: Packs 3x 10bits data in 1x 32bits word interleaving UV and Y components
190                    //     (where Y starts at buffer offset 0 and UV starts at buffer offset pixel_width)
191                    //     so we get 6 (uv,y) pairs every 4x 32bits word in the resulting line
192                    // FIXME: {integer}::div_ceil was stabilised in rustc 1.73.0
193                    let pair_count = usize::min(word_count, self.pixel_width as usize);
194                    anc_len = 4 * 4 * ((pair_count / 6) + if pair_count % 6 == 0 { 0 } else { 1 });
195                }
196            }
197            VideoFormat::Uyvy => {
198                // Anc data stored as bytes
199
200                if self.pixel_width < VBI_HD_MIN_PIXEL_WIDTH {
201                    // SD: Stores 4x bytes in 4x bytes let's keep 32 bits alignment
202                    anc_len = 4 * ((anc_len / 4) + if anc_len % 4 == 0 { 0 } else { 1 });
203                } else {
204                    // HD: Stores 4x bytes in 4x bytes interleaving UV and Y components
205                    //     (where Y starts at buffer offset 0 and UV starts at buffer offset pixel_width)
206                    //     so we get 2 (uv,y) pairs every 4x bytes in the resulting line
207                    // let's keep 32 bits alignment
208                    // FIXME: {integer}::div_ceil was stabilised in rustc 1.73.0
209                    let pair_count = usize::min(anc_len, self.pixel_width as usize);
210                    anc_len = 4 * ((pair_count / 2) + if pair_count % 2 == 0 { 0 } else { 1 });
211                }
212            }
213            _ => unreachable!(),
214        }
215
216        assert!(anc_len < self.line_buffer_len);
217
218        Ok(anc_len)
219    }
220}
221
222impl<'a> TryFrom<&'a crate::VideoInfo> for VideoVBIEncoder {
223    type Error = VideoVBIError;
224
225    fn try_from(info: &'a crate::VideoInfo) -> Result<VideoVBIEncoder, VideoVBIError> {
226        skip_assert_initialized!();
227        VideoVBIEncoder::try_new(info.format(), info.width())
228    }
229}
230
231#[cfg(test)]
232mod tests {
233    use super::*;
234
235    #[test]
236    fn cea608_component() {
237        let mut encoder =
238            VideoVBIEncoder::try_new(VideoFormat::V210, VBI_HD_MIN_PIXEL_WIDTH).unwrap();
239        encoder
240            .add_did16_ancillary(
241                VideoAFDDescriptionMode::Component,
242                VideoAncillaryDID16::S334Eia608,
243                &[0x80, 0x94, 0x2c],
244            )
245            .unwrap();
246
247        let mut buf = vec![0; encoder.line_buffer_len()];
248        let anc_len = encoder.write_line(buf.as_mut_slice()).unwrap();
249        assert_eq!(32, anc_len);
250        assert_eq!(
251            buf[0..anc_len],
252            [
253                0x00, 0x00, 0x00, 0x00, 0xff, 0x03, 0xf0, 0x3f, 0x00, 0x84, 0x05, 0x00, 0x02, 0x01,
254                0x30, 0x20, 0x00, 0x00, 0x06, 0x00, 0x94, 0x01, 0xc0, 0x12, 0x00, 0x98, 0x0a, 0x00,
255                0x00, 0x00, 0x00, 0x00
256            ]
257        );
258    }
259
260    #[test]
261    fn cea608_component_sd() {
262        let mut encoder = VideoVBIEncoder::try_new(VideoFormat::V210, 768).unwrap();
263        encoder
264            .add_did16_ancillary(
265                VideoAFDDescriptionMode::Component,
266                VideoAncillaryDID16::S334Eia608,
267                &[0x80, 0x94, 0x2c],
268            )
269            .unwrap();
270
271        let mut buf = vec![0; encoder.line_buffer_len()];
272        let anc_len = encoder.write_line(buf.as_mut_slice()).unwrap();
273        assert_eq!(16, anc_len);
274        assert_eq!(
275            buf[0..anc_len],
276            [
277                0x00, 0xfc, 0xff, 0x3f, 0x61, 0x09, 0x34, 0x20, 0x80, 0x51, 0xc6, 0x12, 0xa6, 0x02,
278                0x00, 0x00
279            ]
280        );
281    }
282
283    #[test]
284    fn cea608_composite() {
285        let mut encoder =
286            VideoVBIEncoder::try_new(VideoFormat::V210, VBI_HD_MIN_PIXEL_WIDTH).unwrap();
287        encoder
288            .add_did16_ancillary(
289                VideoAFDDescriptionMode::Composite,
290                VideoAncillaryDID16::S334Eia608,
291                &[0x15, 0x94, 0x2c],
292            )
293            .unwrap();
294
295        let mut buf = vec![0; encoder.line_buffer_len()];
296        let anc_len = encoder.write_line(buf.as_mut_slice()).unwrap();
297        assert_eq!(32, anc_len);
298        assert_eq!(
299            buf[0..anc_len],
300            [
301                0x00, 0xf0, 0x0f, 0x00, 0x61, 0x01, 0x20, 0x10, 0x00, 0x0c, 0x08, 0x00, 0x15, 0x01,
302                0x40, 0x19, 0x00, 0xb0, 0x04, 0x00, 0x3b, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
303                0x00, 0x00, 0x00, 0x00
304            ]
305        );
306    }
307
308    #[test]
309    fn cea608_composite_sd() {
310        let mut encoder = VideoVBIEncoder::try_new(VideoFormat::V210, 768).unwrap();
311        encoder
312            .add_did16_ancillary(
313                VideoAFDDescriptionMode::Composite,
314                VideoAncillaryDID16::S334Eia608,
315                &[0x15, 0x94, 0x2c],
316            )
317            .unwrap();
318
319        let mut buf = vec![0; encoder.line_buffer_len()];
320        let anc_len = encoder.write_line(buf.as_mut_slice()).unwrap();
321        assert_eq!(16, anc_len);
322        assert_eq!(
323            buf[0..anc_len],
324            [
325                0xfc, 0x87, 0x25, 0x10, 0x03, 0x56, 0x44, 0x19, 0x2c, 0xed, 0x08, 0x00, 0x00, 0x00,
326                0x00, 0x00
327            ]
328        );
329    }
330
331    #[test]
332    fn cea608_component_uyvy() {
333        let mut encoder =
334            VideoVBIEncoder::try_new(VideoFormat::Uyvy, VBI_HD_MIN_PIXEL_WIDTH).unwrap();
335        encoder
336            .add_did16_ancillary(
337                VideoAFDDescriptionMode::Component,
338                VideoAncillaryDID16::S334Eia608,
339                &[0x80, 0x94, 0x2c],
340            )
341            .unwrap();
342
343        let mut buf = vec![0; encoder.line_buffer_len()];
344        let anc_len = encoder.write_line(buf.as_mut_slice()).unwrap();
345        assert_eq!(20, anc_len);
346        assert_eq!(
347            buf[0..anc_len],
348            [
349                0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x61, 0x00, 0x02, 0x00, 0x03, 0x00, 0x80,
350                0x00, 0x94, 0x00, 0x2c, 0x00, 0xa6
351            ]
352        );
353    }
354
355    #[test]
356    fn cea608_component_sd_uyvy() {
357        let mut encoder = VideoVBIEncoder::try_new(VideoFormat::Uyvy, 768).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!(12, anc_len);
369        assert_eq!(
370            buf[0..anc_len],
371            [0x00, 0xff, 0xff, 0x61, 0x02, 0x03, 0x80, 0x94, 0x2c, 0xa6, 0x00, 0x00]
372        );
373    }
374
375    #[test]
376    fn cea608_composite_uyvy() {
377        let mut encoder =
378            VideoVBIEncoder::try_new(VideoFormat::Uyvy, VBI_HD_MIN_PIXEL_WIDTH).unwrap();
379        encoder
380            .add_did16_ancillary(
381                VideoAFDDescriptionMode::Composite,
382                VideoAncillaryDID16::S334Eia608,
383                &[0x15, 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!(16, anc_len);
390        assert_eq!(
391            buf[0..anc_len],
392            [
393                0x00, 0xfc, 0x00, 0x61, 0x00, 0x02, 0x00, 0x03, 0x00, 0x15, 0x00, 0x94, 0x00, 0x2c,
394                0x00, 0x3b
395            ]
396        );
397    }
398
399    #[test]
400    fn cea608_composite_sd_uyvy() {
401        let mut encoder = VideoVBIEncoder::try_new(VideoFormat::Uyvy, 768).unwrap();
402        encoder
403            .add_did16_ancillary(
404                VideoAFDDescriptionMode::Composite,
405                VideoAncillaryDID16::S334Eia608,
406                &[0x15, 0x94, 0x2c],
407            )
408            .unwrap();
409
410        let mut buf = vec![0; encoder.line_buffer_len()];
411        let anc_len = encoder.write_line(buf.as_mut_slice()).unwrap();
412        assert_eq!(8, anc_len);
413        assert_eq!(
414            buf[0..anc_len],
415            [0xfc, 0x61, 0x02, 0x03, 0x15, 0x94, 0x2c, 0x3b]
416        );
417    }
418
419    #[test]
420    fn insufficient_line_buf_len() {
421        let mut encoder =
422            VideoVBIEncoder::try_new(VideoFormat::V210, VBI_HD_MIN_PIXEL_WIDTH).unwrap();
423        encoder
424            .add_did16_ancillary(
425                VideoAFDDescriptionMode::Component,
426                VideoAncillaryDID16::S334Eia608,
427                &[0x80, 0x94, 0x2c],
428            )
429            .unwrap();
430        let mut buf = vec![0; 10];
431        assert_eq!(
432            encoder.write_line(buf.as_mut_slice()).unwrap_err(),
433            VideoVBIError::InsufficientLineBufLen {
434                found: 10,
435                expected: encoder.line_buffer_len()
436            },
437        );
438    }
439
440    #[test]
441    fn cea708_component() {
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::S334Eia708,
448                &[
449                    0x96, 0x69, 0x55, 0x3f, 0x43, 0x00, 0x00, 0x72, 0xf8, 0xfc, 0x94, 0x2c, 0xf9,
450                    0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00,
451                    0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00,
452                    0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa,
453                    0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00,
454                    0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00,
455                    0xfa, 0x00, 0x00, 0x74, 0x00, 0x00, 0x1b,
456                ],
457            )
458            .unwrap();
459
460        let mut buf = vec![0; encoder.line_buffer_len()];
461        let anc_len = encoder.write_line(buf.as_mut_slice()).unwrap();
462        assert_eq!(256, anc_len);
463        assert_eq!(
464            buf[0..anc_len],
465            [
466                0x00, 0x00, 0x00, 0x00, 0xff, 0x03, 0xf0, 0x3f, 0x00, 0x84, 0x05, 0x00, 0x01, 0x01,
467                0x50, 0x25, 0x00, 0x58, 0x0a, 0x00, 0x69, 0x02, 0x50, 0x25, 0x00, 0xfc, 0x08, 0x00,
468                0x43, 0x01, 0x00, 0x20, 0x00, 0x00, 0x08, 0x00, 0x72, 0x02, 0x80, 0x1f, 0x00, 0xf0,
469                0x0b, 0x00, 0x94, 0x01, 0xc0, 0x12, 0x00, 0xe4, 0x0b, 0x00, 0x00, 0x02, 0x00, 0x20,
470                0x00, 0xe8, 0x0b, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, 0xe8, 0x0b, 0x00, 0x00, 0x02,
471                0x00, 0x20, 0x00, 0xe8, 0x0b, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, 0xe8, 0x0b, 0x00,
472                0x00, 0x02, 0x00, 0x20, 0x00, 0xe8, 0x0b, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, 0xe8,
473                0x0b, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, 0xe8, 0x0b, 0x00, 0x00, 0x02, 0x00, 0x20,
474                0x00, 0xe8, 0x0b, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, 0xe8, 0x0b, 0x00, 0x00, 0x02,
475                0x00, 0x20, 0x00, 0xe8, 0x0b, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, 0xe8, 0x0b, 0x00,
476                0x00, 0x02, 0x00, 0x20, 0x00, 0xe8, 0x0b, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, 0xe8,
477                0x0b, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, 0xe8, 0x0b, 0x00, 0x00, 0x02, 0x00, 0x20,
478                0x00, 0xe8, 0x0b, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, 0xe8, 0x0b, 0x00, 0x00, 0x02,
479                0x00, 0x20, 0x00, 0xe8, 0x0b, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, 0xe8, 0x0b, 0x00,
480                0x00, 0x02, 0x00, 0x20, 0x00, 0xe8, 0x0b, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, 0xe8,
481                0x0b, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, 0xe8, 0x0b, 0x00, 0x00, 0x02, 0x00, 0x20,
482                0x00, 0xe8, 0x0b, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, 0xd0, 0x09, 0x00, 0x00, 0x02,
483                0x00, 0x20, 0x00, 0x6c, 0x08, 0x00, 0xb7, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
484                0x00, 0x00, 0x00, 0x00
485            ]
486        );
487    }
488
489    #[test]
490    fn cea608_and_cea708_component() {
491        let mut encoder =
492            VideoVBIEncoder::try_new(VideoFormat::V210, VBI_HD_MIN_PIXEL_WIDTH).unwrap();
493        encoder
494            .add_did16_ancillary(
495                VideoAFDDescriptionMode::Component,
496                VideoAncillaryDID16::S334Eia608,
497                &[0x80, 0x94, 0x2c],
498            )
499            .unwrap();
500
501        encoder
502            .add_did16_ancillary(
503                VideoAFDDescriptionMode::Component,
504                VideoAncillaryDID16::S334Eia708,
505                &[
506                    0x96, 0x69, 0x55, 0x3f, 0x43, 0x00, 0x00, 0x72, 0xf8, 0xfc, 0x94, 0x2c, 0xf9,
507                    0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00,
508                    0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00,
509                    0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa,
510                    0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00,
511                    0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00,
512                    0xfa, 0x00, 0x00, 0x74, 0x00, 0x00, 0x1b,
513                ],
514            )
515            .unwrap();
516
517        let mut buf = vec![0; encoder.line_buffer_len()];
518        let anc_len = encoder.write_line(buf.as_mut_slice()).unwrap();
519        assert_eq!(272, anc_len);
520        assert_eq!(
521            buf[0..anc_len],
522            [
523                0x00, 0x00, 0x00, 0x00, 0xff, 0x03, 0xf0, 0x3f, 0x00, 0x84, 0x05, 0x00, 0x02, 0x01,
524                0x30, 0x20, 0x00, 0x00, 0x06, 0x00, 0x94, 0x01, 0xc0, 0x12, 0x00, 0x98, 0x0a, 0x00,
525                0x00, 0x00, 0xf0, 0x3f, 0x00, 0xfc, 0x0f, 0x00, 0x61, 0x01, 0x10, 0x10, 0x00, 0x54,
526                0x09, 0x00, 0x96, 0x02, 0x90, 0x26, 0x00, 0x54, 0x09, 0x00, 0x3f, 0x02, 0x30, 0x14,
527                0x00, 0x00, 0x08, 0x00, 0x00, 0x02, 0x20, 0x27, 0x00, 0xe0, 0x07, 0x00, 0xfc, 0x02,
528                0x40, 0x19, 0x00, 0xb0, 0x04, 0x00, 0xf9, 0x02, 0x00, 0x20, 0x00, 0x00, 0x08, 0x00,
529                0xfa, 0x02, 0x00, 0x20, 0x00, 0x00, 0x08, 0x00, 0xfa, 0x02, 0x00, 0x20, 0x00, 0x00,
530                0x08, 0x00, 0xfa, 0x02, 0x00, 0x20, 0x00, 0x00, 0x08, 0x00, 0xfa, 0x02, 0x00, 0x20,
531                0x00, 0x00, 0x08, 0x00, 0xfa, 0x02, 0x00, 0x20, 0x00, 0x00, 0x08, 0x00, 0xfa, 0x02,
532                0x00, 0x20, 0x00, 0x00, 0x08, 0x00, 0xfa, 0x02, 0x00, 0x20, 0x00, 0x00, 0x08, 0x00,
533                0xfa, 0x02, 0x00, 0x20, 0x00, 0x00, 0x08, 0x00, 0xfa, 0x02, 0x00, 0x20, 0x00, 0x00,
534                0x08, 0x00, 0xfa, 0x02, 0x00, 0x20, 0x00, 0x00, 0x08, 0x00, 0xfa, 0x02, 0x00, 0x20,
535                0x00, 0x00, 0x08, 0x00, 0xfa, 0x02, 0x00, 0x20, 0x00, 0x00, 0x08, 0x00, 0xfa, 0x02,
536                0x00, 0x20, 0x00, 0x00, 0x08, 0x00, 0xfa, 0x02, 0x00, 0x20, 0x00, 0x00, 0x08, 0x00,
537                0xfa, 0x02, 0x00, 0x20, 0x00, 0x00, 0x08, 0x00, 0xfa, 0x02, 0x00, 0x20, 0x00, 0x00,
538                0x08, 0x00, 0xfa, 0x02, 0x00, 0x20, 0x00, 0x00, 0x08, 0x00, 0xfa, 0x02, 0x00, 0x20,
539                0x00, 0x00, 0x08, 0x00, 0xfa, 0x02, 0x00, 0x20, 0x00, 0x00, 0x08, 0x00, 0xfa, 0x02,
540                0x00, 0x20, 0x00, 0x00, 0x08, 0x00, 0xfa, 0x02, 0x00, 0x20, 0x00, 0x00, 0x08, 0x00,
541                0xfa, 0x02, 0x00, 0x20, 0x00, 0x00, 0x08, 0x00, 0x74, 0x02, 0x00, 0x20, 0x00, 0x00,
542                0x08, 0x00, 0x1b, 0x02, 0x70, 0x2b
543            ]
544        );
545    }
546}