Welcome to mirror list, hosted at ThFree Co, Russian Federation.

ccutils.rs « src « closedcaption « video - gitlab.freedesktop.org/gstreamer/gst-plugins-rs.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 8d7fdadfdf7f5ab9ab603ac02c484c5a62dbd8a9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
// Copyright (C) 2020 Matthew Waters <matthew@centricular.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the
// Free Software Foundation, Inc., 51 Franklin Street, Suite 500,
// Boston, MA 02110-1335, USA.

use byteorder::{BigEndian, ByteOrder};
use std::fmt;

#[allow(clippy::enum_variant_names)]
#[derive(Debug, Clone, Copy)]
pub enum ParseErrorCode {
    WrongLength,
    WrongMagicSequence,
    WrongLayout,
}

#[derive(Debug, Clone)]
pub struct ParseError {
    pub code: ParseErrorCode,
    pub byte: usize,
    pub msg: String,
}

pub fn extract_cdp(mut data: &[u8]) -> Result<&[u8], ParseError> {
    /* logic from ccconverter */
    let data_len = data.len();

    if data.len() < 11 {
        return Err(ParseError {
            code: ParseErrorCode::WrongLength,
            byte: data_len - data.len(),
            msg: format!(
                "cdp packet too short {}. expected at least {}",
                data.len(),
                11
            ),
        });
    }

    if 0x9669 != BigEndian::read_u16(&data[..2]) {
        return Err(ParseError {
            code: ParseErrorCode::WrongMagicSequence,
            byte: data_len - data.len(),
            msg: String::from("cdp packet does not have initial magic bytes of 0x9669"),
        });
    }
    data = &data[2..];

    if (data[0] as usize) != data_len {
        return Err(ParseError {
            code: ParseErrorCode::WrongLength,
            byte: data_len - data.len(),
            msg: format!(
                "advertised cdp packet length {} does not match length of data {}",
                data[0], data_len
            ),
        });
    }
    data = &data[1..];

    /* skip framerate value */
    data = &data[1..];

    let flags = data[0];
    data = &data[1..];

    if flags & 0x40 == 0 {
        /* no cc_data */
        return Ok(&[]);
    }

    /* skip sequence counter */
    data = &data[2..];

    /* timecode present? */
    if flags & 0x80 == 0x80 {
        if data.len() < 5 {
            return Err(ParseError {
                code: ParseErrorCode::WrongLength,
                byte: data_len - data.len(),
                msg: String::from(
                    "cdp packet signals a timecode but is not large enough to contain a timecode",
                ),
            });
        }
        data = &data[5..];
    }

    /* cc_data */
    if data.len() < 2 {
        return Err(ParseError {
            code: ParseErrorCode::WrongLength,
            byte: data_len - data.len(),
            msg: String::from(
                "cdp packet signals cc_data but is not large enough to contain cc_data",
            ),
        });
    }

    if data[0] != 0x72 {
        return Err(ParseError {
            code: ParseErrorCode::WrongMagicSequence,
            byte: data_len - data.len(),
            msg: String::from("ccp is missing start code 0x72"),
        });
    }
    data = &data[1..];

    let cc_count = data[0];
    data = &data[1..];
    if cc_count & 0xe0 != 0xe0 {
        return Err(ParseError {
            code: ParseErrorCode::WrongMagicSequence,
            byte: data_len - data.len(),
            msg: format!("reserved bits are not 0xe0, found {:02x}", cc_count & 0xe0),
        });
    }
    let cc_count = cc_count & 0x1f;
    let len = 3 * cc_count as usize;

    if len > data.len() {
        return Err(ParseError {
            code: ParseErrorCode::WrongLength,
            byte: data_len - data.len(),
            msg: String::from("cc_data length extends past the end of the cdp packet"),
        });
    }

    /* TODO: validate checksum */

    Ok(&data[..len])
}

impl fmt::Display for ParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?} at byte {}: {}", self.code, self.byte, self.msg)
    }
}

impl std::error::Error for ParseError {}