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 $
7 * Authors: Stéphane Borel <stef@via.ecp.fr>
8 * Juha Yrjola <jyrjola@cc.hut.fi>
9 * German Gomez Garcia <german@piraos.com>
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.
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.
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 *****************************************************************************/
26 /*****************************************************************************
28 *****************************************************************************/
31 #include <string.h> /* memcpy() */
35 #include <vlc/decoder.h>
44 /****************************************************************************
46 ****************************************************************************/
47 static int OpenDecoder ( vlc_object_t * );
48 static int RunDecoder ( decoder_fifo_t * );
50 static int InitThread ( spdif_thread_t * );
51 static void EndThread ( spdif_thread_t * );
52 static void BitstreamCallback ( bit_stream_t *, vlc_bool_t );
54 int parse_syncinfo ( spdif_thread_t * );
56 /****************************************************************************
57 * Local structures and tables
58 ****************************************************************************/
59 static const frame_size_t p_frame_size_code[64] =
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 } }
101 /*****************************************************************************
103 *****************************************************************************/
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" );
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
117 *****************************************************************************/
118 static int OpenDecoder( vlc_object_t *p_this )
120 decoder_fifo_t *p_fifo = (decoder_fifo_t*) p_this;
122 if( p_fifo->i_fourcc != VLC_FOURCC('a','5','2',' ') )
127 p_fifo->pf_run = RunDecoder;
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 )
138 spdif_thread_t * p_spdif;
139 mtime_t i_frame_time;
141 /* PTS of the current frame */
142 mtime_t i_current_pts = 0;
145 /* Allocate the memory needed to store the thread's structure */
146 p_spdif = malloc( sizeof(spdif_thread_t) );
148 if( p_spdif == NULL )
150 msg_Err( p_fifo, "out of memory" );
151 DecoderError( p_fifo );
155 p_spdif->p_fifo = p_fifo;
157 if (InitThread( p_spdif ) )
160 if( p_fifo->b_error )
162 msg_Err( p_fifo, "could not initialize thread" );
165 DecoderError( p_fifo );
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;
175 while( !p_spdif->p_fifo->b_die && !p_spdif->p_fifo->b_error )
177 p_spdif->p_bytes[0] = 0x0b;
178 p_spdif->p_bytes[1] = 0x77;
180 /* Handle the dates */
181 if( p_spdif->i_real_pts )
183 mtime_t i_delta = p_spdif->i_real_pts - i_current_pts -
185 if( i_delta > i_frame_time || i_delta < -i_frame_time )
188 "date discontinuity (%d)", i_delta );
190 i_current_pts = p_spdif->i_real_pts;
191 p_spdif->i_real_pts = 0;
195 i_current_pts += i_frame_time;
198 /* wait a little to avoid an input flood from the a52 input */
199 mwait( i_current_pts - 500000 );
201 vlc_mutex_lock (&p_spdif->p_aout_fifo->data_lock);
203 p_spdif->p_aout_fifo->date[p_spdif->p_aout_fifo->i_end_frame] =
206 p_spdif->p_aout_fifo->i_end_frame =
207 (p_spdif->p_aout_fifo->i_end_frame + 1 ) & AOUT_FIFO_SIZE;
209 p_spdif->p_bytes = ((u8*)(p_spdif->p_aout_fifo->buffer)) +
210 (p_spdif->p_aout_fifo->i_end_frame * i_length );
212 vlc_mutex_unlock (&p_spdif->p_aout_fifo->data_lock);
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
219 while( !p_spdif->p_fifo->b_die
220 && !p_spdif->p_fifo->b_error
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;
228 b_sync = ( ShowBits( &p_spdif->bit_stream, 8 ) == 0x77 );
230 RemoveBits( &p_spdif->bit_stream, 8 );
232 /* Read data from bitstream */
233 GetChunk( &p_spdif->bit_stream, p_spdif->p_bytes + 2, i_length - 2 );
236 /* If b_error is set, the spdif thread enters the error loop */
237 if( p_spdif->p_fifo->b_error )
239 DecoderError( p_spdif->p_fifo );
242 /* End of the spdif decoder thread */
243 EndThread( p_spdif );
248 /****************************************************************************
249 * InitThread: initialize thread data and create output fifo
250 ****************************************************************************/
251 static int InitThread( spdif_thread_t * p_spdif )
253 vlc_bool_t b_sync = 0;
255 /* Temporary buffer to store first A52 frame */
256 p_spdif->p_bytes = malloc( SPDIF_FRAME_SIZE );
258 if( p_spdif->p_bytes == NULL )
260 free( p_spdif->p_bytes );
265 * Initialize the thread properties
267 p_spdif->p_fifo = p_spdif->p_fifo;
269 InitBitstream( &p_spdif->bit_stream, p_spdif->p_fifo,
270 BitstreamCallback, (void*)p_spdif );
273 while( !p_spdif->p_fifo->b_die
274 && !p_spdif->p_fifo->b_error
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;
282 b_sync = ( ShowBits( &p_spdif->bit_stream, 8 ) == 0x77 );
285 if( p_spdif->p_fifo->b_die || p_spdif->p_fifo->b_error )
290 RemoveBits( &p_spdif->bit_stream, 8 );
292 /* Check stream properties */
293 if( parse_syncinfo( p_spdif ) < 0 )
295 msg_Err( p_spdif->p_fifo, "stream not valid" );
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 )
305 msg_Err( p_spdif->p_fifo,
306 "only 48000 Hz streams tested, expect weird things!" );
309 /* The audio output need to be ready for an A52 stream */
310 p_spdif->i_previous_format = config_GetInt( p_spdif->p_fifo,
312 config_PutInt( p_spdif->p_fifo, "audio-format", 8 );
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 );
320 if( p_spdif->p_aout_fifo == NULL )
325 msg_Dbg( p_spdif->p_fifo, "aout fifo #%d created",
326 p_spdif->p_aout_fifo->i_fifo );
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 ));
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) );
344 /*****************************************************************************
345 * EndThread : spdif thread destruction
346 *****************************************************************************/
347 static void EndThread( spdif_thread_t * p_spdif )
349 /* If the audio output fifo was created, we destroy it */
350 if( p_spdif->p_aout_fifo != NULL )
352 aout_DestroyFifo( p_spdif->p_aout_fifo );
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 ) );
361 /* restore previous setting for output format */
362 config_PutInt( p_spdif->p_fifo, "audio-format",
363 p_spdif->i_previous_format );
365 /* Destroy descriptor */
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 )
377 spdif_thread_t * p_spdif;
381 p_spdif = (spdif_thread_t *)p_bit_stream->p_callback_arg;
383 /* p_bit_stream->p_byte += 3; */
386 p_bit_stream->p_decoder_fifo->p_first->i_pts;
387 p_bit_stream->p_decoder_fifo->p_first->i_pts = 0;
391 /****************************************************************************
392 * parse_syncinfo: parse A52 sync info
393 ****************************************************************************/
394 int parse_syncinfo( spdif_thread_t *p_spdif )
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;
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;
406 p_sync_frame = (sync_frame_t*)p_spdif->p_bytes;
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 )
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;
423 if( ( ( p_sync_frame->bsi.bsidmod >> 3 ) & 0x1f ) != 0x08 )
428 p_spdif->info.i_bs_mod = p_sync_frame->bsi.bsidmod & 0x7;