Skip to main content

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::{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    // 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 = 4 * 4 * word_count.div_ceil(12);
187                } else {
188                    // HD: Packs 3x 10bits data in 1x 32bits word interleaving UV and Y components
189                    //     (where Y starts at buffer offset 0 and UV starts at buffer offset pixel_width)
190                    //     so we get 6 (uv,y) pairs every 4x 32bits word in the resulting line
191                    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                // Anc data stored as bytes
197
198                if self.pixel_width < VBI_HD_MIN_PIXEL_WIDTH {
199                    // SD: Stores 4x bytes in 4x bytes let's keep 32 bits alignment
200                    anc_len = 4 * anc_len.div_ceil(4);
201                } else {
202                    // HD: Stores 4x bytes in 4x bytes interleaving UV and Y components
203                    //     (where Y starts at buffer offset 0 and UV starts at buffer offset pixel_width)
204                    //     so we get 2 (uv,y) pairs every 4x bytes in the resulting line
205                    // let's keep 32 bits alignment
206                    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}