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