Commit e5c6a7af authored by Stéphane Borel's avatar Stéphane Borel

-new audio output using direct ac3 pass-through with some sound

cards: it sends raw ac3 frames to an external ac3 decoder. It is very
experimental yet, hasn't any synchro ... but it works well with my
sblive and my dtt3500 speakers (note that you need a patched emu10k1
driver for this to work).

-bug fix in gnome intf thanks to Shane Harper.

-bug fix in input_dvd for chapter change.
parent d3aacbfc
......@@ -57,7 +57,8 @@ AUDIO_OUTPUT = src/audio_output/audio_output.o \
src/audio_output/aout_u8.o \
src/audio_output/aout_s8.o \
src/audio_output/aout_u16.o \
src/audio_output/aout_s16.o
src/audio_output/aout_s16.o \
src/audio_output/aout_spdif.o
VIDEO_OUTPUT = src/video_output/video_output.o \
src/video_output/video_text.o \
......@@ -75,6 +76,9 @@ AC3_DECODER = src/ac3_decoder/ac3_decoder_thread.o \
src/ac3_decoder/ac3_downmix.o \
src/ac3_decoder/ac3_downmix_c.o
AC3_SPDIF = src/ac3_spdif/ac3_spdif.o \
src/ac3_spdif/ac3_iec958.o
LPCM_DECODER = src/lpcm_decoder/lpcm_decoder_thread.o \
src/lpcm_decoder/lpcm_decoder.o
......@@ -107,6 +111,7 @@ C_OBJ = $(INTERFACE) \
$(VIDEO_OUTPUT) \
$(AUDIO_OUTPUT) \
$(AC3_DECODER) \
$(AC3_SPDIF) \
$(LPCM_DECODER) \
$(AUDIO_DECODER) \
$(SPU_DECODER) \
......
......@@ -2,7 +2,7 @@
* audio_output.h : audio output thread interface
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
* $Id: audio_output.h,v 1.31 2001/03/21 13:42:33 sam Exp $
* $Id: audio_output.h,v 1.32 2001/04/29 02:48:51 stef Exp $
*
* Authors: Michel Kaempf <maxx@via.ecp.fr>
*
......@@ -39,7 +39,7 @@
/*
* Macros
*/
#define AOUT_FIFO_ISEMPTY( fifo ) ( (fifo).l_end_frame == (fifo).i_start_frame )
#define AOUT_FIFO_ISEMPTY( fifo ) ( (fifo).l_end_frame == (fifo).l_start_frame )
#define AOUT_FIFO_ISFULL( fifo ) ( ((((fifo).l_end_frame + 1) - (fifo).l_start_frame) & AOUT_FIFO_SIZE) == 0 )
/*****************************************************************************
......@@ -192,6 +192,8 @@ typedef struct aout_thread_s
#define AOUT_FMT_S8 0x00000040
#define AOUT_FMT_U16_LE 0x00000080 /* Little endian U16 */
#define AOUT_FMT_U16_BE 0x00000100 /* Big endian U16 */
#define AOUT_FMT_AC3 0x00000400 /* Dolby Digital AC3 */
#ifdef WORDS_BIGENDIAN
#define AOUT_FMT_S16_NE AOUT_FMT_S16_BE
......
......@@ -3,7 +3,7 @@
* Declaration and extern access to global program object.
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
* $Id: main.h,v 1.15 2001/04/11 02:01:24 henri Exp $
* $Id: main.h,v 1.16 2001/04/29 02:48:51 stef Exp $
*
* Authors: Vincent Seguin <seguin@via.ecp.fr>
*
......@@ -48,7 +48,7 @@ typedef struct
boolean_t b_audio; /* is audio output allowed ? */
boolean_t b_video; /* is video output allowed ? */
boolean_t b_channels; /* is channel changing supported ? */
boolean_t b_dvd; /* DVD mode ? */
boolean_t b_spdif; /* spdif mode ? */
/* Unique threads */
p_vout_thread_t p_vout; /* video output thread */
......
......@@ -10,7 +10,7 @@
* -dvd_udf to find files
*****************************************************************************
* Copyright (C) 1998-2001 VideoLAN
* $Id: input_dvd.c,v 1.51 2001/04/28 03:36:25 sam Exp $
* $Id: input_dvd.c,v 1.52 2001/04/29 02:48:51 stef Exp $
*
* Author: Stphane Borel <stef@via.ecp.fr>
*
......@@ -380,8 +380,8 @@ static void DVDInit( input_thread_t * p_input )
/* reading several block once seems to cause lock-up
* when using input_ToggleES
* who wrote thez damn buggy piece of shit ??? --stef */
p_dvd->i_block_once = 1;//32;
p_input->i_read_once = 8;//128;
p_dvd->i_block_once = 32;
p_input->i_read_once = 128;
i = CSSTest( p_input->i_handle );
......@@ -398,7 +398,7 @@ static void DVDInit( input_thread_t * p_input )
/* Reading structures initialisation */
p_input->p_method_data =
DVDNetlistInit( 2048, 8192, 2048, DVD_LB_SIZE, p_dvd->i_block_once );
DVDNetlistInit( 8192, 16384, 2048, DVD_LB_SIZE, p_dvd->i_block_once );
intf_WarnMsg( 2, "dvd info: netlist initialized" );
/* Ifo allocation & initialisation */
......@@ -552,6 +552,7 @@ static int DVDSetArea( input_thread_t * p_input, input_area_t * p_area )
u16 i_id;
u8 i_ac3;
u8 i_mpeg;
u8 i_lpcm;
u8 i_sub_pic;
u8 i;
int j;
......@@ -741,6 +742,7 @@ static int DVDSetArea( input_thread_t * p_input, input_area_t * p_area )
i_ac3 = 0x7f;
i_mpeg = 0xc0;
i_lpcm = 0x9f;
for( i = 1 ; i <= vts.manager_inf.i_audio_nb ; i++ )
{
......@@ -795,8 +797,24 @@ static int DVDSetArea( input_thread_t * p_input, input_area_t * p_area )
break;
case 0x04: /* LPCM */
#if 0
i_id = ( ( i_lpcm + i ) << 8 ) | 0xbd;
p_es = input_AddES( p_input,
p_input->stream.pp_programs[0], i_id, 0 );
p_es->i_stream_id = i_id;
p_es->i_type = LPCM_AUDIO_ES;
p_es->b_audio = 1;
p_es->i_cat = AUDIO_ES;
strcpy( p_es->psz_desc, Language( hton16(
vts.manager_inf.p_audio_attr[i-1].i_lang_code ) ) );
strcat( p_es->psz_desc, " (lpcm)" );
intf_WarnMsg( 1, "dvd info: audio stream %d %s\t(0x%x)",
i, p_es->psz_desc, i_id );
#else
i_id = 0;
intf_ErrMsg( "dvd warning: LPCM audio not handled yet" );
#endif
break;
case 0x06: /* DTS */
i_id = 0;
......@@ -946,6 +964,7 @@ static int DVDRead( input_thread_t * p_input,
{
thread_dvd_data_t * p_dvd;
dvd_netlist_t * p_netlist;
input_area_t * p_area;
struct iovec * p_vec;
struct data_packet_s * pp_data[p_input->i_read_once];
u8 * pi_cur;
......@@ -958,6 +977,7 @@ static int DVDRead( input_thread_t * p_input,
int i_read_blocks;
off_t i_off;
boolean_t b_eof;
boolean_t b_eot;
p_dvd = (thread_dvd_data_t *)p_input->p_plugin_data;
p_netlist = (dvd_netlist_t *)p_input->p_method_data;
......@@ -994,18 +1014,21 @@ static int DVDRead( input_thread_t * p_input,
/* update chapter : it will be easier when we have navigation
* ES support */
if( title.p_cell_play[p_dvd->i_prg_cell].i_category & 0xf000 )
{
i_angle = p_dvd->i_angle - 1;
}
else
{
i_angle = 0;
}
if( title.chapter_map.pi_start_cell[p_dvd->i_chapter-1] <=
( p_dvd->i_prg_cell - i_angle ) )
if( p_dvd->i_chapter < ( p_dvd->i_chapter_nb - 1 ) )
{
p_dvd->i_chapter++;
if( title.p_cell_play[p_dvd->i_prg_cell].i_category & 0xf000 )
{
i_angle = p_dvd->i_angle - 1;
}
else
{
i_angle = 0;
}
if( title.chapter_map.pi_start_cell[p_dvd->i_chapter] <=
( p_dvd->i_prg_cell - i_angle + 1 ) )
{
p_dvd->i_chapter++;
}
}
vlc_mutex_lock( &p_input->stream.stream_lock );
......@@ -1015,7 +1038,7 @@ static int DVDRead( input_thread_t * p_input,
p_input->stream.p_selected_area->i_part = p_dvd->i_chapter;
/* the synchro has to be reinitialized when we change cell */
p_input->stream.pp_programs[0]->i_synchro_state = SYNCHRO_START;
p_input->stream.pp_programs[0]->i_synchro_state = SYNCHRO_REINIT;
vlc_mutex_unlock( &p_input->stream.stream_lock );
......@@ -1115,18 +1138,30 @@ static int DVDRead( input_thread_t * p_input,
vlc_mutex_lock( &p_input->stream.stream_lock );
p_input->stream.p_selected_area->i_tell += i_read_bytes;
b_eof = !( p_input->stream.p_selected_area->i_tell < p_dvd->i_size );
b_eot = !( p_input->stream.p_selected_area->i_tell < p_dvd->i_size );
b_eof = b_eot && ( ( p_dvd->i_title + 1 ) < p_input->stream.i_area_nb );
p_area = p_input->stream.pp_areas[p_dvd->i_title + 1];
vlc_mutex_unlock( &p_input->stream.stream_lock );
if( ( i_read_blocks == i_block_once ) && ( !b_eof ) )
if( b_eof )
{
return 1;
}
if( b_eot )
{
p_dvd->i_title++;
DVDSetArea( p_input, p_area );
return 0;
}
else
if( i_read_blocks == i_block_once )
{
return 1;
return 0;
}
return -1;
}
/*****************************************************************************
......@@ -1163,7 +1198,7 @@ static void DVDSeek( input_thread_t * p_input, off_t i_off )
p_dvd->i_sector = i_pos >> 11;
i_prg_cell = 0;
i_chapter = 1;
i_chapter = 0;
/* parse vobu address map to find program cell */
while( title.p_cell_play[i_prg_cell].i_end_sector < p_dvd->i_sector )
......@@ -1224,8 +1259,9 @@ static void DVDSeek( input_thread_t * p_input, off_t i_off )
{
i_angle = 0;
}
while( title.chapter_map.pi_start_cell[i_chapter-1] <=
( p_dvd->i_prg_cell - i_angle ) )
while( ( title.chapter_map.pi_start_cell[i_chapter] <=
( p_dvd->i_prg_cell - i_angle + 1 ) ) &&
( i_chapter < ( p_dvd->i_chapter_nb - 1 ) ) )
{
i_chapter++;
}
......
......@@ -2,7 +2,7 @@
* intf_gnome.c: Gnome interface
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
* $Id: intf_gnome.c,v 1.32 2001/04/22 00:08:26 stef Exp $
* $Id: intf_gnome.c,v 1.33 2001/04/29 02:48:51 stef Exp $
*
* Authors: Samuel Hocevar <sam@zoy.org>
* Stphane Borel <stef@via.ecp.fr>
......@@ -444,7 +444,7 @@ static gint GnomeLanguageMenus( gpointer p_data,
GtkWidget * p_item;
GtkWidget * p_item_active;
GSList * p_group;
char * psz_name;
char psz_name[12];
gint i_item;
gint i;
......@@ -463,7 +463,7 @@ static gint GnomeLanguageMenus( gpointer p_data,
p_menu = gtk_menu_new();
/* special case for "off" item */
psz_name = "Off";
sprintf( psz_name, "Off" );
p_item = gtk_radio_menu_item_new_with_label( p_group, psz_name );
p_group = gtk_radio_menu_item_group( GTK_RADIO_MENU_ITEM( p_item ) );
......@@ -491,7 +491,7 @@ static gint GnomeLanguageMenus( gpointer p_data,
if( p_intf->p_input->stream.pp_es[i]->i_cat == i_cat )
{
i_item++;
psz_name = p_intf->p_input->stream.pp_es[i]->psz_desc;
strcpy( psz_name, p_intf->p_input->stream.pp_es[i]->psz_desc );
if( psz_name[0] == '\0' )
{
sprintf( psz_name, "Language %d", i_item );
......@@ -547,7 +547,7 @@ static gint GnomeAngleMenu( gpointer p_data, GtkWidget * p_angle,
void(*pf_toggle)( GtkCheckMenuItem *, gpointer ) )
{
intf_thread_t * p_intf;
char psz_name[10];
char psz_name[12];
GtkWidget * p_angle_menu;
GSList * p_angle_group;
GtkWidget * p_item;
......@@ -618,7 +618,7 @@ static gint GnomeChapterMenu( gpointer p_data, GtkWidget * p_chapter,
void(*pf_toggle )( GtkCheckMenuItem *, gpointer ) )
{
intf_thread_t * p_intf;
char psz_name[10];
char psz_name[12];
GtkWidget * p_chapter_menu;
GtkWidget * p_chapter_submenu;
GtkWidget * p_menu_item;
......@@ -733,7 +733,7 @@ static gint GnomeTitleMenu( gpointer p_data,
void(*pf_toggle )( GtkCheckMenuItem *, gpointer ) )
{
intf_thread_t * p_intf;
char psz_name[10];
char psz_name[12];
GtkWidget * p_title_menu;
GtkWidget * p_title_submenu;
GtkWidget * p_title_item;
......
/*****************************************************************************
* ac3_iec958.c: ac3 to spdif converter
*****************************************************************************
* Copyright (C) 2001 VideoLAN
* $Id: ac3_iec958.c,v 1.1 2001/04/29 02:48:51 stef 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 "defs.h"
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include "config.h"
#include "common.h"
#include "threads.h"
#include "mtime.h"
#include "intf_msg.h" /* intf_DbgMsg(), intf_ErrMsg() */
#include "stream_control.h"
#include "input_ext-dec.h"
#include "audio_output.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( int i_length, u8 * pi_data, u8 * pi_out )
{
const u8 pi_sync[4] = { 0x72, 0xF8, 0x1F, 0x4E };
/* add the spdif headers */
memcpy( pi_out, pi_sync, 4 );
if( i_length )
pi_out[4] = 0x01;
else
pi_out[4] = 0;
pi_out[5] = 0x00;
pi_out[6] = ( i_length *8 ) & 0xFF;
pi_out[7] = ( ( i_length *8 ) >> 8 ) & 0xFF;
swab( pi_data, pi_out + 8, i_length );
/* adds zero to complete the spdif frame
* they will be ignored by the decoder */
memset( pi_out + 8 + i_length, 0, SPDIF_FRAME - 8 - i_length );
}
/****************************************************************************
* ac3_iec958_parse_syncinfo: parse ac3 sync info
****************************************************************************/
int ac3_iec958_parse_syncinfo( ac3_spdif_thread_t *p_spdif,
ac3_info_t *ac3_info,
u8 * pi_ac3 )
{
int pi_sample_rates[4] = { 48000, 44100, 32000, -1 };
int i_frame_rate_code;
int i_frame_size_code;
// u8 * pi_tmp;
sync_frame_t * p_sync_frame;
/* find sync word */
while( ShowBits( &p_spdif->bit_stream, 16 ) != 0xb77 )
{
RemoveBits( &p_spdif->bit_stream, 8 );
}
/* read sync frame */
pi_ac3 = malloc( sizeof(sync_frame_t) );
GetChunk( &p_spdif->bit_stream, pi_ac3, sizeof(sync_frame_t) );
p_sync_frame = (sync_frame_t*)pi_ac3;
/* compute frame rate */
i_frame_rate_code = (p_sync_frame->syncinfo.code >> 6) & 0x03;
ac3_info->i_sample_rate = pi_sample_rates[i_frame_rate_code];
if (ac3_info->i_sample_rate == -1)
{
return -1;
}
/* compute frame size */
i_frame_size_code = p_sync_frame->syncinfo.code & 0x3f;
ac3_info->i_frame_size = 2 *
p_frame_size_code[i_frame_size_code].i_frame_size[i_frame_rate_code];
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;
}
ac3_info->i_bs_mod = p_sync_frame->bsi.bsidmod & 0x7;
// free( pi_tmp );
return 0;
}
/*****************************************************************************
* ac3_iec958.h: ac3 to spdif converter headers
*****************************************************************************
* Copyright (C) 2001 VideoLAN
* $Id: ac3_iec958.h,v 1.1 2001/04/29 02:48:51 stef 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.
****************************************************************************/
#ifndef _AC3_IEC958_H
#define _AC3_IEC958_H
/****************************************************************************
* information about ac3 frame
****************************************************************************/
typedef struct ac3_info_s
{
int i_bit_rate;
int i_frame_size;
int i_sample_rate;
int i_bs_mod;
} ac3_info_t;
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 ( int, u8 *, u8 * );
int ac3_iec958_parse_syncinfo ( struct ac3_spdif_thread_s *,
struct ac3_info_s *, u8 * );
#endif
/*****************************************************************************
* ac3_spdif.c: ac3 pass-through to external decoder with enabled soundcard
*****************************************************************************
* Copyright (C) 2001 VideoLAN
* $Id: ac3_spdif.c,v 1.1 2001/04/29 02:48:51 stef 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 "defs.h"
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include "config.h"
#include "common.h"
#include "threads.h"
#include "mtime.h"
#include "intf_msg.h" /* intf_DbgMsg(), intf_ErrMsg() */
#include "stream_control.h"
#include "input_ext-dec.h"
#include "audio_output.h"
#include "ac3_spdif.h"
#include "ac3_iec958.h"
#define FRAME_NB 8
/****************************************************************************
* Local Prototypes
****************************************************************************/
static int InitThread ( ac3_spdif_thread_t * );
static void RunThread ( ac3_spdif_thread_t * );
static void ErrorThread ( ac3_spdif_thread_t * );
static void EndThread ( ac3_spdif_thread_t * );
static void BitstreamCallback( bit_stream_t *, boolean_t );
/****************************************************************************
* spdif_CreateThread: initialize the spdif thread
****************************************************************************/
vlc_thread_t spdif_CreateThread( adec_config_t * p_config )
{
ac3_spdif_thread_t * p_spdif;
intf_DbgMsg( "spdif debug: creating ac3 pass-through thread" );
/* Allocate the memory needed to store the thread's structure */
if( ( p_spdif = malloc( sizeof(ac3_spdif_thread_t) ) ) == NULL )
{
intf_ErrMsg ( "spdif error: not enough memory "
"for spdif_CreateThread() to create the new thread");
return 0;
}
/*
* Initialize the thread properties
*/
p_spdif->p_config = p_config;
p_spdif->p_fifo = p_config->decoder_config.p_decoder_fifo;
p_spdif->p_aout = p_config->p_aout;
p_spdif->p_aout_fifo = NULL;
/* Spawn the ac3 to spdif thread */
if (vlc_thread_create(&p_spdif->thread_id, "spdif",
(vlc_thread_func_t)RunThread, (void *)p_spdif))
{
intf_ErrMsg( "spdif error: can't spawn spdif thread" );
free( p_spdif );
return 0;
}
intf_DbgMsg( "spdif debug: spdif thread (%p) created", p_spdif );
return p_spdif->thread_id;
}
/*
* Local functions
*/
/****************************************************************************
* InitThread: initialize thread data and create output fifo
****************************************************************************/
static int InitThread( ac3_spdif_thread_t * p_spdif )
{
aout_fifo_t aout_fifo;
p_spdif->p_config->decoder_config.pf_init_bit_stream(
&p_spdif->bit_stream,
p_spdif->p_config->decoder_config.p_decoder_fifo,
BitstreamCallback, (void*)p_spdif );
aout_fifo.i_type = AOUT_ADEC_MONO_FIFO;
aout_fifo.i_channels = 1;
aout_fifo.b_stereo = 0;
aout_fifo.l_frame_size = SPDIF_FRAME;
/* Creating the audio output fifo */
if( (p_spdif->p_aout_fifo =
aout_CreateFifo( p_spdif->p_aout, &aout_fifo ) ) == NULL )
{
return -1;
}
intf_WarnMsg( 1, "aout fifo for spdif created" );
return 0;
}
/****************************************************************************
* RunThread: loop that reads ac3 ES and transform it to
* an spdif compliant stream.
****************************************************************************/
static void RunThread( ac3_spdif_thread_t * p_spdif )
{
ac3_info_t ac3_info;
u8 * pi_ac3;
u8 * pi_iec;
InitThread( p_spdif );
/* temporary buffer to store ac3 frames to be transformed */
pi_ac3 = malloc( /*ac3_info.i_frame_size*/SPDIF_FRAME );
/* check stream properties */
if( ac3_iec958_parse_syncinfo( p_spdif, &ac3_info, pi_ac3 ) < 0)
{
intf_ErrMsg( "spdif error: stream not valid");
exit(1);
}
if( ac3_info.i_sample_rate != 48000) {
intf_ErrMsg( "spdif error: Only 48000 Hz streams supported");
exit(1);
}
GetChunk( &p_spdif->bit_stream, pi_ac3 + sizeof(sync_frame_t),
ac3_info.i_frame_size - sizeof(sync_frame_t) );
vlc_cond_signal( &p_spdif->p_aout_fifo->data_wait );
while( !p_spdif->p_fifo->b_die && !p_spdif->p_fifo->b_error )
{
/* handle the dates */
if(DECODER_FIFO_START(*p_spdif->p_fifo)->i_pts)
{
p_spdif->p_aout_fifo->date[p_spdif->p_aout_fifo->l_end_frame] =
DECODER_FIFO_START(*p_spdif->p_fifo)->i_pts;
DECODER_FIFO_START(*p_spdif->p_fifo)->i_pts = 0;
}
else
{
p_spdif->p_aout_fifo->date[p_spdif->p_aout_fifo->l_end_frame] =
LAST_MDATE;
}
/* write in the first free packet of aout fifo */
pi_iec = (p_spdif->p_aout_fifo->buffer) +
(p_spdif->p_aout_fifo->l_end_frame * SPDIF_FRAME );
/* build burst to be sent to hardware decoder */
ac3_iec958_build_burst( ac3_info.i_frame_size, pi_ac3, pi_iec );
vlc_mutex_lock (&p_spdif->p_aout_fifo->data_lock);
p_spdif->p_aout_fifo->l_end_frame =
(p_spdif->p_aout_fifo->l_end_frame + 1 ) & AOUT_FIFO_SIZE;
vlc_mutex_unlock (&p_spdif->p_aout_fifo->data_lock);
/* find syncword */