]> git.sesse.net Git - vlc/blob - modules/access/sdi.c
visual: don't crash on empty buffers
[vlc] / modules / access / sdi.c
1 /*****************************************************************************
2  * sdi.c: SDI helpers
3  *****************************************************************************
4  * Copyright (C) 2014 Rafaël Carré
5  * Copyright (C) 2009 Michael Niedermayer <michaelni@gmx.at>
6  * Copyright (c) 2009 Baptiste Coudurier <baptiste dot coudurier at gmail dot com>
7  *
8  * This program is free software; you can redistribute it and/or modify it
9  * under the terms of the GNU Lesser General Public License as published by
10  * the Free Software Foundation; either version 2.1 of the License, or
11  * (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this program; if not, write to the Free Software Foundation,
20  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21  *****************************************************************************/
22
23 #include "sdi.h"
24
25 static inline uint32_t av_le2ne32(uint32_t val)
26 {
27     union {
28         uint32_t v;
29         uint8_t b[4];
30     } u;
31     u.v = val;
32     return (u.b[0] << 0) | (u.b[1] << 8) | (u.b[2] << 16) | (u.b[3] << 24);
33 }
34
35 void v210_convert(uint16_t *dst, const uint32_t *bytes, const int width, const int height)
36 {
37     const int stride = ((width + 47) / 48) * 48 * 8 / 3 / 4;
38     uint16_t *y = &dst[0];
39     uint16_t *u = &dst[width * height * 2 / 2];
40     uint16_t *v = &dst[width * height * 3 / 2];
41
42 #define READ_PIXELS(a, b, c)         \
43     do {                             \
44         val  = av_le2ne32(*src++);   \
45         *a++ =  val & 0x3FF;         \
46         *b++ = (val >> 10) & 0x3FF;  \
47         *c++ = (val >> 20) & 0x3FF;  \
48     } while (0)
49
50     for (int h = 0; h < height; h++) {
51         const uint32_t *src = bytes;
52         uint32_t val = 0;
53         int w;
54         for (w = 0; w < width - 5; w += 6) {
55             READ_PIXELS(u, y, v);
56             READ_PIXELS(y, u, y);
57             READ_PIXELS(v, y, u);
58             READ_PIXELS(y, v, y);
59         }
60         if (w < width - 1) {
61             READ_PIXELS(u, y, v);
62
63             val  = av_le2ne32(*src++);
64             *y++ =  val & 0x3FF;
65         }
66         if (w < width - 3) {
67             *u++ = (val >> 10) & 0x3FF;
68             *y++ = (val >> 20) & 0x3FF;
69
70             val  = av_le2ne32(*src++);
71             *v++ =  val & 0x3FF;
72             *y++ = (val >> 10) & 0x3FF;
73         }
74
75         bytes += stride;
76     }
77 }
78
79 #undef vanc_to_cc
80 block_t *vanc_to_cc(vlc_object_t *obj, uint16_t *buf, size_t words)
81 {
82     if (words < 3) {
83         msg_Err(obj, "VANC line too small (%zu words)", words);
84         return NULL;
85     }
86
87     static const uint8_t vanc_header[6] = { 0x00, 0x00, 0xff, 0x03, 0xff, 0x03 };
88     if (memcmp(vanc_header, buf, 3*2)) {
89         /* Does not start with the VANC header */
90         return NULL;
91     }
92
93     size_t len = (buf[5] & 0xff) + 6 + 1;
94     if (len > words) {
95         msg_Err(obj, "Data Count (%zu) > line length (%zu)", len, words);
96         return NULL;
97     }
98
99     uint16_t vanc_sum = 0;
100     for (size_t i = 3; i < len - 1; i++) {
101         uint16_t v = buf[i];
102         int np = v >> 8;
103         int p = parity(v & 0xff);
104         if ((!!p ^ !!(v & 0x100)) || (np != 1 && np != 2)) {
105             msg_Err(obj, "Parity incorrect for word %zu", i);
106             return NULL;
107         }
108         vanc_sum += v;
109         vanc_sum &= 0x1ff;
110         buf[i] &= 0xff;
111     }
112
113     vanc_sum |= ((~vanc_sum & 0x100) << 1);
114     if (buf[len - 1] != vanc_sum) {
115         msg_Err(obj, "VANC checksum incorrect: 0x%.4x != 0x%.4x", vanc_sum, buf[len-1]);
116         return NULL;
117     }
118
119     if (buf[3] != 0x61 /* DID */ || buf[4] != 0x01 /* SDID = CEA-708 */) {
120         //msg_Err(obj, "Not a CEA-708 packet: DID = 0x%.2x SDID = 0x%.2x", buf[3], buf[4]);
121         // XXX : what is Not a CEA-708 packet: DID = 0x61 SDID = 0x02 ?
122         return NULL;
123     }
124
125     /* CDP follows */
126     uint16_t *cdp = &buf[6];
127     if (cdp[0] != 0x96 || cdp[1] != 0x69) {
128         msg_Err(obj, "Invalid CDP header 0x%.2x 0x%.2x", cdp[0], cdp[1]);
129         return NULL;
130     }
131
132     len -= 7; // remove VANC header and checksum
133
134     if (cdp[2] != len) {
135         msg_Err(obj, "CDP len %d != %zu", cdp[2], len);
136         return NULL;
137     }
138
139     uint8_t cdp_sum = 0;
140     for (size_t i = 0; i < len - 1; i++)
141         cdp_sum += cdp[i];
142     cdp_sum = cdp_sum ? 256 - cdp_sum : 0;
143     if (cdp[len - 1] != cdp_sum) {
144         msg_Err(obj, "CDP checksum invalid 0x%.4x != 0x%.4x", cdp_sum, cdp[len-1]);
145         return NULL;
146     }
147
148     uint8_t rate = cdp[3];
149     if (!(rate & 0x0f)) {
150         msg_Err(obj, "CDP frame rate invalid (0x%.2x)", rate);
151         return NULL;
152     }
153     rate >>= 4;
154     if (rate > 8) {
155         msg_Err(obj, "CDP frame rate invalid (0x%.2x)", rate);
156         return NULL;
157     }
158
159     if (!(cdp[4] & 0x43)) /* ccdata_present | caption_service_active | reserved */ {
160         msg_Err(obj, "CDP flags invalid (0x%.2x)", cdp[4]);
161         return NULL;
162     }
163
164     uint16_t hdr = (cdp[5] << 8) | cdp[6];
165     if (cdp[7] != 0x72) /* ccdata_id */ {
166         msg_Err(obj, "Invalid ccdata_id 0x%.2x", cdp[7]);
167         return NULL;
168     }
169
170     unsigned cc_count = cdp[8];
171     if (!(cc_count & 0xe0)) {
172         msg_Err(obj, "Invalid cc_count 0x%.2x", cc_count);
173         return NULL;
174     }
175
176     cc_count &= 0x1f;
177     if ((len - 13) < cc_count * 3) {
178         msg_Err(obj, "Invalid cc_count %d (> %zu)", cc_count * 3, len - 13);
179         return NULL;
180     }
181
182     if (cdp[len - 4] != 0x74) /* footer id */ {
183         msg_Err(obj, "Invalid footer id 0x%.2x", cdp[len-4]);
184         return NULL;
185     }
186
187     uint16_t ftr = (cdp[len - 3] << 8) | cdp[len - 2];
188     if (ftr != hdr) {
189         msg_Err(obj, "Header 0x%.4x != Footer 0x%.4x", hdr, ftr);
190         return NULL;
191     }
192
193     block_t *cc = block_Alloc(cc_count * 3);
194
195     for (size_t i = 0; i < cc_count; i++) {
196         cc->p_buffer[3*i+0] = cdp[9 + 3*i+0] /* & 3 */;
197         cc->p_buffer[3*i+1] = cdp[9 + 3*i+1];
198         cc->p_buffer[3*i+2] = cdp[9 + 3*i+2];
199     }
200
201     return cc;
202 }