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