Commit 17a54d55 authored by Stéphane Borel's avatar Stéphane Borel

-New ES detection based on .ifo for DVD module. It might fail (I have

found one DVD for which ifo seems false).

-Title and chapter selection on the command line (see -t and -T options)
It will allow to watch some DVD that went through menus by default.

-beginning of menus in gnome interface.
parent 4b1da9cc
......@@ -213,6 +213,8 @@
#define INPUT_DVD_DEVICE_VAR "vlc_dvd_device"
#define INPUT_DVD_DEVICE_DEFAULT "/dev/dvd"
#define INPUT_TITLE_VAR "vlc_input_title"
#define INPUT_CHAPTER_VAR "vlc_input_chapter"
#define INPUT_AUDIO_VAR "vlc_input_audio"
#define INPUT_CHANNEL_VAR "vlc_input_channel"
#define INPUT_SUBTITLE_VAR "vlc_input_subtitle"
......
......@@ -2,7 +2,7 @@
* input.h: structures of the input not exported to other modules
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
* $Id: input.h,v 1.30 2001/02/20 02:53:13 stef Exp $
* $Id: input.h,v 1.31 2001/02/22 08:44:45 stef Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
......@@ -66,6 +66,7 @@ struct es_descriptor_s * input_AddES ( struct input_thread_s *,
size_t );
void input_DelES ( struct input_thread_s *, struct es_descriptor_s * );
int input_SelectES ( struct input_thread_s *, struct es_descriptor_s * );
int input_UnSelectES( struct input_thread_s *, struct es_descriptor_s * );
/*****************************************************************************
* Prototypes from input_dec.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.14 2001/02/20 23:30:15 sam Exp $
* $Id: dvd_css.c,v 1.15 2001/02/22 08:44:45 stef Exp $
*
* Author: Stphane Borel <stef@via.ecp.fr>
*
......@@ -1199,7 +1199,7 @@ int CSSGetKey( css_t * p_css )
* produces multiple keys (RT)
*/
intf_WarnMsg( 3, "CSS: Title %d key: %02X %02X %02X %02X %02X",
i_title + 1,
i_title,
p_title_key[i_highest].pi_key[0],
p_title_key[i_highest].pi_key[1],
p_title_key[i_highest].pi_key[2],
......
......@@ -2,7 +2,7 @@
* dvd_ifo.c: Functions for ifo parsing
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
* $Id: dvd_ifo.c,v 1.13 2001/02/20 07:49:12 sam Exp $
* $Id: dvd_ifo.c,v 1.14 2001/02/22 08:44:45 stef Exp $
*
* Author: Stphane Borel <stef@via.ecp.fr>
*
......@@ -528,6 +528,7 @@ static vobu_admap_t ReadMap( ifo_t* p_ifo )
static vmgi_mat_t ReadVMGInfMat( ifo_t* p_ifo )
{
vmgi_mat_t mat;
u64 i_temp;
int i;
// off_t i_start = p_ifo->i_pos;
......@@ -561,20 +562,21 @@ static vmgi_mat_t ReadVMGInfMat( ifo_t* p_ifo )
GETL( &mat.i_c_adt_ssector );
GETL( &mat.i_vobu_admap_ssector );
FLUSH( 32 );
GETS( &mat.i_video_atrt );
// GETS( &mat.video_atrt );
FLUSH(2);
FLUSH( 1 );
GETC( &mat.i_audio_nb );
//fprintf( stderr, "vmgi audio nb : %d\n", mat.i_audio_nb );
for( i=0 ; i < 8 ; i++ )
{
GETLL( &mat.pi_audio_atrt[i] );
GETLL( &i_temp );
}
FLUSH( 17 );
GETC( &mat.i_subpic_nb );
//fprintf( stderr, "vmgi subpic nb : %d\n", mat.i_subpic_nb );
for( i=0 ; i < mat.i_subpic_nb ; i++ )
{
GET( &mat.pi_subpic_atrt[i], 6 );
GET( &i_temp, 6 );
/* FIXME : take care of endianness */
}
......@@ -685,6 +687,7 @@ static vmg_vts_atrt_t ReadVTSAttr( ifo_t* p_ifo )
{
vmg_vts_atrt_t atrt;
int i, j;
u64 i_temp;
off_t i_start = p_ifo->i_pos;
//fprintf( stderr, "VTS ATTR\n" );
......@@ -718,37 +721,39 @@ static vmg_vts_atrt_t ReadVTSAttr( ifo_t* p_ifo )
SEEK_SET );
GETL( &atrt.p_vts_atrt[i].i_ebyte );
GETL( &atrt.p_vts_atrt[i].i_cat_app_type );
GETS( &atrt.p_vts_atrt[i].i_vtsm_video_atrt );
// GETS( &atrt.p_vts_atrt[i].vtsm_video_atrt );
FLUSH(2);
FLUSH( 1 );
GETC( &atrt.p_vts_atrt[i].i_vtsm_audio_nb );
//fprintf( stderr, "m audio nb : %d\n", atrt.p_vts_atrt[i].i_vtsm_audio_nb );
for( j=0 ; j<8 ; j++ )
{
GETLL( &atrt.p_vts_atrt[i].pi_vtsm_audio_atrt[j] );
GETLL( &i_temp );
}
FLUSH( 17 );
GETC( &atrt.p_vts_atrt[i].i_vtsm_subpic_nb );
//fprintf( stderr, "m subp nb : %d\n", atrt.p_vts_atrt[i].i_vtsm_subpic_nb );
for( j=0 ; j<28 ; j++ )
{
GET( &atrt.p_vts_atrt[i].pi_vtsm_subpic_atrt[j], 6 );
GET( &i_temp, 6 );
/* FIXME : Fix endianness issue here */
}
FLUSH( 2 );
GETS( &atrt.p_vts_atrt[i].i_vtstt_video_atrt );
// GETS( &atrt.p_vts_atrt[i].vtstt_video_atrt );
FLUSH(2);
FLUSH( 1 );
GETL( &atrt.p_vts_atrt[i].i_vtstt_audio_nb );
//fprintf( stderr, "tt audio nb : %d\n", atrt.p_vts_atrt[i].i_vtstt_audio_nb );
for( j=0 ; j<8 ; j++ )
{
GETLL( &atrt.p_vts_atrt[i].pi_vtstt_audio_atrt[j] );
GETLL( &i_temp );
}
FLUSH( 17 );
GETC( &atrt.p_vts_atrt[i].i_vtstt_subpic_nb );
//fprintf( stderr, "tt subp nb : %d\n", atrt.p_vts_atrt[i].i_vtstt_subpic_nb );
for( j=0 ; j<28/*atrt.p_vts_atrt[i].i_vtstt_subpic_nb*/ ; j++ )
{
GET( &atrt.p_vts_atrt[i].pi_vtstt_subpic_atrt[j], 6 );
GET( &i_temp, 6 );
/* FIXME : Fix endianness issue here */
}
}
......@@ -825,6 +830,7 @@ static vtsi_mat_t ReadVTSInfMat( ifo_t* p_ifo )
{
vtsi_mat_t mat;
int i;
u64 i_temp;
// off_t i_start = p_ifo->i_pos;
//fprintf( stderr, "VTSI\n" );
......@@ -851,36 +857,61 @@ static vtsi_mat_t ReadVTSInfMat( ifo_t* p_ifo )
GETL( &mat.i_c_adt_ssector );
GETL( &mat.i_vobu_admap_ssector );
FLUSH( 24 );
GETS( &mat.i_m_video_atrt );
// GETS( &mat.m_video_atrt );
FLUSH(2);
FLUSH( 1 );
GETC( &mat.i_m_audio_nb );
for( i=0 ; i<8 ; i++ )
{
GETLL( &mat.pi_m_audio_atrt[i] );
GETLL( &i_temp );
}
FLUSH( 17 );
GETC( &mat.i_m_subpic_nb );
for( i=0 ; i<28 ; i++ )
{
GET( &mat.pi_m_subpic_atrt[i], 6 );
GET( &i_temp, 6 );
/* FIXME : take care of endianness */
}
FLUSH( 2 );
GETS( &mat.i_video_atrt );
// GETS( &mat.video_atrt );
FLUSH(2);
FLUSH( 1 );
GETC( &mat.i_audio_nb );
//fprintf( stderr, "vtsi audio nb : %d\n", mat.i_audio_nb );
for( i=0 ; i<8 ; i++ )
{
GETLL( &mat.pi_audio_atrt[i] );
GETLL( &i_temp );
//fprintf( stderr, "Audio %d: %llx\n", i, i_temp );
i_temp >>= 32;
mat.p_audio_atrt[i].i_lang_code = i_temp & 0xffff;
i_temp >>= 16;
mat.p_audio_atrt[i].i_num_channels = i_temp & 0x7;
i_temp >>= 4;
mat.p_audio_atrt[i].i_sample_freq = i_temp & 0x3;
i_temp >>= 2;
mat.p_audio_atrt[i].i_quantization = i_temp & 0x3;
i_temp >>= 2;
mat.p_audio_atrt[i].i_appl_mode = i_temp & 0x3;
i_temp >>= 2;
mat.p_audio_atrt[i].i_type = i_temp & 0x3;
i_temp >>= 2;
mat.p_audio_atrt[i].i_multichannel_extension = i_temp & 0x1;
i_temp >>= 1;
mat.p_audio_atrt[i].i_coding_mode = i_temp & 0x7;
}
FLUSH( 17 );
GETC( &mat.i_subpic_nb );
//fprintf( stderr, "vtsi subpic nb : %d\n", mat.i_subpic_nb );
for( i=0 ; i<mat.i_subpic_nb ; i++ )
{
GET( &mat.pi_subpic_atrt[i], 6 );
/* FIXME : take care of endianness */
GET( &i_temp, 6 );
i_temp = hton64( i_temp ) >> 16;
//fprintf( stderr, "Subpic %d: %llx\n", i, i_temp );
mat.p_subpic_atrt[i].i_caption = i_temp & 0xff;
i_temp >>= 16;
mat.p_subpic_atrt[i].i_lang_code = i_temp & 0xffff;
i_temp >>= 16;
mat.p_subpic_atrt[i].i_prefix = i_temp & 0xffff;
}
return mat;
......@@ -999,7 +1030,8 @@ int IfoReadVTS( ifo_t* p_ifo )
intf_WarnMsg( 2, "ifo: initializing VTS %d", p_ifo->i_title );
i_title = p_ifo->i_title;
i_off = (off_t)( p_ifo->vmg.ptt_srpt.p_tts[i_title].i_ssector ) *DVD_LB_SIZE
i_off = (off_t)( p_ifo->vmg.ptt_srpt.p_tts[i_title-1].i_ssector )
* DVD_LB_SIZE
+ p_ifo->i_off;
p_ifo->i_pos = lseek( p_ifo->i_fd, i_off, SEEK_SET );
......
......@@ -2,7 +2,7 @@
* dvd_ifo.h: Structures for ifo parsing
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
* $Id: dvd_ifo.h,v 1.7 2001/02/20 02:53:13 stef Exp $
* $Id: dvd_ifo.h,v 1.8 2001/02/22 08:44:45 stef Exp $
*
* Author: Stphane Borel <stef@via.ecp.fr>
*
......@@ -33,6 +33,47 @@
/*
* Program Chain structures
*/
typedef struct ifo_video_s
{
u8 i_compression ;// 2;
u8 i_system ;// 2;
u8 i_ratio ;// 2;
u8 i_perm_displ ;// 2;
u8 i_line21_1 ;// 1;
u8 i_line21_2 ;// 1;
u8 i_source_res ;// 2;
u8 i_letterboxed ;// 1;
u8 i_mode ;// 1;
} ifo_video_t;
/* Audio type information */
typedef struct ifo_audio_s
{
u8 i_coding_mode ;// 3;
u8 i_multichannel_extension ;// 1;
u8 i_type ;// 2;
u8 i_appl_mode ;// 2;
u8 i_quantization ;// 2;
u8 i_sample_freq ;// 2;
// u8 ;// 1;
u8 i_num_channels ;// 3;
u16 i_lang_code ;// 16; // <char> description
u8 i_foo ;// 8; // 0x00000000 ?
u8 i_caption ;// 8;
u8 i_bar ;// 8; // 0x00000000 ?
} ifo_audio_t;
typedef struct ifo_spu_t
{
u16 i_prefix ;// 16; // 0x0100 ?
u16 i_lang_code ;// 16; // <char> description
u8 i_foo ;// 8; // dont know
u8 i_caption ;// 8; // 0x00 ?
} ifo_spu_t;
/* Ifo vitual machine Commands */
typedef struct ifo_command_s
......@@ -241,13 +282,13 @@ typedef struct vmgi_mat_s
u32 i_c_adt_ssector; // 4 bytes
u32 i_vobu_admap_ssector; // 4 bytes
// char[2] ???
u16 i_video_atrt; // 2 bytes
ifo_video_t video_atrt; // 2 bytes
// char ???
u8 i_audio_nb; // 1 byte
u64 pi_audio_atrt[8]; // i_vmgm_audio_nb * 8 bytes
ifo_audio_t p_audio_atrt[8]; // i_vmgm_audio_nb * 8 bytes
// char[16] ???
u8 i_subpic_nb; // 1 byte
u64 pi_subpic_atrt[32]; // i_subpic_nb * 6 bytes
ifo_spu_t p_subpic_atrt[32]; // i_subpic_nb * 6 bytes
} vmgi_mat_t;
......@@ -315,21 +356,21 @@ typedef struct vts_atrt_s
{
u32 i_ebyte; // 4 bytes
u32 i_cat_app_type; // 4 bytes
u16 i_vtsm_video_atrt; // 2 bytes
ifo_video_t vtsm_video_atrt; // 2 bytes
// char ???
u8 i_vtsm_audio_nb; // 1 byte
u64 pi_vtsm_audio_atrt[8]; // 8 * 8 bytes
ifo_audio_t p_vtsm_audio_atrt[8]; // 8 * 8 bytes
// char[17] ???
u8 i_vtsm_subpic_nb; // 1 byte
u64 pi_vtsm_subpic_atrt[28]; // i_vtsm_subpic_nb * 6 bytes
ifo_spu_t p_vtsm_subpic_atrt[28]; // i_vtsm_subpic_nb * 6 bytes
// char[2] ???
u16 i_vtstt_video_atrt; // 2 bytes
ifo_video_t vtstt_video_atrt; // 2 bytes
// char ???
u8 i_vtstt_audio_nb; // 1 byte
u64 pi_vtstt_audio_atrt[8]; // 8 * 8 bytes
ifo_audio_t p_vtstt_audio_atrt[8]; // 8 * 8 bytes
// char[17] ???
u8 i_vtstt_subpic_nb; // 1 byte
u64 pi_vtstt_subpic_atrt[28]; // i_vtstt_subpic_nb * 6 bytes
ifo_spu_t p_vtstt_subpic_atrt[28]; // i_vtstt_subpic_nb * 6 bytes
} vts_atrt_t;
/* Main struct for vts attributes
......@@ -388,22 +429,22 @@ typedef struct vtsi_mat_s
u32 i_c_adt_ssector; // 4 bytes
u32 i_vobu_admap_ssector; // 4 bytes
// char[24] ???
u16 i_m_video_atrt; // 2 bytes
ifo_video_t m_video_atrt; // 2 bytes
// char ???
u8 i_m_audio_nb; // 1 byte
u64 pi_m_audio_atrt[8]; // i_vmgm_audio_nb * 8 bytes
ifo_audio_t p_m_audio_atrt[8]; // i_vmgm_audio_nb * 8 bytes
// char[16] ???
u8 i_m_subpic_nb; // 1 byte
u64 pi_m_subpic_atrt[32]; // i_subpic_nb * 6 bytes
ifo_spu_t p_m_subpic_atrt[32]; // i_subpic_nb * 6 bytes
// !!! only 28 subpics ???
// char[2] ???
u16 i_video_atrt; // 2 bytes
ifo_video_t video_atrt; // 2 bytes
// char ???
u8 i_audio_nb; // 1 byte
u64 pi_audio_atrt[8]; // i_vmgm_audio_nb * 8 bytes
ifo_audio_t p_audio_atrt[8]; // i_vmgm_audio_nb * 8 bytes
// char[16] ???
u8 i_subpic_nb; // 1 byte
u64 pi_subpic_atrt[32]; // i_subpic_nb * 6 bytes
ifo_spu_t p_subpic_atrt[32]; // i_subpic_nb * 6 bytes
} vtsi_mat_t;
/*
......
......@@ -10,7 +10,7 @@
* -dvd_udf to find files
*****************************************************************************
* Copyright (C) 1998-2001 VideoLAN
* $Id: input_dvd.c,v 1.18 2001/02/20 23:30:15 sam Exp $
* $Id: input_dvd.c,v 1.19 2001/02/22 08:44:45 stef Exp $
*
* Author: Stphane Borel <stef@via.ecp.fr>
*
......@@ -278,11 +278,12 @@ void _M( input_getfunctions )( function_list_t * p_function_list )
/*****************************************************************************
* Language: gives the long language name from the two-letters ISO-639 code
*****************************************************************************/
static char * Language( char * p_code )
static char * Language( u16 i_code )
{
int i = 0;
while( !memcmp( lang_tbl[i].p_code, p_code, 2 ) && lang_tbl[i].p_lang_long )
while( memcmp( lang_tbl[i].p_code, &i_code, 2 ) &&
lang_tbl[i].p_lang_long[0] )
{
i++;
}
......@@ -335,33 +336,93 @@ static int DVDCheckCSS( input_thread_t * p_input )
return CSSTest( p_input->i_handle );
}
/*****************************************************************************
* DVDChapterSelect: find the cell corresponding to requested chapter
*****************************************************************************/
static int DVDChapterSelect( thread_dvd_data_t * p_dvd, int i_chapter )
{
pgc_t * p_pgc;
int i_start_cell;
int i_end_cell;
int i_index;
int i_cell;
p_pgc = &p_dvd->ifo.vts.pgci_ti.p_srp[0].pgc;
/* Find cell index in Program chain for current chapter */
i_index = p_pgc->prg_map.pi_entry_cell[i_chapter-1] - 1;
/* Search for cell_index in cell adress_table */
i_cell = 0;
while( p_pgc->p_cell_pos_inf[i_index].i_vob_id >
p_dvd->ifo.vts.c_adt.p_cell_inf[i_cell].i_vob_id )
{
i_cell++;
}
while( p_pgc->p_cell_pos_inf[i_index].i_cell_id >
p_dvd->ifo.vts.c_adt.p_cell_inf[i_cell].i_cell_id )
{
i_cell++;
}
i_start_cell = i_cell;
p_dvd->i_start = p_dvd->ifo.vts.i_pos + DVD_LB_SIZE *
(off_t)( p_dvd->ifo.vts.mat.i_tt_vobs_ssector +
p_dvd->ifo.vts.c_adt.p_cell_inf[i_start_cell].i_ssector );
if( i_chapter == 1 )
{
i_end_cell = i_start_cell + p_pgc->i_cell_nb - 1;
p_dvd->i_size = (off_t)DVD_LB_SIZE *
( p_dvd->ifo.vts.c_adt.p_cell_inf[i_end_cell].i_esector -
p_dvd->ifo.vts.c_adt.p_cell_inf[i_start_cell].i_ssector + 1 );
p_dvd->i_chapter_nb = p_pgc->i_cell_nb;
intf_WarnMsg( 3, "DVD: Start cell: %d End Cell: %d",
i_start_cell, i_end_cell );
}
return 0;
}
/*****************************************************************************
* DVDSetArea: initialize input data for title x, chapter y.
* It should be called for each user navigation request, and to change
* audio or sub-picture streams.
* ---
* Take care that i_title and i_chapter start from 0.
* Take care that i_title starts from 0 (vmg) and i_chapter start from 1.
* i_audio, i_spu start from 1 ; 0 means off.
* A negative value for an argument means it does not change
*****************************************************************************/
static int DVDSetArea( input_thread_t * p_input,
int i_title, int i_chapter,
int i_audio, int i_spu )
{
thread_dvd_data_t * p_method;
// es_descriptor_t * p_es;
off_t i_start;
off_t i_size;
pgc_t * p_pgc;
int i_start_cell;
int i_end_cell;
es_descriptor_t * p_es;
int i_index;
int i_cell;
// int i_nb;
// int i_id;
// int i;
int i_nb;
u16 i_id;
u8 i_ac3;
u8 i_mpeg;
u8 i_sub_pic;
u8 i;
boolean_t b_last;
p_method = (thread_dvd_data_t*)p_input->p_plugin_data;
/* Ifo structures reading */
vlc_mutex_lock( &p_input->stream.stream_lock );
if( i_title >= 0 )
{
/*
* We have to load all title information
*/
/* Change the default area */
p_input->stream.p_selected_area = p_input->stream.pp_areas[i_title];
/* Ifo VTS, and CSS reading */
p_method->ifo.i_title = i_title;
IfoReadVTS( &(p_method->ifo) );
intf_WarnMsg( 2, "Ifo: VTS initialized" );
......@@ -376,251 +437,216 @@ static int DVDSetArea( input_thread_t * p_input,
intf_WarnMsg( 2, "CSS: VTS key initialized" );
}
/* Set selected title start and size */
p_pgc = &p_method->ifo.vts.pgci_ti.p_srp[0].pgc;
/* Find cell index in Program chain */
i_index = p_pgc->prg_map.pi_entry_cell[i_chapter] - 1;
/*
* Set selected title start and size
*/
DVDChapterSelect( p_method, 1 );
/* Search for cell_index in cell adress_table */
i_cell = 0;
while( p_pgc->p_cell_pos_inf[i_index].i_vob_id >
p_method->ifo.vts.c_adt.p_cell_inf[i_cell].i_vob_id )
{
i_cell++;
}
while( p_pgc->p_cell_pos_inf[i_index].i_cell_id >
p_method->ifo.vts.c_adt.p_cell_inf[i_cell].i_cell_id )
{
i_cell++;
}
i_start_cell = i_cell;
i_end_cell = i_start_cell + p_pgc->i_cell_nb - 1;
/* start is : beginning of vts + offset to vobs + offset to vob x */
intf_WarnMsg( 3, "DVD: Start cell: %d End Cell: %d",
i_start_cell, i_end_cell );
p_method->i_start =
lseek( p_input->i_handle, p_method->i_start, SEEK_SET );
p_method->i_start_cell = i_start_cell;
p_method->i_end_cell = i_end_cell;
intf_WarnMsg( 2, "DVD: vobstart at: %lld", p_method->i_start );
intf_WarnMsg( 2, "DVD: stream size: %lld", p_method->i_size );
intf_WarnMsg( 2, "DVD: number of chapters: %lld",
p_method->i_chapter_nb );
/* start is : beginning of vts + offset to vobs + offset to vob x */
i_start = p_method->ifo.vts.i_pos + DVD_LB_SIZE *
( p_method->ifo.vts.mat.i_tt_vobs_ssector +
p_method->ifo.vts.c_adt.p_cell_inf[i_start_cell].i_ssector );
/* Area definition */
p_input->stream.p_selected_area->i_start = p_method->i_start;
p_input->stream.p_selected_area->i_size = p_method->i_size;
p_input->stream.p_selected_area->i_part_nb = p_method->i_chapter_nb;
i_start = lseek( p_input->i_handle, i_start, SEEK_SET );
intf_WarnMsg( 2, "DVD: VOBstart at: %lld", i_start );
/*
* Destroy obsolete ES by reinitializing program 0
* and find all ES in title with ifo data
*/
if( p_input->stream.pp_programs != NULL )
{
input_DelProgram( p_input, p_input->stream.pp_programs[0] );
}
i_size = (off_t)
( p_method->ifo.vts.c_adt.p_cell_inf[i_end_cell].i_esector -
p_method->ifo.vts.c_adt.p_cell_inf[i_start_cell].i_ssector + 1 )
*DVD_LB_SIZE;
intf_WarnMsg( 2, "DVD: stream size: %lld", i_size );
input_AddProgram( p_input, 0, sizeof( stream_ps_data_t ) );
#if 0
p_es = NULL;
vlc_mutex_lock( &p_input->stream.stream_lock );
/* ES 0 -> video MPEG2 */
intf_WarnMsg( 1, "DVD: Video MPEG2 stream" );
p_es = input_AddES( p_input, p_input->stream.pp_programs[0], 0xe0, 0 );
p_es->i_stream_id = 0xe0;
p_es->i_type = MPEG2_VIDEO_ES;
input_SelectES( p_input, p_es );
intf_WarnMsg( 1, "DVD: Video MPEG2 stream" );
/* Audio ES, in the order they appear in .ifo */
i_nb = p_method->ifo.vts.mat.i_audio_nb;
intf_WarnMsg( 1, "DVD: Audio streams %d", i_nb );
for( i = 0 ; i < i_nb ; i++ )
i_ac3 = 0x80;
i_mpeg = 0xc0;
for( i = 1 ; i <= i_nb ; i++ )
{
i_id = ( ( 0x80 + i ) << 8 ) | 0xbd;
#if 0
fprintf( stderr, "Audio %d: %x %x %x %x %x %x\n", i,
p_method->ifo.vts.mat.p_audio_atrt[i].i_coding_mode,
p_method->ifo.vts.mat.p_audio_atrt[i].i_multichannel_extension,
p_method->ifo.vts.mat.p_audio_atrt[i].i_type,
p_method->ifo.vts.mat.p_audio_atrt[i].i_appl_mode,
p_method->ifo.vts.mat.p_audio_atrt[i].i_foo,
p_method->ifo.vts.mat.p_audio_atrt[i].i_bar );
#endif
switch( p_method->ifo.vts.mat.p_audio_atrt[i].i_coding_mode )
{
case 0x00: /* AC3 */
i_id = ( ( 0x7f + i ) << 8 ) | 0xbd;
p_es = input_AddES( p_input,
p_input->stream.pp_programs[0], i_id, 0 );
p_es->i_stream_id = 0xbd;
p_es->i_type = AC3_AUDIO_ES;
p_es->b_audio = 1;
// p_es->psz_desc = p_method->ifo.vts.mat.pi_audio_attr[i];
if( i == 0 )
{
input_SelectES( p_input, p_es );
strcpy( p_es->psz_desc, Language( hton16(
p_method->ifo.vts.mat.p_audio_atrt[i-1].i_lang_code ) ) );
break;
case 0x02:
case 0x03: /* MPEG audio */
i_id = 0xbf + i;
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 = MPEG2_AUDIO_ES;
p_es->b_audio = 1;
strcpy( p_es->psz_desc, Language( hton16(
p_method->ifo.vts.mat.p_audio_atrt[i-1].i_lang_code ) ) );
break;
case 0x04: /* LPCM */
i_id = 0;
intf_ErrMsg( "DVD: LPCM audio not handled yet" );
break;
case 0x06: /* DTS */
i_id = 0;
intf_ErrMsg( "DVD: DTS audio not handled yet" );
break;
default:
i_id = 0;
intf_ErrMsg( "DVD: unkown audio" );
}
intf_WarnMsg( 1, "DVD: Audio stream %d %s\t(0x%x)",
i, p_es->psz_desc, i_id );
}
/* Sub Picture ES */
i_nb = p_method->ifo.vts.mat.i_subpic_nb;
intf_WarnMsg( 1, "DVD: Subpic streams %d", i_nb );
for( i = 0 ; i < i_nb ; i++ )
b_last = 0;
i_sub_pic = 0x20;
for( i = 1 ; i <= i_nb ; i++ )
{
i_id = ( ( 0x20 + i ) << 8 ) | 0xbd;
if( !b_last )
{
i_id = ( i_sub_pic++ << 8 ) | 0xbd;
p_es = input_AddES( p_input,
p_input->stream.pp_programs[0], i_id, 0 );
p_es->i_stream_id = 0xbd;
p_es->i_type = DVD_SPU_ES;
// p_es->psz_desc = p_method->ifo.vts.mat.pi_subpic_attr[i];
if( i == 12 )
{
input_SelectES( p_input, p_es );
}
strcpy( p_es->psz_desc, Language( hton16(
p_method->ifo.vts.mat.p_subpic_atrt[i-1].i_lang_code ) ) );
intf_WarnMsg( 1, "DVD: SPU stream %d %s\t(0x%x)",
i, p_es->psz_desc, i_id );
/* The before the last spu has a 0x0 prefix */
b_last =
( p_method->ifo.vts.mat.p_subpic_atrt[i].i_prefix == 0 );
}
}
/* area definition */
p_input->stream.pp_areas[i_title]->i_start = i_start;
p_input->stream.pp_areas[i_title]->i_size = i_size;
/* No PSM to read in DVD mode */
p_input->stream.pp_programs[0]->b_is_ok = 1;
/* Init has been successfull ; change the default area */
p_input->stream.p_selected_area = p_input->stream.pp_areas[i_title];
} // i_title >= 0
vlc_mutex_unlock( &p_input->stream.stream_lock );
#else
p_input->stream.p_selected_area = p_input->stream.pp_areas[0];
/*
* Select requested ES
*/
if( ( i_audio >= 0 ) || ( i_title >= 0 ) )
{
if( p_input->stream.b_seekable )
/* Audio: we check it is in the range and
* default it to the first if not */
if( i_audio > p_method->ifo.vts.mat.i_audio_nb )
{
stream_ps_data_t * p_demux_data =
(stream_ps_data_t *)p_input->stream.pp_programs[0]->p_demux_data;
i_audio = 1;
}
/* Pre-parse the stream to gather stream_descriptor_t. */
p_input->stream.pp_programs[0]->b_is_ok = 0;
p_demux_data->i_PSM_version = EMPTY_PSM_VERSION;
p_es = p_input->stream.pp_programs[0]->pp_es[i_audio];
while( !p_input->b_die && !p_input->b_error
&& !p_demux_data->b_has_PSM )
/* We can only have one audio channel */
/* Look for a preselected one */
i_index = -1;
for( i = 0 ; i < p_input->stream.i_selected_es_number ; i++ )
{
int i_result, i;
data_packet_t * pp_packets[INPUT_READ_ONCE];
i_result = DVDRead( p_input, pp_packets );
if( i_result == 1 )
if( p_input->stream.pp_selected_es[i]->b_audio )
{
/* EOF */
vlc_mutex_lock( &p_input->stream.stream_lock );
p_input->stream.pp_programs[0]->b_is_ok = 1;
vlc_mutex_unlock( &p_input->stream.stream_lock );
i_index = i;
break;
}
if( i_result == -1 )
{
p_input->b_error = 1;
break;
}
for( i = 0; i < INPUT_READ_ONCE && pp_packets[i] != NULL; i++ )
if( i_index != -1 )
{
/* FIXME: use i_p_config_t */
input_ParsePS( p_input, pp_packets[i] );
input_NetlistDeletePacket( p_input->p_method_data,
pp_packets[i] );
}
/* File too big. */
if( p_input->stream.p_selected_area->i_tell >
INPUT_PREPARSE_LENGTH )
if( p_input->stream.pp_selected_es[i_index] != p_es )
{
break;
}
input_UnSelectES( p_input,
p_input->stream.pp_selected_es[i_index] );
input_SelectES( p_input, p_es );
intf_WarnMsg( 1, "DVD: Audio %d selected -> %s (0x%x)",
i_audio, p_es->psz_desc, p_es->i_id );
}
lseek( p_input->i_handle, i_start, SEEK_SET );
vlc_mutex_lock( &p_input->stream.stream_lock );
/* i_tell is an indicator from the beginning of the stream,
* not of the DVD */
p_input->stream.p_selected_area->i_tell = 0;
if( p_demux_data->b_has_PSM )
{
/* (The PSM decoder will care about spawning the decoders) */
p_input->stream.pp_programs[0]->b_is_ok = 1;
}
#ifdef AUTO_SPAWN
else
{
/* (We have to do it ourselves) */
int i_es;
/* FIXME: we should do multiple passes in case an audio type
* is not present */
for( i_es = 0;
i_es < p_input->stream.pp_programs[0]->i_es_number;
i_es++ )
{
#define p_es p_input->stream.pp_programs[0]->pp_es[i_es]
switch( p_es->i_type )
{
case MPEG1_VIDEO_ES:
case MPEG2_VIDEO_ES:
input_SelectES( p_input, p_es );
break;
case MPEG1_AUDIO_ES:
case MPEG2_AUDIO_ES:
if( main_GetIntVariable( INPUT_CHANNEL_VAR, 0 )
== (p_es->i_id & 0x1F) )
switch( main_GetIntVariable( INPUT_AUDIO_VAR, 0 ) )
{
case 0:
main_PutIntVariable( INPUT_AUDIO_VAR,
REQUESTED_MPEG );
case REQUESTED_MPEG:
input_SelectES( p_input, p_es );
intf_WarnMsg( 1, "DVD: Audio %d selected -> %s (0x%x)",
i_audio, p_es->psz_desc, p_es->i_id );
}
break;
case AC3_AUDIO_ES:
if( main_GetIntVariable( INPUT_CHANNEL_VAR, 0 )
== ((p_es->i_id & 0xF00) >> 8) )
switch( main_GetIntVariable( INPUT_AUDIO_VAR, 0 ) )
{
case 0:
main_PutIntVariable( INPUT_AUDIO_VAR,
REQUESTED_AC3 );
case REQUESTED_AC3:
input_SelectES( p_input, p_es );
}
break;
case DVD_SPU_ES:
if( main_GetIntVariable( INPUT_SUBTITLE_VAR, -1 )
== ((p_es->i_id & 0x1F00) >> 8) )
if( ( i_spu >= 0 ) || ( i_title >= 0 ) )
{
input_SelectES( p_input, p_es );
}
break;
/* For spu: no one if none or a not existed one requested */
if( ( i_spu <= p_method->ifo.vts.mat.i_subpic_nb ) && ( i_spu > 0 ) )
{
input_SelectES( p_input, ( p_es = p_input->stream.pp_programs[0]->
pp_es[ i_spu + p_method->ifo.vts.mat.i_audio_nb ] ) );
case LPCM_AUDIO_ES:
/* FIXME ! */
break;
intf_WarnMsg( 1, "DVD: SPU %d selected -> %s (0x%x)",
i_spu, p_es->psz_desc, p_es->i_id );
}
}
}
#endif
#ifdef STATS
input_DumpStream( p_input );
#endif
/*
* Chapter selection
*/
if( ( i_chapter > 0 ) &&
( i_chapter <= p_input->stream.p_selected_area->i_part_nb ) )
{
DVDChapterSelect( p_method, i_chapter );
/* FIXME : ugly kludge */
p_input->stream.p_selected_area->i_size = i_size;
p_input->stream.p_selected_area->i_part = i_chapter;
vlc_mutex_unlock( &p_input->stream.stream_lock );
DVDSeek( p_input, p_method->i_start -
p_input->stream.p_selected_area->i_start );
intf_WarnMsg( 2, "DVD: Chapter %d start at: %lld", i_chapter,
p_input->stream.p_selected_area->i_tell );
}
else
{
/* The programs will be added when we read them. */
vlc_mutex_lock( &p_input->stream.stream_lock );
p_input->stream.pp_programs[0]->b_is_ok = 0;
/* FIXME : ugly kludge */
p_input->stream.p_selected_area->i_size = i_size;
/* No PSM to read in DVD mode, we already have all information */
p_input->stream.pp_programs[0]->b_is_ok = 1;
vlc_mutex_unlock( &p_input->stream.stream_lock );
}
#endif
return 0;
}
......@@ -631,6 +657,10 @@ static int DVDSetArea( input_thread_t * p_input,
static void DVDInit( input_thread_t * p_input )
{
thread_dvd_data_t * p_method;
int i_title;
int i_chapter;
int i_audio;
int i_spu;
int i;
if( (p_method = malloc( sizeof(thread_dvd_data_t) )) == NULL )
......@@ -674,7 +704,6 @@ static void DVDInit( input_thread_t * p_input )
/* Initialize ES structures */
input_InitStream( p_input, sizeof( stream_ps_data_t ) );
input_AddProgram( p_input, 0, sizeof( stream_ps_data_t ) );
/* Set stream and area data */
vlc_mutex_lock( &p_input->stream.stream_lock );
......@@ -682,9 +711,12 @@ static void DVDInit( input_thread_t * p_input )
/* FIXME: We consider here that one title is one title set
* it is not true !!! */
intf_WarnMsg( 2, "DVD: Number of titles: %d\n",
p_method->ifo.vmg.mat.i_tts_nb );
#define area p_input->stream.pp_areas
/* We start from 1 here since area 0 is reserved for video_ts.vob */
for( i = 1 ; i < p_method->ifo.vmg.mat.i_tts_nb ; i++ )
for( i = 1 ; i <= p_method->ifo.vmg.mat.i_tts_nb ; i++ )
{
input_AddArea( p_input );
......@@ -709,10 +741,32 @@ static void DVDInit( input_thread_t * p_input )
vlc_mutex_unlock( &p_input->stream.stream_lock );
/* By default, set all parameters to 0 */
/* FIXME: wrong kludge to get first title number */
DVDSetArea( p_input, p_method->ifo.vmg.ptt_srpt.p_tts[0].i_tts_nb - 1,
0, 0, 0 );
/* Get requested title - if none try to find one where is the movie */
i_title = main_GetIntVariable( INPUT_TITLE_VAR,
p_method->ifo.vmg.ptt_srpt.p_tts[0].i_tts_nb );
if( i_title <= 0 || i_title >= p_method->ifo.vmg.mat.i_tts_nb )
{
i_title = p_method->ifo.vmg.ptt_srpt.p_tts[0].i_tts_nb;
}
/* Get requested chapter - if none defaults to first one */
i_chapter = main_GetIntVariable( INPUT_CHAPTER_VAR, 1 );
if( i_chapter <= 0 )
{
i_chapter = 1;
}
/* For audio: first one if none or a not existing one specified */
i_audio = main_GetIntVariable( INPUT_CHANNEL_VAR, 1 );
if( i_audio <= 0 )
{
main_PutIntVariable( INPUT_CHANNEL_VAR, 1 );
i_audio = 1;
}
i_spu = main_GetIntVariable( INPUT_SUBTITLE_VAR, 0 );
DVDSetArea( p_input, i_title, i_chapter, i_audio, i_spu );
return;
}
......@@ -739,67 +793,74 @@ static void DVDEnd( input_thread_t * p_input )
static int DVDRead( input_thread_t * p_input,
data_packet_t ** pp_packets )
{
byte_t p_header[6];
data_packet_t * p_data;
size_t i_packet_size;
int i_packet, i_error;
thread_dvd_data_t * p_method;
netlist_t * p_netlist;
struct iovec * p_vec;
struct data_packet_s * p_data;
u8 * pi_cur;
int i_packet_size;
int i_packet;
int i_pos;
int i;
boolean_t b_first_packet;
p_method = ( thread_dvd_data_t * ) p_input->p_plugin_data;
p_netlist = ( netlist_t * ) p_input->p_method_data;
p_method = (thread_dvd_data_t *)p_input->p_plugin_data;
/* Get an iovec pointer */
if( ( p_vec = input_NetlistGetiovec( p_netlist ) ) == NULL )
memset( pp_packets, 0, INPUT_READ_ONCE * sizeof(data_packet_t *) );
for( i_packet = 0; i_packet < INPUT_READ_ONCE; i_packet++ )
{
/* Read what we believe to be a packet header. */
if( (i_error = SafeRead( p_input, p_header, 6 )) )
{
intf_ErrMsg( "DVD: read error" );
return -1;
return( i_error );
}
/* Reads from DVD */
readv( p_input->i_handle, p_vec, p_method->i_read_once );
if( (U32_AT(p_header) & 0xFFFFFF00) != 0x100L )
{
/* This is not the startcode of a packet. Read the stream
* until we find one. */
u32 i_startcode = U32_AT(p_header);
int i_nb;
byte_t i_dummy;
if( p_method->b_encrypted )
if( i_startcode )
{
/* It is common for MPEG-1 streams to pad with zeros
* (although it is forbidden by the recommendation), so
* don't bother everybody in this case. */
intf_WarnMsg( 1, "Garbage at input (%x)", i_startcode );
}
while( (i_startcode & 0xFFFFFF00) != 0x100L )
{
i_startcode <<= 8;
if( (i_nb = SafeRead( p_input, &i_dummy, 1 )) != 0 )
{
for( i=0 ; i<p_method->i_read_once ; i++ )
i_startcode |= i_dummy;
}
else
{
CSSDescrambleSector( p_method->css.pi_title_key,
p_vec[i].iov_base );
((u8*)(p_vec[i].iov_base))[0x14] &= 0x8F;
return( 1 );
}
}
/* Update netlist indexes */
input_NetlistMviovec( p_netlist, p_method->i_read_once, &p_data );
i_packet = 0;
/* Read headers to compute payload length */
for( i = 0 ; i < p_method->i_read_once ; i++ )
{
i_pos = 0;
b_first_packet = 1;
while( i_pos < p_netlist->i_buffer_size )
/* Packet found. */
*(u32 *)p_header = U32_AT(&i_startcode);
if( (i_error = SafeRead( p_input, p_header + 4, 2 )) )
{
pi_cur = (u8*)(p_vec[i].iov_base + i_pos);
/*default header */
if( U32_AT( pi_cur ) != 0x1BA )
return( i_error );
}
}
if( U32_AT(p_header) != 0x1BA )
{
/* That's the case for all packets, except pack header. */
i_packet_size = U16_AT( pi_cur + 4 );
i_packet_size = U16_AT(&p_header[4]);
}
else
{
/* Pack header. */
if( ( pi_cur[4] & 0xC0 ) == 0x40 )
if( (p_header[4] & 0xC0) == 0x40 )
{
/* MPEG-2 */
i_packet_size = 8;
}
else if( ( pi_cur[4] & 0xF0 ) == 0x20 )
else if( (p_header[4] & 0xF0) == 0x20 )
{
/* MPEG-1 */
i_packet_size = 6;
......@@ -810,31 +871,42 @@ static int DVDRead( input_thread_t * p_input,
return( -1 );
}
}
if( b_first_packet )
/* Fetch a packet of the appropriate size. */
if( (p_data = NewPacket( p_input, i_packet_size + 6 )) == NULL )
{
p_data->b_discard_payload = 0;
b_first_packet = 0;
intf_ErrMsg( "Out of memory" );
return( -1 );
}
else
/* Copy the header we already read. */
memcpy( p_data->p_buffer, p_header, 6 );
/* Read the remaining of the packet. */
if( i_packet_size && (i_error =
SafeRead( p_input, p_data->p_buffer + 6, i_packet_size )) )
{
p_data = input_NetlistNewPacket( p_netlist ,
i_packet_size + 6 );
memcpy( p_data->p_buffer,
p_vec[i].iov_base + i_pos , i_packet_size + 6 );
return( i_error );
}
p_data->p_payload_end = p_data->p_payload_start + i_packet_size + 6;
pp_packets[i_packet] = p_data;
i_packet++;
i_pos += i_packet_size + 6;
/* In MPEG-2 pack headers we still have to read stuffing bytes. */
if( U32_AT(p_header) == 0x1BA )
{
if( i_packet_size == 8 && (p_data->p_buffer[13] & 0x7) != 0 )
{
/* MPEG-2 stuffing bytes */
byte_t p_garbage[8];
if( (i_error = SafeRead( p_input, p_garbage,
p_data->p_buffer[13] & 0x7)) )
{
return( i_error );
}
}
}
pp_packets[i_packet] = NULL;
vlc_mutex_lock( &p_input->stream.stream_lock );
p_input->stream.p_selected_area->i_tell +=
p_method->i_read_once *DVD_LB_SIZE;
vlc_mutex_unlock( &p_input->stream.stream_lock );
/* Give the packet to the other input stages. */
pp_packets[i_packet] = p_data;
}
return( 0 );
}
......
......@@ -35,9 +35,9 @@ typedef struct thread_dvd_data_s
boolean_t b_encrypted; // CSS encryption
int i_read_once; // NB of bytes read by DVDRead
int i_start_byte;
int i_start_cell;
int i_end_cell;
int i_chapter_nb;
off_t i_start;
off_t i_size;
/* Scrambling Information */
struct css_s css;
......
......@@ -584,3 +584,51 @@ on_intf_window_drag_data_received (GtkWidget *widget,
}
}
void
on_menubar_audio_activate (GtkMenuItem *menuitem,
gpointer user_data)
{
}
void
on_menubar_subtitles_activate (GtkMenuItem *menuitem,
gpointer user_data)
{
}
void
on_popup_title_activate (GtkMenuItem *menuitem,
gpointer user_data)
{
}
void
on_popup_chapter_activate (GtkMenuItem *menuitem,
gpointer user_data)
{
}
void
on_popup_audio_activate (GtkMenuItem *menuitem,
gpointer user_data)
{
}
void
on_popup_subtitle_activate (GtkMenuItem *menuitem,
gpointer user_data)
{
}
......@@ -197,3 +197,27 @@ on_intf_window_drag_data_received (GtkWidget *widget,
guint info,
guint time,
gpointer user_data);
void
on_menubar_audio_activate (GtkMenuItem *menuitem,
gpointer user_data);
void
on_menubar_subtitles_activate (GtkMenuItem *menuitem,
gpointer user_data);
void
on_popup_title_activate (GtkMenuItem *menuitem,
gpointer user_data);
void
on_popup_chapter_activate (GtkMenuItem *menuitem,
gpointer user_data);
void
on_popup_audio_activate (GtkMenuItem *menuitem,
gpointer user_data);
void
on_popup_subtitle_activate (GtkMenuItem *menuitem,
gpointer user_data);
......@@ -46,6 +46,21 @@ static GnomeUIInfo menubar_view_menu_uiinfo[] =
static GnomeUIInfo menubar_settings_menu_uiinfo[] =
{
{
GNOME_APP_UI_ITEM, N_("_Audio"),
N_("Select audio channel"),
(gpointer) on_menubar_audio_activate, NULL, NULL,
GNOME_APP_PIXMAP_NONE, NULL,
0, (GdkModifierType) 0, NULL
},
{
GNOME_APP_UI_ITEM, N_("_Subtitles"),
N_("Select subtitle unit"),
(gpointer) on_menubar_subtitles_activate, NULL, NULL,
GNOME_APP_PIXMAP_NONE, NULL,
0, (GdkModifierType) 0, NULL
},
GNOMEUIINFO_SEPARATOR,
GNOMEUIINFO_MENU_PREFERENCES_ITEM (on_menubar_preferences_activate, NULL),
GNOMEUIINFO_END
};
......@@ -143,10 +158,25 @@ create_intf_window (void)
(GtkDestroyNotify) gtk_widget_unref);
gtk_widget_ref (menubar_settings_menu_uiinfo[0].widget);
gtk_object_set_data_full (GTK_OBJECT (intf_window), "menubar_preferences",
gtk_object_set_data_full (GTK_OBJECT (intf_window), "menubar_audio",
menubar_settings_menu_uiinfo[0].widget,
(GtkDestroyNotify) gtk_widget_unref);
gtk_widget_set_sensitive (menubar_settings_menu_uiinfo[0].widget, FALSE);
gtk_widget_ref (menubar_settings_menu_uiinfo[1].widget);
gtk_object_set_data_full (GTK_OBJECT (intf_window), "menubar_subtitles",
menubar_settings_menu_uiinfo[1].widget,
(GtkDestroyNotify) gtk_widget_unref);
gtk_widget_ref (menubar_settings_menu_uiinfo[2].widget);
gtk_object_set_data_full (GTK_OBJECT (intf_window), "separator5",
menubar_settings_menu_uiinfo[2].widget,
(GtkDestroyNotify) gtk_widget_unref);
gtk_widget_ref (menubar_settings_menu_uiinfo[3].widget);
gtk_object_set_data_full (GTK_OBJECT (intf_window), "menubar_preferences",
menubar_settings_menu_uiinfo[3].widget,
(GtkDestroyNotify) gtk_widget_unref);
gtk_widget_set_sensitive (menubar_settings_menu_uiinfo[3].widget, FALSE);
gtk_widget_ref (menubar_uiinfo[3].widget);
gtk_object_set_data_full (GTK_OBJECT (intf_window), "menubar_help",
......@@ -394,6 +424,18 @@ create_intf_window (void)
return intf_window;
}
static GnomeUIInfo popup_title_menu_uiinfo[] =
{
{
GNOME_APP_UI_ITEM, N_("_Chapter"),
NULL,
(gpointer) on_popup_chapter_activate, NULL, NULL,
GNOME_APP_PIXMAP_NONE, NULL,
0, (GdkModifierType) 0, NULL
},
GNOMEUIINFO_END
};
static GnomeUIInfo intf_popup_uiinfo[] =
{
{
......@@ -427,6 +469,28 @@ static GnomeUIInfo intf_popup_uiinfo[] =
GNOMEUIINFO_SEPARATOR,
GNOMEUIINFO_MENU_OPEN_ITEM (on_popup_open_activate, NULL),
GNOMEUIINFO_SEPARATOR,
{
GNOME_APP_UI_SUBTREE, N_("_Title"),
N_("Select Title"),
popup_title_menu_uiinfo, NULL, NULL,
GNOME_APP_PIXMAP_NONE, NULL,
0, (GdkModifierType) 0, NULL
},
{
GNOME_APP_UI_ITEM, N_("Audio"),
N_("Select audio channel"),
(gpointer) on_popup_audio_activate, NULL, NULL,
GNOME_APP_PIXMAP_NONE, NULL,
0, (GdkModifierType) 0, NULL
},
{
GNOME_APP_UI_ITEM, N_("_Subtitle"),
NULL,
(gpointer) on_popup_subtitle_activate, NULL, NULL,
GNOME_APP_PIXMAP_NONE, NULL,
0, (GdkModifierType) 0, NULL
},
GNOMEUIINFO_SEPARATOR,
GNOMEUIINFO_MENU_ABOUT_ITEM (on_popup_about_activate, NULL),
GNOMEUIINFO_MENU_EXIT_ITEM (on_popup_exit_activate, NULL),
GNOMEUIINFO_END
......@@ -478,15 +542,40 @@ create_intf_popup (void)
(GtkDestroyNotify) gtk_widget_unref);
gtk_widget_ref (intf_popup_uiinfo[7].widget);
gtk_object_set_data_full (GTK_OBJECT (intf_popup), "popup_about",
gtk_object_set_data_full (GTK_OBJECT (intf_popup), "popup_title",
intf_popup_uiinfo[7].widget,
(GtkDestroyNotify) gtk_widget_unref);
gtk_widget_ref (popup_title_menu_uiinfo[0].widget);
gtk_object_set_data_full (GTK_OBJECT (intf_popup), "popup_chapter",
popup_title_menu_uiinfo[0].widget,
(GtkDestroyNotify) gtk_widget_unref);
gtk_widget_ref (intf_popup_uiinfo[8].widget);
gtk_object_set_data_full (GTK_OBJECT (intf_popup), "popup_exit",
gtk_object_set_data_full (GTK_OBJECT (intf_popup), "popup_audio",
intf_popup_uiinfo[8].widget,
(GtkDestroyNotify) gtk_widget_unref);
gtk_widget_ref (intf_popup_uiinfo[9].widget);
gtk_object_set_data_full (GTK_OBJECT (intf_popup), "popup_subtitle",
intf_popup_uiinfo[9].widget,
(GtkDestroyNotify) gtk_widget_unref);
gtk_widget_ref (intf_popup_uiinfo[10].widget);
gtk_object_set_data_full (GTK_OBJECT (intf_popup), "separator4",
intf_popup_uiinfo[10].widget,
(GtkDestroyNotify) gtk_widget_unref);
gtk_widget_ref (intf_popup_uiinfo[11].widget);
gtk_object_set_data_full (GTK_OBJECT (intf_popup), "popup_about",
intf_popup_uiinfo[11].widget,
(GtkDestroyNotify) gtk_widget_unref);
gtk_widget_ref (intf_popup_uiinfo[12].widget);
gtk_object_set_data_full (GTK_OBJECT (intf_popup), "popup_exit",
intf_popup_uiinfo[12].widget,
(GtkDestroyNotify) gtk_widget_unref);
return intf_popup;
}
......
......@@ -162,6 +162,38 @@
<class>GtkMenu</class>
<name>menubar_settings_menu</name>
<widget>
<class>GtkMenuItem</class>
<name>menubar_audio</name>
<tooltip>Select audio channel</tooltip>
<signal>
<name>activate</name>
<handler>on_menubar_audio_activate</handler>
<last_modification_time>Thu, 22 Feb 2001 05:42:43 GMT</last_modification_time>
</signal>
<label>_Audio</label>
<right_justify>False</right_justify>
</widget>
<widget>
<class>GtkMenuItem</class>
<name>menubar_subtitles</name>
<tooltip>Select subtitle unit</tooltip>
<signal>
<name>activate</name>
<handler>on_menubar_subtitles_activate</handler>
<last_modification_time>Thu, 22 Feb 2001 05:42:43 GMT</last_modification_time>
</signal>
<label>_Subtitles</label>
<right_justify>False</right_justify>
</widget>
<widget>
<class>GtkMenuItem</class>
<name>separator5</name>
<right_justify>False</right_justify>
</widget>
<widget>
<class>GtkPixmapMenuItem</class>
<name>menubar_preferences</name>
......@@ -559,6 +591,67 @@
<right_justify>False</right_justify>
</widget>
<widget>
<class>GtkMenuItem</class>
<name>popup_title</name>
<tooltip>Select Title</tooltip>
<signal>
<name>activate</name>
<handler>on_popup_title_activate</handler>
<last_modification_time>Thu, 22 Feb 2001 05:35:57 GMT</last_modification_time>
</signal>
<label>_Title</label>
<right_justify>False</right_justify>
<widget>
<class>GtkMenu</class>
<name>popup_title_menu</name>
<widget>
<class>GtkMenuItem</class>
<name>popup_chapter</name>
<signal>
<name>activate</name>
<handler>on_popup_chapter_activate</handler>
<last_modification_time>Thu, 22 Feb 2001 05:48:48 GMT</last_modification_time>
</signal>
<label>_Chapter</label>
<right_justify>False</right_justify>
</widget>
</widget>
</widget>
<widget>
<class>GtkMenuItem</class>
<name>popup_audio</name>
<tooltip>Select audio channel</tooltip>
<signal>
<name>activate</name>
<handler>on_popup_audio_activate</handler>
<last_modification_time>Thu, 22 Feb 2001 05:35:57 GMT</last_modification_time>
</signal>
<label>Audio</label>
<right_justify>False</right_justify>
</widget>
<widget>
<class>GtkMenuItem</class>
<name>popup_subtitle</name>
<signal>
<name>activate</name>
<handler>on_popup_subtitle_activate</handler>
<last_modification_time>Thu, 22 Feb 2001 05:35:57 GMT</last_modification_time>
</signal>
<label>_Subtitle</label>
<right_justify>False</right_justify>
</widget>
<widget>
<class>GtkMenuItem</class>
<name>separator4</name>
<right_justify>False</right_justify>
</widget>
<widget>
<class>GtkPixmapMenuItem</class>
<name>popup_about</name>
......
......@@ -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.33 2001/02/20 08:47:25 stef Exp $
* $Id: input_programs.c,v 1.34 2001/02/22 08:44:45 stef Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
......@@ -263,7 +263,7 @@ input_area_t * input_AddArea( input_thread_t * p_input )
p_input->stream.pp_areas[i_area_index]->i_start = 0;
p_input->stream.pp_areas[i_area_index]->i_size = 0;
p_input->stream.pp_areas[i_area_index]->i_tell = 0;
p_input->stream.pp_areas[i_area_index]->i_seek = 0;
p_input->stream.pp_areas[i_area_index]->i_seek = NO_SEEK;
p_input->stream.pp_areas[i_area_index]->i_part_nb = 0;
p_input->stream.pp_areas[i_area_index]->i_part= 0;
......@@ -281,7 +281,7 @@ void input_DelArea( input_thread_t * p_input, input_area_t * p_area )
ASSERT( p_area );
intf_DbgMsg("Deleting description for area %d", p_area->i_number);
intf_DbgMsg("Deleting description for area %d", p_area->i_nb );
/* Find the area in the areas table */
for( i_area_index = 0; i_area_index < p_input->stream.i_area_nb;
......@@ -303,7 +303,7 @@ void input_DelArea( input_thread_t * p_input, input_area_t * p_area )
if( p_input->stream.i_area_nb && p_input->stream.pp_areas == NULL)
{
intf_ErrMsg( "input error: unable to realloc area list"
" in input_Delarea" );
" in input_DelArea" );
}
/* Free the description of this area */
......@@ -680,3 +680,49 @@ int input_SelectES( input_thread_t * p_input, es_descriptor_t * p_es )
}
return( 0 );
}
/*****************************************************************************
* input_UnSelectES: removes an ES from the list of selected ES
*****************************************************************************/
int input_UnSelectES( input_thread_t * p_input, es_descriptor_t * p_es )
{
int i_index = 0;
#ifdef DEBUG_INPUT
intf_DbgMsg( "UnSelecting ES 0x%x", p_es->i_id );
#endif
if( p_es->p_decoder_fifo == NULL )
{
intf_ErrMsg( "ES %d is not selected", p_es->i_id );
return( -1 );
}
input_EndDecoder( p_input, p_es );
if( p_es->p_decoder_fifo == NULL )
{
p_input->stream.i_selected_es_number--;
while( ( i_index < p_input->stream.i_selected_es_number ) &&
( p_input->stream.pp_selected_es[i_index] != p_es ) )
{
i_index++;
}
p_input->stream.pp_selected_es[i_index] =
p_input->stream.pp_selected_es[p_input->stream.i_selected_es_number];
p_input->stream.pp_selected_es = realloc(
p_input->stream.pp_selected_es,
p_input->stream.i_selected_es_number
* sizeof(es_descriptor_t *) );
if( p_input->stream.pp_selected_es == NULL )
{
intf_ErrMsg( "Unable to realloc memory in input_SelectES" );
return(-1);
}
}
return( 0 );
}
......@@ -140,6 +140,8 @@ static const struct option longopts[] =
{ "overlay", 0, 0, OPT_OVERLAY },
/* DVD options */
{ "dvdtitle", 1, 0, 't' },
{ "dvdchapter", 1, 0, 'T' },
{ "dvdaudio", 1, 0, 'a' },
{ "dvdchannel", 1, 0, 'c' },
{ "dvdsubtitle", 1, 0, 's' },
......@@ -157,7 +159,7 @@ static const struct option longopts[] =
};
/* Short options */
static const char *psz_shortopts = "hHvga:s:c:";
static const char *psz_shortopts = "hHvgt:T:a:s:c:";
#endif
......@@ -624,6 +626,12 @@ static int GetConfiguration( int i_argc, char *ppsz_argv[], char *ppsz_env[] )
break;
/* DVD options */
case 't':
main_PutIntVariable( INPUT_TITLE_VAR, atoi(optarg) );
break;
case 'T':
main_PutIntVariable( INPUT_CHAPTER_VAR, atoi(optarg) );
break;
case 'a':
if ( ! strcmp(optarg, "ac3") )
main_PutIntVariable( INPUT_AUDIO_VAR, REQUESTED_AC3 );
......@@ -734,6 +742,8 @@ static void Usage( int i_fashion )
"\n --yuv <module> \tYUV method"
"\n --synchro <type> \tforce synchro algorithm"
"\n"
"\n -t, --dvdtitle <num> \tchoose DVD title"
"\n -T, --dvdchapter <num> \tchoose DVD chapter"
"\n -a, --dvdaudio <type> \tchoose DVD audio type"
"\n -c, --dvdchannel <channel> \tchoose DVD audio channel"
"\n -s, --dvdsubtitle <channel> \tchoose DVD subtitle channel"
......@@ -783,6 +793,8 @@ static void Usage( int i_fashion )
/* DVD parameters */
intf_MsgImm( "\nDVD parameters:"
"\n " INPUT_DVD_DEVICE_VAR "=<device> \tDVD device"
"\n " INPUT_TITLE_VAR "=<title> \ttitle number"
"\n " INPUT_CHAPTER_VAR "=<chapter> \tchapter number"
"\n " INPUT_AUDIO_VAR "={ac3|lpcm|mpeg|off} \taudio type"
"\n " INPUT_CHANNEL_VAR "=[0-15] \taudio channel"
"\n " INPUT_SUBTITLE_VAR "=[0-31] \tsubtitle channel" );
......
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