]> git.sesse.net Git - vlc/blob - modules/codec/cc.h
Be more explicit on faad error.
[vlc] / modules / codec / cc.h
1 /*****************************************************************************
2  * cc.h
3  *****************************************************************************
4  * Copyright (C) 2007 Laurent Aimar
5  * $Id$
6  *
7  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
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 General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 #ifndef _CC_H
25 #define _CC_H 1
26
27 #include <vlc_bits.h>
28
29 /* CC have a maximum rate of 9600 bit/s (per field?) */
30 #define CC_MAX_DATA_SIZE (2 * 3*600)
31 typedef struct
32 {
33     /* Which channel are present */
34     bool pb_present[4];
35
36     /* */
37     bool b_reorder;
38
39     /* CC data per field
40      *  byte[x+0]: field (0/1)
41      *  byte[x+1]: cc data 1
42      *  byte[x+2]: cc data 2
43      */
44     int     i_data;
45     uint8_t p_data[CC_MAX_DATA_SIZE];
46 } cc_data_t;
47
48 static inline int cc_Channel( int i_field, const uint8_t p_data[2] )
49 {
50     const uint8_t d = p_data[0] & 0x7f;
51     if( i_field != 0 && i_field != 1 )
52         return -1;
53     if( d == 0x14 )
54         return 2*i_field + 0;
55     else if( d == 0x1c )
56         return 2*i_field + 1;
57     /* unknown(middle of a command)  or not cc channel */
58     return -1;
59 }
60 static inline void cc_Init( cc_data_t *c )
61 {
62     int i;
63
64     for( i = 0; i < 4; i++ )
65         c-> pb_present[i] = false; 
66     c->i_data = 0;
67     c->b_reorder = false;
68 }
69 static inline void cc_Exit( cc_data_t *c )
70 {
71     VLC_UNUSED(c);
72     return;
73 }
74 static inline void cc_Flush( cc_data_t *c )
75 {
76     c->i_data = 0;
77 }
78 static inline void cc_Extract( cc_data_t *c, const uint8_t *p_src, int i_src )
79 {
80     static const uint8_t p_cc_ga94[4] = { 0x47, 0x41, 0x39, 0x34 };
81     static const uint8_t p_cc_dvd[4] = { 0x43, 0x43, 0x01, 0xf8 };
82     static const uint8_t p_cc_replaytv4a[2] = { 0xbb, 0x02 };
83     static const uint8_t p_cc_replaytv4b[2] = { 0xcc, 0x02 };
84     static const uint8_t p_cc_replaytv5a[2] = { 0x99, 0x02 };
85     static const uint8_t p_cc_replaytv5b[2] = { 0xaa, 0x02 };
86     static const uint8_t p_cc_scte20[2] = { 0x03, 0x81 };
87     //static const uint8_t p_afd_start[4] = { 0x44, 0x54, 0x47, 0x31 };
88
89     if( i_src < 4 )
90         return;
91
92     if( !memcmp( p_cc_ga94, p_src, 4 ) && i_src >= 5+1+1+1 && p_src[4] == 0x03 )
93     {
94         /* Extract CC from DVB/ATSC TS */
95         /* cc_data()
96          *          u1 reserved(1)
97          *          u1 process_cc_data_flag
98          *          u1 additional_data_flag
99          *          u5 cc_count
100          *          u8 reserved(1111 1111)
101          *          for cc_count
102          *              u5 marker bit(1111 1)
103          *              u1 cc_valid
104          *              u2 cc_type
105          *              u8 cc_data_1
106          *              u8 cc_data_2
107          *          u8 marker bit(1111 1111)
108          *          if additional_data_flag
109          *              unknown
110          */
111         /* cc_type:
112          *  0x00: field 1
113          *  0x01: field 2
114          */
115         const uint8_t *cc = &p_src[5];
116         const int i_count_cc = cc[0]&0x1f;
117         int i;
118
119         if( !(cc[0]&0x40) ) // process flag
120             return;
121         if( i_src < 5 + 1+1 + i_count_cc*3 + 1)  // broken packet
122             return;
123         if( i_count_cc <= 0 )   // no cc present
124             return;
125         if( cc[2+i_count_cc * 3] != 0xff )  // marker absent
126             return;
127         cc += 2;
128
129         for( i = 0; i < i_count_cc; i++, cc += 3 )
130         {
131             int i_field = cc[0] & 0x03;
132             int i_channel;
133             if( ( cc[0] & 0xfc ) != 0xfc )
134                 continue;
135             if( i_field != 0 && i_field != 1 )
136                 continue;
137             if( c->i_data + 3 > CC_MAX_DATA_SIZE )
138                 continue;
139
140             i_channel = cc_Channel( i_field, &cc[1] );
141             if( i_channel >= 0 && i_channel < 4 )
142                 c->pb_present[i_channel] = true;
143
144             c->p_data[c->i_data++] = i_field;
145             c->p_data[c->i_data++] = cc[1];
146             c->p_data[c->i_data++] = cc[2];
147         }
148         c->b_reorder = true;
149     }
150     else if( !memcmp( p_cc_dvd, p_src, 4 ) && i_src > 4+1 )
151     {
152         /* DVD CC */
153         const int b_truncate = p_src[4] & 0x01;
154         const int i_field_first = (p_src[4] & 0x80) ? 0 : 1;
155         const int i_count_cc2 = (p_src[4] >> 1) & 0xf;
156         const uint8_t *cc = &p_src[5];
157         int i;
158
159         if( i_src < 4+1+6*i_count_cc2 - ( b_truncate ? 3 : 0) )
160             return;
161         for( i = 0; i < i_count_cc2; i++ )
162         {
163             int j;
164             for( j = 0; j < 2; j++, cc += 3 )
165             {
166                 const int i_field = j == i_field_first ? 0 : 1;
167                 int i_channel;
168
169                 if( b_truncate && i == i_count_cc2 - 1 && j == 1 )
170                     break;
171                 if( cc[0] != 0xff && cc[0] != 0xfe )
172                     continue;
173                 if( c->i_data + 3 > CC_MAX_DATA_SIZE )
174                     continue;
175
176                 i_channel = cc_Channel( i_field, &cc[1] );
177                 if( i_channel >= 0 && i_channel < 4 )
178                     c->pb_present[i_channel] = true;
179                 c->p_data[c->i_data++] = i_field;
180                 c->p_data[c->i_data++] = cc[1];
181                 c->p_data[c->i_data++] = cc[2];
182             }
183         }
184         c->b_reorder = false;
185     }
186     else if( i_src >= 2+2 + 2+2 &&
187              ( ( !memcmp( p_cc_replaytv4a, &p_src[0], 2 ) && !memcmp( p_cc_replaytv4b, &p_src[4], 2 ) ) ||
188                ( !memcmp( p_cc_replaytv5a, &p_src[0], 2 ) && !memcmp( p_cc_replaytv5b, &p_src[4], 2 ) ) ) )
189     {
190         /* ReplayTV CC */
191         const uint8_t *cc = &p_src[0];
192         int i;
193         if( c->i_data + 2*3 > CC_MAX_DATA_SIZE )
194             return;
195
196         for( i = 0; i < 2; i++, cc += 4 )
197         {
198             const int i_field = i == 0 ? 1 : 0;
199             int i_channel = cc_Channel( i_field, &cc[2] );
200             if( i_channel >= 0 && i_channel < 4 )
201                 c->pb_present[i_channel] = true;
202             c->p_data[c->i_data++] = i_field;
203             c->p_data[c->i_data++] = cc[2];
204             c->p_data[c->i_data++] = cc[3];
205         }
206         c->b_reorder = false;
207     }
208     else if( !memcmp( p_cc_scte20, p_src, 2 ) && i_src > 2 )
209     {
210         /* SCTE-20 CC */
211         bs_t s;
212         bs_init( &s, &p_src[2], i_src - 2 );
213         const int i_cc_count = bs_read( &s, 5 );
214         for( int i = 0; i < i_cc_count; i++ )
215         {
216             bs_skip( &s, 2 );
217             const int i_field_idx = bs_read( &s, 2 );
218             bs_skip( &s, 5 );
219             uint8_t cc[2];
220             for( int j = 0; j < 2; j++ )
221             {
222                 cc[j] = 0;
223                 for( int k = 0; k < 8; k++ )
224                     cc[j] |= bs_read( &s, 1 ) << k;
225             }
226             bs_skip( &s, 1 );
227
228             if( i_field_idx != 1 && i_field_idx != 2 )
229                 continue;
230             if( c->i_data + 2*3 > CC_MAX_DATA_SIZE )
231                 continue;
232
233             const int i_field = i_field_idx - 1;
234             const int i_channel = cc_Channel( i_field, cc );
235             if( i_channel >= 0 && i_channel < 4 )
236                 c->pb_present[i_channel] = true;
237
238             c->p_data[c->i_data++] = i_field;
239             c->p_data[c->i_data++] = cc[0];
240             c->p_data[c->i_data++] = cc[1];
241         }
242         c->b_reorder = true;
243     }
244     else
245     {
246 #if 0
247 #define V(x) ( ( x < 0x20 || x >= 0x7f ) ? '?' : x )
248         fprintf( stderr, "-------------- unknown user data " );
249         for( int i = 0; i < i_src; i++ )
250             fprintf( stderr, "%2.2x ", p_src[i] );
251         for( int i = 0; i < i_src; i++ )
252             fprintf( stderr, "%c ", V(p_src[i]) );
253         fprintf( stderr, "\n" );
254 #undef V
255 #endif
256         /* TODO DVD CC, ... */
257     }
258 }
259
260 #endif /* _CC_H */
261