]> git.sesse.net Git - vlc/blob - modules/demux/a52.c
Add a bunch of helper functions/macros and start using them:
[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     p_sys->p_packetizer = vlc_object_create( p_demux, VLC_OBJECT_DECODER );
150     p_sys->p_packetizer->pf_decode_audio = 0;
151     p_sys->p_packetizer->pf_decode_video = 0;
152     p_sys->p_packetizer->pf_decode_sub = 0;
153     p_sys->p_packetizer->pf_packetize = 0;
154
155     /* Initialization of decoder structure */
156     es_format_Init( &p_sys->p_packetizer->fmt_in, AUDIO_ES,
157                     VLC_FOURCC( 'a', '5', '2', ' ' ) );
158
159     p_sys->p_packetizer->p_module =
160         module_Need( p_sys->p_packetizer, "packetizer", NULL, 0 );
161     if( !p_sys->p_packetizer->p_module )
162     {
163         msg_Err( p_demux, "cannot find A52 packetizer" );
164         return VLC_EGENERIC;
165     }
166
167     /* Create one program */
168     p_sys->p_es = es_out_Add( p_demux->out, &p_sys->p_packetizer->fmt_in );
169
170     return VLC_SUCCESS;
171 }
172
173 /*****************************************************************************
174  * Close: frees unused data
175  *****************************************************************************/
176 static void Close( vlc_object_t * p_this )
177 {
178     demux_t        *p_demux = (demux_t*)p_this;
179     demux_sys_t    *p_sys = p_demux->p_sys;
180
181     /* Unneed module */
182     module_Unneed( p_sys->p_packetizer, p_sys->p_packetizer->p_module );
183
184     /* Delete the decoder */
185     vlc_object_destroy( p_sys->p_packetizer );
186
187     free( p_sys );
188 }
189
190 /*****************************************************************************
191  * Demux: reads and demuxes data packets
192  *****************************************************************************
193  * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
194  *****************************************************************************/
195 static int Demux( demux_t *p_demux )
196 {
197     demux_sys_t *p_sys = p_demux->p_sys;
198     block_t     *p_block_in, *p_block_out;
199
200      /* Align stream */
201     int64_t i_pos = stream_Tell( p_demux->s );
202     if( i_pos % 2 ) stream_Read( p_demux->s, NULL, 1 );
203
204     if( !( p_block_in = stream_Block( p_demux->s, A52_PACKET_SIZE ) ) )
205     {
206         return 0;
207     }
208
209     if( !p_sys->b_big_endian && p_block_in->i_buffer )
210     {
211         /* Convert to big endian */
212
213 #ifdef HAVE_SWAB
214         swab(p_block_in->p_buffer, p_block_in->p_buffer, p_block_in->i_buffer);
215
216 #else
217         int i;
218         byte_t *p_tmp, tmp;
219         p_tmp = p_block_in->p_buffer;
220         for( i = p_block_in->i_buffer / 2 ; i-- ; )
221         {
222             tmp = p_tmp[0];
223             p_tmp[0] = p_tmp[1];
224             p_tmp[1] = tmp;
225             p_tmp += 2;
226         }
227 #endif
228     }
229
230     if( p_sys->b_start )
231         p_block_in->i_pts = p_block_in->i_dts = 1;
232     else
233         p_block_in->i_pts = p_block_in->i_dts = 0;
234
235     while( (p_block_out = p_sys->p_packetizer->pf_packetize(
236                 p_sys->p_packetizer, &p_block_in )) )
237     {
238         p_sys->b_start = VLC_FALSE;
239
240         while( p_block_out )
241         {
242             block_t *p_next = p_block_out->p_next;
243
244             /* We assume a constant bitrate */
245             if( p_block_out->i_length )
246             {
247                 p_sys->i_mux_rate =
248                     p_block_out->i_buffer * I64C(1000000)/p_block_out->i_length;
249             }
250
251             /* set PCR */
252             es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_block_out->i_dts );
253
254             es_out_Send( p_demux->out, p_sys->p_es, p_block_out );
255
256             p_block_out = p_next;
257         }
258     }
259
260     return 1;
261 }
262
263 /*****************************************************************************
264  * Control:
265  *****************************************************************************/
266 static int Control( demux_t *p_demux, int i_query, va_list args )
267 {
268     demux_sys_t *p_sys  = p_demux->p_sys;
269     if( i_query == DEMUX_SET_TIME )
270         return VLC_EGENERIC;
271     else
272         return demux2_vaControlHelper( p_demux->s,
273                                        0, -1,
274                                        8*p_sys->i_mux_rate, 1, i_query, args );
275 }
276
277 /*****************************************************************************
278  * CheckSync: Check if buffer starts with an A52 sync code
279  *****************************************************************************/
280 static int CheckSync( uint8_t *p_peek, vlc_bool_t *p_big_endian )
281 {
282     /* Little endian version of the bitstream */
283     if( p_peek[0] == 0x77 && p_peek[1] == 0x0b &&
284         p_peek[4] < 0x60 /* bsid < 12 */ )
285     {
286         *p_big_endian = VLC_FALSE;
287         return VLC_SUCCESS;
288     }
289     /* Big endian version of the bitstream */
290     else if( p_peek[0] == 0x0b && p_peek[1] == 0x77 &&
291              p_peek[5] < 0x60 /* bsid < 12 */ )
292     {
293         *p_big_endian = VLC_TRUE;
294         return VLC_SUCCESS;
295     }
296
297     return VLC_EGENERIC;
298 }
299
300