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 BLOCK_FLAG_ORDERED_CAPTIONS (0x01 << BLOCK_FLAG_PRIVATE_SHIFT)
31 #define CC_PKT_BYTE0(field) (0xFC | (0x03 & field))
33 /* CC have a maximum rate of 9600 bit/s (per field?) */
34 #define CC_MAX_DATA_SIZE (2 * 3*600)
35 enum cc_payload_type_e
45 /* Which channel are present */
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
)
68 for( i
= 0; i
< 4; i
++ )
69 c
-> pb_present
[i
] = false;
72 c
->i_payload_type
= CC_PAYLOAD_NONE
;
73 c
->i_payload_other_count
= 0;
75 static inline void cc_Exit( cc_data_t
*c
)
80 static inline void cc_Flush( cc_data_t
*c
)
85 static inline void cc_AppendData( cc_data_t
*c
, uint8_t cc_preamble
, const uint8_t cc
[2] )
87 uint8_t i_field
= cc_preamble
& 0x03;
88 if( i_field
== 0 || i_field
== 1 )
90 c
->pb_present
[2*i_field
+0] =
91 c
->pb_present
[2*i_field
+1] = true;
94 c
->p_data
[c
->i_data
++] = cc_preamble
;
95 c
->p_data
[c
->i_data
++] = cc
[0];
96 c
->p_data
[c
->i_data
++] = cc
[1];
99 static inline void cc_Extract( cc_data_t
*c
, enum cc_payload_type_e i_payload_type
,
100 bool b_top_field_first
, const uint8_t *p_src
, int i_src
)
102 if( c
->i_payload_type
!= CC_PAYLOAD_NONE
&& c
->i_payload_type
!= i_payload_type
)
104 c
->i_payload_other_count
++;
105 if( c
->i_payload_other_count
< 50 )
108 c
->i_payload_type
= i_payload_type
;
109 c
->i_payload_other_count
= 0;
111 if( i_payload_type
== CC_PAYLOAD_GA94
)
115 * u1 process_cc_data_flag
116 * u1 additional_data_flag
118 * u8 reserved(1111 1111)
120 * u5 marker bit(1111 1)
125 * u8 marker bit(1111 1111)
126 * if additional_data_flag
133 const uint8_t *cc
= &p_src
[0];
134 const int i_count_cc
= cc
[0]&0x1f;
137 if( !(cc
[0]&0x40) ) // process flag
139 if( i_src
< 1+1 + i_count_cc
*3 + 1) // broken packet
141 if( i_count_cc
<= 0 ) // no cc present
143 if( cc
[2+i_count_cc
* 3] != 0xff ) // marker absent
147 for( i
= 0; i
< i_count_cc
; i
++, cc
+= 3 )
149 if( c
->i_data
+ 3 > CC_MAX_DATA_SIZE
)
152 cc_AppendData( c
, cc
[0], &cc
[1] );
156 else if( i_payload_type
== CC_PAYLOAD_DVD
)
159 * (u32 stripped earlier)
160 * u32 (0x43 0x43 0x01 0xf8)
161 * u1 caption_odd_field_first (CC1/CC2)
163 * u5 cc_block_count (== cc_count / 2)
164 * u1 caption_extra_field_added (because odd cc_count)
165 * for cc_block_count * 2 + caption_extra_field_added
171 const int b_truncate
= p_src
[4] & 0x01;
172 const int i_field_first
= (p_src
[4] & 0x80) ? 0 : 1;
173 const int i_count_cc2
= (p_src
[4] >> 1) & 0xf;
174 const uint8_t *cc
= &p_src
[5];
177 if( i_src
< 4+1+6*i_count_cc2
- ( b_truncate
? 3 : 0) )
179 for( i
= 0; i
< i_count_cc2
; i
++ )
182 for( j
= 0; j
< 2; j
++, cc
+= 3 )
184 const int i_field
= j
== i_field_first
? 0 : 1;
186 if( b_truncate
&& i
== i_count_cc2
- 1 && j
== 1 )
188 if( (cc
[0] & 0xfe) != 0xfe )
190 if( c
->i_data
+ 3 > CC_MAX_DATA_SIZE
)
193 cc_AppendData( c
, CC_PKT_BYTE0(i_field
), &cc
[1] );
196 c
->b_reorder
= false;
198 else if( i_payload_type
== CC_PAYLOAD_REPLAYTV
)
200 const uint8_t *cc
= &p_src
[0];
201 for( int i_cc_count
= i_src
>> 2; i_cc_count
> 0;
202 i_cc_count
--, cc
+= 4 )
204 if( c
->i_data
+ 3 > CC_MAX_DATA_SIZE
)
206 uint8_t i_field
= (cc
[0] & 0x02) >> 1;
207 cc_AppendData( c
, CC_PKT_BYTE0(i_field
), &cc
[2] );
209 c
->b_reorder
= false;
211 else /* CC_PAYLOAD_SCTE20 */
214 * (u32 stripped earlier)
224 * un additional_realtimevideodata
228 bs_init( &s
, &p_src
[2], i_src
- 2 );
229 const int i_cc_count
= bs_read( &s
, 5 );
230 for( int i
= 0; i
< i_cc_count
; i
++ )
233 const int i_field_idx
= bs_read( &s
, 2 );
236 for( int j
= 0; j
< 2; j
++ )
239 for( int k
= 0; k
< 8; k
++ )
240 cc
[j
] |= bs_read( &s
, 1 ) << k
;
244 if( i_field_idx
== 0 )
246 if( c
->i_data
+ 2*3 > CC_MAX_DATA_SIZE
)
249 /* 1,2,3 -> 0,1,0. I.E. repeated field 3 is merged with field 1 */
250 int i_field
= ((i_field_idx
- 1) & 1);
251 if (!b_top_field_first
)
254 cc_AppendData( c
, CC_PKT_BYTE0(i_field
), &cc
[0] );
261 static inline void cc_ProbeAndExtract( cc_data_t
*c
, bool b_top_field_first
, const uint8_t *p_src
, int i_src
)
263 static const uint8_t p_cc_ga94
[4] = { 0x47, 0x41, 0x39, 0x34 };
264 static const uint8_t p_cc_dvd
[4] = { 0x43, 0x43, 0x01, 0xf8 }; /* ascii 'CC', type_code, cc_block_size */
265 static const uint8_t p_cc_replaytv4a
[2] = { 0xbb, 0x02 };/* RTV4K, BB02xxxxCC02 */
266 static const uint8_t p_cc_replaytv4b
[2] = { 0xcc, 0x02 };/* see DVR-ClosedCaption in samples */
267 static const uint8_t p_cc_replaytv5a
[2] = { 0x99, 0x02 };/* RTV5K, 9902xxxxAA02 */
268 static const uint8_t p_cc_replaytv5b
[2] = { 0xaa, 0x02 };/* see DVR-ClosedCaption in samples */
269 static const uint8_t p_cc_scte20
[2] = { 0x03, 0x81 }; /* user_data_type_code, SCTE 20 */
270 static const uint8_t p_cc_scte20_old
[2] = { 0x03, 0x01 };/* user_data_type_code, old, Note 1 */
275 enum cc_payload_type_e i_payload_type
;
276 if( !memcmp( p_cc_ga94
, p_src
, 4 ) && i_src
>= 5+1+1+1 && p_src
[4] == 0x03 )
278 /* CC from DVB/ATSC TS */
279 i_payload_type
= CC_PAYLOAD_GA94
;
283 else if( !memcmp( p_cc_dvd
, p_src
, 4 ) && i_src
> 4+1 )
285 i_payload_type
= CC_PAYLOAD_DVD
;
287 else if( i_src
>= 2+2 + 2+2 &&
288 ( ( !memcmp( p_cc_replaytv4a
, &p_src
[0], 2 ) && !memcmp( p_cc_replaytv4b
, &p_src
[4], 2 ) ) ||
289 ( !memcmp( p_cc_replaytv5a
, &p_src
[0], 2 ) && !memcmp( p_cc_replaytv5b
, &p_src
[4], 2 ) ) ) )
291 i_payload_type
= CC_PAYLOAD_REPLAYTV
;
293 else if( ( !memcmp( p_cc_scte20
, p_src
, 2 ) ||
294 !memcmp( p_cc_scte20_old
, p_src
, 2 ) ) && i_src
> 2 )
296 i_payload_type
= CC_PAYLOAD_SCTE20
;
298 else if (p_src
[0] == 0x03 && p_src
[1] == i_src
- 2) /* DIRECTV */
300 i_payload_type
= CC_PAYLOAD_GA94
;
307 #define V(x) ( ( x < 0x20 || x >= 0x7f ) ? '?' : x )
308 fprintf( stderr
, "-------------- unknown user data " );
309 for( int i
= 0; i
< i_src
; i
++ )
310 fprintf( stderr
, "%2.2x ", p_src
[i
] );
311 for( int i
= 0; i
< i_src
; i
++ )
312 fprintf( stderr
, "%c ", V(p_src
[i
]) );
313 fprintf( stderr
, "\n" );
319 cc_Extract( c
, i_payload_type
, b_top_field_first
, p_src
, i_src
);