/src/vlc/modules/codec/cc.h
Line | Count | Source (jump to first uncovered line) |
1 | | /***************************************************************************** |
2 | | * cc.h |
3 | | ***************************************************************************** |
4 | | * Copyright (C) 2007 Laurent Aimar |
5 | | * |
6 | | * Authors: Laurent Aimar <fenrir@via.ecp.fr> |
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 program 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 |
16 | | * GNU 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 | | #ifndef VLC_CC_H_ |
24 | | #define VLC_CC_H_ |
25 | | |
26 | | #include <vlc_bits.h> |
27 | | |
28 | 0 | #define CC_PKT_BYTE0(field) (0xFC | (0x03 & field)) |
29 | | |
30 | | /* CC have a maximum rate of 9600 bit/s (per field?) */ |
31 | | #define CC_MAX_DATA_SIZE (2 * 3*600) |
32 | | enum cc_payload_type_e |
33 | | { |
34 | | CC_PAYLOAD_NONE, |
35 | | CC_PAYLOAD_RAW, |
36 | | CC_PAYLOAD_GA94, |
37 | | CC_PAYLOAD_DVD, |
38 | | CC_PAYLOAD_REPLAYTV, |
39 | | CC_PAYLOAD_SCTE20, |
40 | | CC_PAYLOAD_CDP, |
41 | | }; |
42 | | typedef struct |
43 | | { |
44 | | /* Which channel are present */ |
45 | | uint64_t i_708channels; |
46 | | uint8_t i_608channels; |
47 | | |
48 | | /* */ |
49 | | bool b_reorder; |
50 | | struct |
51 | | { |
52 | | uint8_t pktsize; |
53 | | uint8_t seq; |
54 | | uint8_t sid_bs; |
55 | | enum |
56 | | { |
57 | | CEA708_PKT_END, |
58 | | CEA708_PKT_WAIT_BLOCK_HEADER, |
59 | | CEA708_PKT_WAIT_EXT_BLOCK_HEADER, |
60 | | CEA708_PKT_IN_BLOCK, |
61 | | } state; |
62 | | } cea708; |
63 | | |
64 | | /* */ |
65 | | enum cc_payload_type_e i_payload_type; |
66 | | int i_payload_other_count; |
67 | | |
68 | | /* CC data per field |
69 | | * byte[x+0]: field (0/1) |
70 | | * byte[x+1]: cc data 1 |
71 | | * byte[x+2]: cc data 2 |
72 | | */ |
73 | | size_t i_data; |
74 | | uint8_t p_data[CC_MAX_DATA_SIZE]; |
75 | | } cc_data_t; |
76 | | |
77 | | static inline void cc_Init( cc_data_t *c ) |
78 | 0 | { |
79 | 0 | c->i_608channels = 0; |
80 | 0 | c->i_708channels = 0; |
81 | 0 | c->i_data = 0; |
82 | 0 | c->b_reorder = false; |
83 | 0 | c->cea708.pktsize = 0; |
84 | 0 | c->cea708.seq = 0; |
85 | 0 | c->cea708.sid_bs = 0; |
86 | 0 | c->cea708.state = CEA708_PKT_END; |
87 | 0 | c->i_payload_type = CC_PAYLOAD_NONE; |
88 | 0 | c->i_payload_other_count = 0; |
89 | 0 | } Unexecuted instantiation: mp4.c:cc_Init Unexecuted instantiation: ty.c:cc_Init Unexecuted instantiation: hxxx_common.c:cc_Init Unexecuted instantiation: mpegvideo.c:cc_Init Unexecuted instantiation: vc1.c:cc_Init |
90 | | static inline void cc_Exit( cc_data_t *c ) |
91 | 0 | { |
92 | 0 | VLC_UNUSED(c); |
93 | 0 | return; |
94 | 0 | } Unexecuted instantiation: mp4.c:cc_Exit Unexecuted instantiation: ty.c:cc_Exit Unexecuted instantiation: hxxx_common.c:cc_Exit Unexecuted instantiation: mpegvideo.c:cc_Exit Unexecuted instantiation: vc1.c:cc_Exit |
95 | | static inline void cc_Flush( cc_data_t *c ) |
96 | 0 | { |
97 | 0 | c->i_data = 0; |
98 | 0 | c->cea708.state = CEA708_PKT_END; |
99 | 0 | } Unexecuted instantiation: mp4.c:cc_Flush Unexecuted instantiation: ty.c:cc_Flush Unexecuted instantiation: hxxx_common.c:cc_Flush Unexecuted instantiation: mpegvideo.c:cc_Flush Unexecuted instantiation: vc1.c:cc_Flush |
100 | | |
101 | | static inline void cc_ProbeCEA708OneByte( cc_data_t *c, bool b_start, const uint8_t cc ) |
102 | 0 | { |
103 | 0 | if( b_start ) |
104 | 0 | { |
105 | 0 | const uint8_t i_pkt_sequence = cc >> 6; |
106 | 0 | if( i_pkt_sequence > 0 && ((c->cea708.seq + 1) % 4) != i_pkt_sequence ) |
107 | 0 | { |
108 | 0 | c->cea708.pktsize = 0; |
109 | 0 | c->cea708.seq = i_pkt_sequence; |
110 | 0 | c->cea708.state = CEA708_PKT_END; |
111 | 0 | } |
112 | 0 | else |
113 | 0 | { |
114 | 0 | c->cea708.seq = i_pkt_sequence; |
115 | 0 | c->cea708.pktsize = cc & 63; |
116 | 0 | if( c->cea708.pktsize == 0 ) |
117 | 0 | c->cea708.pktsize = 127; |
118 | 0 | else |
119 | 0 | c->cea708.pktsize = c->cea708.pktsize * 2 - 1; |
120 | 0 | c->cea708.state = CEA708_PKT_WAIT_BLOCK_HEADER; |
121 | 0 | } |
122 | 0 | } |
123 | 0 | else if( c->cea708.pktsize == 0 ) /* empty pkt reading service blocks */ |
124 | 0 | { |
125 | 0 | c->cea708.state = CEA708_PKT_END; |
126 | 0 | } |
127 | 0 | else if( c->cea708.state != CEA708_PKT_END ) |
128 | 0 | { |
129 | 0 | switch( c->cea708.state ) |
130 | 0 | { |
131 | 0 | case CEA708_PKT_WAIT_BLOCK_HEADER: /* Byte is service block header */ |
132 | 0 | { |
133 | 0 | uint8_t i_sid = cc >> 5; |
134 | 0 | c->cea708.sid_bs = cc & 0x1F; |
135 | 0 | if( i_sid != 0x00 && c->cea708.sid_bs != 0 ) |
136 | 0 | { |
137 | 0 | if( i_sid != 0x07 ) |
138 | 0 | { |
139 | 0 | const uint8_t mask = (1 << --i_sid); |
140 | 0 | c->i_708channels |= (mask + (mask - 1)); |
141 | 0 | c->cea708.state = CEA708_PKT_IN_BLOCK; |
142 | 0 | } |
143 | 0 | else if( c->cea708.sid_bs < 2 ) |
144 | 0 | { |
145 | 0 | c->cea708.state = CEA708_PKT_END; |
146 | 0 | } |
147 | 0 | else |
148 | 0 | { |
149 | | /* need to look up next byte in next pkt */ |
150 | 0 | c->cea708.state = CEA708_PKT_WAIT_EXT_BLOCK_HEADER; |
151 | 0 | } |
152 | 0 | } |
153 | 0 | else c->cea708.state = CEA708_PKT_END; |
154 | 0 | } break; |
155 | | |
156 | 0 | case CEA708_PKT_WAIT_EXT_BLOCK_HEADER: |
157 | 0 | { |
158 | 0 | uint8_t i_extsid = cc & 0x3F; |
159 | 0 | if( i_extsid >= 0x07 ) |
160 | 0 | { |
161 | 0 | const uint8_t mask = (1 << --i_extsid); |
162 | 0 | c->i_708channels |= (mask + (mask - 1)); |
163 | 0 | } |
164 | 0 | if( c->cea708.sid_bs == 0 ) |
165 | 0 | c->cea708.state = CEA708_PKT_WAIT_BLOCK_HEADER; |
166 | 0 | else |
167 | 0 | c->cea708.state = CEA708_PKT_IN_BLOCK; |
168 | 0 | } break; |
169 | | |
170 | 0 | case CEA708_PKT_IN_BLOCK: |
171 | 0 | { |
172 | 0 | c->cea708.sid_bs--; |
173 | 0 | if( c->cea708.sid_bs == 0 ) |
174 | 0 | c->cea708.state = CEA708_PKT_WAIT_BLOCK_HEADER; |
175 | 0 | } break; |
176 | | |
177 | 0 | default: |
178 | 0 | vlc_assert_unreachable(); |
179 | 0 | break; |
180 | 0 | } |
181 | 0 | c->cea708.pktsize--; |
182 | |
|
183 | 0 | if(c->cea708.pktsize == 0) |
184 | 0 | c->cea708.state = CEA708_PKT_END; |
185 | 0 | } |
186 | 0 | } Unexecuted instantiation: mp4.c:cc_ProbeCEA708OneByte Unexecuted instantiation: ty.c:cc_ProbeCEA708OneByte Unexecuted instantiation: hxxx_common.c:cc_ProbeCEA708OneByte Unexecuted instantiation: mpegvideo.c:cc_ProbeCEA708OneByte Unexecuted instantiation: vc1.c:cc_ProbeCEA708OneByte |
187 | | |
188 | | static inline void cc_ProbeCEA708( cc_data_t *c, uint8_t i_field, const uint8_t cc[2] ) |
189 | 0 | { |
190 | 0 | if( i_field == 3 ) /* DTVCC_PACKET_START */ |
191 | 0 | cc_ProbeCEA708OneByte( c, true, cc[0] ); |
192 | 0 | else /* DTVCC_PACKET_DATA */ |
193 | 0 | cc_ProbeCEA708OneByte( c, false, cc[0] ); |
194 | 0 | cc_ProbeCEA708OneByte( c, false, cc[1] ); |
195 | 0 | } Unexecuted instantiation: mp4.c:cc_ProbeCEA708 Unexecuted instantiation: ty.c:cc_ProbeCEA708 Unexecuted instantiation: hxxx_common.c:cc_ProbeCEA708 Unexecuted instantiation: mpegvideo.c:cc_ProbeCEA708 Unexecuted instantiation: vc1.c:cc_ProbeCEA708 |
196 | | |
197 | | static inline bool cc_AppendData( cc_data_t *c, uint8_t cc_preamble, const uint8_t cc[2] ) |
198 | 0 | { |
199 | 0 | if (c->i_data + 3 > ARRAY_SIZE(c->p_data)) |
200 | 0 | return false; |
201 | | |
202 | 0 | const uint8_t i_field = cc_preamble & 0x03; |
203 | 0 | if( i_field == 0 || i_field == 1 ) /* NTSC_CC_FIELD_1 NTSC_CC_FIELD_2 */ |
204 | 0 | { |
205 | 0 | c->i_608channels |= (3 << (2 * i_field)); |
206 | 0 | } |
207 | 0 | else |
208 | 0 | { |
209 | 0 | cc_ProbeCEA708( c, i_field, cc ); |
210 | | /* By default enable at least channel 1 */ |
211 | 0 | c->i_708channels |= 1; |
212 | 0 | } |
213 | |
|
214 | 0 | c->p_data[c->i_data++] = cc_preamble; |
215 | 0 | c->p_data[c->i_data++] = cc[0]; |
216 | 0 | c->p_data[c->i_data++] = cc[1]; |
217 | 0 | return true; |
218 | 0 | } Unexecuted instantiation: mp4.c:cc_AppendData Unexecuted instantiation: ty.c:cc_AppendData Unexecuted instantiation: hxxx_common.c:cc_AppendData Unexecuted instantiation: mpegvideo.c:cc_AppendData Unexecuted instantiation: vc1.c:cc_AppendData |
219 | | |
220 | | static inline void cc_Extract( cc_data_t *c, enum cc_payload_type_e i_payload_type, |
221 | | bool b_top_field_first, const uint8_t *p_src, int i_src ) |
222 | 0 | { |
223 | 0 | if( c->i_payload_type != CC_PAYLOAD_NONE && c->i_payload_type != i_payload_type ) |
224 | 0 | { |
225 | 0 | c->i_payload_other_count++; |
226 | 0 | if( c->i_payload_other_count < 50 ) |
227 | 0 | return; |
228 | 0 | } |
229 | 0 | c->i_payload_type = i_payload_type; |
230 | 0 | c->i_payload_other_count = 0; |
231 | |
|
232 | 0 | if( i_payload_type == CC_PAYLOAD_RAW ) |
233 | 0 | { |
234 | 0 | for( int i = 0; i + 2 < i_src; i += 3 ) |
235 | 0 | { |
236 | 0 | const uint8_t *cc = &p_src[i]; |
237 | 0 | if (!cc_AppendData( c, cc[0], &cc[1] )) |
238 | 0 | break; |
239 | 0 | } |
240 | 0 | c->b_reorder = true; |
241 | 0 | } |
242 | 0 | else if( i_payload_type == CC_PAYLOAD_GA94 ) |
243 | 0 | { |
244 | | /* cc_data() |
245 | | * u1 reserved(1) |
246 | | * u1 process_cc_data_flag |
247 | | * u1 additional_data_flag |
248 | | * u5 cc_count |
249 | | * u8 reserved(1111 1111) |
250 | | * for cc_count |
251 | | * u5 marker bit(1111 1) |
252 | | * u1 cc_valid |
253 | | * u2 cc_type |
254 | | * u8 cc_data_1 |
255 | | * u8 cc_data_2 |
256 | | * u8 marker bit(1111 1111) |
257 | | * if additional_data_flag |
258 | | * unknown |
259 | | */ |
260 | | /* cc_type: |
261 | | * 0x00: field 1 |
262 | | * 0x01: field 2 |
263 | | */ |
264 | 0 | const uint8_t *cc = &p_src[0]; |
265 | 0 | const int i_count_cc = cc[0]&0x1f; |
266 | 0 | int i; |
267 | |
|
268 | 0 | if( !(cc[0]&0x40) ) // process flag |
269 | 0 | return; |
270 | 0 | if( i_src < 1+1 + i_count_cc*3 + 1) // broken packet |
271 | 0 | return; |
272 | 0 | if( i_count_cc <= 0 ) // no cc present |
273 | 0 | return; |
274 | 0 | if( cc[2+i_count_cc * 3] != 0xff ) // marker absent |
275 | 0 | return; |
276 | 0 | cc += 2; |
277 | |
|
278 | 0 | for( i = 0; i < i_count_cc; i++, cc += 3 ) |
279 | 0 | { |
280 | 0 | if (!cc_AppendData( c, cc[0], &cc[1] )) |
281 | 0 | break; |
282 | 0 | } |
283 | 0 | c->b_reorder = true; |
284 | 0 | } |
285 | 0 | else if( i_payload_type == CC_PAYLOAD_DVD ) |
286 | 0 | { |
287 | | /* user_data |
288 | | * (u32 stripped earlier) |
289 | | * u32 (0x43 0x43 0x01 0xf8) |
290 | | * u1 caption_odd_field_first (CC1/CC2) |
291 | | * u1 caption_filler |
292 | | * u5 cc_block_count (== cc_count / 2) |
293 | | * u1 caption_extra_field_added (because odd cc_count) |
294 | | * for cc_block_count * 2 + caption_extra_field_added |
295 | | * u7 cc_filler_1 |
296 | | * u1 cc_field_is_odd |
297 | | * u8 cc_data_1 |
298 | | * u8 cc_data_2 |
299 | | */ |
300 | 0 | const int b_truncate = p_src[4] & 0x01; |
301 | 0 | const int i_count_cc2 = ((p_src[4] >> 1) & 0x1f); |
302 | 0 | const uint8_t *cc = &p_src[5]; |
303 | 0 | i_src -= 5; |
304 | 0 | int i; |
305 | |
|
306 | 0 | #define CC_ALIGNMENT_TEST (0x7f) |
307 | |
|
308 | 0 | for( i = 0; i < 2*i_count_cc2 + b_truncate && i_src >= 3; i++, cc+=3 ) |
309 | 0 | { |
310 | 0 | if( (cc[0] >> 1) == CC_ALIGNMENT_TEST ) |
311 | 0 | { |
312 | 0 | const bool even_field = (cc[0] & 0x01) ? 0 : 1; |
313 | 0 | if (!cc_AppendData( c, CC_PKT_BYTE0(even_field), &cc[1] )) |
314 | 0 | break; |
315 | 0 | } |
316 | 0 | i_src -= 3; |
317 | 0 | } |
318 | 0 | c->b_reorder = false; |
319 | 0 | } |
320 | 0 | else if( i_payload_type == CC_PAYLOAD_REPLAYTV ) |
321 | 0 | { |
322 | 0 | const uint8_t *cc = &p_src[0]; |
323 | 0 | for( int i_cc_count = i_src >> 2; i_cc_count > 0; |
324 | 0 | i_cc_count--, cc += 4 ) |
325 | 0 | { |
326 | 0 | uint8_t i_field = (cc[0] & 0x02) >> 1; |
327 | 0 | if (!cc_AppendData( c, CC_PKT_BYTE0(i_field), &cc[2] )) |
328 | 0 | return; |
329 | 0 | } |
330 | 0 | c->b_reorder = false; |
331 | 0 | } |
332 | 0 | else if( i_payload_type == CC_PAYLOAD_SCTE20 ) |
333 | 0 | { |
334 | | /* user_data(2) |
335 | | * (u32 stripped earlier) |
336 | | * u16 p_cc_scte20 |
337 | | * u5 cc_count |
338 | | * for cc_count |
339 | | * u2 cc_priority |
340 | | * u2 cc_field_num |
341 | | * u5 cc_line_offset |
342 | | * u8 cc_data_1[1:8] |
343 | | * u8 cc_data_2[1:8] |
344 | | * u1 marker bit |
345 | | * un additional_realtimevideodata |
346 | | * un reserved |
347 | | */ |
348 | 0 | bs_t s; |
349 | 0 | bs_init( &s, &p_src[2], i_src - 2 ); |
350 | 0 | const int i_cc_count = bs_read( &s, 5 ); |
351 | 0 | for( int i = 0; i < i_cc_count; i++ ) |
352 | 0 | { |
353 | 0 | bs_skip( &s, 2 ); |
354 | 0 | const int i_field_idx = bs_read( &s, 2 ); |
355 | 0 | bs_skip( &s, 5 ); |
356 | 0 | uint8_t cc[2]; |
357 | 0 | for( int j = 0; j < 2; j++ ) |
358 | 0 | { |
359 | 0 | cc[j] = 0; |
360 | 0 | for( int k = 0; k < 8; k++ ) |
361 | 0 | cc[j] |= bs_read( &s, 1 ) << k; |
362 | 0 | } |
363 | 0 | bs_skip( &s, 1 ); |
364 | |
|
365 | 0 | if( i_field_idx == 0 ) |
366 | 0 | continue; |
367 | | |
368 | | /* 1,2,3 -> 0,1,0. I.E. repeated field 3 is merged with field 1 */ |
369 | 0 | int i_field = ((i_field_idx - 1) & 1); |
370 | 0 | if (!b_top_field_first) |
371 | 0 | i_field ^= 1; |
372 | |
|
373 | 0 | if (!cc_AppendData( c, CC_PKT_BYTE0(i_field), &cc[0] )) |
374 | 0 | continue; |
375 | 0 | } |
376 | 0 | c->b_reorder = true; |
377 | 0 | } |
378 | 0 | else // CC_PAYLOAD_CDP |
379 | 0 | { |
380 | 0 | # define CDP_FLAG_TIME_CODE_PRESENT (1<<7) |
381 | 0 | # define CDP_FLAG_CC_DATA_PRESENT (1<<6) |
382 | 0 | # define CDP_FLAG_SVC_INFO_PRESENT (1<<5) |
383 | 0 | # define CDP_FLAG_SVC_INFO_START (1<<4) |
384 | 0 | # define CDP_FLAG_SVC_INFO_CHANGE (1<<3) |
385 | 0 | # define CDP_FLAG_SVC_INFO_COMPLETE (1<<2) |
386 | 0 | # define CDP_FLAG_CAPTION_SVC_ACTIVE (1<<1) |
387 | |
|
388 | 0 | if(i_src < 7) |
389 | 0 | return; |
390 | | |
391 | | /* ST334-2 5.2 cdp_header() */ |
392 | 0 | uint8_t cdp_length = p_src[2]; |
393 | 0 | if(cdp_length < 8 || cdp_length > i_src) |
394 | 0 | return; |
395 | 0 | uint8_t cdp_flags = p_src[4]; |
396 | | |
397 | | /* skip header */ |
398 | 0 | p_src += 7; i_src -= 7; |
399 | | |
400 | | /* 5.3 time_code_section() */ |
401 | 0 | if( cdp_flags & CDP_FLAG_TIME_CODE_PRESENT ) |
402 | 0 | { |
403 | 0 | if( i_src < 5 ) // Shall be 5 bytes |
404 | 0 | return; |
405 | 0 | p_src += 5; i_src += 5; |
406 | 0 | } |
407 | | /* 5.4 ccdata_section */ |
408 | 0 | if( cdp_flags & CDP_FLAG_CC_DATA_PRESENT ) |
409 | 0 | { |
410 | | /* ccdata_section() |
411 | | * u8 0x72 |
412 | | * u3 marker bits(111) |
413 | | * u5 cc_count |
414 | | * for cc_count |
415 | | * u5 marker bits(1111 1) |
416 | | * u1 cc_valid |
417 | | * u2 cc_type |
418 | | * u8 cc_data_1 |
419 | | * u8 cc_data_2 |
420 | | */ |
421 | 0 | if( i_src < 2 || p_src[0] != 0x72 ) // marker |
422 | 0 | return; |
423 | | |
424 | 0 | const uint8_t *cc = &p_src[1]; |
425 | 0 | const int i_count_cc = cc[0]&0x1f; |
426 | |
|
427 | 0 | if( i_src - 2 < i_count_cc*3 ) // broken packet |
428 | 0 | return; |
429 | 0 | cc += 1; |
430 | 0 | for( int i = 0; i < i_count_cc; i++, cc += 3 ) |
431 | 0 | { |
432 | 0 | if (!cc_AppendData( c, cc[0], &cc[1] )) |
433 | 0 | break; |
434 | 0 | } |
435 | 0 | } |
436 | | /* remaining data */ |
437 | 0 | c->b_reorder = false; |
438 | 0 | } |
439 | 0 | } Unexecuted instantiation: mp4.c:cc_Extract Unexecuted instantiation: ty.c:cc_Extract Unexecuted instantiation: hxxx_common.c:cc_Extract Unexecuted instantiation: mpegvideo.c:cc_Extract Unexecuted instantiation: vc1.c:cc_Extract |
440 | | |
441 | | |
442 | | static inline void cc_ProbeAndExtract( cc_data_t *c, bool b_top_field_first, const uint8_t *p_src, int i_src ) |
443 | 0 | { |
444 | 0 | static const uint8_t p_cc_ga94[4] = { 0x47, 0x41, 0x39, 0x34 }; |
445 | 0 | static const uint8_t p_cc_dvd[4] = { 0x43, 0x43, 0x01, 0xf8 }; /* ascii 'CC', type_code, cc_block_size */ |
446 | 0 | static const uint8_t p_cc_replaytv4a[2] = { 0xbb, 0x02 };/* RTV4K, BB02xxxxCC02 */ |
447 | 0 | static const uint8_t p_cc_replaytv4b[2] = { 0xcc, 0x02 };/* see DVR-ClosedCaption in samples */ |
448 | 0 | static const uint8_t p_cc_replaytv5a[2] = { 0x99, 0x02 };/* RTV5K, 9902xxxxAA02 */ |
449 | 0 | static const uint8_t p_cc_replaytv5b[2] = { 0xaa, 0x02 };/* see DVR-ClosedCaption in samples */ |
450 | 0 | static const uint8_t p_cc_scte20[2] = { 0x03, 0x81 }; /* user_data_type_code, SCTE 20 */ |
451 | 0 | static const uint8_t p_cc_scte20_old[2] = { 0x03, 0x01 };/* user_data_type_code, old, Note 1 */ |
452 | |
|
453 | 0 | if( i_src < 4 ) |
454 | 0 | return; |
455 | | |
456 | 0 | enum cc_payload_type_e i_payload_type; |
457 | 0 | if( !memcmp( p_cc_ga94, p_src, 4 ) && i_src >= 5+1+1+1 && p_src[4] == 0x03 ) |
458 | 0 | { |
459 | | /* CC from DVB/ATSC TS */ |
460 | 0 | i_payload_type = CC_PAYLOAD_GA94; |
461 | 0 | i_src -= 5; |
462 | 0 | p_src += 5; |
463 | 0 | } |
464 | 0 | else if( !memcmp( p_cc_dvd, p_src, 4 ) && i_src > 4+1 ) |
465 | 0 | { |
466 | 0 | i_payload_type = CC_PAYLOAD_DVD; |
467 | 0 | } |
468 | 0 | else if( i_src >= 2+2 + 2+2 && |
469 | 0 | ( ( !memcmp( p_cc_replaytv4a, &p_src[0], 2 ) && !memcmp( p_cc_replaytv4b, &p_src[4], 2 ) ) || |
470 | 0 | ( !memcmp( p_cc_replaytv5a, &p_src[0], 2 ) && !memcmp( p_cc_replaytv5b, &p_src[4], 2 ) ) ) ) |
471 | 0 | { |
472 | 0 | i_payload_type = CC_PAYLOAD_REPLAYTV; |
473 | 0 | } |
474 | 0 | else if( ( !memcmp( p_cc_scte20, p_src, 2 ) || |
475 | 0 | !memcmp( p_cc_scte20_old, p_src, 2 ) ) && i_src > 2 ) |
476 | 0 | { |
477 | 0 | i_payload_type = CC_PAYLOAD_SCTE20; |
478 | 0 | } |
479 | 0 | else if (p_src[0] == 0x03 && p_src[1] == i_src - 2) /* DIRECTV */ |
480 | 0 | { |
481 | 0 | i_payload_type = CC_PAYLOAD_GA94; |
482 | 0 | i_src -= 2; |
483 | 0 | p_src += 2; |
484 | 0 | } |
485 | 0 | else if (p_src[0] == 0x96 && p_src[1] == 0x69) /* CDP */ |
486 | 0 | { |
487 | 0 | i_payload_type = CC_PAYLOAD_CDP; |
488 | 0 | } |
489 | 0 | else |
490 | 0 | { |
491 | | #if 0 |
492 | | #define V(x) ( ( x < 0x20 || x >= 0x7f ) ? '?' : x ) |
493 | | fprintf( stderr, "-------------- unknown user data " ); |
494 | | for( int i = 0; i < i_src; i++ ) |
495 | | fprintf( stderr, "%2.2x ", p_src[i] ); |
496 | | for( int i = 0; i < i_src; i++ ) |
497 | | fprintf( stderr, "%c ", V(p_src[i]) ); |
498 | | fprintf( stderr, "\n" ); |
499 | | #undef V |
500 | | #endif |
501 | 0 | return; |
502 | 0 | } |
503 | | |
504 | 0 | cc_Extract( c, i_payload_type, b_top_field_first, p_src, i_src ); |
505 | 0 | } Unexecuted instantiation: mp4.c:cc_ProbeAndExtract Unexecuted instantiation: ty.c:cc_ProbeAndExtract Unexecuted instantiation: hxxx_common.c:cc_ProbeAndExtract Unexecuted instantiation: mpegvideo.c:cc_ProbeAndExtract Unexecuted instantiation: vc1.c:cc_ProbeAndExtract |
506 | | |
507 | | #endif /* _CC_H */ |
508 | | |