]> git.sesse.net Git - vlc/blob - modules/demux/a52.c
Some more demux and access code factorization
[vlc] / modules / demux / a52.c
1 /*****************************************************************************
2  * a52.c : raw A/52 stream input module for vlc
3  *****************************************************************************
4  * Copyright (C) 2001 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/input.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( 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     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( strncmp( p_demux->psz_demux, "a52", 3 ) )
133         {
134             return VLC_EGENERIC;
135         }
136
137         /* User forced */
138         msg_Err( p_demux, "this doesn't look like a A52 audio stream, "
139                  "continuing anyway" );
140     }
141
142     /* Fill p_demux fields */
143     STANDARD_DEMUX_INIT; p_sys = p_demux->p_sys;
144     p_sys->b_start = VLC_TRUE;
145     p_sys->i_mux_rate = 0;
146     p_sys->b_big_endian = b_big_endian;
147
148     /* Load the A52 packetizer */
149     INIT_APACKETIZER( p_sys->p_packetizer, 'a', '5', '2', ' ' );
150     LOAD_PACKETIZER_OR_FAIL( p_sys->p_packetizer, "A52" );
151
152     /* Create one program */
153     p_sys->p_es = es_out_Add( p_demux->out, &p_sys->p_packetizer->fmt_in );
154
155     return VLC_SUCCESS;
156 }
157
158 /*****************************************************************************
159  * Close: frees unused data
160  *****************************************************************************/
161 static void Close( vlc_object_t * p_this )
162 {
163     demux_t        *p_demux = (demux_t*)p_this;
164     demux_sys_t    *p_sys = p_demux->p_sys;
165
166     DESTROY_PACKETIZER( p_sys->p_packetizer );
167     free( p_sys );
168 }
169
170 /*****************************************************************************
171  * Demux: reads and demuxes data packets
172  *****************************************************************************
173  * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
174  *****************************************************************************/
175 static int Demux( demux_t *p_demux )
176 {
177     demux_sys_t *p_sys = p_demux->p_sys;
178     block_t     *p_block_in, *p_block_out;
179
180      /* Align stream */
181     int64_t i_pos = stream_Tell( p_demux->s );
182     if( i_pos % 2 ) stream_Read( p_demux->s, NULL, 1 );
183
184     if( !( p_block_in = stream_Block( p_demux->s, A52_PACKET_SIZE ) ) )
185     {
186         return 0;
187     }
188
189     if( !p_sys->b_big_endian && p_block_in->i_buffer )
190     {
191         /* Convert to big endian */
192
193 #ifdef HAVE_SWAB
194         swab(p_block_in->p_buffer, p_block_in->p_buffer, p_block_in->i_buffer);
195
196 #else
197         int i;
198         byte_t *p_tmp, tmp;
199         p_tmp = p_block_in->p_buffer;
200         for( i = p_block_in->i_buffer / 2 ; i-- ; )
201         {
202             tmp = p_tmp[0];
203             p_tmp[0] = p_tmp[1];
204             p_tmp[1] = tmp;
205             p_tmp += 2;
206         }
207 #endif
208     }
209
210     if( p_sys->b_start )
211         p_block_in->i_pts = p_block_in->i_dts = 1;
212     else
213         p_block_in->i_pts = p_block_in->i_dts = 0;
214
215     while( (p_block_out = p_sys->p_packetizer->pf_packetize(
216                 p_sys->p_packetizer, &p_block_in )) )
217     {
218         p_sys->b_start = VLC_FALSE;
219
220         while( p_block_out )
221         {
222             block_t *p_next = p_block_out->p_next;
223
224             /* We assume a constant bitrate */
225             if( p_block_out->i_length )
226             {
227                 p_sys->i_mux_rate =
228                     p_block_out->i_buffer * I64C(1000000)/p_block_out->i_length;
229             }
230
231             /* set PCR */
232             es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_block_out->i_dts );
233
234             es_out_Send( p_demux->out, p_sys->p_es, p_block_out );
235
236             p_block_out = p_next;
237         }
238     }
239
240     return 1;
241 }
242
243 /*****************************************************************************
244  * Control:
245  *****************************************************************************/
246 static int Control( demux_t *p_demux, int i_query, va_list args )
247 {
248     demux_sys_t *p_sys  = p_demux->p_sys;
249     if( i_query == DEMUX_SET_TIME )
250         return VLC_EGENERIC;
251     else
252         return demux2_vaControlHelper( p_demux->s,
253                                        0, -1,
254                                        8*p_sys->i_mux_rate, 1, i_query, args );
255 }
256
257 /*****************************************************************************
258  * CheckSync: Check if buffer starts with an A52 sync code
259  *****************************************************************************/
260 static int CheckSync( uint8_t *p_peek, vlc_bool_t *p_big_endian )
261 {
262     /* Little endian version of the bitstream */
263     if( p_peek[0] == 0x77 && p_peek[1] == 0x0b &&
264         p_peek[4] < 0x60 /* bsid < 12 */ )
265     {
266         *p_big_endian = VLC_FALSE;
267         return VLC_SUCCESS;
268     }
269     /* Big endian version of the bitstream */
270     else if( p_peek[0] == 0x0b && p_peek[1] == 0x77 &&
271              p_peek[5] < 0x60 /* bsid < 12 */ )
272     {
273         *p_big_endian = VLC_TRUE;
274         return VLC_SUCCESS;
275     }
276
277     return VLC_EGENERIC;
278 }
279
280