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