Commit 3dd67e8f authored by Stéphane Borel's avatar Stéphane Borel

*Move iec958/spdif encapsulation from ac3_spdif to aout_spdif.
It will eventually allows to use ac3_adec or a52 for spdif output.

*Remove an ugly loop in aout_spdif.
parent f9f1cc85
ac3_spdif_SOURCES = ac3_spdif.c ac3_iec958.c
ac3_spdif_SOURCES = ac3_spdif.c
/*****************************************************************************
* ac3_iec958.c: ac3 to spdif converter
*****************************************************************************
* Copyright (C) 2001 VideoLAN
* $Id: ac3_iec958.c,v 1.5 2001/12/30 07:09:54 sam Exp $
*
* Authors: Stphane Borel <stef@via.ecp.fr>
* Juha Yrjola <jyrjola@cc.hut.fi>
* German Gomez Garcia <german@piraos.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
****************************************************************************/
/****************************************************************************
* Preamble
****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h> /* memset() */
#include <fcntl.h>
#include <videolan/vlc.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include "audio_output.h"
#include "stream_control.h"
#include "input_ext-dec.h"
#include "ac3_spdif.h"
#include "ac3_iec958.h"
/****************************************************************************
* Local structures and tables
****************************************************************************/
typedef struct frame_size_s
{
u16 i_bit_rate;
u16 i_frame_size[3];
} frame_size_t;
static const frame_size_t p_frame_size_code[64] =
{
{ 32 ,{64 ,69 ,96 } },
{ 32 ,{64 ,70 ,96 } },
{ 40 ,{80 ,87 ,120 } },
{ 40 ,{80 ,88 ,120 } },
{ 48 ,{96 ,104 ,144 } },
{ 48 ,{96 ,105 ,144 } },
{ 56 ,{112 ,121 ,168 } },
{ 56 ,{112 ,122 ,168 } },
{ 64 ,{128 ,139 ,192 } },
{ 64 ,{128 ,140 ,192 } },
{ 80 ,{160 ,174 ,240 } },
{ 80 ,{160 ,175 ,240 } },
{ 96 ,{192 ,208 ,288 } },
{ 96 ,{192 ,209 ,288 } },
{ 112 ,{224 ,243 ,336 } },
{ 112 ,{224 ,244 ,336 } },
{ 128 ,{256 ,278 ,384 } },
{ 128 ,{256 ,279 ,384 } },
{ 160 ,{320 ,348 ,480 } },
{ 160 ,{320 ,349 ,480 } },
{ 192 ,{384 ,417 ,576 } },
{ 192 ,{384 ,418 ,576 } },
{ 224 ,{448 ,487 ,672 } },
{ 224 ,{448 ,488 ,672 } },
{ 256 ,{512 ,557 ,768 } },
{ 256 ,{512 ,558 ,768 } },
{ 320 ,{640 ,696 ,960 } },
{ 320 ,{640 ,697 ,960 } },
{ 384 ,{768 ,835 ,1152 } },
{ 384 ,{768 ,836 ,1152 } },
{ 448 ,{896 ,975 ,1344 } },
{ 448 ,{896 ,976 ,1344 } },
{ 512 ,{1024 ,1114 ,1536 } },
{ 512 ,{1024 ,1115 ,1536 } },
{ 576 ,{1152 ,1253 ,1728 } },
{ 576 ,{1152 ,1254 ,1728 } },
{ 640 ,{1280 ,1393 ,1920 } },
{ 640 ,{1280 ,1394 ,1920 } }
};
/****************************************************************************
* ac3_iec958_build_burst: builds an iec958/spdif frame based on an ac3 frame
****************************************************************************/
void ac3_iec958_build_burst( ac3_spdif_thread_t *p_spdif )
{
const u8 p_sync[6] = { 0x72, 0xF8, 0x1F, 0x4E, 0x01, 0x00 };
int i_length = p_spdif->ac3_info.i_frame_size;
#ifndef HAVE_SWAB
/* Skip the first byte if i_length is odd */
u16 * p_in = (u16 *)( p_spdif->p_ac3 + ( i_length & 0x1 ) );
u16 * p_out = (u16 *)p_spdif->p_iec;
#endif
/* Add the spdif headers */
memcpy( p_spdif->p_iec, p_sync, 6 );
p_spdif->p_iec[6] = ( i_length * 8 ) & 0xFF;
p_spdif->p_iec[7] = ( ( i_length * 8 ) >> 8 ) & 0xFF;
#ifdef HAVE_SWAB
swab( p_spdif->p_ac3, p_spdif->p_iec + 8, i_length );
#else
/* i_length should be even */
i_length &= ~0x1;
while( i_length )
{
*p_out = ( (*p_in & 0x00ff) << 16 ) | ( (*p_in & 0xff00) >> 16 );
p_in++;
p_out++;
i_length -= 2;
}
#endif
/* Add zeroes to complete the spdif frame,
* they will be ignored by the decoder */
memset( p_spdif->p_iec + 8 + i_length, 0, SPDIF_FRAME_SIZE - 8 - i_length );
}
/****************************************************************************
* ac3_iec958_parse_syncinfo: parse ac3 sync info
****************************************************************************/
int ac3_iec958_parse_syncinfo( ac3_spdif_thread_t *p_spdif )
{
int p_sample_rates[4] = { 48000, 44100, 32000, -1 };
int i_frame_rate_code;
int i_frame_size_code;
sync_frame_t * p_sync_frame;
/* Read sync frame */
GetChunk( &p_spdif->bit_stream, p_spdif->p_ac3 + 2,
sizeof(sync_frame_t) - 2 );
p_sync_frame = (sync_frame_t*)p_spdif->p_ac3;
/* Compute frame rate */
i_frame_rate_code = (p_sync_frame->syncinfo.code >> 6) & 0x03;
p_spdif->ac3_info.i_sample_rate = p_sample_rates[i_frame_rate_code];
if( p_spdif->ac3_info.i_sample_rate == -1 )
{
return -1;
}
/* Compute frame size */
i_frame_size_code = p_sync_frame->syncinfo.code & 0x3f;
p_spdif->ac3_info.i_frame_size = 2 *
p_frame_size_code[i_frame_size_code].i_frame_size[i_frame_rate_code];
p_spdif->ac3_info.i_bit_rate =
p_frame_size_code[i_frame_size_code].i_bit_rate;
if( ( ( p_sync_frame->bsi.bsidmod >> 3 ) & 0x1f ) != 0x08 )
{
return -1;
}
p_spdif->ac3_info.i_bs_mod = p_sync_frame->bsi.bsidmod & 0x7;
return 0;
}
/*****************************************************************************
* ac3_iec958.h: ac3 to spdif converter headers
*****************************************************************************
* Copyright (C) 2001 VideoLAN
* $Id: ac3_iec958.h,v 1.1 2001/11/13 12:09:17 henri Exp $
*
* Authors: Stphane Borel <stef@via.ecp.fr>
* Juha Yrjola <jyrjola@cc.hut.fi>
* German Gomez Garcia <german@piraos.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
****************************************************************************/
/****************************************************************************
* information about ac3 frame
****************************************************************************/
typedef struct sync_frame_s
{
struct syncinfo
{
u8 syncword[2];
u8 crc1[2];
u8 code;
} syncinfo;
struct bsi
{
u8 bsidmod;
u8 acmod;
} bsi;
} sync_frame_t;
/****************************************************************************
* Prototypes
****************************************************************************/
void ac3_iec958_build_burst ( struct ac3_spdif_thread_s * );
int ac3_iec958_parse_syncinfo ( struct ac3_spdif_thread_s * );
This diff is collapsed.
......@@ -2,7 +2,7 @@
* ac3_spdif.h: header for ac3 pass-through
*****************************************************************************
* Copyright (C) 2001 VideoLAN
* $Id: ac3_spdif.h,v 1.2 2002/03/12 18:37:46 stef Exp $
* $Id: ac3_spdif.h,v 1.3 2002/03/15 01:47:16 stef Exp $
*
* Authors: Stéphane Borel <stef@via.ecp.fr>
*
......@@ -21,6 +21,31 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
****************************************************************************/
/****************************************************************************
* information about ac3 frame
****************************************************************************/
typedef struct sync_frame_s
{
struct syncinfo
{
u8 syncword[2];
u8 crc1[2];
u8 code;
} syncinfo;
struct bsi
{
u8 bsidmod;
u8 acmod;
} bsi;
} sync_frame_t;
typedef struct frame_size_s
{
u16 i_bit_rate;
u16 i_frame_size[3];
} frame_size_t;
typedef struct ac3_info_s
{
int i_bit_rate;
......@@ -54,7 +79,6 @@ typedef struct ac3_spdif_thread_s
*/
ac3_info_t ac3_info;
u8 * p_ac3;
u8 * p_iec;
/* current pes date */
mtime_t i_pts;
......
......@@ -2,7 +2,7 @@
* aout_spdif.c: AC3 passthrough output
*****************************************************************************
* Copyright (C) 2001 VideoLAN
* $Id: aout_spdif.c,v 1.25 2002/03/08 00:26:07 bozo Exp $
* $Id: aout_spdif.c,v 1.26 2002/03/15 01:47:16 stef Exp $
*
* Authors: Michel Kaempf <maxx@via.ecp.fr>
* Stphane Borel <stef@via.ecp.fr>
......@@ -31,9 +31,53 @@
#include <videolan/vlc.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include "audio_output.h"
#include "aout_spdif.h"
/****************************************************************************
* iec958_build_burst: builds an iec958/spdif frame
****************************************************************************/
void iec958_build_burst( u8 * p_buf, aout_fifo_t * p_fifo )
{
const u8 p_sync[6] = { 0x72, 0xF8, 0x1F, 0x4E, 0x01, 0x00 };
int i_length = p_fifo->i_frame_size;
#ifndef HAVE_SWAB
/* Skip the first byte if i_length is odd */
u16 * p_in = (u16 *)( p_fifo->buffer + ( i_length & 0x1 ) );
u16 * p_out = (u16 *)p_buf;
#endif
/* Add the spdif headers */
memcpy( p_buf, p_sync, 6 );
p_buf[6] = ( i_length * 8 ) & 0xFF;
p_buf[7] = ( ( i_length * 8 ) >> 8 ) & 0xFF;
#ifdef HAVE_SWAB
swab( p_fifo->buffer + p_fifo->i_start_frame * i_length,
p_buf + 8, i_length );
#else
/* i_length should be even */
i_length &= ~0x1;
while( i_length )
{
*p_out = ( (*p_in & 0x00ff) << 16 ) | ( (*p_in & 0xff00) >> 16 );
p_in++;
p_out++;
i_length -= 2;
}
#endif
/* Add zeroes to complete the spdif frame,
* they will be ignored by the decoder */
memset( p_buf + 8 + i_length, 0, SPDIF_FRAME_SIZE - 8 - i_length );
}
/*****************************************************************************
* aout_SpdifThread: audio output thread that sends raw spdif data
* to an external decoder
......@@ -49,88 +93,78 @@ void aout_SpdifThread( aout_thread_t * p_aout )
int i_fifo;
mtime_t m_frame_time = 0;
mtime_t m_play;
mtime_t m_old = 0;
while( !p_aout->b_die )
{
for( i_fifo = 0 ; i_fifo < AOUT_MAX_FIFOS ; i_fifo++ )
i_fifo = 0;
/* Find spdif fifo */
while( ( p_aout->fifo[i_fifo].i_format != AOUT_FIFO_SPDIF ) &&
( i_fifo < AOUT_MAX_FIFOS ) )
{
i_fifo++;
}
while( !p_aout->b_die &&
!p_aout->fifo[i_fifo].b_die )
{
/* The loop reads each fifo so that we can change the stream
* on the fly but mulitplexing is not handled yet so
* the sound will be broken if more than one fifo has data */
/* TODO: write the muliplexer :) */
if( p_aout->fifo[i_fifo].i_format == AOUT_FIFO_SPDIF )
vlc_mutex_lock( &p_aout->fifo[i_fifo].data_lock );
if( !AOUT_FIFO_ISEMPTY( p_aout->fifo[i_fifo] ) )
{
vlc_mutex_lock( &p_aout->fifo[i_fifo].data_lock );
if( p_aout->fifo[i_fifo].b_die )
{
vlc_mutex_unlock( &p_aout->fifo[i_fifo].data_lock );
/* Copy data from fifo to buffer to release the
* lock earlier */
iec958_build_burst( p_aout->buffer,
&p_aout->fifo[i_fifo] );
vlc_mutex_lock( &p_aout->fifos_lock );
aout_FreeFifo( &p_aout->fifo[i_fifo] );
vlc_mutex_unlock( &p_aout->fifos_lock );
}
else if( !AOUT_FIFO_ISEMPTY( p_aout->fifo[i_fifo] ) )
m_play = p_aout->fifo[i_fifo].date[p_aout->fifo[i_fifo].
i_start_frame];
p_aout->fifo[i_fifo].i_start_frame =
(p_aout->fifo[i_fifo].i_start_frame + 1 )
& AOUT_FIFO_SIZE;
/* Compute the theorical duration of an ac3 frame */
m_frame_time = 1000000 * AC3_FRAME_SIZE
/ p_aout->fifo[i_fifo].i_rate;
vlc_mutex_unlock( &p_aout->fifo[i_fifo].data_lock );
/* Play spdif frame to the external decoder
* the kernel driver will sleep until the
* dsp buffer is empty enough to accept the data */
if( m_play > ( mdate() - m_frame_time ) )
{
/* Copy data from fifo to buffer to release the
* lock earlier */
FAST_MEMCPY( p_aout->buffer,
(byte_t *)p_aout->fifo[i_fifo].buffer
+ p_aout->fifo[i_fifo].i_start_frame
* SPDIF_FRAME_SIZE,
SPDIF_FRAME_SIZE );
m_play = p_aout->fifo[i_fifo].date[p_aout->fifo[i_fifo].
i_start_frame];
p_aout->fifo[i_fifo].i_start_frame =
(p_aout->fifo[i_fifo].i_start_frame + 1 )
& AOUT_FIFO_SIZE;
/* Compute the theorical duration of an ac3 frame */
m_frame_time = 1000000 * AC3_FRAME_SIZE
/ p_aout->fifo[i_fifo].i_rate;
vlc_mutex_unlock( &p_aout->fifo[i_fifo].data_lock );
/* Play spdif frame to the external decoder
* the kernel driver will sleep until the
* dsp buffer is empty enough to accept the data */
if( m_play > ( mdate() - m_frame_time ) )
#if 0
/* check continuity */
if( (m_play - m_old) != m_frame_time )
{
/* check continuity */
if( (m_play - m_old) != m_frame_time )
{
mwait( m_play - m_frame_time );
}
else
{
mwait( m_play - 2 * m_frame_time );
}
m_old = m_play;
p_aout->pf_getbufinfo( p_aout, 0 );
p_aout->pf_play( p_aout, (byte_t *)p_aout->buffer,
SPDIF_FRAME_SIZE );
mwait( m_play - m_frame_time );
}
else
{
mwait( m_play - 2 * m_frame_time );
}
m_old = m_play;
#else
mwait( m_play - m_frame_time );
#endif
p_aout->pf_getbufinfo( p_aout, 0 );
p_aout->pf_play( p_aout, (byte_t *)p_aout->buffer,
SPDIF_FRAME_SIZE );
}
else
{
vlc_mutex_unlock( &p_aout->fifo[i_fifo].data_lock );
msleep( m_frame_time );
intf_WarnMsg( 3, "aout warning: empty spdif fifo" );
}
}
else
{
vlc_mutex_unlock( &p_aout->fifo[i_fifo].data_lock );
msleep( m_frame_time );
intf_WarnMsg( 3, "aout warning: empty spdif fifo" );
}
}
}
vlc_mutex_lock( &p_aout->fifos_lock );
for ( i_fifo = 0; i_fifo < AOUT_MAX_FIFOS; i_fifo++ )
{
vlc_mutex_lock( &p_aout->fifos_lock );
aout_FreeFifo( &p_aout->fifo[i_fifo] );
vlc_mutex_unlock( &p_aout->fifos_lock );
}
vlc_mutex_unlock( &p_aout->fifos_lock );
return;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment