]> git.sesse.net Git - vlc/blob - modules/codec/lpcm.c
A bit of headers cleanup
[vlc] / modules / codec / lpcm.c
1 /*****************************************************************************
2  * lpcm.c: lpcm decoder/packetizer module
3  *****************************************************************************
4  * Copyright (C) 1999-2005 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Samuel Hocevar <sam@zoy.org>
8  *          Henri Fallon <henri@videolan.org>
9  *          Christophe Massiot <massiot@via.ecp.fr>
10  *          Gildas Bazin <gbazin@videolan.org>
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
25  *****************************************************************************/
26
27 /*****************************************************************************
28  * Preamble
29  *****************************************************************************/
30 #include <vlc/vlc.h>
31 #include <vlc_codec.h>
32 #include <vlc_aout.h>
33
34 /*****************************************************************************
35  * decoder_sys_t : lpcm decoder descriptor
36  *****************************************************************************/
37 struct decoder_sys_t
38 {
39     /* Module mode */
40     vlc_bool_t b_packetizer;
41
42     /*
43      * Output properties
44      */
45     audio_date_t end_date;
46
47 };
48
49 /*
50  * LPCM header :
51  * - PES header
52  * - private stream ID (16 bits) == 0xA0 -> not in the bitstream
53  *
54  * - frame number (8 bits)
55  * - unknown (16 bits) == 0x0003 ?
56  * - unknown (4 bits)
57  * - current frame (4 bits)
58  * - unknown (2 bits)
59  * - frequency (2 bits) 0 == 48 kHz, 1 == 32 kHz, 2 == ?, 3 == ?
60  * - unknown (1 bit)
61  * - number of channels - 1 (3 bits) 1 == 2 channels
62  * - start code (8 bits) == 0x80
63  */
64
65 #define LPCM_HEADER_LEN 6
66
67 /*****************************************************************************
68  * Local prototypes
69  *****************************************************************************/
70 static int  OpenDecoder   ( vlc_object_t * );
71 static int  OpenPacketizer( vlc_object_t * );
72 static void CloseDecoder  ( vlc_object_t * );
73
74 static void *DecodeFrame  ( decoder_t *, block_t ** );
75
76 /*****************************************************************************
77  * Module descriptor
78  *****************************************************************************/
79 vlc_module_begin();
80
81     set_category( CAT_INPUT );
82     set_subcategory( SUBCAT_INPUT_ACODEC );
83     set_description( _("Linear PCM audio decoder") );
84     set_capability( "decoder", 100 );
85     set_callbacks( OpenDecoder, CloseDecoder );
86
87     add_submodule();
88     set_description( _("Linear PCM audio packetizer") );
89     set_capability( "packetizer", 100 );
90     set_callbacks( OpenPacketizer, CloseDecoder );
91
92 vlc_module_end();
93
94 /*****************************************************************************
95  * OpenDecoder: probe the decoder and return score
96  *****************************************************************************/
97 static int OpenDecoder( vlc_object_t *p_this )
98 {
99     decoder_t *p_dec = (decoder_t*)p_this;
100     decoder_sys_t *p_sys;
101
102     if( p_dec->fmt_in.i_codec != VLC_FOURCC('l','p','c','m')
103          && p_dec->fmt_in.i_codec != VLC_FOURCC('l','p','c','b') )
104     {   
105         return VLC_EGENERIC;
106     }
107
108     /* Allocate the memory needed to store the decoder's structure */
109     if( ( p_dec->p_sys = p_sys =
110           (decoder_sys_t *)malloc(sizeof(decoder_sys_t)) ) == NULL )
111     {
112         msg_Err( p_dec, "out of memory" );
113         return VLC_EGENERIC;
114     }
115
116     /* Misc init */
117     p_sys->b_packetizer = VLC_FALSE;
118     aout_DateSet( &p_sys->end_date, 0 );
119
120     /* Set output properties */
121     p_dec->fmt_out.i_cat = AUDIO_ES;
122
123     if( p_dec->fmt_out.audio.i_bitspersample == 24 )
124     {
125         p_dec->fmt_out.i_codec = VLC_FOURCC('s','2','4','b');
126     }
127     else
128     {
129         p_dec->fmt_out.i_codec = VLC_FOURCC('s','1','6','b');
130         p_dec->fmt_out.audio.i_bitspersample = 16;
131     }
132
133     /* Set callback */
134     p_dec->pf_decode_audio = (aout_buffer_t *(*)(decoder_t *, block_t **))
135         DecodeFrame;
136     p_dec->pf_packetize    = (block_t *(*)(decoder_t *, block_t **))
137         DecodeFrame;
138
139     return VLC_SUCCESS;
140 }
141
142 static int OpenPacketizer( vlc_object_t *p_this )
143 {
144     decoder_t *p_dec = (decoder_t*)p_this;
145
146     int i_ret = OpenDecoder( p_this );
147
148     if( i_ret != VLC_SUCCESS ) return i_ret;
149
150     p_dec->p_sys->b_packetizer = VLC_TRUE;
151
152     p_dec->fmt_out.i_codec = VLC_FOURCC('l','p','c','m');
153
154     return i_ret;
155 }
156
157 /*****************************************************************************
158  * DecodeFrame: decodes an lpcm frame.
159  ****************************************************************************
160  * Beware, this function must be fed with complete frames (PES packet).
161  *****************************************************************************/
162 static void *DecodeFrame( decoder_t *p_dec, block_t **pp_block )
163 {
164     decoder_sys_t *p_sys = p_dec->p_sys;
165     block_t       *p_block;
166     unsigned int  i_rate = 0, i_original_channels = 0, i_channels = 0;
167     int           i_frame_length, i_bitspersample;
168     uint8_t       i_header;
169
170     if( !pp_block || !*pp_block ) return NULL;
171
172     p_block = *pp_block;
173     *pp_block = NULL; /* So the packet doesn't get re-sent */
174
175     /* Date management */
176     if( p_block->i_pts > 0 &&
177         p_block->i_pts != aout_DateGet( &p_sys->end_date ) )
178     {
179         aout_DateSet( &p_sys->end_date, p_block->i_pts );
180     }
181
182     if( !aout_DateGet( &p_sys->end_date ) )
183     {
184         /* We've just started the stream, wait for the first PTS. */
185         block_Release( p_block );
186         return NULL;
187     }
188
189     if( p_block->i_buffer <= LPCM_HEADER_LEN )
190     {
191         msg_Err(p_dec, "frame is too short");
192         block_Release( p_block );
193         return NULL;
194     }
195
196     i_header = p_block->p_buffer[4];
197     switch ( (i_header >> 4) & 0x3 )
198     {
199     case 0:
200         i_rate = 48000;
201         break;
202     case 1:
203         i_rate = 96000;
204         break;
205     case 2:
206         i_rate = 44100;
207         break;
208     case 3:
209         i_rate = 32000;
210         break;
211     }
212
213     i_channels = (i_header & 0x7);
214     switch ( i_channels )
215     {
216     case 0:
217         i_original_channels = AOUT_CHAN_CENTER;
218         break;
219     case 1:
220         i_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
221         break;
222     case 2:
223         /* This is unsure. */
224         i_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_LFE;
225         break;
226     case 3:
227         i_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
228                                | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
229         break;
230     case 4:
231         /* This is unsure. */
232         i_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
233                                | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
234                                | AOUT_CHAN_LFE;
235         break;
236     case 5:
237         i_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
238                                | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
239                                | AOUT_CHAN_CENTER | AOUT_CHAN_LFE;
240         break;
241     case 6:
242         i_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
243                                | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
244                                | AOUT_CHAN_CENTER | AOUT_CHAN_MIDDLELEFT
245                                | AOUT_CHAN_MIDDLERIGHT;
246         break;
247     case 7:
248         i_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
249                                | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
250                                | AOUT_CHAN_CENTER | AOUT_CHAN_MIDDLELEFT
251                                | AOUT_CHAN_MIDDLERIGHT | AOUT_CHAN_LFE;
252         break;
253     }
254
255     switch ( (i_header >> 6) & 0x3 )
256     {
257     case 2:
258         p_dec->fmt_out.i_codec = VLC_FOURCC('s','2','4','b');
259         p_dec->fmt_out.audio.i_bitspersample = 24;
260         i_bitspersample = 24;
261         break;
262     case 1:
263         p_dec->fmt_out.i_codec = VLC_FOURCC('s','2','4','b');
264         p_dec->fmt_out.audio.i_bitspersample = 24;
265         i_bitspersample = 20;
266         break;
267     case 0:
268     default:
269         p_dec->fmt_out.i_codec = VLC_FOURCC('s','1','6','b');
270         p_dec->fmt_out.audio.i_bitspersample = 16;
271         i_bitspersample = 16;
272         break;
273     }
274
275     /* Check frame sync and drop it. */
276     if( p_block->p_buffer[5] != 0x80 )
277     {
278         msg_Warn( p_dec, "no frame sync" );
279         block_Release( p_block );
280         return NULL;
281     }
282
283     /* Set output properties */
284     if( p_dec->fmt_out.audio.i_rate != i_rate )
285     {
286         aout_DateInit( &p_sys->end_date, i_rate );
287         aout_DateSet( &p_sys->end_date, p_block->i_pts );
288     }
289     p_dec->fmt_out.audio.i_rate = i_rate;
290     p_dec->fmt_out.audio.i_channels = i_channels + 1;
291     p_dec->fmt_out.audio.i_original_channels = i_original_channels;
292     p_dec->fmt_out.audio.i_physical_channels
293         = i_original_channels & AOUT_CHAN_PHYSMASK;
294
295     i_frame_length = (p_block->i_buffer - LPCM_HEADER_LEN) /
296         p_dec->fmt_out.audio.i_channels * 8 / i_bitspersample;
297
298     if( p_sys->b_packetizer )
299     {
300         p_dec->fmt_out.i_codec = VLC_FOURCC('l','p','c','m');
301         p_block->i_pts = p_block->i_dts = aout_DateGet( &p_sys->end_date );
302         p_block->i_length =
303             aout_DateIncrement( &p_sys->end_date, i_frame_length ) -
304             p_block->i_pts;
305
306         /* Just pass on the incoming frame */
307         return p_block;
308     }
309     else
310     {
311         aout_buffer_t *p_aout_buffer;
312         p_aout_buffer = p_dec->pf_aout_buffer_new( p_dec, i_frame_length );
313         if( p_aout_buffer == NULL ) return NULL;
314
315         p_aout_buffer->start_date = aout_DateGet( &p_sys->end_date );
316         p_aout_buffer->end_date =
317             aout_DateIncrement( &p_sys->end_date, i_frame_length );
318
319         p_block->p_buffer += LPCM_HEADER_LEN;
320         p_block->i_buffer -= LPCM_HEADER_LEN;
321
322         /* 20/24 bits LPCM use special packing */
323         if( i_bitspersample == 24 )
324         {
325             uint8_t *p_out = p_aout_buffer->p_buffer;
326
327             while( p_block->i_buffer / 12 )
328             {
329                 /* Sample 1 */
330                 p_out[0] = p_block->p_buffer[0];
331                 p_out[1] = p_block->p_buffer[1];
332                 p_out[2] = p_block->p_buffer[8];
333                 /* Sample 2 */
334                 p_out[3] = p_block->p_buffer[2];
335                 p_out[4] = p_block->p_buffer[3];
336                 p_out[5] = p_block->p_buffer[9];
337                 /* Sample 3 */
338                 p_out[6] = p_block->p_buffer[4];
339                 p_out[7] = p_block->p_buffer[5];
340                 p_out[8] = p_block->p_buffer[10];
341                 /* Sample 4 */
342                 p_out[9] = p_block->p_buffer[6];
343                 p_out[10] = p_block->p_buffer[7];
344                 p_out[11] = p_block->p_buffer[11];
345
346                 p_block->i_buffer -= 12;
347                 p_block->p_buffer += 12;
348                 p_out += 12;
349             }
350         }
351         else if( i_bitspersample == 20 )
352         {
353             uint8_t *p_out = p_aout_buffer->p_buffer;
354
355             while( p_block->i_buffer / 10 )
356             {
357                 /* Sample 1 */
358                 p_out[0] = p_block->p_buffer[0];
359                 p_out[1] = p_block->p_buffer[1];
360                 p_out[2] = p_block->p_buffer[8] & 0xF0;
361                 /* Sample 2 */
362                 p_out[3] = p_block->p_buffer[2];
363                 p_out[4] = p_block->p_buffer[3];
364                 p_out[5] = p_block->p_buffer[8] << 4;
365                 /* Sample 3 */
366                 p_out[6] = p_block->p_buffer[4];
367                 p_out[7] = p_block->p_buffer[5];
368                 p_out[8] = p_block->p_buffer[9] & 0xF0;
369                 /* Sample 4 */
370                 p_out[9] = p_block->p_buffer[6];
371                 p_out[10] = p_block->p_buffer[7];
372                 p_out[11] = p_block->p_buffer[9] << 4;
373
374                 p_block->i_buffer -= 10;
375                 p_block->p_buffer += 10;
376                 p_out += 12;
377             }
378         }
379         else
380         {
381             memcpy( p_aout_buffer->p_buffer,
382                     p_block->p_buffer, p_block->i_buffer );
383         }
384
385         block_Release( p_block );
386         return p_aout_buffer;
387     }
388 }
389
390 /*****************************************************************************
391  * CloseDecoder : lpcm decoder destruction
392  *****************************************************************************/
393 static void CloseDecoder( vlc_object_t *p_this )
394 {
395     decoder_t *p_dec = (decoder_t*)p_this;
396     free( p_dec->p_sys );
397 }