]> git.sesse.net Git - vlc/blob - modules/demux/a52.c
* modules/demux/a52.c: better detection code.
[vlc] / modules / demux / a52.c
1 /*****************************************************************************
2  * a52.c : raw A/52 stream input module for vlc
3  *****************************************************************************
4  * Copyright (C) 2001 VideoLAN
5  * $Id: a52.c,v 1.4 2004/02/13 22:37:35 gbazin Exp $
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., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <vlc/vlc.h>
28 #include <vlc/input.h>
29 #include <vlc_codec.h>
30
31 #ifdef HAVE_UNISTD_H
32 #   include <unistd.h>
33 #endif
34
35 #define PCM_FRAME_SIZE (1536 * 4)
36 #define A52_PACKET_SIZE (4 * PCM_FRAME_SIZE)
37 #define A52_MAX_HEADER_SIZE 10
38
39 /*****************************************************************************
40  * Local prototypes
41  *****************************************************************************/
42 static int  Open  ( vlc_object_t * );
43 static void Close ( vlc_object_t * );
44 static int  Demux ( input_thread_t * );
45
46 static int Control( input_thread_t *, int, va_list );
47
48 struct demux_sys_t
49 {
50     vlc_bool_t  b_start;
51     es_out_id_t *p_es;
52
53     /* Packetizer */
54     decoder_t *p_packetizer;
55
56     int i_mux_rate;
57     vlc_bool_t b_big_endian;
58 };
59
60 /*****************************************************************************
61  * Module descriptor
62  *****************************************************************************/
63 vlc_module_begin();
64     set_description( _("Raw A/52 demuxer") );
65     set_capability( "demux", 145 );
66     set_callbacks( Open, Close );
67     add_shortcut( "a52" );
68 vlc_module_end();
69
70 /*****************************************************************************
71  * CheckSync: Check if buffer starts with an A52 sync code
72  *****************************************************************************/
73 int CheckSync( uint8_t *p_peek, vlc_bool_t *p_big_endian )
74 {
75     /* Little endian version of the bitstream */
76     if( p_peek[0] == 0x77 && p_peek[1] == 0x0b &&
77         p_peek[4] < 0x60 /* bsid < 12 */ )
78     {
79         *p_big_endian = VLC_FALSE;
80         return VLC_SUCCESS;
81     }
82     /* Big endian version of the bitstream */
83     else if( p_peek[0] == 0x0b && p_peek[1] == 0x77 &&
84              p_peek[5] < 0x60 /* bsid < 12 */ )
85     {
86         *p_big_endian = VLC_TRUE;
87         return VLC_SUCCESS;
88     }
89
90     return VLC_EGENERIC;
91 }
92
93 /*****************************************************************************
94  * Open: initializes ES structures
95  *****************************************************************************/
96 static int Open( vlc_object_t * p_this )
97 {
98     input_thread_t *p_input = (input_thread_t *)p_this;
99     demux_sys_t    *p_sys;
100     byte_t *       p_peek;
101     int            i_peek = 0;
102     vlc_bool_t     b_big_endian;
103
104     p_input->pf_demux = Demux;
105     p_input->pf_demux_control = Control;
106     p_input->pf_rewind = NULL;
107
108     /* Check if we are dealing with a WAV file */
109     if( input_Peek( p_input, &p_peek, 12 ) == 12 &&
110         !strncmp( p_peek, "RIFF", 4 ) && !strncmp( &p_peek[8], "WAVE", 4 ) )
111     {
112         int i_size;
113
114         /* Skip the wave header */
115         i_peek = 12 + 8;
116         while( input_Peek( p_input, &p_peek, i_peek ) == i_peek &&
117                strncmp( p_peek + i_peek - 8, "data", 4 ) )
118         {
119             i_peek += GetDWLE( p_peek + i_peek - 4 ) + 8;
120         }
121
122         /* TODO: should check wave format and sample_rate */
123
124         /* Some A52 wav files don't begin with a sync code so we do a more
125          * extensive search */
126         i_size = input_Peek( p_input, &p_peek, i_peek + A52_PACKET_SIZE * 2);
127         i_size -= (PCM_FRAME_SIZE + A52_MAX_HEADER_SIZE);
128
129         while( i_peek < i_size )
130         {
131             if( CheckSync( p_peek + i_peek, &b_big_endian ) != VLC_SUCCESS )
132                 /* The data is stored in 16 bits words */
133                 i_peek += 2;
134             else
135             {
136                 /* Check following sync code */
137                 if( CheckSync( p_peek + i_peek + PCM_FRAME_SIZE,
138                                &b_big_endian ) != VLC_SUCCESS )
139                 {
140                     i_peek += 2;
141                     continue;
142                 }
143
144                 break;
145             }
146         }
147     }
148
149     /* Have a peep at the show. */
150     if( input_Peek( p_input, &p_peek, i_peek + A52_MAX_HEADER_SIZE * 2 ) <
151         i_peek + A52_MAX_HEADER_SIZE * 2 )
152     {
153         /* Stream too short */
154         msg_Warn( p_input, "cannot peek()" );
155         return VLC_EGENERIC;
156     }
157
158     if( CheckSync( p_peek + i_peek, &b_big_endian ) != VLC_SUCCESS )
159     {
160         if( p_input->psz_demux && !strncmp( p_input->psz_demux, "a52", 3 ) )
161         {
162             /* User forced */
163             msg_Err( p_input, "this doesn't look like a A52 audio stream, "
164                      "continuing anyway" );
165         }
166         else
167         {
168             return VLC_EGENERIC;
169         }
170     }
171
172     p_input->p_demux_data = p_sys = malloc( sizeof( demux_sys_t ) );
173     p_sys->b_start = VLC_TRUE;
174     p_sys->i_mux_rate = 0;
175     p_sys->b_big_endian = b_big_endian;
176
177     /*
178      * Load the A52 packetizer
179      */
180     p_sys->p_packetizer = vlc_object_create( p_input, VLC_OBJECT_DECODER );
181     p_sys->p_packetizer->pf_decode_audio = 0;
182     p_sys->p_packetizer->pf_decode_video = 0;
183     p_sys->p_packetizer->pf_decode_sub = 0;
184     p_sys->p_packetizer->pf_packetize = 0;
185
186     /* Initialization of decoder structure */
187     es_format_Init( &p_sys->p_packetizer->fmt_in, AUDIO_ES,
188                     VLC_FOURCC( 'a', '5', '2', ' ' ) );
189
190     p_sys->p_packetizer->p_module =
191         module_Need( p_sys->p_packetizer, "packetizer", NULL );
192     if( !p_sys->p_packetizer->p_module )
193     {
194         msg_Err( p_input, "cannot find A52 packetizer" );
195         return VLC_EGENERIC;
196     }
197
198     /* Create one program */
199     vlc_mutex_lock( &p_input->stream.stream_lock );
200     if( input_InitStream( p_input, 0 ) == -1 )
201     {
202         vlc_mutex_unlock( &p_input->stream.stream_lock );
203         msg_Err( p_input, "cannot init stream" );
204         return VLC_EGENERIC;
205     }
206     p_input->stream.i_mux_rate = 0;
207     vlc_mutex_unlock( &p_input->stream.stream_lock );
208
209     p_sys->p_es =
210         es_out_Add( p_input->p_es_out, &p_sys->p_packetizer->fmt_in );
211
212     return VLC_SUCCESS;
213 }
214
215 /*****************************************************************************
216  * Close: frees unused data
217  *****************************************************************************/
218 static void Close( vlc_object_t * p_this )
219 {
220     input_thread_t *p_input = (input_thread_t*)p_this;
221     demux_sys_t    *p_sys = p_input->p_demux_data;
222
223     /* Unneed module */
224     module_Unneed( p_sys->p_packetizer, p_sys->p_packetizer->p_module );
225
226     /* Delete the decoder */
227     vlc_object_destroy( p_sys->p_packetizer );
228
229     free( p_sys );
230 }
231
232 /*****************************************************************************
233  * Demux: reads and demuxes data packets
234  *****************************************************************************
235  * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
236  *****************************************************************************/
237 static int Demux( input_thread_t * p_input )
238 {
239     demux_sys_t  *p_sys = p_input->p_demux_data;
240     block_t *p_block_in, *p_block_out;
241
242      /* Align stream */
243     int64_t i_pos = stream_Tell( p_input->s );
244     if( i_pos % 2 ) stream_Read( p_input->s, NULL, 1 );
245
246     if( !( p_block_in = stream_Block( p_input->s, A52_PACKET_SIZE ) ) )
247     {
248         return 0;
249     }
250
251     if( !p_sys->b_big_endian && p_block_in->i_buffer )
252     {
253         /* Convert to big endian */
254
255 #ifdef HAVE_SWAB
256         swab(p_block_in->p_buffer, p_block_in->p_buffer, p_block_in->i_buffer);
257
258 #else
259         int i;
260         byte_t *p_tmp, tmp;
261         p_tmp = p_block_in->p_buffer;
262         for( i = p_block_in->i_buffer / 2 ; i-- ; )
263         {
264             tmp = p_tmp[0];
265             p_tmp[0] = p_tmp[1];
266             p_tmp[1] = tmp;
267             p_tmp += 2;
268         }
269 #endif
270     }
271
272     if( p_sys->b_start )
273         p_block_in->i_pts = p_block_in->i_dts = 1;
274     else
275         p_block_in->i_pts = p_block_in->i_dts = 0;
276
277     while( (p_block_out = p_sys->p_packetizer->pf_packetize(
278                 p_sys->p_packetizer, &p_block_in )) )
279     {
280         p_sys->b_start = VLC_FALSE;
281
282         while( p_block_out )
283         {
284             block_t *p_next = p_block_out->p_next;
285
286             /* We assume a constant bitrate */
287             if( p_block_out->i_length )
288             p_sys->i_mux_rate =
289                 p_block_out->i_buffer * I64C(1000000) / p_block_out->i_length;
290             p_input->stream.i_mux_rate = p_sys->i_mux_rate / 50;
291
292             input_ClockManageRef( p_input,
293                                   p_input->stream.p_selected_program,
294                                   p_block_out->i_pts * 9 / 100 );
295
296             p_block_in->b_discontinuity = 0;
297             p_block_out->i_dts = p_block_out->i_pts =
298                 input_ClockGetTS( p_input, p_input->stream.p_selected_program,
299                                   p_block_out->i_pts * 9 / 100 );
300
301             es_out_Send( p_input->p_es_out, p_sys->p_es, p_block_out );
302
303             p_block_out = p_next;
304         }
305     }
306
307     return 1;
308 }
309
310 /*****************************************************************************
311  * Control:
312  *****************************************************************************/
313 static int Control( input_thread_t *p_input, int i_query, va_list args )
314 {
315     demux_sys_t *p_sys  = (demux_sys_t *)p_input->p_demux_data;
316     int64_t *pi64;
317
318     switch( i_query )
319     {
320         case DEMUX_GET_TIME:
321             pi64 = (int64_t*)va_arg( args, int64_t * );
322             if( p_sys->i_mux_rate > 0 )
323             {
324                 *pi64 = I64C(1000000) * stream_Tell( p_input->s ) /
325                         p_sys->i_mux_rate;
326                 return VLC_SUCCESS;
327             }
328             *pi64 = 0;
329             return VLC_EGENERIC;
330
331         case DEMUX_GET_LENGTH:
332             pi64 = (int64_t*)va_arg( args, int64_t * );
333             if( p_sys->i_mux_rate > 0 )
334             {
335                 *pi64 = I64C(1000000) * stream_Size( p_input->s ) /
336                         p_sys->i_mux_rate;
337                 return VLC_SUCCESS;
338             }
339             *pi64 = 0;
340             return VLC_EGENERIC;
341
342         default:
343             return demux_vaControlDefault( p_input, i_query, args );
344     }
345 }