1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright (C) 2007 Laurent Aimar
6 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
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 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.
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 *****************************************************************************/
28 #define CC_PKT_BYTE0(field) (0xFC | (0x03 & field))
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
43 /* Which channel are present */
44 uint64_t i_708channels
;
45 uint8_t i_608channels
;
57 CEA708_PKT_WAIT_BLOCK_HEADER
,
58 CEA708_PKT_WAIT_EXT_BLOCK_HEADER
,
64 enum cc_payload_type_e i_payload_type
;
65 int i_payload_other_count
;
68 * byte[x+0]: field (0/1)
69 * byte[x+1]: cc data 1
70 * byte[x+2]: cc data 2
73 uint8_t p_data
[CC_MAX_DATA_SIZE
];
76 static inline void cc_Init( cc_data_t
*c
)
82 c
->cea708
.pktsize
= 0;
85 c
->cea708
.state
= CEA708_PKT_END
;
86 c
->i_payload_type
= CC_PAYLOAD_NONE
;
87 c
->i_payload_other_count
= 0;
89 static inline void cc_Exit( cc_data_t
*c
)
94 static inline void cc_Flush( cc_data_t
*c
)
97 c
->cea708
.state
= CEA708_PKT_END
;
100 static inline void cc_ProbeCEA708OneByte( cc_data_t
*c
, bool b_start
, const uint8_t cc
)
104 const uint8_t i_pkt_sequence
= cc
>> 6;
105 if( i_pkt_sequence
> 0 && ((c
->cea708
.seq
+ 1) % 4) != i_pkt_sequence
)
107 c
->cea708
.pktsize
= 0;
108 c
->cea708
.seq
= i_pkt_sequence
;
109 c
->cea708
.state
= CEA708_PKT_END
;
113 c
->cea708
.seq
= i_pkt_sequence
;
114 c
->cea708
.pktsize
= cc
& 63;
115 if( c
->cea708
.pktsize
== 0 )
116 c
->cea708
.pktsize
= 127;
118 c
->cea708
.pktsize
= c
->cea708
.pktsize
* 2 - 1;
119 c
->cea708
.state
= CEA708_PKT_WAIT_BLOCK_HEADER
;
122 else if( c
->cea708
.pktsize
== 0 ) /* empty pkt reading service blocks */
124 c
->cea708
.state
= CEA708_PKT_END
;
126 else if( c
->cea708
.state
!= CEA708_PKT_END
)
128 switch( c
->cea708
.state
)
130 case CEA708_PKT_WAIT_BLOCK_HEADER
: /* Byte is service block header */
132 uint8_t i_sid
= cc
>> 5;
133 c
->cea708
.sid_bs
= cc
& 0x1F;
134 if( i_sid
!= 0x00 && c
->cea708
.sid_bs
!= 0 )
138 const uint8_t mask
= (1 << --i_sid
);
139 c
->i_708channels
|= (mask
+ (mask
- 1));
140 c
->cea708
.state
= CEA708_PKT_IN_BLOCK
;
142 else if( c
->cea708
.sid_bs
< 2 )
144 c
->cea708
.state
= CEA708_PKT_END
;
148 /* need to look up next byte in next pkt */
149 c
->cea708
.state
= CEA708_PKT_WAIT_EXT_BLOCK_HEADER
;
152 else c
->cea708
.state
= CEA708_PKT_END
;
155 case CEA708_PKT_WAIT_EXT_BLOCK_HEADER
:
157 uint8_t i_extsid
= cc
& 0x3F;
158 if( i_extsid
>= 0x07 )
160 const uint8_t mask
= (1 << --i_extsid
);
161 c
->i_708channels
|= (mask
+ (mask
- 1));
163 if( c
->cea708
.sid_bs
== 0 )
164 c
->cea708
.state
= CEA708_PKT_WAIT_BLOCK_HEADER
;
166 c
->cea708
.state
= CEA708_PKT_IN_BLOCK
;
169 case CEA708_PKT_IN_BLOCK
:
172 if( c
->cea708
.sid_bs
== 0 )
173 c
->cea708
.state
= CEA708_PKT_WAIT_BLOCK_HEADER
;
177 vlc_assert_unreachable();
182 if(c
->cea708
.pktsize
== 0)
183 c
->cea708
.state
= CEA708_PKT_END
;
187 static inline void cc_ProbeCEA708( cc_data_t
*c
, uint8_t i_field
, const uint8_t cc
[2] )
189 if( i_field
== 3 ) /* DTVCC_PACKET_START */
190 cc_ProbeCEA708OneByte( c
, true, cc
[0] );
191 else /* DTVCC_PACKET_DATA */
192 cc_ProbeCEA708OneByte( c
, false, cc
[0] );
193 cc_ProbeCEA708OneByte( c
, false, cc
[1] );
196 static inline void cc_AppendData( cc_data_t
*c
, uint8_t cc_preamble
, const uint8_t cc
[2] )
198 const uint8_t i_field
= cc_preamble
& 0x03;
199 if( i_field
== 0 || i_field
== 1 ) /* NTSC_CC_FIELD_1 NTSC_CC_FIELD_2 */
201 c
->i_608channels
|= (3 << (2 * i_field
));
205 cc_ProbeCEA708( c
, i_field
, cc
);
206 /* By default enable at least channel 1 */
207 c
->i_708channels
|= 1;
210 c
->p_data
[c
->i_data
++] = cc_preamble
;
211 c
->p_data
[c
->i_data
++] = cc
[0];
212 c
->p_data
[c
->i_data
++] = cc
[1];
215 static inline void cc_Extract( cc_data_t
*c
, enum cc_payload_type_e i_payload_type
,
216 bool b_top_field_first
, const uint8_t *p_src
, int i_src
)
218 if( c
->i_payload_type
!= CC_PAYLOAD_NONE
&& c
->i_payload_type
!= i_payload_type
)
220 c
->i_payload_other_count
++;
221 if( c
->i_payload_other_count
< 50 )
224 c
->i_payload_type
= i_payload_type
;
225 c
->i_payload_other_count
= 0;
227 if( i_payload_type
== CC_PAYLOAD_RAW
)
229 for( int i
= 0; i
+ 2 < i_src
; i
+= 3 )
231 if( c
->i_data
+ 3 > CC_MAX_DATA_SIZE
)
234 const uint8_t *cc
= &p_src
[i
];
235 cc_AppendData( c
, cc
[0], &cc
[1] );
239 else if( i_payload_type
== CC_PAYLOAD_GA94
)
243 * u1 process_cc_data_flag
244 * u1 additional_data_flag
246 * u8 reserved(1111 1111)
248 * u5 marker bit(1111 1)
253 * u8 marker bit(1111 1111)
254 * if additional_data_flag
261 const uint8_t *cc
= &p_src
[0];
262 const int i_count_cc
= cc
[0]&0x1f;
265 if( !(cc
[0]&0x40) ) // process flag
267 if( i_src
< 1+1 + i_count_cc
*3 + 1) // broken packet
269 if( i_count_cc
<= 0 ) // no cc present
271 if( cc
[2+i_count_cc
* 3] != 0xff ) // marker absent
275 for( i
= 0; i
< i_count_cc
; i
++, cc
+= 3 )
277 if( c
->i_data
+ 3 > CC_MAX_DATA_SIZE
)
280 cc_AppendData( c
, cc
[0], &cc
[1] );
284 else if( i_payload_type
== CC_PAYLOAD_DVD
)
287 * (u32 stripped earlier)
288 * u32 (0x43 0x43 0x01 0xf8)
289 * u1 caption_odd_field_first (CC1/CC2)
291 * u5 cc_block_count (== cc_count / 2)
292 * u1 caption_extra_field_added (because odd cc_count)
293 * for cc_block_count * 2 + caption_extra_field_added
299 const int b_truncate
= p_src
[4] & 0x01;
300 const int i_field_first
= (p_src
[4] & 0x80) ? 0 : 1;
301 const int i_count_cc2
= (p_src
[4] >> 1) & 0xf;
302 const uint8_t *cc
= &p_src
[5];
305 if( i_src
< 4+1+6*i_count_cc2
- ( b_truncate
? 3 : 0) )
307 for( i
= 0; i
< i_count_cc2
; i
++ )
310 for( j
= 0; j
< 2; j
++, cc
+= 3 )
312 const int i_field
= j
== i_field_first
? 0 : 1;
314 if( b_truncate
&& i
== i_count_cc2
- 1 && j
== 1 )
316 if( (cc
[0] & 0xfe) != 0xfe )
318 if( c
->i_data
+ 3 > CC_MAX_DATA_SIZE
)
321 cc_AppendData( c
, CC_PKT_BYTE0(i_field
), &cc
[1] );
324 c
->b_reorder
= false;
326 else if( i_payload_type
== CC_PAYLOAD_REPLAYTV
)
328 const uint8_t *cc
= &p_src
[0];
329 for( int i_cc_count
= i_src
>> 2; i_cc_count
> 0;
330 i_cc_count
--, cc
+= 4 )
332 if( c
->i_data
+ 3 > CC_MAX_DATA_SIZE
)
334 uint8_t i_field
= (cc
[0] & 0x02) >> 1;
335 cc_AppendData( c
, CC_PKT_BYTE0(i_field
), &cc
[2] );
337 c
->b_reorder
= false;
339 else /* CC_PAYLOAD_SCTE20 */
342 * (u32 stripped earlier)
352 * un additional_realtimevideodata
356 bs_init( &s
, &p_src
[2], i_src
- 2 );
357 const int i_cc_count
= bs_read( &s
, 5 );
358 for( int i
= 0; i
< i_cc_count
; i
++ )
361 const int i_field_idx
= bs_read( &s
, 2 );
364 for( int j
= 0; j
< 2; j
++ )
367 for( int k
= 0; k
< 8; k
++ )
368 cc
[j
] |= bs_read( &s
, 1 ) << k
;
372 if( i_field_idx
== 0 )
374 if( c
->i_data
+ 2*3 > CC_MAX_DATA_SIZE
)
377 /* 1,2,3 -> 0,1,0. I.E. repeated field 3 is merged with field 1 */
378 int i_field
= ((i_field_idx
- 1) & 1);
379 if (!b_top_field_first
)
382 cc_AppendData( c
, CC_PKT_BYTE0(i_field
), &cc
[0] );
389 static inline void cc_ProbeAndExtract( cc_data_t
*c
, bool b_top_field_first
, const uint8_t *p_src
, int i_src
)
391 static const uint8_t p_cc_ga94
[4] = { 0x47, 0x41, 0x39, 0x34 };
392 static const uint8_t p_cc_dvd
[4] = { 0x43, 0x43, 0x01, 0xf8 }; /* ascii 'CC', type_code, cc_block_size */
393 static const uint8_t p_cc_replaytv4a
[2] = { 0xbb, 0x02 };/* RTV4K, BB02xxxxCC02 */
394 static const uint8_t p_cc_replaytv4b
[2] = { 0xcc, 0x02 };/* see DVR-ClosedCaption in samples */
395 static const uint8_t p_cc_replaytv5a
[2] = { 0x99, 0x02 };/* RTV5K, 9902xxxxAA02 */
396 static const uint8_t p_cc_replaytv5b
[2] = { 0xaa, 0x02 };/* see DVR-ClosedCaption in samples */
397 static const uint8_t p_cc_scte20
[2] = { 0x03, 0x81 }; /* user_data_type_code, SCTE 20 */
398 static const uint8_t p_cc_scte20_old
[2] = { 0x03, 0x01 };/* user_data_type_code, old, Note 1 */
403 enum cc_payload_type_e i_payload_type
;
404 if( !memcmp( p_cc_ga94
, p_src
, 4 ) && i_src
>= 5+1+1+1 && p_src
[4] == 0x03 )
406 /* CC from DVB/ATSC TS */
407 i_payload_type
= CC_PAYLOAD_GA94
;
411 else if( !memcmp( p_cc_dvd
, p_src
, 4 ) && i_src
> 4+1 )
413 i_payload_type
= CC_PAYLOAD_DVD
;
415 else if( i_src
>= 2+2 + 2+2 &&
416 ( ( !memcmp( p_cc_replaytv4a
, &p_src
[0], 2 ) && !memcmp( p_cc_replaytv4b
, &p_src
[4], 2 ) ) ||
417 ( !memcmp( p_cc_replaytv5a
, &p_src
[0], 2 ) && !memcmp( p_cc_replaytv5b
, &p_src
[4], 2 ) ) ) )
419 i_payload_type
= CC_PAYLOAD_REPLAYTV
;
421 else if( ( !memcmp( p_cc_scte20
, p_src
, 2 ) ||
422 !memcmp( p_cc_scte20_old
, p_src
, 2 ) ) && i_src
> 2 )
424 i_payload_type
= CC_PAYLOAD_SCTE20
;
426 else if (p_src
[0] == 0x03 && p_src
[1] == i_src
- 2) /* DIRECTV */
428 i_payload_type
= CC_PAYLOAD_GA94
;
435 #define V(x) ( ( x < 0x20 || x >= 0x7f ) ? '?' : x )
436 fprintf( stderr
, "-------------- unknown user data " );
437 for( int i
= 0; i
< i_src
; i
++ )
438 fprintf( stderr
, "%2.2x ", p_src
[i
] );
439 for( int i
= 0; i
< i_src
; i
++ )
440 fprintf( stderr
, "%c ", V(p_src
[i
]) );
441 fprintf( stderr
, "\n" );
447 cc_Extract( c
, i_payload_type
, b_top_field_first
, p_src
, i_src
);