]> git.sesse.net Git - vlc/blob - modules/codec/spdif/spdif.c
1aadb2abf0987eeaf40bf4da62b46e1299dd149a
[vlc] / modules / codec / spdif / spdif.c
1 /*****************************************************************************
2  * spdif.c: A52 pass-through to external decoder with enabled soundcard
3  *****************************************************************************
4  * Copyright (C) 2001 VideoLAN
5  * $Id: spdif.c,v 1.2 2002/08/08 00:35:11 sam Exp $
6  *
7  * Authors: Stéphane Borel <stef@via.ecp.fr>
8  *          Juha Yrjola <jyrjola@cc.hut.fi>
9  *          German Gomez Garcia <german@piraos.com>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  * 
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
24  *****************************************************************************/
25
26 /*****************************************************************************
27  * Preamble
28  *****************************************************************************/
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>                                              /* memcpy() */
32 #include <fcntl.h>
33
34 #include <vlc/vlc.h>
35 #include <vlc/decoder.h>
36 #include <vlc/aout.h>
37
38 #ifdef HAVE_UNISTD_H
39 #   include <unistd.h>
40 #endif
41
42 #include "spdif.h"
43
44 /****************************************************************************
45  * Local prototypes
46  ****************************************************************************/
47 static int  OpenDecoder    ( vlc_object_t * );
48 static int  RunDecoder     ( decoder_fifo_t * );
49
50 static int  InitThread        ( spdif_thread_t * );
51 static void EndThread         ( spdif_thread_t * );
52 static void BitstreamCallback ( bit_stream_t *, vlc_bool_t );
53
54 int         parse_syncinfo    ( spdif_thread_t * );
55
56 /****************************************************************************
57  * Local structures and tables
58  ****************************************************************************/
59 static const frame_size_t p_frame_size_code[64] =
60 {
61         { 32  ,{64   ,69   ,96   } },
62         { 32  ,{64   ,70   ,96   } },
63         { 40  ,{80   ,87   ,120  } },
64         { 40  ,{80   ,88   ,120  } },
65         { 48  ,{96   ,104  ,144  } },
66         { 48  ,{96   ,105  ,144  } },
67         { 56  ,{112  ,121  ,168  } },
68         { 56  ,{112  ,122  ,168  } },
69         { 64  ,{128  ,139  ,192  } },
70         { 64  ,{128  ,140  ,192  } },
71         { 80  ,{160  ,174  ,240  } },
72         { 80  ,{160  ,175  ,240  } },
73         { 96  ,{192  ,208  ,288  } },
74         { 96  ,{192  ,209  ,288  } },
75         { 112 ,{224  ,243  ,336  } },
76         { 112 ,{224  ,244  ,336  } },
77         { 128 ,{256  ,278  ,384  } },
78         { 128 ,{256  ,279  ,384  } },
79         { 160 ,{320  ,348  ,480  } },
80         { 160 ,{320  ,349  ,480  } },
81         { 192 ,{384  ,417  ,576  } },
82         { 192 ,{384  ,418  ,576  } },
83         { 224 ,{448  ,487  ,672  } },
84         { 224 ,{448  ,488  ,672  } },
85         { 256 ,{512  ,557  ,768  } },
86         { 256 ,{512  ,558  ,768  } },
87         { 320 ,{640  ,696  ,960  } },
88         { 320 ,{640  ,697  ,960  } },
89         { 384 ,{768  ,835  ,1152 } },
90         { 384 ,{768  ,836  ,1152 } },
91         { 448 ,{896  ,975  ,1344 } },
92         { 448 ,{896  ,976  ,1344 } },
93         { 512 ,{1024 ,1114 ,1536 } },
94         { 512 ,{1024 ,1115 ,1536 } },
95         { 576 ,{1152 ,1253 ,1728 } },
96         { 576 ,{1152 ,1254 ,1728 } },
97         { 640 ,{1280 ,1393 ,1920 } },
98         { 640 ,{1280 ,1394 ,1920 } }
99 };
100
101 /*****************************************************************************
102  * Module descriptor
103  *****************************************************************************/
104 vlc_module_begin();
105     set_description( _("SPDIF pass-through A52 decoder") );
106     set_capability( "decoder", 0 );
107     set_callbacks( OpenDecoder, NULL );
108     add_shortcut( "pass_through" );
109     add_shortcut( "pass" );
110 vlc_module_end();
111
112 /*****************************************************************************
113  * OpenDecoder: probe the decoder and return score
114  *****************************************************************************
115  * Tries to launch a decoder and return score so that the interface is able 
116  * to chose.
117  *****************************************************************************/
118 static int OpenDecoder( vlc_object_t *p_this ) 
119 {   
120     decoder_fifo_t *p_fifo = (decoder_fifo_t*) p_this;
121
122     if( p_fifo->i_fourcc != VLC_FOURCC('a','5','2',' ') )
123     {   
124         return VLC_EGENERIC; 
125     }
126
127     p_fifo->pf_run = RunDecoder;
128     return VLC_SUCCESS;
129 }
130
131 /****************************************************************************
132  * RunDecoder: the whole thing
133  ****************************************************************************
134  * This function is called just after the thread is launched.
135  ****************************************************************************/
136 static int RunDecoder( decoder_fifo_t *p_fifo )
137 {
138     spdif_thread_t *   p_spdif;
139     mtime_t     i_frame_time;
140     vlc_bool_t  b_sync;
141     /* PTS of the current frame */
142     mtime_t     i_current_pts = 0;
143     u16         i_length;
144     
145     /* Allocate the memory needed to store the thread's structure */
146     p_spdif = malloc( sizeof(spdif_thread_t) );
147
148     if( p_spdif == NULL )
149     {
150         msg_Err( p_fifo, "out of memory" );
151         DecoderError( p_fifo );
152         return( -1 );
153     }
154   
155     p_spdif->p_fifo = p_fifo; 
156     
157     if (InitThread( p_spdif ) )
158     {
159         
160         if( p_fifo->b_error )
161         {
162             msg_Err( p_fifo, "could not initialize thread" );
163         }
164
165         DecoderError( p_fifo );
166         free( p_spdif );
167         return( -1 );
168     }
169
170     /* Compute the theorical duration of an A52 frame */
171     i_frame_time = 1000000 * A52_FRAME_SIZE /
172                              p_spdif->info.i_sample_rate;
173     i_length = p_spdif->info.i_frame_size;
174     
175     while( !p_spdif->p_fifo->b_die && !p_spdif->p_fifo->b_error )
176     {
177         p_spdif->p_bytes[0] = 0x0b;
178         p_spdif->p_bytes[1] = 0x77;
179         
180          /* Handle the dates */
181         if( p_spdif->i_real_pts )
182         {
183             mtime_t     i_delta = p_spdif->i_real_pts - i_current_pts -
184                                   i_frame_time;
185             if( i_delta > i_frame_time || i_delta < -i_frame_time )
186             {
187                 msg_Warn( p_fifo,
188                           "date discontinuity (%d)", i_delta );
189             }
190             i_current_pts = p_spdif->i_real_pts;
191             p_spdif->i_real_pts = 0;
192         }
193         else
194         {
195             i_current_pts += i_frame_time;
196         }
197
198         /* wait a little to avoid an input flood from the a52 input */
199         mwait( i_current_pts - 500000 );
200
201         vlc_mutex_lock (&p_spdif->p_aout_fifo->data_lock);
202         
203         p_spdif->p_aout_fifo->date[p_spdif->p_aout_fifo->i_end_frame] =
204             i_current_pts;
205
206         p_spdif->p_aout_fifo->i_end_frame = 
207                 (p_spdif->p_aout_fifo->i_end_frame + 1 ) & AOUT_FIFO_SIZE;
208         
209         p_spdif->p_bytes = ((u8*)(p_spdif->p_aout_fifo->buffer)) +
210                      (p_spdif->p_aout_fifo->i_end_frame * i_length );
211         
212         vlc_mutex_unlock (&p_spdif->p_aout_fifo->data_lock);
213
214         /* Find syncword again in case of stream discontinuity */
215         /* Here we have p_spdif->i_pts == 0
216          * Therefore a non-zero value after a call to GetBits() means the PES
217          * has changed. */
218         b_sync = 0;
219         while( !p_spdif->p_fifo->b_die
220             && !p_spdif->p_fifo->b_error
221             && !b_sync )
222         {
223             while( !p_spdif->p_fifo->b_die
224                 && !p_spdif->p_fifo->b_error
225                 && GetBits( &p_spdif->bit_stream, 8 ) != 0x0b );
226             p_spdif->i_real_pts = p_spdif->i_pts;
227             p_spdif->i_pts = 0;
228             b_sync = ( ShowBits( &p_spdif->bit_stream, 8 ) == 0x77 );
229         }
230         RemoveBits( &p_spdif->bit_stream, 8 );
231
232         /* Read data from bitstream */
233         GetChunk( &p_spdif->bit_stream, p_spdif->p_bytes + 2, i_length - 2 );
234     }
235
236     /* If b_error is set, the spdif thread enters the error loop */
237     if( p_spdif->p_fifo->b_error )
238     {
239         DecoderError( p_spdif->p_fifo );
240     }
241
242     /* End of the spdif decoder thread */
243     EndThread( p_spdif );
244     
245     return( 0 );
246 }
247
248 /****************************************************************************
249  * InitThread: initialize thread data and create output fifo
250  ****************************************************************************/
251 static int InitThread( spdif_thread_t * p_spdif )
252 {
253     vlc_bool_t b_sync = 0;
254
255     /* Temporary buffer to store first A52 frame */
256     p_spdif->p_bytes = malloc( SPDIF_FRAME_SIZE );
257
258     if( p_spdif->p_bytes == NULL )
259     {
260         free( p_spdif->p_bytes );
261         return( -1 );
262     }
263
264     /*
265      * Initialize the thread properties
266      */
267     p_spdif->p_fifo = p_spdif->p_fifo;
268
269     InitBitstream( &p_spdif->bit_stream, p_spdif->p_fifo,
270                    BitstreamCallback, (void*)p_spdif );
271
272     /* Find syncword */
273     while( !p_spdif->p_fifo->b_die
274         && !p_spdif->p_fifo->b_error
275         && !b_sync )
276     {
277         while( !p_spdif->p_fifo->b_die
278             && !p_spdif->p_fifo->b_error
279             && GetBits( &p_spdif->bit_stream, 8 ) != 0x0b );
280         p_spdif->i_real_pts = p_spdif->i_pts;
281         p_spdif->i_pts = 0;
282         b_sync = ( ShowBits( &p_spdif->bit_stream, 8 ) == 0x77 );
283     }
284
285     if( p_spdif->p_fifo->b_die || p_spdif->p_fifo->b_error )
286     {
287         return -1;
288     }
289
290     RemoveBits( &p_spdif->bit_stream, 8 );
291
292     /* Check stream properties */
293     if( parse_syncinfo( p_spdif ) < 0 )
294     {
295         msg_Err( p_spdif->p_fifo, "stream not valid" );
296
297         return( -1 );
298     }
299
300     /* Check that we can handle the rate 
301      * FIXME: we should check that we have the same rate for all fifos 
302      * but all rates should be supported by the decoder (32, 44.1, 48) */
303     if( p_spdif->info.i_sample_rate != 48000 )
304     {
305         msg_Err( p_spdif->p_fifo,
306                  "only 48000 Hz streams tested, expect weird things!" );
307     }
308
309     /* The audio output need to be ready for an A52 stream */
310     p_spdif->i_previous_format = config_GetInt( p_spdif->p_fifo,
311                                                 "audio-format" );
312     config_PutInt( p_spdif->p_fifo, "audio-format", 8 );
313     
314     /* Creating the audio output fifo */
315     p_spdif->p_aout_fifo =
316                     aout_CreateFifo( p_spdif->p_fifo, AOUT_FIFO_SPDIF,
317                                      1, p_spdif->info.i_sample_rate,
318                                      p_spdif->info.i_frame_size, NULL );
319
320     if( p_spdif->p_aout_fifo == NULL )
321     {
322         return( -1 );
323     }
324
325     msg_Dbg( p_spdif->p_fifo, "aout fifo #%d created",
326                               p_spdif->p_aout_fifo->i_fifo );
327
328     /* Put read data into fifo */
329     memcpy( (u8*)(p_spdif->p_aout_fifo->buffer) +
330                  (p_spdif->p_aout_fifo->i_end_frame *
331                    p_spdif->info.i_frame_size ),
332             p_spdif->p_bytes, sizeof(sync_frame_t) );
333     free( p_spdif->p_bytes );
334     p_spdif->p_bytes = ((u8*)(p_spdif->p_aout_fifo->buffer) +
335                              (p_spdif->p_aout_fifo->i_end_frame *
336                               p_spdif->info.i_frame_size ));
337
338     GetChunk( &p_spdif->bit_stream, p_spdif->p_bytes + sizeof(sync_frame_t),
339         p_spdif->info.i_frame_size - sizeof(sync_frame_t) );
340
341     return( 0 );
342 }
343
344 /*****************************************************************************
345  * EndThread : spdif thread destruction
346  *****************************************************************************/
347 static void EndThread( spdif_thread_t * p_spdif )
348 {
349     /* If the audio output fifo was created, we destroy it */
350     if( p_spdif->p_aout_fifo != NULL )
351     {
352         aout_DestroyFifo( p_spdif->p_aout_fifo );
353
354         /* Make sure the output thread leaves the NextFrame() function */
355         vlc_mutex_lock( &(p_spdif->p_aout_fifo->data_lock ) );
356         vlc_cond_signal( &(p_spdif->p_aout_fifo->data_wait ) );
357         vlc_mutex_unlock( &(p_spdif->p_aout_fifo->data_lock ) );
358         
359     }
360
361     /* restore previous setting for output format */
362     config_PutInt( p_spdif->p_fifo, "audio-format",
363                                     p_spdif->i_previous_format );
364
365     /* Destroy descriptor */
366     free( p_spdif );
367 }
368
369 /*****************************************************************************
370  * BitstreamCallback: Import parameters from the new data/PES packet
371  *****************************************************************************
372  * This function is called by input's NextDataPacket.
373  *****************************************************************************/
374 static void BitstreamCallback( bit_stream_t * p_bit_stream,
375                                vlc_bool_t b_new_pes )
376 {
377     spdif_thread_t *    p_spdif;
378
379     if( b_new_pes )
380     {
381         p_spdif = (spdif_thread_t *)p_bit_stream->p_callback_arg;
382
383 /*        p_bit_stream->p_byte += 3; */
384
385         p_spdif->i_pts =
386             p_bit_stream->p_decoder_fifo->p_first->i_pts;
387         p_bit_stream->p_decoder_fifo->p_first->i_pts = 0;
388     }
389 }
390
391 /****************************************************************************
392  * parse_syncinfo: parse A52 sync info
393  ****************************************************************************/
394 int parse_syncinfo( spdif_thread_t *p_spdif )
395 {
396     int             p_sample_rates[4] = { 48000, 44100, 32000, -1 };
397     int             i_frame_rate_code;
398     int             i_frame_size_code;
399     sync_frame_t *  p_sync_frame;
400
401     /* Read sync frame */
402     GetChunk( &p_spdif->bit_stream, p_spdif->p_bytes + 2,
403               sizeof(sync_frame_t) - 2 );
404     if( p_spdif->p_fifo->b_die ) return -1;
405
406     p_sync_frame = (sync_frame_t*)p_spdif->p_bytes;
407
408     /* Compute frame rate */
409     i_frame_rate_code = (p_sync_frame->syncinfo.code >> 6) & 0x03;
410     p_spdif->info.i_sample_rate = p_sample_rates[i_frame_rate_code];
411     if( p_spdif->info.i_sample_rate == -1 )
412     {
413         return -1;
414     }
415
416     /* Compute frame size */
417     i_frame_size_code = p_sync_frame->syncinfo.code & 0x3f;
418     p_spdif->info.i_frame_size = 2 *
419         p_frame_size_code[i_frame_size_code].i_frame_size[i_frame_rate_code];
420     p_spdif->info.i_bit_rate =
421         p_frame_size_code[i_frame_size_code].i_bit_rate;
422
423     if( ( ( p_sync_frame->bsi.bsidmod >> 3 ) & 0x1f ) != 0x08 )
424     {
425         return -1;
426     }
427
428     p_spdif->info.i_bs_mod = p_sync_frame->bsi.bsidmod & 0x7;
429
430     return 0;
431 }