contrib: soxr: enable by default
[vlc.git] / modules / access / sdi.c
blobcd6a97a1904aff3bddec3c943a4f14bebdcb25bc
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>
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.
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.
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 *****************************************************************************/
23 #include "sdi.h"
25 static inline uint32_t av_le2ne32(uint32_t val)
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);
35 void v210_convert(uint16_t *dst, const uint32_t *bytes, const int width, const int height)
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];
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)
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);
60 if (w < width - 1) {
61 READ_PIXELS(u, y, v);
63 val = av_le2ne32(*src++);
64 *y++ = val & 0x3FF;
66 if (w < width - 3) {
67 *u++ = (val >> 10) & 0x3FF;
68 *y++ = (val >> 20) & 0x3FF;
70 val = av_le2ne32(*src++);
71 *v++ = val & 0x3FF;
72 *y++ = (val >> 10) & 0x3FF;
75 bytes += stride;
79 #undef vanc_to_cc
80 block_t *vanc_to_cc(vlc_object_t *obj, uint16_t *buf, size_t words)
82 if (words < 3) {
83 msg_Err(obj, "VANC line too small (%zu words)", words);
84 return NULL;
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;
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;
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;
108 vanc_sum += v;
109 vanc_sum &= 0x1ff;
110 buf[i] &= 0xff;
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;
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;
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;
132 len -= 7; // remove VANC header and checksum
134 if (cdp[2] != len) {
135 msg_Err(obj, "CDP len %d != %zu", cdp[2], len);
136 return NULL;
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;
148 uint8_t rate = cdp[3];
149 if (!(rate & 0x0f)) {
150 msg_Err(obj, "CDP frame rate invalid (0x%.2x)", rate);
151 return NULL;
153 rate >>= 4;
154 if (rate > 8) {
155 msg_Err(obj, "CDP frame rate invalid (0x%.2x)", rate);
156 return NULL;
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;
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;
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;
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;
182 if (cdp[len - 4] != 0x74) /* footer id */ {
183 msg_Err(obj, "Invalid footer id 0x%.2x", cdp[len-4]);
184 return NULL;
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;
193 block_t *cc = block_Alloc(cc_count * 3);
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];
201 return cc;