]> git.sesse.net Git - vlc/blob - modules/codec/cc.h
mediacodec: fix warning
[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 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.
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 Lesser General Public License for more details.
18  *
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  *****************************************************************************/
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 enum
32 {
33     CC_PAYLOAD_NONE,
34     CC_PAYLOAD_GA94,
35     CC_PAYLOAD_DVD,
36     CC_PAYLOAD_REPLAYTV,
37     CC_PAYLOAD_SCTE20,
38 };
39 typedef struct
40 {
41     /* Which channel are present */
42     bool pb_present[4];
43
44     /* */
45     bool b_reorder;
46
47     /* */
48     int i_payload_type;
49     int i_payload_other_count;
50
51     /* CC data per field
52      *  byte[x+0]: field (0/1)
53      *  byte[x+1]: cc data 1
54      *  byte[x+2]: cc data 2
55      */
56     int     i_data;
57     uint8_t p_data[CC_MAX_DATA_SIZE];
58 } cc_data_t;
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     c->i_payload_type = CC_PAYLOAD_NONE;
69     c->i_payload_other_count = 0;
70 }
71 static inline void cc_Exit( cc_data_t *c )
72 {
73     VLC_UNUSED(c);
74     return;
75 }
76 static inline void cc_Flush( cc_data_t *c )
77 {
78     c->i_data = 0;
79 }
80
81 static inline void cc_AppendData( cc_data_t *c, int i_field, const uint8_t cc[2] )
82 {
83     if( i_field == 0 || i_field == 1 )
84     {
85         c->pb_present[2*i_field+0] =
86         c->pb_present[2*i_field+1] = true;
87     }
88
89     c->p_data[c->i_data++] = i_field;
90     c->p_data[c->i_data++] = cc[0];
91     c->p_data[c->i_data++] = cc[1];
92 }
93
94 static inline void cc_Extract( cc_data_t *c, bool b_top_field_first, const uint8_t *p_src, int i_src )
95 {
96     static const uint8_t p_cc_ga94[4] = { 0x47, 0x41, 0x39, 0x34 };
97     static const uint8_t p_cc_dvd[4] = { 0x43, 0x43, 0x01, 0xf8 };
98     static const uint8_t p_cc_replaytv4a[2] = { 0xbb, 0x02 };
99     static const uint8_t p_cc_replaytv4b[2] = { 0xcc, 0x02 };
100     static const uint8_t p_cc_replaytv5a[2] = { 0x99, 0x02 };
101     static const uint8_t p_cc_replaytv5b[2] = { 0xaa, 0x02 };
102     static const uint8_t p_cc_scte20[2] = { 0x03, 0x81 };
103     static const uint8_t p_cc_scte20_old[2] = { 0x03, 0x01 };
104
105     if( i_src < 4 )
106         return;
107
108     int i_payload_type;
109     if( !memcmp( p_cc_ga94, p_src, 4 ) && i_src >= 5+1+1+1 && p_src[4] == 0x03 )
110     {
111         /* CC from DVB/ATSC TS */
112         i_payload_type = CC_PAYLOAD_GA94;
113     }
114     else if( !memcmp( p_cc_dvd, p_src, 4 ) && i_src > 4+1 )
115     {
116         i_payload_type = CC_PAYLOAD_DVD;
117     }
118     else if( i_src >= 2+2 + 2+2 &&
119              ( ( !memcmp( p_cc_replaytv4a, &p_src[0], 2 ) && !memcmp( p_cc_replaytv4b, &p_src[4], 2 ) ) ||
120                ( !memcmp( p_cc_replaytv5a, &p_src[0], 2 ) && !memcmp( p_cc_replaytv5b, &p_src[4], 2 ) ) ) )
121     {
122         i_payload_type = CC_PAYLOAD_REPLAYTV;
123     }
124     else if( ( !memcmp( p_cc_scte20, p_src, 2 ) ||
125                !memcmp( p_cc_scte20_old, p_src, 2 ) ) && i_src > 2 )
126     {
127         i_payload_type = CC_PAYLOAD_SCTE20;
128     }
129     else
130     {
131 #if 0
132 #define V(x) ( ( x < 0x20 || x >= 0x7f ) ? '?' : x )
133         fprintf( stderr, "-------------- unknown user data " );
134         for( int i = 0; i < i_src; i++ )
135             fprintf( stderr, "%2.2x ", p_src[i] );
136         for( int i = 0; i < i_src; i++ )
137             fprintf( stderr, "%c ", V(p_src[i]) );
138         fprintf( stderr, "\n" );
139 #undef V
140 #endif
141         return;
142     }
143
144     if( c->i_payload_type != CC_PAYLOAD_NONE && c->i_payload_type != i_payload_type )
145     {
146         c->i_payload_other_count++;
147         if( c->i_payload_other_count < 50 )
148             return;
149     }
150     c->i_payload_type        = i_payload_type;
151     c->i_payload_other_count = 0;
152
153     if( i_payload_type == CC_PAYLOAD_GA94 )
154     {
155         /* cc_data()
156          *          u1 reserved(1)
157          *          u1 process_cc_data_flag
158          *          u1 additional_data_flag
159          *          u5 cc_count
160          *          u8 reserved(1111 1111)
161          *          for cc_count
162          *              u5 marker bit(1111 1)
163          *              u1 cc_valid
164          *              u2 cc_type
165          *              u8 cc_data_1
166          *              u8 cc_data_2
167          *          u8 marker bit(1111 1111)
168          *          if additional_data_flag
169          *              unknown
170          */
171         /* cc_type:
172          *  0x00: field 1
173          *  0x01: field 2
174          */
175         const uint8_t *cc = &p_src[5];
176         const int i_count_cc = cc[0]&0x1f;
177         int i;
178
179         if( !(cc[0]&0x40) ) // process flag
180             return;
181         if( i_src < 5 + 1+1 + i_count_cc*3 + 1)  // broken packet
182             return;
183         if( i_count_cc <= 0 )   // no cc present
184             return;
185         if( cc[2+i_count_cc * 3] != 0xff )  // marker absent
186             return;
187         cc += 2;
188
189         for( i = 0; i < i_count_cc; i++, cc += 3 )
190         {
191             int i_field = cc[0] & 0x03;
192             if( ( cc[0] & 0xfc ) != 0xfc )
193                 continue;
194             if( i_field != 0 && i_field != 1 )
195                 continue;
196             if( c->i_data + 3 > CC_MAX_DATA_SIZE )
197                 continue;
198
199             cc_AppendData( c, i_field, &cc[1] );
200         }
201         c->b_reorder = true;
202     }
203     else if( i_payload_type == CC_PAYLOAD_DVD )
204     {
205         const int b_truncate = p_src[4] & 0x01;
206         const int i_field_first = (p_src[4] & 0x80) ? 0 : 1;
207         const int i_count_cc2 = (p_src[4] >> 1) & 0xf;
208         const uint8_t *cc = &p_src[5];
209         int i;
210
211         if( i_src < 4+1+6*i_count_cc2 - ( b_truncate ? 3 : 0) )
212             return;
213         for( i = 0; i < i_count_cc2; i++ )
214         {
215             int j;
216             for( j = 0; j < 2; j++, cc += 3 )
217             {
218                 const int i_field = j == i_field_first ? 0 : 1;
219
220                 if( b_truncate && i == i_count_cc2 - 1 && j == 1 )
221                     break;
222                 if( cc[0] != 0xff && cc[0] != 0xfe )
223                     continue;
224                 if( c->i_data + 3 > CC_MAX_DATA_SIZE )
225                     continue;
226
227                 cc_AppendData( c, i_field, &cc[1] );
228             }
229         }
230         c->b_reorder = false;
231     }
232     else if( i_payload_type == CC_PAYLOAD_REPLAYTV )
233     {
234         const uint8_t *cc = &p_src[0];
235         int i;
236         if( c->i_data + 2*3 > CC_MAX_DATA_SIZE )
237             return;
238
239         for( i = 0; i < 2; i++, cc += 4 )
240         {
241             const int i_field = i == 0 ? 1 : 0;
242
243             cc_AppendData( c, i_field, &cc[2] );
244         }
245         c->b_reorder = false;
246     }
247     else
248     {
249         bs_t s;
250         bs_init( &s, &p_src[2], i_src - 2 );
251         const int i_cc_count = bs_read( &s, 5 );
252         for( int i = 0; i < i_cc_count; i++ )
253         {
254             bs_skip( &s, 2 );
255             const int i_field_idx = bs_read( &s, 2 );
256             bs_skip( &s, 5 );
257             uint8_t cc[2];
258             for( int j = 0; j < 2; j++ )
259             {
260                 cc[j] = 0;
261                 for( int k = 0; k < 8; k++ )
262                     cc[j] |= bs_read( &s, 1 ) << k;
263             }
264             bs_skip( &s, 1 );
265
266             if( i_field_idx == 0 )
267                 continue;
268             if( c->i_data + 2*3 > CC_MAX_DATA_SIZE )
269                 continue;
270
271             /* 1,2,3 -> 0,1,0. I.E. repeated field 3 is merged with field 1 */
272             int i_field = ((i_field_idx - 1) & 1);
273             if (!b_top_field_first)
274                 i_field ^= 1;
275
276             cc_AppendData( c, i_field, &cc[0] );
277         }
278         c->b_reorder = true;
279     }
280 }
281
282 #endif /* _CC_H */
283