1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright (C) 2007 Laurent Aimar
7 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU Lesser General Public License as published by
11 * the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
29 #define CC_PKT_BYTE0(field) (0xFC | (0x03 & field))
31 /* CC have a maximum rate of 9600 bit/s (per field?) */
32 #define CC_MAX_DATA_SIZE (2 * 3*600)
33 enum cc_payload_type_e
44 /* Which channel are present */
45 uint64_t i_708channels
;
46 uint8_t i_608channels
;
52 enum cc_payload_type_e i_payload_type
;
53 int i_payload_other_count
;
56 * byte[x+0]: field (0/1)
57 * byte[x+1]: cc data 1
58 * byte[x+2]: cc data 2
61 uint8_t p_data
[CC_MAX_DATA_SIZE
];
64 static inline void cc_Init( cc_data_t
*c
)
70 c
->i_payload_type
= CC_PAYLOAD_NONE
;
71 c
->i_payload_other_count
= 0;
73 static inline void cc_Exit( cc_data_t
*c
)
78 static inline void cc_Flush( cc_data_t
*c
)
83 static inline void cc_AppendData( cc_data_t
*c
, uint8_t cc_preamble
, const uint8_t cc
[2] )
85 uint8_t i_field
= cc_preamble
& 0x03;
86 if( i_field
== 0 || i_field
== 1 )
87 c
->i_608channels
|= (3 << (2 * i_field
));
89 c
->i_708channels
|= 1;
91 c
->p_data
[c
->i_data
++] = cc_preamble
;
92 c
->p_data
[c
->i_data
++] = cc
[0];
93 c
->p_data
[c
->i_data
++] = cc
[1];
96 static inline void cc_Extract( cc_data_t
*c
, enum cc_payload_type_e i_payload_type
,
97 bool b_top_field_first
, const uint8_t *p_src
, int i_src
)
99 if( c
->i_payload_type
!= CC_PAYLOAD_NONE
&& c
->i_payload_type
!= i_payload_type
)
101 c
->i_payload_other_count
++;
102 if( c
->i_payload_other_count
< 50 )
105 c
->i_payload_type
= i_payload_type
;
106 c
->i_payload_other_count
= 0;
108 if( i_payload_type
== CC_PAYLOAD_RAW
)
110 for( int i
= 0; i
+ 2 < i_src
; i
+= 3 )
112 if( c
->i_data
+ 3 > CC_MAX_DATA_SIZE
)
115 const uint8_t *cc
= &p_src
[i
];
116 cc_AppendData( c
, cc
[0], &cc
[1] );
120 else if( i_payload_type
== CC_PAYLOAD_GA94
)
124 * u1 process_cc_data_flag
125 * u1 additional_data_flag
127 * u8 reserved(1111 1111)
129 * u5 marker bit(1111 1)
134 * u8 marker bit(1111 1111)
135 * if additional_data_flag
142 const uint8_t *cc
= &p_src
[0];
143 const int i_count_cc
= cc
[0]&0x1f;
146 if( !(cc
[0]&0x40) ) // process flag
148 if( i_src
< 1+1 + i_count_cc
*3 + 1) // broken packet
150 if( i_count_cc
<= 0 ) // no cc present
152 if( cc
[2+i_count_cc
* 3] != 0xff ) // marker absent
156 for( i
= 0; i
< i_count_cc
; i
++, cc
+= 3 )
158 if( c
->i_data
+ 3 > CC_MAX_DATA_SIZE
)
161 cc_AppendData( c
, cc
[0], &cc
[1] );
165 else if( i_payload_type
== CC_PAYLOAD_DVD
)
168 * (u32 stripped earlier)
169 * u32 (0x43 0x43 0x01 0xf8)
170 * u1 caption_odd_field_first (CC1/CC2)
172 * u5 cc_block_count (== cc_count / 2)
173 * u1 caption_extra_field_added (because odd cc_count)
174 * for cc_block_count * 2 + caption_extra_field_added
180 const int b_truncate
= p_src
[4] & 0x01;
181 const int i_field_first
= (p_src
[4] & 0x80) ? 0 : 1;
182 const int i_count_cc2
= (p_src
[4] >> 1) & 0xf;
183 const uint8_t *cc
= &p_src
[5];
186 if( i_src
< 4+1+6*i_count_cc2
- ( b_truncate
? 3 : 0) )
188 for( i
= 0; i
< i_count_cc2
; i
++ )
191 for( j
= 0; j
< 2; j
++, cc
+= 3 )
193 const int i_field
= j
== i_field_first
? 0 : 1;
195 if( b_truncate
&& i
== i_count_cc2
- 1 && j
== 1 )
197 if( (cc
[0] & 0xfe) != 0xfe )
199 if( c
->i_data
+ 3 > CC_MAX_DATA_SIZE
)
202 cc_AppendData( c
, CC_PKT_BYTE0(i_field
), &cc
[1] );
205 c
->b_reorder
= false;
207 else if( i_payload_type
== CC_PAYLOAD_REPLAYTV
)
209 const uint8_t *cc
= &p_src
[0];
210 for( int i_cc_count
= i_src
>> 2; i_cc_count
> 0;
211 i_cc_count
--, cc
+= 4 )
213 if( c
->i_data
+ 3 > CC_MAX_DATA_SIZE
)
215 uint8_t i_field
= (cc
[0] & 0x02) >> 1;
216 cc_AppendData( c
, CC_PKT_BYTE0(i_field
), &cc
[2] );
218 c
->b_reorder
= false;
220 else /* CC_PAYLOAD_SCTE20 */
223 * (u32 stripped earlier)
233 * un additional_realtimevideodata
237 bs_init( &s
, &p_src
[2], i_src
- 2 );
238 const int i_cc_count
= bs_read( &s
, 5 );
239 for( int i
= 0; i
< i_cc_count
; i
++ )
242 const int i_field_idx
= bs_read( &s
, 2 );
245 for( int j
= 0; j
< 2; j
++ )
248 for( int k
= 0; k
< 8; k
++ )
249 cc
[j
] |= bs_read( &s
, 1 ) << k
;
253 if( i_field_idx
== 0 )
255 if( c
->i_data
+ 2*3 > CC_MAX_DATA_SIZE
)
258 /* 1,2,3 -> 0,1,0. I.E. repeated field 3 is merged with field 1 */
259 int i_field
= ((i_field_idx
- 1) & 1);
260 if (!b_top_field_first
)
263 cc_AppendData( c
, CC_PKT_BYTE0(i_field
), &cc
[0] );
270 static inline void cc_ProbeAndExtract( cc_data_t
*c
, bool b_top_field_first
, const uint8_t *p_src
, int i_src
)
272 static const uint8_t p_cc_ga94
[4] = { 0x47, 0x41, 0x39, 0x34 };
273 static const uint8_t p_cc_dvd
[4] = { 0x43, 0x43, 0x01, 0xf8 }; /* ascii 'CC', type_code, cc_block_size */
274 static const uint8_t p_cc_replaytv4a
[2] = { 0xbb, 0x02 };/* RTV4K, BB02xxxxCC02 */
275 static const uint8_t p_cc_replaytv4b
[2] = { 0xcc, 0x02 };/* see DVR-ClosedCaption in samples */
276 static const uint8_t p_cc_replaytv5a
[2] = { 0x99, 0x02 };/* RTV5K, 9902xxxxAA02 */
277 static const uint8_t p_cc_replaytv5b
[2] = { 0xaa, 0x02 };/* see DVR-ClosedCaption in samples */
278 static const uint8_t p_cc_scte20
[2] = { 0x03, 0x81 }; /* user_data_type_code, SCTE 20 */
279 static const uint8_t p_cc_scte20_old
[2] = { 0x03, 0x01 };/* user_data_type_code, old, Note 1 */
284 enum cc_payload_type_e i_payload_type
;
285 if( !memcmp( p_cc_ga94
, p_src
, 4 ) && i_src
>= 5+1+1+1 && p_src
[4] == 0x03 )
287 /* CC from DVB/ATSC TS */
288 i_payload_type
= CC_PAYLOAD_GA94
;
292 else if( !memcmp( p_cc_dvd
, p_src
, 4 ) && i_src
> 4+1 )
294 i_payload_type
= CC_PAYLOAD_DVD
;
296 else if( i_src
>= 2+2 + 2+2 &&
297 ( ( !memcmp( p_cc_replaytv4a
, &p_src
[0], 2 ) && !memcmp( p_cc_replaytv4b
, &p_src
[4], 2 ) ) ||
298 ( !memcmp( p_cc_replaytv5a
, &p_src
[0], 2 ) && !memcmp( p_cc_replaytv5b
, &p_src
[4], 2 ) ) ) )
300 i_payload_type
= CC_PAYLOAD_REPLAYTV
;
302 else if( ( !memcmp( p_cc_scte20
, p_src
, 2 ) ||
303 !memcmp( p_cc_scte20_old
, p_src
, 2 ) ) && i_src
> 2 )
305 i_payload_type
= CC_PAYLOAD_SCTE20
;
307 else if (p_src
[0] == 0x03 && p_src
[1] == i_src
- 2) /* DIRECTV */
309 i_payload_type
= CC_PAYLOAD_GA94
;
316 #define V(x) ( ( x < 0x20 || x >= 0x7f ) ? '?' : x )
317 fprintf( stderr
, "-------------- unknown user data " );
318 for( int i
= 0; i
< i_src
; i
++ )
319 fprintf( stderr
, "%2.2x ", p_src
[i
] );
320 for( int i
= 0; i
< i_src
; i
++ )
321 fprintf( stderr
, "%c ", V(p_src
[i
]) );
322 fprintf( stderr
, "\n" );
328 cc_Extract( c
, i_payload_type
, b_top_field_first
, p_src
, i_src
);