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

*More cleanification in gtk interface: now to change the

title/chapter/audio/spu/angle, we tell the input to do intead of doing
it inside the interface. It results in fewer locks during the changes.

*The dvd plugin reads again blocks of 32 sectors to gain speed since
there are no more lock-ups during stream change. I've also created a new
file that contain function to described video and audio streams with ifo
datas.

The changes are made only for gtk. We should update the other interfaces
soon (beos at least).

There is a memory corruption somewhere that make the vlc crash. I've no
idea where to search.
parent 62b322c2
......@@ -4,7 +4,7 @@
* control the pace of reading.
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
* $Id: input_ext-intf.h,v 1.36 2001/05/01 12:22:18 sam Exp $
* $Id: input_ext-intf.h,v 1.37 2001/05/19 00:39:29 stef Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
......@@ -193,9 +193,12 @@ typedef struct stream_descriptor_s
/* if (b_seekable) : */
int i_area_nb;
input_area_t ** pp_areas; /* list of areas in stream == offset
* interval with own properties */
input_area_t ** pp_areas; /* list of areas in stream == offset
* interval with own properties */
input_area_t * p_selected_area;
input_area_t * p_new_area; /* Newly selected area from
* the interface */
u32 i_mux_rate; /* the rate we read the stream (in
* units of 50 bytes/s) ; 0 if undef */
......@@ -216,6 +219,10 @@ typedef struct stream_descriptor_s
es_descriptor_t ** pp_es; /* carried elementary streams */
int i_selected_es_number;
es_descriptor_t ** pp_selected_es; /* ES with a decoder */
es_descriptor_t * p_newly_selected_es; /* ES selected from
* the interface */
es_descriptor_t * p_removed_es; /* ES removed from the interface */
/* Stream control */
stream_ctrl_t control;
......@@ -346,3 +353,5 @@ int input_ChangeES ( struct input_thread_s *, struct es_descriptor_s *, u8 );
int input_ToggleES ( struct input_thread_s *,
struct es_descriptor_s *,
boolean_t );
int input_ChangeArea( input_thread_t *, input_area_t * );
......@@ -7,7 +7,7 @@
# Objects
#
PLUGIN_C = dvd.o input_dvd.o dvd_netlist.o dvd_ioctl.o dvd_ifo.o dvd_udf.o dvd_css.o
PLUGIN_C = dvd.o input_dvd.o dvd_netlist.o dvd_ioctl.o dvd_ifo.o dvd_udf.o dvd_css.o dvd_summary.o
BUILTIN_C = $(PLUGIN_C:%.o=BUILTIN_%.o)
ALL_OBJ = $(PLUGIN_C) $(BUILTIN_C)
......
......@@ -2,7 +2,7 @@
* dvd_css.c: Functions for DVD authentification and unscrambling
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
* $Id: dvd_css.c,v 1.28 2001/05/07 03:14:09 stef Exp $
* $Id: dvd_css.c,v 1.29 2001/05/19 00:39:29 stef Exp $
*
* Author: Stphane Borel <stef@via.ecp.fr>
*
......@@ -48,7 +48,6 @@
#include "dvd_csstables.h"
#endif /* HAVE_CSS */
#include "dvd_ioctl.h"
#include "dvd_ifo.h"
#include "input_dvd.h"
......
......@@ -2,7 +2,7 @@
* dvd_css.h: Structures for DVD authentification and unscrambling
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
* $Id: dvd_css.h,v 1.7 2001/04/11 04:31:59 sam Exp $
* $Id: dvd_css.h,v 1.8 2001/05/19 00:39:29 stef Exp $
*
* Author: Stphane Borel <stef@via.ecp.fr>
*
......@@ -55,3 +55,12 @@ typedef struct css_s
dvd_key_t pi_title_key;
} css_t;
/*****************************************************************************
* Prototypes in dvd_css.c
*****************************************************************************/
struct css_s;
int CSSTest ( int );
int CSSInit ( int, struct css_s * );
int CSSGetKey ( int, struct css_s * );
int CSSDescrambleSector ( u8 * , u8 * );
......@@ -2,7 +2,7 @@
* dvd_ifo.c: Functions for ifo parsing
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
* $Id: dvd_ifo.c,v 1.26 2001/05/07 04:42:42 sam Exp $
* $Id: dvd_ifo.c,v 1.27 2001/05/19 00:39:29 stef Exp $
*
* Author: Stphane Borel <stef@via.ecp.fr>
*
......@@ -43,7 +43,6 @@
#include "intf_msg.h"
#include "dvd_ifo.h"
#include "dvd_udf.h"
#include "dvd_css.h"
#include "input_dvd.h"
/*
......@@ -508,6 +507,7 @@ int IfoTitleSet( ifo_t * p_ifo )
off_t i_off;
off_t i_start;
u64 i_temp;
u16 i_short;
int i, j;
if( p_ifo->vts.b_initialized )
......@@ -570,8 +570,27 @@ DumpBits( p_ifo, pi_buffer, &p_current, 2 );
/* FIXME : take care of endianness */
}
DumpBits( p_ifo, pi_buffer, &p_current, 2 );
// GETS( &manager_inf.video_atrt );
DumpBits( p_ifo, pi_buffer, &p_current, 2 );
i_short = ReadWord( p_ifo, pi_buffer, &p_current );
i_short >>= 2;
manager_inf.video_attr.i_mode = i_short & 0x1;
i_short >>= 1;
manager_inf.video_attr.i_letterboxed = i_short & 0x1;
i_short >>= 1;
manager_inf.video_attr.i_source_res = i_short & 0x3;
i_short >>= 2;
manager_inf.video_attr.i_line21_2 = i_short & 0x1;
i_short >>= 1;
manager_inf.video_attr.i_line21_1 = i_short & 0x1;
i_short >>= 1;
manager_inf.video_attr.i_perm_displ = i_short & 0x3;
i_short >>= 2;
manager_inf.video_attr.i_ratio = i_short & 0x3;
i_short >>= 2;
manager_inf.video_attr.i_system = i_short & 0x3;
i_short >>= 2;
manager_inf.video_attr.i_compression = i_short & 0x3;
DumpBits( p_ifo, pi_buffer, &p_current, 1 );
manager_inf.i_audio_nb = ReadByte( p_ifo, pi_buffer, &p_current );
//fprintf( stderr, "vtsi audio nb : %d\n", manager_inf.i_audio_nb );
......@@ -613,7 +632,9 @@ DumpBits( p_ifo, pi_buffer, &p_current, 2 );
i_temp = hton64( i_temp ) >> 16;
//fprintf( stderr, "Subpic %d: %llx\n", i, i_temp );
manager_inf.p_spu_attr[i].i_caption = i_temp & 0xff;
i_temp >>= 16;
i_temp >>= 8;
manager_inf.p_spu_attr[i].i_foo = i_temp & 0xff;
i_temp >>= 8;
manager_inf.p_spu_attr[i].i_lang_code = i_temp & 0xffff;
i_temp >>= 16;
manager_inf.p_spu_attr[i].i_prefix = i_temp & 0xffff;
......@@ -929,6 +950,8 @@ static int ReadTitle( ifo_t * p_ifo, title_t * p_title, off_t i_pos )
u8 pi_buffer[DVD_LB_SIZE];
u8 * p_current;
off_t i_start;
u16 i_audio;
u32 i_spu;
int i;
p_current = FillBuffer( p_ifo, pi_buffer, i_pos );
......@@ -945,11 +968,25 @@ static int ReadTitle( ifo_t * p_ifo, title_t * p_title, off_t i_pos )
p_title->i_prohibited_user_op = ReadDouble( p_ifo, pi_buffer, &p_current );
for( i = 0 ; i < 8 ; i++ )
{
p_title->pi_audio_status[i] = ReadWord( p_ifo, pi_buffer, &p_current );
i_audio = ReadWord( p_ifo, pi_buffer, &p_current );
p_title->pi_audio_status[i].i_foo = i_audio & 0xff;
i_audio >>= 8;
p_title->pi_audio_status[i].i_position = i_audio & 0x07;
i_audio >>= 7;
p_title->pi_audio_status[i].i_available = i_audio;
}
for( i = 0 ; i < 32 ; i++ )
{
p_title->pi_subpic_status[i] = ReadDouble( p_ifo, pi_buffer, &p_current );
i_spu = ReadDouble( p_ifo, pi_buffer, &p_current );
p_title->pi_spu_status[i].i_position_pan = i_spu & 0x1f;
i_spu >>= 8;
p_title->pi_spu_status[i].i_position_letter = i_spu & 0x1f;
i_spu >>= 8;
p_title->pi_spu_status[i].i_position_wide = i_spu & 0x1f;
i_spu >>= 8;
p_title->pi_spu_status[i].i_position_43 = i_spu & 0x1f;
i_spu >>= 7;
p_title->pi_spu_status[i].i_available = i_spu;
}
p_title->i_next_title_num = ReadWord( p_ifo, pi_buffer, &p_current );
p_title->i_prev_title_num = ReadWord( p_ifo, pi_buffer, &p_current );
......
......@@ -2,7 +2,7 @@
* dvd_ifo.h: Structures for ifo parsing
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
* $Id: dvd_ifo.h,v 1.14 2001/04/22 00:08:25 stef Exp $
* $Id: dvd_ifo.h,v 1.15 2001/05/19 00:39:30 stef Exp $
*
* Author: Stphane Borel <stef@via.ecp.fr>
*
......@@ -65,6 +65,14 @@ typedef struct ifo_audio_s
u8 i_bar ;// 8; // 0x00000000 ?
} ifo_audio_t;
/* Audio Status */
typedef struct audio_status_s
{
u8 i_available; // 1
u8 i_position; // 7
u8 i_foo; // 8
} audio_status_t;
typedef struct ifo_spu_t
{
u16 i_prefix ;// 16; // 0x0100 ?
......@@ -73,6 +81,15 @@ typedef struct ifo_spu_t
u8 i_caption ;// 8; // 0x00 ?
} ifo_spu_t;
/* Subpicture status */
typedef struct spu_status_s
{
u8 i_available; //1
u8 i_position_43; //7
u8 i_position_wide; //8
u8 i_position_letter; //8
u8 i_position_pan; //8
} spu_status_t;
/* Ifo vitual machine Commands */
......@@ -153,8 +170,8 @@ typedef struct title_s
u8 i_cell_nb; // 1 byte
u32 i_play_time; // 4 bytes
u32 i_prohibited_user_op; // 4 bytes
u16 pi_audio_status[8]; // 8*2 bytes
u32 pi_subpic_status[32]; // 32*4 bytes
audio_status_t pi_audio_status[8]; // 8*2 bytes
spu_status_t pi_spu_status[32]; // 32*4 bytes
u16 i_next_title_num; // 2 bytes
u16 i_prev_title_num; // 2 bytes
u16 i_go_up_title_num; // 2 bytes
......@@ -530,3 +547,13 @@ typedef struct ifo_s
vts_t vts; /* Vts ifo for current title set */
} ifo_t;
/*****************************************************************************
* Prototypes in dvd_ifo.c
*****************************************************************************/
struct thread_dvd_data_s;
int IfoCreate ( struct thread_dvd_data_s * );
int IfoInit ( struct ifo_s * );
int IfoTitleSet ( struct ifo_s * );
void IfoDestroy ( struct ifo_s * );
/*****************************************************************************
* dvd_summary.c: set of functions to print options of selected title
* found in .ifo.
*****************************************************************************
* Copyright (C) 1998-2001 VideoLAN
* $Id: dvd_summary.c,v 1.1 2001/05/19 00:39:30 stef Exp $
*
* Author: Stphane 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.
*****************************************************************************/
/*****************************************************************************
* Preamble
*****************************************************************************/
#include "defs.h"
#ifdef HAVE_CSS
#define MODULE_NAME dvd
#else /* HAVE_CSS */
#define MODULE_NAME dvdnocss
#endif /* HAVE_CSS */
#include "modules_inner.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <string.h>
#ifdef STRNCASECMP_IN_STRINGS_H
# include <strings.h>
#endif
#include <errno.h>
#include "config.h"
#include "common.h"
#include "threads.h"
#include "mtime.h"
#include "tests.h"
#include "intf_msg.h"
#include "main.h"
#include "dvd_ifo.h"
#include "input_dvd.h"
#include "debug.h"
#include "modules.h"
/*****************************************************************************
* Local tables
*****************************************************************************/
static struct
{
char p_code[3];
char p_lang_long[20];
}
lang_tbl[] =
{
/* The ISO 639 language codes.
* Language names with * prefix are not spelled in their own language
*/
{ " ", "Not Specified" },
{ "aa", "*Afar" },
{ "ab", "*Abkhazian" },
{ "af", "*Afrikaans" },
{ "am", "*Amharic" },
{ "ar", "*Arabic" },
{ "as", "*Assamese" },
{ "ay", "*Aymara" },
{ "az", "*Azerbaijani" },
{ "ba", "*Bashkir" },
{ "be", "*Byelorussian" },
{ "bg", "*Bulgarian" },
{ "bh", "*Bihari" },
{ "bi", "*Bislama" },
{ "bn", "*Bengali; Bangla" },
{ "bo", "*Tibetan" },
{ "br", "*Breton" },
{ "ca", "*Catalan" },
{ "co", "*Corsican" },
{ "cs", "*Czech(Ceske)" },
{ "cy", "*Welsh" },
{ "da", "Dansk" },
{ "de", "Deutsch" },
{ "dz", "*Bhutani" },
{ "el", "*Greek" },
{ "en", "English" },
{ "eo", "*Esperanto" },
{ "es", "Espanol" },
{ "et", "*Estonian" },
{ "eu", "*Basque" },
{ "fa", "*Persian" },
{ "fi", "Suomi" },
{ "fj", "*Fiji" },
{ "fo", "*Faroese" },
{ "fr", "Francais" },
{ "fy", "*Frisian" },
{ "ga", "*Irish" },
{ "gd", "*Scots Gaelic" },
{ "gl", "*Galician" },
{ "gn", "*Guarani" },
{ "gu", "*Gujarati" },
{ "ha", "*Hausa" },
{ "he", "*Hebrew" }, /* formerly iw */
{ "hi", "*Hindi" },
{ "hr", "Hrvatski" }, /* Croatian */
{ "hu", "Magyar" },
{ "hy", "*Armenian" },
{ "ia", "*Interlingua" },
{ "id", "*Indonesian" }, /* formerly in */
{ "ie", "*Interlingue" },
{ "ik", "*Inupiak" },
{ "in", "*Indonesian" }, /* replaced by id */
{ "is", "Islenska" },
{ "it", "Italiano" },
{ "iu", "*Inuktitut" },
{ "iw", "*Hebrew" }, /* replaced by he */
{ "ja", "*Japanese" },
{ "ji", "*Yiddish" }, /* replaced by yi */
{ "jw", "*Javanese" },
{ "ka", "*Georgian" },
{ "kk", "*Kazakh" },
{ "kl", "*Greenlandic" },
{ "km", "*Cambodian" },
{ "kn", "*Kannada" },
{ "ko", "*Korean" },
{ "ks", "*Kashmiri" },
{ "ku", "*Kurdish" },
{ "ky", "*Kirghiz" },
{ "la", "*Latin" },
{ "ln", "*Lingala" },
{ "lo", "*Laothian" },
{ "lt", "*Lithuanian" },
{ "lv", "*Latvian, Lettish" },
{ "mg", "*Malagasy" },
{ "mi", "*Maori" },
{ "mk", "*Macedonian" },
{ "ml", "*Malayalam" },
{ "mn", "*Mongolian" },
{ "mo", "*Moldavian" },
{ "mr", "*Marathi" },
{ "ms", "*Malay" },
{ "mt", "*Maltese" },
{ "my", "*Burmese" },
{ "na", "*Nauru" },
{ "ne", "*Nepali" },
{ "nl", "Nederlands" },
{ "no", "Norsk" },
{ "oc", "*Occitan" },
{ "om", "*(Afan) Oromo" },
{ "or", "*Oriya" },
{ "pa", "*Punjabi" },
{ "pl", "*Polish" },
{ "ps", "*Pashto, Pushto" },
{ "pt", "Portugues" },
{ "qu", "*Quechua" },
{ "rm", "*Rhaeto-Romance" },
{ "rn", "*Kirundi" },
{ "ro", "*Romanian" },
{ "ru", "*Russian" },
{ "rw", "*Kinyarwanda" },
{ "sa", "*Sanskrit" },
{ "sd", "*Sindhi" },
{ "sg", "*Sangho" },
{ "sh", "*Serbo-Croatian" },
{ "si", "*Sinhalese" },
{ "sk", "*Slovak" },
{ "sl", "*Slovenian" },
{ "sm", "*Samoan" },
{ "sn", "*Shona" },
{ "so", "*Somali" },
{ "sq", "*Albanian" },
{ "sr", "*Serbian" },
{ "ss", "*Siswati" },
{ "st", "*Sesotho" },
{ "su", "*Sundanese" },
{ "sv", "Svenska" },
{ "sw", "*Swahili" },
{ "ta", "*Tamil" },
{ "te", "*Telugu" },
{ "tg", "*Tajik" },
{ "th", "*Thai" },
{ "ti", "*Tigrinya" },
{ "tk", "*Turkmen" },
{ "tl", "*Tagalog" },
{ "tn", "*Setswana" },
{ "to", "*Tonga" },
{ "tr", "*Turkish" },
{ "ts", "*Tsonga" },
{ "tt", "*Tatar" },
{ "tw", "*Twi" },
{ "ug", "*Uighur" },
{ "uk", "*Ukrainian" },
{ "ur", "*Urdu" },
{ "uz", "*Uzbek" },
{ "vi", "*Vietnamese" },
{ "vo", "*Volapuk" },
{ "wo", "*Wolof" },
{ "xh", "*Xhosa" },
{ "yi", "*Yiddish" }, /* formerly ji */
{ "yo", "*Yoruba" },
{ "za", "*Zhuang" },
{ "zh", "*Chinese" },
{ "zu", "*Zulu" },
{ "\0", "" }
};
/*
* Local tools to decode some data in ifo
*/
/*****************************************************************************
* IfoLanguage: gives the long language name from the two-letters
* ISO-639 code
*****************************************************************************/
char * IfoLanguage( u16 i_code )
{
int i = 0;
while( memcmp( lang_tbl[i].p_code, &i_code, 2 ) &&
lang_tbl[i].p_lang_long[0] )
{
i++;
}
return lang_tbl[i].p_lang_long;
}
/****************************************************************************
* IfoPrintTitle
****************************************************************************/
void IfoPrintTitle( thread_dvd_data_t * p_dvd )
{
intf_WarnMsg( 5, "***************************************************" );
intf_WarnMsg( 5, "dvd info: title: %d", p_dvd->i_title );
intf_WarnMsg( 5, " vobstart at: %lld", p_dvd->i_start );
intf_WarnMsg( 5, " stream size: %lld", p_dvd->i_size );
intf_WarnMsg( 5, " number of chapters: %d", p_dvd->i_chapter_nb );
intf_WarnMsg( 5, " number of angles: %d", p_dvd->i_angle_nb );
intf_WarnMsg( 5, "***************************************************\n" );
}
/****************************************************************************
* IfoPrintVideo
****************************************************************************/
#define video p_dvd->p_ifo->vts.manager_inf.video_attr
void IfoPrintVideo( thread_dvd_data_t * p_dvd )
{
char psz_ratio[12];
char psz_perm_displ[4][23] =
{
"pan-scan & letterboxed",
"pan-scan",
"letterboxed",
"not specified"
};
char psz_source_res[4][28] =
{
"720x480 ntsc or 720x576 pal",
"704x480 ntsc or 704x576 pal",
"352x480 ntsc or 352x576 pal",
"352x240 ntsc or 352x288 pal"
};
switch( video.i_ratio )
{
case 0:
sprintf( psz_ratio, "4:3" );
break;
case 3:
sprintf( psz_ratio, "16:9" );
break;
default:
sprintf( psz_ratio, "undef" );
break;
}
intf_WarnMsg( 5, "***********************************************" );
intf_WarnMsg( 5, "dvd info: video" );
intf_WarnMsg( 5, " compression: mpeg-%d", video.i_compression+1 );
intf_WarnMsg( 5, " tv system: %s Hz",
video.i_system ? "pal 625/50" : "ntsc 525/60" );
intf_WarnMsg( 5, " aspect ratio: %s", psz_ratio );
intf_WarnMsg( 5, " display mode: %s",
psz_perm_displ[video.i_perm_displ] );
intf_WarnMsg( 5, " line21-1: %s",
video.i_line21_1 ? "data present in GOP" : "" );
intf_WarnMsg( 5, " line21-2: %s",
video.i_line21_2 ? "data present in GOP" : "" );
intf_WarnMsg( 5, " source res: %s",
psz_source_res[video.i_source_res] );
intf_WarnMsg( 5, " letterboxed: %s",
video.i_letterboxed ? "yes" : "no" );
intf_WarnMsg( 5, " mode: %s",
video.i_mode ? "film (625/50 only)" : "camera");
intf_WarnMsg( 5, "***********************************************\n" );
}
#undef video
/****************************************************************************
* IfoPrintAudio
****************************************************************************/
#define audio p_dvd->p_ifo->vts.manager_inf.p_audio_attr[i-1]
#define audio_status \
p_dvd->p_ifo->vts.title_unit.p_title[p_dvd->i_title_id-1].title.pi_audio_status[i-1]
void IfoPrintAudio( thread_dvd_data_t * p_dvd, int i )
{
if( audio_status.i_available )
{
char ppsz_mode[7][9] =
{ "ac3", "unknown", "mpeg-1", "mpeg-2", "lpcm", "sdds", "dts" };
char ppsz_appl_mode[3][15] =
{ "not specified", "karaoke", "surround sound" };
char psz_caption[25];
char ppsz_quant[4][10] =
{ "16 bits", "20 bits", "24 bits", "drc" };
intf_WarnMsg( 5, "***********************************************" );
intf_WarnMsg( 5, "dvd info: audio %d" , i );
intf_WarnMsg( 5, " language: %s",
IfoLanguage( hton16( audio.i_lang_code ) ) );
intf_WarnMsg( 5, " mode: %s", ppsz_mode[audio.i_coding_mode & 0x7] );
intf_WarnMsg( 5, " channel(s): %d %s",
audio.i_num_channels + 1,
audio.i_multichannel_extension ? "ext." : "" );
intf_WarnMsg( 5, " sampling: %d Hz",
audio.i_sample_freq ? 96000 : 48000 );
intf_WarnMsg( 5, " appl_mode: %s",
ppsz_appl_mode[audio.i_appl_mode & 0x2] );
switch( audio.i_caption )
{
case 1:
sprintf( psz_caption, "normal caption" );
break;
case 3:
sprintf( psz_caption, "directors comments" );
break;
default:
sprintf( psz_caption, " " );
break;
}
intf_WarnMsg( 5, " caption: %s", psz_caption );
intf_WarnMsg( 5, " quantization: %s",
ppsz_quant[audio.i_quantization & 0x3] );
intf_WarnMsg( 5, " status: %x", audio_status.i_position );
intf_WarnMsg( 5, "***********************************************\n" );
}
}
#undef audio_status
#undef audio
/****************************************************************************
* IfoPrintSpu
****************************************************************************/
#define spu p_dvd->p_ifo->vts.manager_inf.p_spu_attr[i-1]
#define spu_status \
p_dvd->p_ifo->vts.title_unit.p_title[p_dvd->i_title_id-1].title.pi_spu_status[i-1]
void IfoPrintSpu( thread_dvd_data_t * p_dvd, int i )
{
if( spu_status.i_available )
{
intf_WarnMsg( 5, "***********************************************" );
intf_WarnMsg( 5, "dvd info: spu %d", i );
intf_WarnMsg( 5, " caption: %d", spu.i_caption );
intf_WarnMsg( 5, " language: %s",
IfoLanguage( hton16( spu.i_lang_code ) ) );