]> git.sesse.net Git - vlc/blob - modules/demux/a52.c
Let the input handle meta data and attachments for ac3 audio
[vlc] / modules / demux / a52.c
1 /*****************************************************************************
2  * a52.c : raw A/52 stream input module for vlc
3  *****************************************************************************
4  * Copyright (C) 2001-2007 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Gildas Bazin <gbazin@netcourrier.com>
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 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <vlc/vlc.h>
28 #include <vlc_demux.h>
29 #include <vlc_codec.h>
30
31 #ifdef HAVE_UNISTD_H
32 #   include <unistd.h>
33 #endif
34
35 /*****************************************************************************
36  * Module descriptor
37  *****************************************************************************/
38 static int  Open  ( vlc_object_t * );
39 static void Close ( vlc_object_t * );
40
41 vlc_module_begin();
42     set_category( CAT_INPUT );
43     set_subcategory( SUBCAT_INPUT_DEMUX );
44     set_description( _("Raw A/52 demuxer") );
45     set_capability( "demux2", 145 );
46     set_callbacks( Open, Close );
47     add_shortcut( "a52" );
48 vlc_module_end();
49
50 /*****************************************************************************
51  * Local prototypes
52  *****************************************************************************/
53 static int Demux  ( demux_t * );
54 static int Control( demux_t *, int, va_list );
55
56 struct demux_sys_t
57 {
58     vlc_bool_t  b_start;
59     es_out_id_t *p_es;
60
61     /* Packetizer */
62     decoder_t *p_packetizer;
63
64     int i_mux_rate;
65     vlc_bool_t b_big_endian;
66 };
67
68 static int CheckSync( const uint8_t *p_peek, vlc_bool_t *p_big_endian );
69
70 #define PCM_FRAME_SIZE (1536 * 4)
71 #define A52_PACKET_SIZE (4 * PCM_FRAME_SIZE)
72 #define A52_MAX_HEADER_SIZE 10
73
74
75 /*****************************************************************************
76  * Open: initializes ES structures
77  *****************************************************************************/
78 static int Open( vlc_object_t * p_this )
79 {
80     demux_t     *p_demux = (demux_t*)p_this;
81     demux_sys_t *p_sys;
82     const byte_t*p_peek;
83     int         i_peek = 0;
84     vlc_bool_t  b_big_endian = 0; /* Arbitrary initialisation */
85
86     /* Check if we are dealing with a WAV file */
87     if( stream_Peek( p_demux->s, &p_peek, 12 ) == 12 &&
88         !memcmp( p_peek, "RIFF", 4 ) && !memcmp( p_peek + 8, "WAVE", 4 ) )
89     {
90         int i_size;
91
92         /* Skip the wave header */
93         i_peek = 12 + 8;
94         while( stream_Peek( p_demux->s, &p_peek, i_peek ) == i_peek &&
95                memcmp( p_peek + i_peek - 8, "data", 4 ) )
96         {
97             i_peek += GetDWLE( p_peek + i_peek - 4 ) + 8;
98         }
99
100         /* TODO: should check wave format and sample_rate */
101
102         /* Some A52 wav files don't begin with a sync code so we do a more
103          * extensive search */
104         i_size = stream_Peek( p_demux->s, &p_peek, i_peek + A52_PACKET_SIZE * 2);
105         i_size -= (PCM_FRAME_SIZE + A52_MAX_HEADER_SIZE);
106
107         while( i_peek < i_size )
108         {
109             if( CheckSync( p_peek + i_peek, &b_big_endian ) != VLC_SUCCESS )
110                 /* The data is stored in 16 bits words */
111                 i_peek += 2;
112             else
113             {
114                 /* Check following sync code */
115                 if( CheckSync( p_peek + i_peek + PCM_FRAME_SIZE,
116                                &b_big_endian ) != VLC_SUCCESS )
117                 {
118                     i_peek += 2;
119                     continue;
120                 }
121
122                 break;
123             }
124         }
125     }
126
127     /* Have a peep at the show. */
128     CHECK_PEEK( p_peek, i_peek + A52_MAX_HEADER_SIZE * 2 );
129
130     if( CheckSync( p_peek + i_peek, &b_big_endian ) != VLC_SUCCESS )
131     {
132         if( !p_demux->b_force )
133             return VLC_EGENERIC;
134
135         /* User forced */
136         msg_Err( p_demux, "this doesn't look like a A52 audio stream, "
137                  "continuing anyway" );
138     }
139
140     /* Fill p_demux fields */
141     DEMUX_INIT_COMMON(); p_sys = p_demux->p_sys;
142     p_sys->b_start = VLC_TRUE;
143     p_sys->i_mux_rate = 0;
144     p_sys->b_big_endian = b_big_endian;
145
146     /* Load the A52 packetizer */
147     INIT_APACKETIZER( p_sys->p_packetizer, 'a', '5', '2', ' ' );
148     LOAD_PACKETIZER_OR_FAIL( p_sys->p_packetizer, "A52" );
149
150     /* Create one program */
151     p_sys->p_es = es_out_Add( p_demux->out, &p_sys->p_packetizer->fmt_in );
152
153     return VLC_SUCCESS;
154 }
155
156 /*****************************************************************************
157  * Close: frees unused data
158  *****************************************************************************/
159 static void Close( vlc_object_t * p_this )
160 {
161     demux_t        *p_demux = (demux_t*)p_this;
162     demux_sys_t    *p_sys = p_demux->p_sys;
163
164     DESTROY_PACKETIZER( p_sys->p_packetizer );
165     free( p_sys );
166 }
167
168 /*****************************************************************************
169  * Demux: reads and demuxes data packets
170  *****************************************************************************
171  * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
172  *****************************************************************************/
173 static int Demux( demux_t *p_demux )
174 {
175     demux_sys_t *p_sys = p_demux->p_sys;
176     block_t     *p_block_in, *p_block_out;
177
178      /* Align stream */
179     int64_t i_pos = stream_Tell( p_demux->s );
180     if( i_pos % 2 ) stream_Read( p_demux->s, NULL, 1 );
181
182     if( !( p_block_in = stream_Block( p_demux->s, A52_PACKET_SIZE ) ) )
183     {
184         return 0;
185     }
186
187     if( !p_sys->b_big_endian && p_block_in->i_buffer )
188     {
189         /* Convert to big endian */
190
191 #ifdef HAVE_SWAB
192         swab(p_block_in->p_buffer, p_block_in->p_buffer, p_block_in->i_buffer);
193
194 #else
195         int i;
196         byte_t *p_tmp, tmp;
197         p_tmp = p_block_in->p_buffer;
198         for( i = p_block_in->i_buffer / 2 ; i-- ; )
199         {
200             tmp = p_tmp[0];
201             p_tmp[0] = p_tmp[1];
202             p_tmp[1] = tmp;
203             p_tmp += 2;
204         }
205 #endif
206     }
207
208     if( p_sys->b_start )
209         p_block_in->i_pts = p_block_in->i_dts = 1;
210     else
211         p_block_in->i_pts = p_block_in->i_dts = 0;
212
213     while( (p_block_out = p_sys->p_packetizer->pf_packetize(
214                 p_sys->p_packetizer, &p_block_in )) )
215     {
216         p_sys->b_start = VLC_FALSE;
217
218         while( p_block_out )
219         {
220             block_t *p_next = p_block_out->p_next;
221
222             /* We assume a constant bitrate */
223             if( p_block_out->i_length )
224             {
225                 p_sys->i_mux_rate =
226                     p_block_out->i_buffer * I64C(1000000)/p_block_out->i_length;
227             }
228
229             /* set PCR */
230             es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_block_out->i_dts );
231
232             es_out_Send( p_demux->out, p_sys->p_es, p_block_out );
233
234             p_block_out = p_next;
235         }
236     }
237
238     return 1;
239 }
240
241 /*****************************************************************************
242  * Control:
243  *****************************************************************************/
244 static int Control( demux_t *p_demux, int i_query, va_list args )
245 {
246     demux_sys_t *p_sys  = p_demux->p_sys;
247     if( i_query == DEMUX_SET_TIME )
248     {
249         return VLC_EGENERIC;
250     }
251     else if( i_query == DEMUX_HAS_UNSUPPORTED_META )
252     {
253         vlc_bool_t *pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t* );
254         *pb_bool = VLC_TRUE;
255         return VLC_SUCCESS;
256     }
257     else
258     {
259         return demux2_vaControlHelper( p_demux->s,
260                                        0, -1,
261                                        8*p_sys->i_mux_rate, 1, i_query, args );
262     }
263 }
264
265 /*****************************************************************************
266  * CheckSync: Check if buffer starts with an A52 sync code
267  *****************************************************************************/
268 static int CheckSync( const uint8_t *p_peek, vlc_bool_t *p_big_endian )
269 {
270     /* Little endian version of the bitstream */
271     if( p_peek[0] == 0x77 && p_peek[1] == 0x0b &&
272         p_peek[4] < 0x60 /* bsid < 12 */ )
273     {
274         *p_big_endian = VLC_FALSE;
275         return VLC_SUCCESS;
276     }
277     /* Big endian version of the bitstream */
278     else if( p_peek[0] == 0x0b && p_peek[1] == 0x77 &&
279              p_peek[5] < 0x60 /* bsid < 12 */ )
280     {
281         *p_big_endian = VLC_TRUE;
282         return VLC_SUCCESS;
283     }
284
285     return VLC_EGENERIC;
286 }
287
288