]> git.sesse.net Git - vlc/commitdiff
-new audio output using direct ac3 pass-through with some sound
authorStéphane Borel <stef@videolan.org>
Sun, 29 Apr 2001 02:48:51 +0000 (02:48 +0000)
committerStéphane Borel <stef@videolan.org>
Sun, 29 Apr 2001 02:48:51 +0000 (02:48 +0000)
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.

13 files changed:
Makefile
include/audio_output.h
include/main.h
plugins/dvd/input_dvd.c
plugins/gnome/intf_gnome.c
src/ac3_spdif/ac3_iec958.c [new file with mode: 0644]
src/ac3_spdif/ac3_iec958.h [new file with mode: 0644]
src/ac3_spdif/ac3_spdif.c [new file with mode: 0644]
src/ac3_spdif/ac3_spdif.h [new file with mode: 0644]
src/audio_output/aout_common.h
src/audio_output/audio_output.c
src/input/input_programs.c
src/interface/main.c

index 6740d6b5ccd2fc05a427ab3bb5e52cf7aa39bad1..b62b1372eac429fa2de3edd8502c8becc7453bf1 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -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) \
index 71309dd2a1094609c354ecd0d3db81b8756ede0f..0576f2415a95fe490b34e918c6e72c88f976c7ae 100644 (file)
@@ -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
index c1806a3620b5259bf5dac63a4aa95f658e31cfe8..d5965d0937e4d4d4bcb0b78ab840d84567865577 100644 (file)
@@ -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 */
index 2dbd2366d3596b1df32c18810f7bb8b183e017bf..782c47ecfa0e5f4e1135c23750c02e4c64764968 100644 (file)
@@ -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: Stéphane 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++;
     }
index 5832faba0e2783cbdc447e08af23ca42e5e80d3c..6c4a67b9ee70d683a2f56ffd3aef360da22b8b15 100644 (file)
@@ -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>
  *          Stéphane 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;
diff --git a/src/ac3_spdif/ac3_iec958.c b/src/ac3_spdif/ac3_iec958.c
new file mode 100644 (file)
index 0000000..e5595a0
--- /dev/null
@@ -0,0 +1,173 @@
+/*****************************************************************************
+ * 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: Stéphane 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;
+}
diff --git a/src/ac3_spdif/ac3_iec958.h b/src/ac3_spdif/ac3_iec958.h
new file mode 100644 (file)
index 0000000..025507a
--- /dev/null
@@ -0,0 +1,62 @@
+/*****************************************************************************
+ * 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: Stéphane 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
diff --git a/src/ac3_spdif/ac3_spdif.c b/src/ac3_spdif/ac3_spdif.c
new file mode 100644 (file)
index 0000000..788e34c
--- /dev/null
@@ -0,0 +1,287 @@
+/*****************************************************************************
+ * 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: Stéphane 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 */
+        while( ShowBits( &p_spdif->bit_stream, 16 ) != 0xb77 ) 
+        {
+            RemoveBits( &p_spdif->bit_stream, 8 );
+        }
+
+        /* read data from bitstream */
+        GetChunk( &p_spdif->bit_stream, pi_ac3, ac3_info.i_frame_size );
+    }
+
+    free( pi_ac3 );
+
+    /* If b_error is set, the ac3 spdif thread enters the error loop */
+    if( p_spdif->p_fifo->b_error )
+    {
+        ErrorThread( p_spdif );
+    }
+
+    /* End of the ac3 decoder thread */
+    EndThread( p_spdif );
+
+    return;
+}
+
+/*****************************************************************************
+ * ErrorThread : ac3 spdif's RunThread() error loop
+ *****************************************************************************/
+static void ErrorThread( ac3_spdif_thread_t * p_spdif )
+{
+    /* We take the lock, because we are going to read/write the start/end
+     * indexes of the decoder fifo */
+    vlc_mutex_lock (&p_spdif->p_fifo->data_lock);
+
+    /* Wait until a `die' order is sent */
+    while( !p_spdif->p_fifo->b_die )
+    {
+        /* Trash all received PES packets */
+        while( !DECODER_FIFO_ISEMPTY( *p_spdif->p_fifo ) )
+        {
+            p_spdif->p_fifo->pf_delete_pes(p_spdif->p_fifo->p_packets_mgt,
+                    DECODER_FIFO_START( *p_spdif->p_fifo ) );
+            DECODER_FIFO_INCSTART( *p_spdif->p_fifo );
+        }
+
+        /* Waiting for the input thread to put new PES packets in the fifo */
+        vlc_cond_wait( &p_spdif->p_fifo->data_wait,
+                       &p_spdif->p_fifo->data_lock );
+    }
+
+    /* We can release the lock before leaving */
+    vlc_mutex_unlock( &p_spdif->p_fifo->data_lock );
+}
+
+/*****************************************************************************
+ * EndThread : ac3 spdif thread destruction
+ *****************************************************************************/
+static void EndThread( ac3_spdif_thread_t * p_spdif )
+{
+    intf_DbgMsg( "spdif debug: destroying thread %p", p_spdif );
+
+    /* If the audio output fifo was created, we destroy it */
+    if( p_spdif->p_aout_fifo != NULL )
+    {
+        aout_DestroyFifo( p_spdif->p_aout_fifo );
+
+        /* Make sure the output thread leaves the NextFrame() function */
+        vlc_mutex_lock( &(p_spdif->p_aout_fifo->data_lock ) );
+        vlc_cond_signal( &(p_spdif->p_aout_fifo->data_wait ) );
+        vlc_mutex_unlock( &(p_spdif->p_aout_fifo->data_lock ) );
+        
+    }
+
+    /* Destroy descriptor */
+    free( p_spdif->p_config );
+    free( p_spdif );
+
+    intf_DbgMsg ("spdif debug: thread %p destroyed", p_spdif );
+}
+
+/*****************************************************************************
+ * BitstreamCallback: Import parameters from the new data/PES packet
+ *****************************************************************************
+ * This function is called by input's NextDataPacket.
+ *****************************************************************************/
+static void BitstreamCallback ( bit_stream_t * p_bit_stream,
+                                        boolean_t b_new_pes)
+{
+    if( b_new_pes )
+    {
+        p_bit_stream->p_byte += 3;
+    }
+}
diff --git a/src/ac3_spdif/ac3_spdif.h b/src/ac3_spdif/ac3_spdif.h
new file mode 100644 (file)
index 0000000..908989d
--- /dev/null
@@ -0,0 +1,62 @@
+/*****************************************************************************
+ * ac3_spdif.h: header for ac3 pass-through
+ *****************************************************************************
+ * Copyright (C) 2001 VideoLAN
+ * $Id: ac3_spdif.h,v 1.1 2001/04/29 02:48:51 stef Exp $
+ *
+ * Authors: Stéphane Borel <stef@via.ecp.fr>
+ *
+ * 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_SPDIF_H
+#define _AC3_SPDIF_H
+
+#define SPDIF_FRAME 6144
+
+/*****************************************************************************
+ * ac3_spdif_thread_t : ac3 pass-through thread descriptor
+ *****************************************************************************/
+typedef struct ac3_spdif_thread_s
+{
+    /*
+     * Thread properties
+     */
+    vlc_thread_t        thread_id;                /* id for thread functions */
+
+    /*
+     * Input properties
+     */
+    decoder_fifo_t *    p_fifo;                /* stores the PES stream data */
+    adec_config_t *     p_config;
+
+    /* The bit stream structure handles the PES stream at the bit level */
+    bit_stream_t        bit_stream;
+    int                 i_available;
+                
+    /*
+     * Output properties
+     */
+    aout_fifo_t *       p_aout_fifo;/* stores the decompressed audio frames */
+    aout_thread_t *     p_aout;         /* needed to create the audio fifo */
+
+} ac3_spdif_thread_t;
+
+/*****************************************************************************
+ * Prototypes
+ *****************************************************************************/
+vlc_thread_t    spdif_CreateThread( adec_config_t * p_config );
+
+#endif
index fc8ed13e087ca93a8c3a5b9de2ce29bae596b5e3..f1e537ab2cb91a4cef620a45e1685bf6459b6a1c 100644 (file)
@@ -2,7 +2,7 @@
  * aout_common.h: audio output inner functions
  *****************************************************************************
  * Copyright (C) 1999, 2000, 2001 VideoLAN
- * $Id: aout_common.h,v 1.2 2001/03/21 13:42:34 sam Exp $
+ * $Id: aout_common.h,v 1.3 2001/04/29 02:48:51 stef Exp $
  *
  * Authors: Michel Kaempf <maxx@via.ecp.fr>
  *
@@ -32,6 +32,7 @@ void aout_U16MonoThread       ( aout_thread_t * p_aout );
 void aout_U16StereoThread     ( aout_thread_t * p_aout );
 void aout_S16MonoThread       ( aout_thread_t * p_aout );
 void aout_S16StereoThread     ( aout_thread_t * p_aout );
+void aout_SpdifThread         ( aout_thread_t * p_aout );
 
 #define UPDATE_INCREMENT( increment, integer ) \
     if ( ((increment).l_remainder += (increment).l_euclidean_remainder) >= 0 )\
index de60d0348bba8bd9054f7eee3920383b2aa97534..79892cd664cc78f79d453cf805d356cee5729df9 100644 (file)
@@ -2,7 +2,7 @@
  * audio_output.c : audio output thread
  *****************************************************************************
  * Copyright (C) 1999, 2000, 2001 VideoLAN
- * $Id: audio_output.c,v 1.57 2001/04/28 03:36:25 sam Exp $
+ * $Id: audio_output.c,v 1.58 2001/04/29 02:48:51 stef Exp $
  *
  * Authors: Michel Kaempf <maxx@via.ecp.fr>
  *
@@ -119,6 +119,14 @@ aout_thread_t *aout_CreateThread( int *pi_status )
         return( NULL );
     }
 
+    /* special setting for ac3 pass-through mode */
+    if( p_main->b_spdif )
+    {
+        p_aout->i_format   = AOUT_FMT_AC3;
+        p_aout->i_channels = 1;
+        p_aout->l_rate = 48000;
+    }
+
     /* FIXME: only works for i_channels == 1 or 2 ?? */
     p_aout->b_stereo = ( p_aout->i_channels == 2 ) ? 1 : 0;
 
@@ -209,8 +217,13 @@ static int aout_SpawnThread( aout_thread_t * p_aout )
             l_bytes = 1 * sizeof(s16) * p_aout->l_units;
             aout_thread = (void *)aout_S16MonoThread;
             break;
+        case AOUT_FMT_AC3:
+            intf_WarnMsg( 2, "aout info: ac3 pass-through thread" );
+            l_bytes = 0;
+            aout_thread = (void *)aout_SpdifThread;
+            break;
 
-                default:
+        default:
             intf_ErrMsg( "aout error: unknown audio output format (%i)",
                          p_aout->i_format );
             return( -1 );
@@ -246,7 +259,6 @@ static int aout_SpawnThread( aout_thread_t * p_aout )
             l_bytes = 2 * sizeof(s16) * p_aout->l_units;
             aout_thread = (void *)aout_S16StereoThread;
             break;
-
         default:
             intf_ErrMsg( "aout error: unknown audio output format %i",
                          p_aout->i_format );
index 82356a85ccb958d0de3686c7abd10f8a1046ef82..ca1996bbd608ad992068f4cbead70946a7567644 100644 (file)
@@ -2,7 +2,7 @@
  * input_programs.c: es_descriptor_t, pgrm_descriptor_t management
  *****************************************************************************
  * Copyright (C) 1999, 2000 VideoLAN
- * $Id: input_programs.c,v 1.52 2001/04/28 03:36:25 sam Exp $
+ * $Id: input_programs.c,v 1.53 2001/04/29 02:48:51 stef Exp $
  *
  * Authors: Christophe Massiot <massiot@via.ecp.fr>
  *
@@ -599,6 +599,8 @@ static adec_config_t * GetAdecConfig( input_thread_t * p_input,
 /* FIXME */
 vlc_thread_t adec_CreateThread( void * );
 vlc_thread_t ac3dec_CreateThread( void * );
+vlc_thread_t ac3spdif_CreateThread( void * );
+vlc_thread_t spdif_CreateThread( void * );
 vlc_thread_t vpar_CreateThread( void * );
 vlc_thread_t spudec_CreateThread( void * );
 
@@ -659,7 +661,15 @@ int input_SelectES( input_thread_t * p_input, es_descriptor_t * p_es )
     case AC3_AUDIO_ES:
         if( p_main->b_audio )
         {
-            decoder.pf_create_thread = ac3dec_CreateThread;
+            if( !p_main->b_spdif )
+            {
+                decoder.pf_create_thread = ac3dec_CreateThread;
+            }
+            else
+            {
+                decoder.pf_create_thread = spdif_CreateThread;
+            }
+
             p_config = (void *)GetAdecConfig( p_input, p_es );
 
             /* Release the lock, not to block the input thread during
@@ -669,7 +679,30 @@ int input_SelectES( input_thread_t * p_input, es_descriptor_t * p_es )
             vlc_mutex_lock( &p_input->stream.stream_lock );
         }
         break;
+#if 0
+    case LPCM_AUDIO_ES:
+        if( p_main->b_audio )
+        {
+            if( p_main->b_spdif )
+            {
+                decoder.pf_create_thread = spdif_CreateThread;
+            }
+            else
+            {
+                intf_ErrMsg( "input error: LPCM audio not handled yet" );
+                break;
+            }
+
+            p_config = (void *)GetAdecConfig( p_input, p_es );
 
+            /* Release the lock, not to block the input thread during
+             * the creation of the thread. */
+            vlc_mutex_unlock( &p_input->stream.stream_lock );
+            p_es->thread_id = input_RunDecoder( &decoder, p_config );
+            vlc_mutex_lock( &p_input->stream.stream_lock );
+        }
+        break;
+#endif
     case DVD_SPU_ES:
         if( p_main->b_video )
         {
index 7679075a133e720c6144de16659531719c48d617..6b04662b747b6fc7a237879eb0fecf3cf6f5c248 100644 (file)
@@ -4,7 +4,7 @@
  * and spawn threads.
  *****************************************************************************
  * Copyright (C) 1998, 1999, 2000 VideoLAN
- * $Id: main.c,v 1.89 2001/04/28 03:36:25 sam Exp $
+ * $Id: main.c,v 1.90 2001/04/29 02:48:51 stef Exp $
  *
  * Authors: Vincent Seguin <seguin@via.ecp.fr>
  *          Samuel Hocevar <sam@zoy.org>
@@ -94,6 +94,7 @@
 #define OPT_NOAUDIO             150
 #define OPT_STEREO              151
 #define OPT_MONO                152
+#define OPT_SPDIF               153
 
 #define OPT_NOVIDEO             160
 #define OPT_DISPLAY             161
@@ -141,6 +142,7 @@ static const struct option longopts[] =
     {   "aout",             1,          0,      'A' },
     {   "stereo",           0,          0,      OPT_STEREO },
     {   "mono",             0,          0,      OPT_MONO },
+    {   "spdif",            0,          0,      OPT_SPDIF },
 
     /* Video options */
     {   "novideo",          0,          0,      OPT_NOVIDEO },
@@ -522,6 +524,7 @@ static int GetConfiguration( int *pi_argc, char *ppsz_argv[], char *ppsz_env[] )
     p_main->b_audio     = 1;
     p_main->b_video     = 1;
     p_main->b_channels  = 0;
+    p_main->b_spdif     = 0;
 
     p_main->i_warning_level = 4;
 
@@ -605,6 +608,9 @@ static int GetConfiguration( int *pi_argc, char *ppsz_argv[], char *ppsz_env[] )
         case OPT_MONO:                                             /* --mono */
             main_PutIntVariable( AOUT_STEREO_VAR, 0 );
             break;
+        case OPT_SPDIF:                                           /* --spdif */
+            p_main->b_spdif = 1;
+            break;
 
         /* Video options */
         case OPT_NOVIDEO:                                       /* --novideo */
@@ -757,6 +763,7 @@ static void Usage( int i_fashion )
           "\n      --noaudio                  \tdisable audio"
           "\n  -A, --aout <module>            \taudio output method"
           "\n      --stereo, --mono           \tstereo/mono audio"
+          "\n      --spdif                    \tac3 pass-through mode"
           "\n"
           "\n      --novideo                  \tdisable video"
           "\n  -V, --vout <module>            \tvideo output method"