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

. Beginning of dvd_input.

. Parsing of ifo file almost completed.
. Still does not work well.
parent e360e2a4
......@@ -186,6 +186,8 @@ INTERFACE = src/interface/main.o \
INPUT = src/input/input_ps.o \
src/input/input_ts.o \
src/input/dvd_ifo.o \
src/input/input_dvd.o \
src/input/mpeg_system.o \
src/input/input_ext-dec.o \
src/input/input_dec.o \
......
......@@ -211,6 +211,8 @@
* mark it to be presented */
#define DEFAULT_PTS_DELAY (.2*CLOCK_FREQ)
#define INPUT_DVD_DEVICE_VAR "vlc_dvd_device"
#define INPUT_DVD_DEVICE_DEFAULT "/dev/dvd"
#define INPUT_DVD_AUDIO_VAR "vlc_dvd_audio"
#define INPUT_DVD_CHANNEL_VAR "vlc_dvd_channel"
#define INPUT_DVD_SUBTITLE_VAR "vlc_dvd_subtitle"
......@@ -243,9 +245,9 @@
#define AOUT_STEREO_DEFAULT 1
/* Volume */
#define VOLUME_DEFAULT 256
#define VOLUME_STEP 5
#define VOLUME_MAX 765
#define VOLUME_DEFAULT 512
#define VOLUME_STEP 128
#define VOLUME_MAX 1024
/* Environment variable for output rate, and default value */
#define AOUT_RATE_VAR "vlc_audio_rate"
......
......@@ -4,7 +4,7 @@
* control the pace of reading.
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
* $Id: input_ext-intf.h,v 1.8 2000/12/21 19:24:26 massiot Exp $
* $Id: input_ext-intf.h,v 1.9 2001/01/14 07:08:00 stef Exp $
*
* Authors:
*
......@@ -255,6 +255,7 @@ typedef struct input_config_s
/* Input methods */
#define INPUT_METHOD_NONE 0 /* input thread is inactive */
#define INPUT_METHOD_FILE 10 /* stream is read from file p_source */
#define INPUT_METHOD_DVD 11 /* stream is read from dvd device */
#define INPUT_METHOD_UCAST 20 /* UDP unicast */
#define INPUT_METHOD_MCAST 21 /* UDP multicast */
#define INPUT_METHOD_BCAST 22 /* UDP broadcast */
......
......@@ -44,6 +44,7 @@ typedef struct
boolean_t b_audio; /* is audio output allowed ? */
boolean_t b_video; /* is video output allowed ? */
boolean_t b_vlans; /* are vlans supported ? */
boolean_t b_dvd; /* DVD mode ? */
/* Unique threads */
p_aout_thread_t p_aout; /* audio output thread */
......
/*****************************************************************************
* dvd_ifo.c: Functions for ifo parsing
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
*
* 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 <stdio.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <malloc.h>
#include "common.h"
#include "intf_msg.h"
#include "dvd_ifo.h"
/*
* IFO Management.
*/
/*****************************************************************************
* IfoFindStart : When reading directly on a device, finds the offset to the
* beginning of video_ts.ifo.
*****************************************************************************/
static int IfoFindStart( ifo_t* p_ifo )
{
char psz_ifo_start[12] = "DVDVIDEO-VMG";
char psz_test[12];
read( p_ifo->i_fd, psz_test, 12 );
while( strncmp( psz_test, psz_ifo_start, 12 ) != 0 )
{
/* The start of ifo file is on a sector boundary */
p_ifo->i_pos = lseek( p_ifo->i_fd,
p_ifo->i_pos + DVD_LB_SIZE,
SEEK_SET );
read( p_ifo->i_fd, psz_test, 12 );
}
p_ifo->i_off = p_ifo->i_pos;
fprintf( stderr, "VMG Off : %d\n", p_ifo->i_off );
return 0;
}
/*****************************************************************************
* IfoFindVTS : beginning of vts_*.ifo.
*****************************************************************************/
static int IfoFindVTS( ifo_t* p_ifo )
{
char psz_ifo_start[12] = "DVDVIDEO-VTS";
char psz_test[12];
read( p_ifo->i_fd, psz_test, 12 );
while( strncmp( psz_test, psz_ifo_start, 12 ) != 0 )
{
/* The start of ifo file is on a sector boundary */
p_ifo->i_pos = lseek( p_ifo->i_fd,
p_ifo->i_pos + DVD_LB_SIZE,
SEEK_SET );
read( p_ifo->i_fd, psz_test, 12 );
}
p_ifo->i_off = p_ifo->i_pos;
fprintf( stderr, "VTS Off : %d\n", p_ifo->i_off );
return 0;
}
/*****************************************************************************
* IfoInit : Creates an ifo structure and prepares for parsing directly
* on DVD device.
*****************************************************************************/
ifo_t IfoInit( int i_fd )
{
ifo_t ifo;
/* If we are here the dvd device has already been opened */
ifo.i_fd = i_fd;
/* No data at the beginning of the disk
* 512000 bytes is just another value :) */
ifo.i_pos = lseek( ifo.i_fd, 250 *DVD_LB_SIZE, SEEK_SET );
/* FIXME : use udf filesystem to find the beginning of the file */
IfoFindStart( &ifo );
return ifo;
}
/*****************************************************************************
* IfoEnd : Frees all the memory allocated to ifo structures
*****************************************************************************/
void IfoEnd( ifo_t* p_ifo )
{
int i,j;
/* Free structures from video title sets */
for( j=0 ; j<p_ifo->vmg.mat.i_tts_nb ; j++ )
{
free( p_ifo->p_vts[j].vobu_admap.pi_vobu_ssector );
free( p_ifo->p_vts[j].c_adt.p_cell_inf );
free( p_ifo->p_vts[j].m_vobu_admap.pi_vobu_ssector );
free( p_ifo->p_vts[j].m_c_adt.p_cell_inf );
for( i=0 ; i<p_ifo->p_vts[j].tmap_ti.i_nb ; i++ )
{
free( p_ifo->p_vts[j].tmap_ti.p_tmap[i].pi_sector );
}
free( p_ifo->p_vts[j].tmap_ti.pi_sbyte );
free( p_ifo->p_vts[j].tmap_ti.p_tmap );
free( p_ifo->p_vts[j].pgci_ti.p_lu_desc );
free( p_ifo->p_vts[j].pgci_ti.p_lu );
free( p_ifo->p_vts[j].pgci_ut.p_lu_desc );
free( p_ifo->p_vts[j].pgci_ut.p_lu );
}
free( p_ifo->p_vts );
/* Free structures from video manager */
free( p_ifo->vmg.vobu_admap.pi_vobu_ssector );
free( p_ifo->vmg.c_adt.p_cell_inf );
for( i=0 ; i<p_ifo->vmg.pgci_ut.i_lu_nb ; i++ )
{
free( p_ifo->vmg.pgci_ut.p_lu[i].p_srp );
}
free( p_ifo->vmg.pgci_ut.p_lu_desc );
free( p_ifo->vmg.pgci_ut.p_lu );
for( i=1 ; i<=8 ; i++ )
{
free( p_ifo->vmg.ptl_mait.p_ptl_mask->ppi_ptl_mask[i] );
}
free( p_ifo->vmg.ptl_mait.p_ptl_desc );
free( p_ifo->vmg.ptl_mait.p_ptl_mask );
free( p_ifo->vmg.vts_atrt.pi_vts_atrt_sbyte );
free( p_ifo->vmg.vts_atrt.p_vts_atrt );
free( p_ifo->vmg.pgc.p_cell_pos_inf );
free( p_ifo->vmg.pgc.p_cell_play_inf );
free( p_ifo->vmg.pgc.prg_map.pi_entry_cell );
free( p_ifo->vmg.pgc.com_tab.psz_cell_com );
free( p_ifo->vmg.pgc.com_tab.psz_post_com );
free( p_ifo->vmg.pgc.com_tab.psz_pre_com );
return;
}
/*
* Macros to process ifo files
*/
#define GET( p_field , i_len ) \
{ \
read( p_ifo->i_fd , p_field , i_len ); \
fprintf(stderr, "Pos : %d\n", p_ifo->i_pos - i_start); \
p_ifo->i_pos = lseek( p_ifo->i_fd , p_ifo->i_pos + i_len , SEEK_SET );\
}
#define GETC( p_field ) \
{ \
read( p_ifo->i_fd , p_field , 1 ); \
fprintf(stderr, "Pos : %d Value : %d\n", p_ifo->i_pos - i_start, \
*p_field ); \
p_ifo->i_pos = lseek( p_ifo->i_fd , p_ifo->i_pos + 1 , SEEK_SET ); \
}
#define GETS( p_field ) \
{ \
read( p_ifo->i_fd , p_field , 2 ); \
*p_field = ntohs( *p_field ); \
fprintf(stderr, "Pos : %d Value : %d\n", p_ifo->i_pos - i_start, \
*p_field ); \
p_ifo->i_pos = lseek( p_ifo->i_fd , p_ifo->i_pos + 2 , SEEK_SET ); \
}
#define GETL( p_field ) \
{ \
read( p_ifo->i_fd , p_field , 4 ); \
*p_field = ntohl( *p_field ); \
fprintf(stderr, "Pos : %d Value : %d\n", p_ifo->i_pos - i_start, \
*p_field ); \
p_ifo->i_pos = lseek( p_ifo->i_fd , p_ifo->i_pos + 4 , SEEK_SET ); \
}
#define GETLL( p_field ) \
{ \
read( p_ifo->i_fd , p_field , 8 ); \
*p_field = ntoh64( *p_field ); \
fprintf(stderr, "Pos : %d Value : %lld\n", p_ifo->i_pos - i_start, \
*p_field ); \
p_ifo->i_pos = lseek( p_ifo->i_fd , p_ifo->i_pos + 8 , SEEK_SET ); \
}
#define FLUSH( i_len ) \
{ \
fprintf(stderr, "Pos : %d\n", p_ifo->i_pos - i_start ); \
p_ifo->i_pos = lseek( p_ifo->i_fd , p_ifo->i_pos + i_len , SEEK_SET );\
}
/*
* Function common to Video Manager and Video Title set Processing
*/
/*****************************************************************************
* ReadPGC : Fills the Program Chain structure.
*****************************************************************************/
static pgc_t ReadPGC( ifo_t* p_ifo )
{
pgc_t pgc;
int i;
int i_start = p_ifo->i_pos;
fprintf( stderr, "PGC\n" );
FLUSH(2);
GETC( &pgc.i_prg_nb );
GETC( &pgc.i_cell_nb );
GETL( &pgc.i_play_time );
GETL( &pgc.i_prohibited_user_op );
for( i=0 ; i<8 ; i++ )
{
GETS( &pgc.pi_audio_status[i] );
}
for( i=0 ; i<32 ; i++ )
{
GETL( &pgc.pi_subpic_status[i] );
}
GETS( &pgc.i_next_pgc_nb );
GETS( &pgc.i_prev_pgc_nb );
GETS( &pgc.i_goup_pgc_nb );
GETC( &pgc.i_still_time );
GETC( &pgc.i_play_mode );
for( i=0 ; i<16 ; i++ )
{
GETL( &pgc.pi_yuv_color[i] );
/* FIXME : We have to erase the extra bit */
}
GETS( &pgc.i_com_tab_sbyte );
GETS( &pgc.i_prg_map_sbyte );
GETS( &pgc.i_cell_play_inf_sbyte );
GETS( &pgc.i_cell_pos_inf_sbyte );
/* Parsing of pgc_com_tab_t */
if( pgc.i_com_tab_sbyte )
{
p_ifo->i_pos = lseek( p_ifo->i_fd, i_start
+ pgc.i_com_tab_sbyte, SEEK_SET );
GETS( &pgc.com_tab.i_pre_com_nb );
GETS( &pgc.com_tab.i_post_com_nb );
GETS( &pgc.com_tab.i_cell_com_nb );
pgc.com_tab.psz_pre_com = malloc(sizeof(8*pgc.com_tab.i_pre_com_nb));
if( pgc.com_tab.psz_pre_com == NULL )
{
intf_ErrMsg( "Out of memory" );
p_ifo->b_error = 1;
return pgc;
}
GET( pgc.com_tab.psz_pre_com, 8*pgc.com_tab.i_pre_com_nb );
pgc.com_tab.psz_post_com = malloc(sizeof(8*pgc.com_tab.i_pre_com_nb));
if( pgc.com_tab.psz_post_com == NULL )
{
intf_ErrMsg( "Out of memory" );
p_ifo->b_error = 1;
return pgc;
}
GET( pgc.com_tab.psz_post_com, 8*pgc.com_tab.i_post_com_nb );
pgc.com_tab.psz_cell_com = malloc(sizeof(8*pgc.com_tab.i_pre_com_nb));
if( pgc.com_tab.psz_cell_com == NULL )
{
intf_ErrMsg( "Out of memory" );
p_ifo->b_error = 1;
return pgc;
}
GET( pgc.com_tab.psz_cell_com, 8*pgc.com_tab.i_cell_com_nb );
}
/* Parsing of pgc_prg_map_t */
if( pgc.i_prg_map_sbyte )
{
p_ifo->i_pos = lseek( p_ifo->i_fd, i_start
+ pgc.i_prg_map_sbyte, SEEK_SET );
pgc.prg_map.pi_entry_cell = malloc( sizeof(pgc.i_prg_nb) );
if( pgc.prg_map.pi_entry_cell == NULL )
{
intf_ErrMsg( "Out of memory" );
p_ifo->b_error = 1;
return pgc;
}
GET( pgc.prg_map.pi_entry_cell, pgc.i_prg_nb );
/* FIXME : check endianness here */
}
/* Parsing of cell_play_inf_t */
if( pgc.i_cell_play_inf_sbyte )
{
p_ifo->i_pos = lseek( p_ifo->i_fd, i_start
+ pgc.i_cell_play_inf_sbyte, SEEK_SET );
pgc.p_cell_play_inf = malloc( pgc.i_cell_nb *sizeof(cell_play_inf_t) );
if( pgc.p_cell_play_inf == NULL )
{
intf_ErrMsg( "Out of memory" );
p_ifo->b_error = 1;
return pgc;
}
for( i=0 ; i<pgc.i_cell_nb ; i++ )
{
GETS( &pgc.p_cell_play_inf[i].i_cat );
GETC( &pgc.p_cell_play_inf[i].i_still_time );
GETS( &pgc.p_cell_play_inf[i].i_com_nb );
GETL( &pgc.p_cell_play_inf[i].i_play_time );
GETL( &pgc.p_cell_play_inf[i].i_entry_sector );
GETL( &pgc.p_cell_play_inf[i].i_first_ilvu_vobu_esector );
GETL( &pgc.p_cell_play_inf[i].i_lvobu_ssector );
GETL( &pgc.p_cell_play_inf[i].i_lsector );
}
}
/* Parsing of cell_pos_inf_map */
if( pgc.i_cell_pos_inf_sbyte )
{
p_ifo->i_pos = lseek( p_ifo->i_fd, i_start
+ pgc.i_cell_pos_inf_sbyte, SEEK_SET );
pgc.p_cell_pos_inf = malloc( pgc.i_cell_nb *sizeof(cell_pos_inf_t) );
if( pgc.p_cell_play_inf == NULL )
{
intf_ErrMsg( "Out of memory" );
p_ifo->b_error = 1;
return pgc;
}
for( i=0 ; i<pgc.i_cell_nb ; i++ )
{
GETS( &pgc.p_cell_pos_inf[i].i_vob_id );
FLUSH( 1 );
GETC( &pgc.p_cell_pos_inf[i].i_cell_id );
}
}
return pgc;
}
/*****************************************************************************
* ReadUnitTable : Fills the Language Unit structure.
*****************************************************************************/
static pgci_ut_t ReadUnitTable( ifo_t* p_ifo )
{
pgci_ut_t lang;
int i, j;
int i_start = p_ifo->i_pos;
fprintf( stderr, "LU\n" );
GETS( &lang.i_lu_nb );
FLUSH( 2 );
GETL( &lang.i_ebyte );
lang.p_lu_desc = malloc( lang.i_lu_nb *sizeof(pgci_lu_desc_t) );
if( lang.p_lu_desc == NULL )
{
intf_ErrMsg( "Out of memory" );
p_ifo->b_error = 1;
return lang;
}
for( i=0 ; i<lang.i_lu_nb ; i++ )
{
GETS( &lang.p_lu_desc[i].i_lang_code );
FLUSH( 1 );
GETC( &lang.p_lu_desc[i].i_existence_mask );
GETL( &lang.p_lu_desc[i].i_lu_sbyte );
}
lang.p_lu = malloc( lang.i_lu_nb *sizeof(pgci_lu_t) );
if( lang.p_lu == NULL )
{
intf_ErrMsg( "Out of memory" );
p_ifo->b_error = 1;
return lang;
}
for( i=0 ; i<lang.i_lu_nb ; i++ )
{
p_ifo->i_pos = lseek( p_ifo->i_fd, i_start +
lang.p_lu_desc[i].i_lu_sbyte,
SEEK_SET );
GETS( &lang.p_lu[i].i_srp_nb );
FLUSH( 2 );
GETL( &lang.p_lu[i].i_lu_ebyte );
lang.p_lu[i].p_srp = malloc( lang.p_lu[i].i_srp_nb *
sizeof(pgci_srp_t) );
if( lang.p_lu[i].p_srp == NULL )
{
intf_ErrMsg( "Out of memory" );
p_ifo->b_error = 1;
return lang;
}
for( j=0 ; j<lang.p_lu[i].i_srp_nb ; j++ )
{
GETC( &lang.p_lu[i].p_srp[j].i_pgc_cat_mask );
GETC( &lang.p_lu[i].p_srp[j].i_pgc_cat );
GETS( &lang.p_lu[i].p_srp[j].i_par_mask );
GETL( &lang.p_lu[i].p_srp[j].i_pgci_sbyte );
}
for( j=0 ; j<lang.p_lu[i].i_srp_nb ; j++ )
{
p_ifo->i_pos = lseek( p_ifo->i_fd,
i_start + lang.p_lu[i].p_srp[j].i_pgci_sbyte,
SEEK_SET );
/* FIXME : Bad parsing somiewhere by here : various information
* don't match */
//lang.p_lu[i].p_srp[j].pgc = ReadPGC( p_ifo );
}
}
return lang;
}
/*****************************************************************************
* ReadCellInf : Fills the Cell Information structure.
*****************************************************************************/
static c_adt_t ReadCellInf( ifo_t* p_ifo )
{
c_adt_t c_adt;
int i, i_max;
int i_start = p_ifo->i_pos;
fprintf( stderr, "CELL ADD\n" );
GETS( &c_adt.i_vob_nb );
FLUSH( 2 );
GETL( &c_adt.i_ebyte );
i_max = ( i_start + c_adt.i_ebyte + 1 - p_ifo->i_pos ) / sizeof(cell_inf_t);
c_adt.p_cell_inf = malloc( i_max *sizeof(cell_inf_t) );
if( c_adt.p_cell_inf == NULL )
{
intf_ErrMsg( "Out of memory" );
p_ifo->b_error = 1;
return c_adt;
}
for( i=0 ; i<i_max ; i++ )
{
GETS( &c_adt.p_cell_inf[i].i_vob_id );
GETC( &c_adt.p_cell_inf[i].i_cell_id );
FLUSH( 1 );
GETL( &c_adt.p_cell_inf[i].i_ssector );
GETL( &c_adt.p_cell_inf[i].i_esector );
}
return c_adt;
}
/*****************************************************************************
* ReadMap : Fills the VOBU Map structure.
*****************************************************************************/
static vobu_admap_t ReadMap( ifo_t* p_ifo )
{
vobu_admap_t map;
int i, i_max;
int i_start = p_ifo->i_pos;
fprintf( stderr, "VOBU ADMAP\n" );
GETL( &map.i_ebyte );
i_max = ( i_start + map.i_ebyte + 1 - p_ifo->i_pos ) / sizeof(u32);
map.pi_vobu_ssector = malloc( i_max *sizeof(u32) );
for( i=0 ; i<i_max ; i++ )
{
GETL( &map.pi_vobu_ssector[i] );
}
return map;
}
/*
* Video Manager Information Processing.
* This is what is contained in video_ts.ifo.
*/
/*****************************************************************************
* ReadVMGInfMat : Fills the Management Information structure.
*****************************************************************************/
static vmgi_mat_t ReadVMGInfMat( ifo_t* p_ifo )
{
vmgi_mat_t mat;
int i;
int i_start = p_ifo->i_pos;
fprintf( stderr, "VMGI\n" );
GET( mat.psz_id , 12 );
mat.psz_id[12] = '\0';
GETL( &mat.i_lsector );
FLUSH( 12 );
GETL( &mat.i_i_lsector );
FLUSH( 1 );
GETC( &mat.i_spec_ver );
GETL( &mat.i_cat );
GETS( &mat.i_vol_nb );
GETS( &mat.i_vol );
GETC( &mat.i_disc_side );
FLUSH( 19 );
GETS( &mat.i_tts_nb );
GET( mat.psz_provider_id, 32 );
GETLL( &mat.i_pos_code );
FLUSH( 24 );
GETL( &mat.i_i_mat_ebyte );
GETL( &mat.i_fp_pgc_sbyte );
FLUSH( 56 );
GETL( &mat.i_vobs_ssector );
GETL( &mat.i_ptt_srpt_ssector );
GETL( &mat.i_pgci_ut_ssector );
GETL( &mat.i_ptl_mait_ssector );
GETL( &mat.i_vts_atrt_ssector );
GETL( &mat.i_txtdt_mg_ssector );
GETL( &mat.i_c_adt_ssector );
GETL( &mat.i_vobu_admap_ssector );
FLUSH( 32 );
GETS( &mat.i_video_atrt );
FLUSH( 1 );
GETC( &mat.i_audio_nb );
for( i=0 ; i < 8 ; i++ )
{
GETLL( &mat.pi_audio_atrt[i] );
}
FLUSH( 17 );
GETC( &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 */
}
return mat;
}
/*****************************************************************************
* ReadVMGTitlePointer : Fills the Part Of Title Search Pointer structure.
*****************************************************************************/
static vmg_ptt_srpt_t ReadVMGTitlePointer( ifo_t* p_ifo )
{
vmg_ptt_srpt_t ptr;
int i;
int i_start = p_ifo->i_pos;
fprintf( stderr, "PTR\n" );
GETS( &ptr.i_ttu_nb );
FLUSH( 2 );
GETL( &ptr.i_ebyte );
/* Parsing of tts */
ptr.p_tts = malloc( ptr.i_ttu_nb *sizeof(tts_t) );
if( ptr.p_tts == NULL )
{
intf_ErrMsg( "Out of memory" );
p_ifo->b_error = 1;
return ptr;
}
for( i=0 ; i<ptr.i_ttu_nb ; i++ )
{
GETC( &ptr.p_tts[i].i_play_type );
GETC( &ptr.p_tts[i].i_angle_nb );
GETS( &ptr.p_tts[i].i_ptt_nb );
GETS( &ptr.p_tts[i].i_parental_id );
GETC( &ptr.p_tts[i].i_tts_nb );
GETC( &ptr.p_tts[i].i_vts_ttn );
GETL( &ptr.p_tts[i].i_ssector );
}
return ptr;
}
/*****************************************************************************
* ReadParentalInf : Fills the Parental Management structure.
*****************************************************************************/
static vmg_ptl_mait_t ReadParentalInf( ifo_t* p_ifo )
{
vmg_ptl_mait_t par;
int i, j, k;
int i_start = p_ifo->i_pos;
fprintf( stderr, "PTL\n" );
GETS( &par.i_country_nb );
GETS( &par.i_vts_nb );
GETL( &par.i_ebyte );
par.p_ptl_desc = malloc( par.i_country_nb *sizeof(vmg_ptl_mai_desc_t) );
if( par.p_ptl_desc == NULL )
{
intf_ErrMsg( "Out of memory" );
p_ifo->b_error = 1;
return par;
}
for( i=0 ; i<par.i_country_nb ; i++ )
{
GETS( &par.p_ptl_desc[i].i_country_code );
FLUSH( 2 );
GETS( &par.p_ptl_desc[i].i_ptl_mai_sbyte );
FLUSH( 2 );
}
par.p_ptl_mask = malloc( par.i_country_nb *sizeof(vmg_ptl_mask_t) );
if( par.p_ptl_mask == NULL )
{
intf_ErrMsg( "Out of memory" );
p_ifo->b_error = 1;
return par;
}
for( i=0 ; i<par.i_country_nb ; i++ )
{
p_ifo->i_pos = lseek( p_ifo->i_fd, i_start +
par.p_ptl_desc[i].i_ptl_mai_sbyte, SEEK_SET );
for( j=1 ; j<=8 ; j++ )
{
par.p_ptl_mask[i].ppi_ptl_mask[j] =
malloc( par.i_vts_nb *sizeof(u16) );
if( par.p_ptl_mask[i].ppi_ptl_mask[j] == NULL )
{
intf_ErrMsg( "Out of memory" );
p_ifo->b_error = 1;
return par;
}
for( k=0 ; k<par.i_vts_nb ; k++ )
{
GETS( &par.p_ptl_mask[i].ppi_ptl_mask[j][k] );
}
}
}
return par;
}
/*****************************************************************************
* ReadVTSAttr : Fills the structure about VTS attributes.
*****************************************************************************/
static vmg_vts_atrt_t ReadVTSAttr( ifo_t* p_ifo )
{
vmg_vts_atrt_t atrt;
int i, j;
int i_start = p_ifo->i_pos;
fprintf( stderr, "VTS ATTR\n" );
GETS( &atrt.i_vts_nb );
FLUSH( 2 );
GETL( &atrt.i_ebyte );
atrt.pi_vts_atrt_sbyte = malloc( atrt.i_vts_nb *sizeof(u32) );
if( atrt.pi_vts_atrt_sbyte == NULL )
{
intf_ErrMsg( "Out of memory" );
p_ifo->b_error = 1;
return atrt;
}
for( i=0 ; i<atrt.i_vts_nb ; i++ )
{
GETL( &atrt.pi_vts_atrt_sbyte[i] );
}
atrt.p_vts_atrt = malloc( atrt.i_vts_nb *sizeof(vts_atrt_t) );
if( atrt.p_vts_atrt == NULL )
{
intf_ErrMsg( "Out of memory" );
p_ifo->b_error = 1;
return atrt;
}
for( i=0 ; i<atrt.i_vts_nb ; i++ )
{
p_ifo->i_pos = lseek( p_ifo->i_fd, i_start + atrt.pi_vts_atrt_sbyte[i],
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 );
FLUSH( 1 );
GETC( &atrt.p_vts_atrt[i].i_vtsm_audio_nb );
for( j=0 ; j<atrt.p_vts_atrt[i].i_vtsm_audio_nb ; j++ )
{
GETLL( &atrt.p_vts_atrt[i].pi_vtsm_audio_atrt[j] );
}
FLUSH( 1 );
GETC( &atrt.p_vts_atrt[i].i_vtsm_subpic_nb );
for( j=0 ; j<atrt.p_vts_atrt[i].i_vtsm_subpic_nb ; j++ )
{
GET( &atrt.p_vts_atrt[i].pi_vtsm_subpic_atrt[j], 6 );
/* FIXME : Fix endianness issue here */
}
GETS( &atrt.p_vts_atrt[i].i_vtstt_video_atrt );
FLUSH( 1 );
GETL( &atrt.p_vts_atrt[i].i_vtstt_audio_nb );
for( j=0 ; j<atrt.p_vts_atrt[i].i_vtstt_audio_nb ; j++ )
{
GETLL( &atrt.p_vts_atrt[i].pi_vtstt_audio_atrt[j] );
}
FLUSH( 1 );
GETC( &atrt.p_vts_atrt[i].i_vtstt_subpic_nb );
for( j=0 ; j<atrt.p_vts_atrt[i].i_vtstt_subpic_nb ; j++ )
{
GET( &atrt.p_vts_atrt[i].pi_vtstt_subpic_atrt[j], 6 );
/* FIXME : Fix endianness issue here */
}
}
return atrt;
}
/*****************************************************************************
* ReadVMG : Parse video_ts.ifo file to fill the Video Manager structure.
*****************************************************************************/
static vmg_t ReadVMG( ifo_t* p_ifo )
{
vmg_t vmg;
p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off, SEEK_SET);
vmg.mat = ReadVMGInfMat( p_ifo );
p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
vmg.mat.i_fp_pgc_sbyte, SEEK_SET );
vmg.pgc = ReadPGC( p_ifo );
if( vmg.mat.i_ptt_srpt_ssector )
{
p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
vmg.mat.i_ptt_srpt_ssector *DVD_LB_SIZE,
SEEK_SET );
vmg.ptt_srpt = ReadVMGTitlePointer( p_ifo );
}
if( vmg.mat.i_pgci_ut_ssector )
{
p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
vmg.mat.i_pgci_ut_ssector *DVD_LB_SIZE,
SEEK_SET );
vmg.pgci_ut = ReadUnitTable( p_ifo );
}
if( vmg.mat.i_ptl_mait_ssector )
{
p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
vmg.mat.i_ptl_mait_ssector *DVD_LB_SIZE,
SEEK_SET );
vmg.ptl_mait = ReadParentalInf( p_ifo );
}
if( vmg.mat.i_vts_atrt_ssector )
{
p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
vmg.mat.i_vts_atrt_ssector *DVD_LB_SIZE,
SEEK_SET );
vmg.vts_atrt = ReadVTSAttr( p_ifo );
}
if( vmg.mat.i_c_adt_ssector )
{
p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
vmg.mat.i_c_adt_ssector *DVD_LB_SIZE,
SEEK_SET );
vmg.c_adt = ReadCellInf( p_ifo );
}
if( vmg.mat.i_vobu_admap_ssector )
{
p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
vmg.mat.i_vobu_admap_ssector *DVD_LB_SIZE,
SEEK_SET );
vmg.vobu_admap = ReadMap( p_ifo );
}
return vmg;
}
/*
* Video Title Set Information Processing.
* This is what is contained in vts_*.ifo.
*/
/*****************************************************************************
* ReadVTSInfMat : Fills the Title Set Information structure.
*****************************************************************************/
static vtsi_mat_t ReadVTSInfMat( ifo_t* p_ifo )
{
vtsi_mat_t mat;
int i;
int i_start = p_ifo->i_pos;
fprintf( stderr, "VTSI\n" );
GET( mat.psz_id , 12 );
mat.psz_id[12] = '\0';
GETL( &mat.i_lsector );
FLUSH( 12 );
GETL( &mat.i_i_lsector );
FLUSH( 1 );
GETC( &mat.i_spec_ver );
GETL( &mat.i_cat );
FLUSH( 90 );
GETL( &mat.i_mat_ebyte );
FLUSH( 60 );
GETL( &mat.i_m_vobs_ssector );
GETL( &mat.i_tt_vobs_ssector );
GETL( &mat.i_ptt_srpt_ssector );
GETL( &mat.i_pgcit_ssector );
GETL( &mat.i_m_pgci_ut_ssector );
GETL( &mat.i_tmap_ti_ssector );
GETL( &mat.i_m_c_adt_ssector );
GETL( &mat.i_m_vobu_admap_ssector );
GETL( &mat.i_c_adt_ssector );
GETL( &mat.i_vobu_admap_ssector );
FLUSH( 24 );
GETS( &mat.i_m_video_atrt );
FLUSH( 1 );
GETC( &mat.i_m_audio_nb );
for( i=0 ; i<8 ; i++ )
{
GETLL( &mat.pi_m_audio_atrt[i] );
}
FLUSH( 17 );
GETC( &mat.i_m_subpic_nb );
for( i=0 ; i<28 ; i++ )
{
GET( &mat.pi_m_subpic_atrt[i], 6 );
/* FIXME : take care of endianness */
}
FLUSH( 2 );
GETS( &mat.i_video_atrt );
FLUSH( 1 );
GETC( &mat.i_audio_nb );
for( i=0 ; i<8 ; i++ )
{
GETLL( &mat.pi_audio_atrt[i] );
}
FLUSH( 17 );
GETC( &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 */
}
return mat;
}
/*****************************************************************************
* ReadVTSTitlePointer : Fills the Part Of Title Search Pointer structure.
*****************************************************************************/
static vts_ptt_srpt_t ReadVTSTitlePointer( ifo_t* p_ifo )
{
vts_ptt_srpt_t ptr;
int i;
int i_start = p_ifo->i_pos;
fprintf( stderr, "PTR\n" );
GETS( &ptr.i_ttu_nb );
FLUSH( 2 );
GETL( &ptr.i_ebyte );
ptr.pi_ttu_sbyte = malloc( ptr.i_ttu_nb *sizeof(u32) );
if( ptr.pi_ttu_sbyte == NULL )
{
intf_ErrMsg( "Out of memory" );
p_ifo->b_error = 1;
return ptr;
}
for( i=0 ; i<ptr.i_ttu_nb ; i++ )
{
GETL( &ptr.pi_ttu_sbyte[i] );
}
/* Parsing of tts */
ptr.p_ttu = malloc( ptr.i_ttu_nb *sizeof(ttu_t) );
if( ptr.p_ttu == NULL )
{
intf_ErrMsg( "Out of memory" );
p_ifo->b_error = 1;
return ptr;
}
for( i=0 ; i<ptr.i_ttu_nb ; i++ )
{
p_ifo->i_pos = lseek( p_ifo->i_fd, i_start +
ptr.pi_ttu_sbyte[i], SEEK_SET );
GETS( &ptr.p_ttu[i].i_pgc_nb );
GETS( &ptr.p_ttu[i].i_prg_nb );
}
return ptr;
}
/*****************************************************************************
* ReadVTSTimeMap : Fills the time map table
*****************************************************************************/
static vts_tmap_ti_t ReadVTSTimeMap( ifo_t* p_ifo )
{
vts_tmap_ti_t tmap;
int i,j;
int i_start = p_ifo->i_pos;
fprintf( stderr, "TMAP\n" );
GETS( &tmap.i_nb );
FLUSH( 2 );
GETL( &tmap.i_ebyte );
tmap.pi_sbyte = malloc( tmap.i_nb *sizeof(u32) );
if( tmap.pi_sbyte == NULL )
{
intf_ErrMsg( "Out of memory" );
p_ifo->b_error = 1;
return tmap;
}
for( i=0 ; i<tmap.i_nb ; i++ )
{
GETL( &tmap.pi_sbyte[i] );
}
tmap.p_tmap = malloc( tmap.i_nb *sizeof(tmap_t) );
if( tmap.p_tmap == NULL )
{
intf_ErrMsg( "Out of memory" );
p_ifo->b_error = 1;
return tmap;
}
for( i=0 ; i<tmap.i_nb ; i++ )
{
GETC( &tmap.p_tmap[i].i_time_unit );
FLUSH( 1 );
GETS( &tmap.p_tmap[i].i_entry_nb );
tmap.p_tmap[i].pi_sector =
malloc( tmap.p_tmap[i].i_entry_nb *sizeof(u32) );
if( tmap.p_tmap[i].pi_sector == NULL )
{
intf_ErrMsg( "Out of memory" );
p_ifo->b_error = 1;
return tmap;
}
for( j=0 ; j<tmap.p_tmap[i].i_entry_nb ; j++ )
{
GETL( &tmap.p_tmap[i].pi_sector[j] );
}
}
return tmap;
}
/*****************************************************************************
* ReadVTS : Parse vts*.ifo files to fill the Video Title Set structure.
*****************************************************************************/
static vts_t ReadVTS( ifo_t* p_ifo )
{
vts_t vts;
vts.i_pos = p_ifo->i_pos;
vts.mat = ReadVTSInfMat( p_ifo );
if( vts.mat.i_ptt_srpt_ssector )
{
p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
vts.mat.i_ptt_srpt_ssector *DVD_LB_SIZE,
SEEK_SET );
vts.ptt_srpt = ReadVTSTitlePointer( p_ifo );
}
if( vts.mat.i_m_pgci_ut_ssector )
{
p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
vts.mat.i_m_pgci_ut_ssector *DVD_LB_SIZE,
SEEK_SET );
vts.pgci_ut = ReadUnitTable( p_ifo );
}
if( vts.mat.i_pgcit_ssector )
{
p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
vts.mat.i_pgcit_ssector *DVD_LB_SIZE,
SEEK_SET );
vts.pgci_ti = ReadUnitTable( p_ifo );
}
if( vts.mat.i_tmap_ti_ssector )
{
p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
vts.mat.i_tmap_ti_ssector *DVD_LB_SIZE,
SEEK_SET );
vts.tmap_ti = ReadVTSTimeMap( p_ifo );
}
if( vts.mat.i_m_c_adt_ssector )
{
p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
vts.mat.i_m_c_adt_ssector *DVD_LB_SIZE,
SEEK_SET );
vts.m_c_adt = ReadCellInf( p_ifo );
}
if( vts.mat.i_m_vobu_admap_ssector )
{
p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
vts.mat.i_m_vobu_admap_ssector *DVD_LB_SIZE,
SEEK_SET );
vts.m_vobu_admap = ReadMap( p_ifo );
}
if( vts.mat.i_c_adt_ssector )
{
p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
vts.mat.i_c_adt_ssector *DVD_LB_SIZE,
SEEK_SET );
vts.c_adt = ReadCellInf( p_ifo );
}
if( vts.mat.i_vobu_admap_ssector )
{
p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
vts.mat.i_vobu_admap_ssector *DVD_LB_SIZE,
SEEK_SET );
vts.vobu_admap = ReadMap( p_ifo );
}
return vts;
}
/*
* DVD Information Management
*/
/*****************************************************************************
* IfoRead : Function that fills structure and calls specified functions
* to do it.
*****************************************************************************/
void IfoRead( ifo_t* p_ifo )
{
int i;
p_ifo->vmg = ReadVMG( p_ifo );
p_ifo->p_vts = malloc( p_ifo->vmg.mat.i_tts_nb *sizeof(vts_t) );
if( p_ifo->p_vts == NULL )
{
intf_ErrMsg( "Out of memory" );
p_ifo->b_error = 1;
return;
}
for( i=0 ; i<1/*p_ifo->vmg.mat.i_tts_nb*/ ; i++ )
{
p_ifo->i_pos = lseek( p_ifo->i_fd,
p_ifo->vmg.ptt_srpt.p_tts[i].i_ssector *DVD_LB_SIZE,
SEEK_SET );
/* FIXME : use udf filesystem to avoid this */
IfoFindVTS( p_ifo );
p_ifo->p_vts[i] = ReadVTS( p_ifo );
}
return;
}
/*****************************************************************************
* ifo.h: Structures for ifo parsing
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
*
* 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
*****************************************************************************/
#define DVD_LB_SIZE 2048
/*****************************************************************************
* Common structures for Video Management and Video Title sets
*****************************************************************************/
/*
* Program Chain structures
*/
/* Program Chain Command Table
- start at i_pgc_com_tab_sbyte */
typedef struct pgc_com_tab_s
{
u16 i_pre_com_nb; // 2 bytes
u16 i_post_com_nb; // 2 bytes
u16 i_cell_com_nb; // 2 bytes
// char[2] ???
char* psz_pre_com; // i_pre_com_nb * 8 bytes
char* psz_post_com; // i_post_com_nb * 8 bytes
char* psz_cell_com; // i_cell_com_nb * 8 bytes
} pgc_com_tab_t;
/* Program Chain Map Table
* - start at "i_pgc_prg_map_sbyte" */
typedef struct pgc_prg_map_s
{
u8* pi_entry_cell; // i_prg_nb * 1 byte
} pgc_prg_map_t;
/* Cell Playback Information Table
* we have a pointer to such a structure for each cell
* - first start at "i_cell_play_inf_sbyte" */
typedef struct cell_play_inf_s
{
/* This information concerns the currently selected cell */
u16 i_cat; // 2 bytes
u8 i_still_time; // 1 byte; in seconds; ff=inf
u8 i_com_nb; // 1 byte; 0 = no com
u32 i_play_time; // 4 bytes
u32 i_entry_sector; // 4 bytes
u32 i_first_ilvu_vobu_esector; // 4 bytes; ???
u32 i_lvobu_ssector; // 4 bytes
u32 i_lsector; // 4 bytes
} cell_play_inf_t;
/* Cell Position Information Table
* we have a pointer to such a structure for each cell
* - first start at "i_cell_pos_inf_sbyte" */
typedef struct cell_pos_inf_s
{
/* This information concerns the currently selected cell */
u16 i_vob_id; // 2 bytes
// char ???
u8 i_cell_id; // 1 byte
} cell_pos_inf_t;
/* Main structure for Program Chain
* - start at i_fp_pgc_sbyte
* - or at i_vmgm_pgci_sbyte in vmgm_pgci_srp_t */
typedef struct pgc_s
{
/* Global features of program chain */
// char[2] ???
u8 i_prg_nb; // 1 byte
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
u16 i_next_pgc_nb; // 2 bytes
u16 i_prev_pgc_nb; // 2 bytes
u16 i_goup_pgc_nb; // 2 bytes
u8 i_still_time; // 1 byte ; in seconds
u8 i_play_mode; // 1 byte
/* In video_ts.ifo, the 3 significant bytes of each color are
* preceded by 1 unsignificant byte */
u32 pi_yuv_color[16]; // 16*3 bytes
/* Here come the start bytes of the following structures */
u16 i_com_tab_sbyte; // 2 bytes
u16 i_prg_map_sbyte; // 2 bytes
u16 i_cell_play_inf_sbyte; // 2 bytes
u16 i_cell_pos_inf_sbyte; // 2 bytes
/* Predefined structures */
pgc_com_tab_t com_tab;
pgc_prg_map_t prg_map;
cell_play_inf_t* p_cell_play_inf; // i_cell_nb * 24 bytes
cell_pos_inf_t* p_cell_pos_inf; // i_cell_nb * 4 bytes
} pgc_t;
/*
* Menu PGCI Unit Table
*/
/* Menu PGCI Language unit Descriptor */
typedef struct pgci_lu_desc_s
{
u16 i_lang_code; // 2 bytes (ISO-xx)
// char ???
u8 i_existence_mask; // 1 byte
u32 i_lu_sbyte; // 4 bytes
} pgci_lu_desc_t;
typedef struct pgci_srp_s
{
u8 i_pgc_cat_mask; // 1 byte
u8 i_pgc_cat; // 1 byte
u16 i_par_mask; // 2 bytes
u32 i_pgci_sbyte; // 4 bytes
pgc_t pgc;
} pgci_srp_t;
/* Menu PGCI Language Unit Table
* - start at i_lu_sbyte */
typedef struct pgci_lu_s
{
u16 i_srp_nb; // 2 bytes
// char[2] ???
u32 i_lu_ebyte; // 4 bytes
pgci_srp_t* p_srp; // i_srp_nb * 8 bytes
} pgci_lu_t;
/* Main Struct for Menu PGCI
* - start at i_*_pgci_ut_ssector */
typedef struct pgci_ut_s
{
u16 i_lu_nb; // 2 bytes; ???
// char[2] ???
u32 i_ebyte; // 4 bytes
pgci_lu_desc_t* p_lu_desc; // i_lu_nb * 8 bytes
pgci_lu_t* p_lu; // i_lu_nb * 8 bytes
} pgci_ut_t;
/*
* Cell Adress Table Information
*/
typedef struct cell_inf_s
{
u16 i_vob_id; // 2 bytes
u8 i_cell_id; // 1 byte
// char ???
u32 i_ssector; // 4 bytes
u32 i_esector; // 4 bytes
} cell_inf_t;
typedef struct c_adt_s
{
u16 i_vob_nb; // 2 bytes
// char[2] ???
u32 i_ebyte; // 4 bytes
cell_inf_t* p_cell_inf;
} c_adt_t;
/*
* VOBU Adress Map Table
*/
typedef struct vobu_admap_s
{
u32 i_ebyte; // 4 bytes
u32* pi_vobu_ssector; // (nb of vobu) * 4 bytes
} vobu_admap_t;
/*****************************************************************************
* Structures for Video Management (cf video_ts.ifo)
*****************************************************************************/
/*
* Video Manager Information Management Table
*/
typedef struct vmgi_mat_s
{
char psz_id[13]; // 12 bytes (DVDVIDEO-VMG)
u32 i_lsector; // 4 bytes
// char[12] ???
u32 i_i_lsector; // 4 bytes
// char ???
u8 i_spec_ver; // 1 byte
u32 i_cat; // 4 bytes
u16 i_vol_nb; // 2 bytes
u16 i_vol; // 2 bytes
u8 i_disc_side; // 1 bytes
// char[20] ???
u16 i_tts_nb; // 2 bytes
char psz_provider_id[32]; // 32 bytes
u64 i_pos_code; // 8 bytes
// char[24] ???
u32 i_i_mat_ebyte; // 4 bytes
u32 i_fp_pgc_sbyte; // 4 bytes
// char[56] ???
u32 i_vobs_ssector; // 4 bytes
u32 i_ptt_srpt_ssector; // 4 bytes
u32 i_pgci_ut_ssector; // 4 bytes
u32 i_ptl_mait_ssector; // 4 bytes
u32 i_vts_atrt_ssector; // 4 bytes
u32 i_txtdt_mg_ssector; // 4 bytes
u32 i_c_adt_ssector; // 4 bytes
u32 i_vobu_admap_ssector; // 4 bytes
// char[2] ???
u16 i_video_atrt; // 2 bytes
// char ???
u8 i_audio_nb; // 1 byte
u64 pi_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
} vmgi_mat_t;
/*
* Part Of Title Search Pointer Table Information
*/
/* Title sets structure
* we have a pointer to this structure for each tts */
typedef struct tts_s
{
u8 i_play_type; // 1 byte
u8 i_angle_nb; // 1 byte
u16 i_ptt_nb; // 2 bytes; Chapters/PGs
u16 i_parental_id; // 2 bytes
u8 i_tts_nb; // 1 byte (VTS#)
u8 i_vts_ttn; // 1 byte ???
u32 i_ssector; // 4 bytes
} tts_t;
/* Main struct for tts
* - start at "i_vmg_ptt_srpt_ssector" */
typedef struct vmg_ptt_srpt_s
{
u16 i_ttu_nb; // 2 bytes
// char[2] ???
u32 i_ebyte; // 4 bytes
tts_t* p_tts; // i_ttu_nb * 12 bytes
} vmg_ptt_srpt_t;
/*
* Parental Management Information Table
*/
typedef struct vmg_ptl_mai_desc_s
{
u16 i_country_code; // 2 bytes
// char[2] ???
u16 i_ptl_mai_sbyte; // 2 bytes
// char[2] ???
} vmg_ptl_mai_desc_t;
typedef struct vmg_ptl_mask_s
{
u16* ppi_ptl_mask[8]; // (i_vts_nb +1) * 8 * 2 bytes
} vmg_ptl_mask_t;
/* Main struct for parental management
* - start at i_vmg_ptl_mait_ssector */
typedef struct vmg_ptl_mait_s
{
u16 i_country_nb; // 2 bytes
u16 i_vts_nb; // 2 bytes
u32 i_ebyte; // 4 bytes
vmg_ptl_mai_desc_t* p_ptl_desc; // i_country_nb * 8 bytes
vmg_ptl_mask_t* p_ptl_mask; // i_country_nb * sizeof(vmg_ptl_mask_t)
} vmg_ptl_mait_t;
/*
* Video Title Set Attribute Table
*/
/* Attribute structure : one for each vts
* - start at pi_atrt_sbyte */
typedef struct vts_atrt_s
{
u32 i_ebyte; // 4 bytes
u32 i_cat_app_type; // 4 bytes
u16 i_vtsm_video_atrt; // 2 bytes
// char ???
u8 i_vtsm_audio_nb; // 1 byte
u64 pi_vtsm_audio_atrt[8]; // i_vtsm_audio_nb * 8 bytes
// char ???
u8 i_vtsm_subpic_nb; // 1 byte
u64 pi_vtsm_subpic_atrt[32]; // i_vtsm_subpic_nb * 6 bytes
u16 i_vtstt_video_atrt; // 2 bytes
// char ???
u8 i_vtstt_audio_nb; // 1 byte
u64 pi_vtstt_audio_atrt[8]; // i_vtstt_audio_nb * 8 bytes
// char ???
u8 i_vtstt_subpic_nb; // 1 byte
u64 pi_vtstt_subpic_atrt[32]; // i_vtstt_subpic_nb * 6 bytes
} vts_atrt_t;
/* Main struct for vts attributes
* - start at i_vmg_vts_atrt_ssector */
typedef struct vmg_vts_atrt_s
{
u16 i_vts_nb; // 2 bytes
// char[2] ???
u32 i_ebyte; // 4 bytes
u32* pi_vts_atrt_sbyte; // i_vts_nb * 4 bytes
vts_atrt_t* p_vts_atrt;
} vmg_vts_atrt_t;
/*
* Global Structure for Video Manager
*/
typedef struct vmg_s
{
vmgi_mat_t mat;
pgc_t pgc;
vmg_ptt_srpt_t ptt_srpt;
pgci_ut_t pgci_ut;
vmg_ptl_mait_t ptl_mait;
vmg_vts_atrt_t vts_atrt;
c_adt_t c_adt;
vobu_admap_t vobu_admap;
} vmg_t;
/*****************************************************************************
* Structures for Video Title Sets (cf vts_*.ifo)
****************************************************************************/
/*
* Video Title Sets Information Management Table
*/
typedef struct vtsi_mat_s
{
char psz_id[13]; // 12 bytes (DVDVIDEO-VTS)
u32 i_lsector; // 4 bytes
// char[12] ???
u32 i_i_lsector; // 4 bytes
// char ???
u8 i_spec_ver; // 1 byte
u32 i_cat; // 4 bytes
// char[90] ???
u32 i_mat_ebyte; // 4 bytes
// char[60] ???
u32 i_m_vobs_ssector; // 4 bytes
u32 i_tt_vobs_ssector; // 4 bytes
u32 i_ptt_srpt_ssector; // 4 bytes
u32 i_pgcit_ssector; // 4 bytes
u32 i_m_pgci_ut_ssector; // 4 bytes
u32 i_tmap_ti_ssector; // 4 bytes
u32 i_m_c_adt_ssector; // 4 bytes
u32 i_m_vobu_admap_ssector; // 4 bytes
u32 i_c_adt_ssector; // 4 bytes
u32 i_vobu_admap_ssector; // 4 bytes
// char[24] ???
u16 i_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
// char[16] ???
u8 i_m_subpic_nb; // 1 byte
u64 pi_m_subpic_atrt[32]; // i_subpic_nb * 6 bytes
// !!! only 28 subpics ???
// char[2] ???
u16 i_video_atrt; // 2 bytes
// char ???
u8 i_audio_nb; // 1 byte
u64 pi_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
} vtsi_mat_t;
/*
* Part Of Title Search Pointer Table Information
*/
/* Title sets structure
* we have a pointer to this structure for each tts */
typedef struct ttu_s
{
u16 i_pgc_nb; // 2 bytes; Chapters/PGs
u16 i_prg_nb; // 2 bytes
} ttu_t;
/* Main struct for tts
* - start at "i_vts_ptt_srpt_ssector" */
typedef struct vts_ptt_srpt_s
{
u16 i_ttu_nb; // 2 bytes
// char[2] ???
u32 i_ebyte; // 4 bytes
u32* pi_ttu_sbyte;
ttu_t* p_ttu; // i_ttu_nb * 4 bytes
} vts_ptt_srpt_t;
/*
* Time Map table information
*/
/* Time Map structure */
typedef struct tmap_s
{
u8 i_time_unit; // 1 byte
// char ???
u16 i_entry_nb; // 2 bytes
u32* pi_sector; // i_entry_nb * 4 bytes
} tmap_t;
/* Main structure for tmap_ti
* - start at "i_tmap_ti_ssector" */
typedef struct vts_tmap_ti_s
{
u16 i_nb; // 2 bytes
// char[2] ???
u32 i_ebyte; // 4 bytes
u32* pi_sbyte; // i_tmap_nb * 4 bytes
tmap_t* p_tmap;
} vts_tmap_ti_t;
/*
* Video Title Set
*/
typedef struct vts_s
{
u32 i_pos;
vtsi_mat_t mat;
/* Part Of Title Search Pointer Table Info */
vts_ptt_srpt_t ptt_srpt;
/* Video Title Set Menu PGCI Unit Table */
pgci_ut_t pgci_ut;
/* Video Title Set Program Chain Info Table */
pgci_ut_t pgci_ti;
/* Video Title Set Time Map Table */
vts_tmap_ti_t tmap_ti;
/* VTSM Cell Adress Table Information */
c_adt_t m_c_adt;
/* VTSM VOBU Adress Map Table */
vobu_admap_t m_vobu_admap;
/* VTS Cell Adress Table Information */
c_adt_t c_adt;
/* VTS VOBU Adress Map Table */
vobu_admap_t vobu_admap;
} vts_t;
/*
* Global Ifo Structure
*/
typedef struct ifo_s
{
/* File descriptor for the device */
int i_fd;
/* Offset to video_ts.ifo on the device */
u32 i_off;
/* Position of stream pointer */
u32 i_pos;
/* Error Management */
boolean_t b_error;
/* Structure described in video_ts */
vmg_t vmg;
/* Table of vts ifos */
vts_t * p_vts;
} ifo_t;
/*****************************************************************************
* Prototypes in ifo.c
*****************************************************************************/
ifo_t IfoInit( int );
void IfoRead( ifo_t* );
......@@ -4,7 +4,7 @@
* decoders.
*****************************************************************************
* Copyright (C) 1998, 1999, 2000 VideoLAN
* $Id: input.c,v 1.67 2001/01/07 04:31:18 henri Exp $
* $Id: input.c,v 1.68 2001/01/14 07:08:00 stef Exp $
*
* Authors:
*
......@@ -62,6 +62,7 @@ static void ErrorThread ( input_thread_t *p_input );
static void EndThread ( input_thread_t *p_input );
static void NetworkOpen ( input_thread_t *p_input );
static void FileOpen ( input_thread_t *p_input );
static void DvdOpen ( input_thread_t *p_input );
/*****************************************************************************
* input_CreateThread: creates a new input thread
......@@ -223,6 +224,7 @@ static void RunThread( input_thread_t *p_input )
* InitThread: init the input thread
*****************************************************************************/
input_capabilities_t * PSKludge( void );
input_capabilities_t * DVDKludge( void );
static void InitThread( input_thread_t * p_input )
{
/* Initialize default settings for spawned decoders */
......@@ -243,6 +245,13 @@ static void InitThread( input_thread_t * p_input )
{
case INPUT_METHOD_FILE: /* file methods */
FileOpen( p_input );
/* Probe plugin (FIXME: load plugins before & write this) */
p_input->p_plugin = PSKludge();
break;
case INPUT_METHOD_DVD: /* DVD method */
DvdOpen( p_input );
/* DVD plugin */
p_input->p_plugin = DVDKludge();
break;
case INPUT_METHOD_VLAN_BCAST: /* vlan network method */
/* if( !p_main->b_vlans )
......@@ -269,8 +278,6 @@ static void InitThread( input_thread_t * p_input )
free( p_input->p_config );
/* Probe plugin (FIXME: load plugins before & write this) */
p_input->p_plugin = PSKludge();
p_input->p_plugin->pf_init( p_input );
*p_input->pi_status = THREAD_READY;
......@@ -398,3 +405,27 @@ static void FileOpen( input_thread_t * p_input )
#undef p_config
}
/*****************************************************************************
* DvdOpen : open the dvd device
*****************************************************************************/
static void DvdOpen( input_thread_t * p_input )
{
intf_Msg( "Opening DVD %s", p_input->p_config->p_source );
if( (p_input->i_handle = open( p_input->p_config->p_source,
O_RDONLY|O_LARGEFILE )) == (-1) )
{
intf_ErrMsg( "input error: cannot open device %s", strerror(errno) );
p_input->b_error = 1;
return;
}
vlc_mutex_lock( &p_input->stream.stream_lock );
p_input->stream.b_pace_control = 1;
p_input->stream.b_seekable = 1;
p_input->stream.i_size = 0;
p_input->stream.i_tell = 0;
vlc_mutex_unlock( &p_input->stream.stream_lock );
}
/*****************************************************************************
* input_dvd.c: DVD reading
*****************************************************************************
* Copyright (C) 1998-2001 VideoLAN
*
* 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"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <netinet/in.h>
#include <string.h>
#include <errno.h>
#include <malloc.h>
#include "config.h"
#include "common.h"
#include "threads.h"
#include "mtime.h"
#include "intf_msg.h"
#include "main.h"
#include "stream_control.h"
#include "input_ext-intf.h"
#include "input_ext-dec.h"
#include "input.h"
#include "dvd_ifo.h"
#include "input_dvd.h"
#include "mpeg_system.h"
#include "debug.h"
/*****************************************************************************
* Local prototypes
*****************************************************************************/
static int DVDProbe ( struct input_thread_s * );
static int DVDRead ( struct input_thread_s *,
data_packet_t * p_packets[INPUT_READ_ONCE] );
static void DVDInit ( struct input_thread_s * );
static void DVDEnd ( struct input_thread_s * );
static int DVDSeek ( struct input_thread_s *, off_t );
static int DVDRewind ( struct input_thread_s * );
static struct data_packet_s * NewPacket ( void *, size_t );
static void DeletePacket( void *, struct data_packet_s * );
static void DeletePES ( void *, struct pes_packet_s * );
/*
* Data reading functions
*/
/*****************************************************************************
* DVDProbe: check the stream
*****************************************************************************/
static int DVDProbe( input_thread_t * p_input )
{
/* verify that the first three bytes are 0x000001, or unscramble and
* re-do. */
return 1;
}
/*****************************************************************************
* DVDInit: initializes DVD structures
*****************************************************************************/
static void DVDInit( input_thread_t * p_input )
{
thread_dvd_data_t * p_method;
u32 i_start;// = 2048*90000;
if( (p_method = malloc( sizeof(thread_dvd_data_t) )) == NULL )
{
intf_ErrMsg( "Out of memory" );
p_input->b_error = 1;
return;
}
p_input->p_plugin_data = (void *)p_method;
lseek( p_input->i_handle, 0, SEEK_SET );
vlc_mutex_lock( &p_input->stream.stream_lock );
p_method->ifo = IfoInit( p_input->i_handle );
IfoRead( &(p_method->ifo) );
vlc_mutex_unlock( &p_input->stream.stream_lock );
i_start = p_method->ifo.p_vts[0].i_pos +
p_method->ifo.p_vts[0].mat.i_tt_vobs_ssector *DVD_LB_SIZE;
fprintf(stderr, "Begin at : %d\n", i_start );
lseek( p_input->i_handle, i_start, SEEK_SET );
input_InitStream( p_input, sizeof( stream_ps_data_t ) );
input_AddProgram( p_input, 0, sizeof( stream_ps_data_t ) );
if( p_input->stream.b_seekable )
{
stream_ps_data_t * p_demux_data =
(stream_ps_data_t *)p_input->stream.pp_programs[0]->p_demux_data;
/* 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;
while( !p_input->b_die && !p_input->b_error
&& !p_demux_data->b_has_PSM )
{
int i_result, i;
data_packet_t * pp_packets[INPUT_READ_ONCE];
i_result = DVDRead( p_input, pp_packets );
if( i_result == 1 )
{
/* 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 );
break;
}
if( i_result == -1 )
{
p_input->b_error = 1;
break;
}
for( i = 0; i < INPUT_READ_ONCE && pp_packets[i] != NULL; i++ )
{
/* FIXME: use i_p_config_t */
input_ParsePS( p_input, pp_packets[i] );
DeletePacket( p_input->p_method_data, pp_packets[i] );
}
/* File too big. */
if( p_input->stream.i_tell > INPUT_PREPARSE_LENGTH )
{
break;
}
}
lseek( p_input->i_handle, i_start, SEEK_SET );
vlc_mutex_lock( &p_input->stream.stream_lock );
p_input->stream.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_DVD_AUDIO_VAR, 0 )
== REQUESTED_MPEG
&& main_GetIntVariable( INPUT_DVD_CHANNEL_VAR, 0 )
== (p_es->i_id & 0x1F) )
{
input_SelectES( p_input, p_es );
}
break;
case AC3_AUDIO_ES:
if( main_GetIntVariable( INPUT_DVD_AUDIO_VAR, 0 )
== REQUESTED_AC3
&& main_GetIntVariable( INPUT_DVD_CHANNEL_VAR, 0 )
== ((p_es->i_id & 0xF00) >> 8) )
{
input_SelectES( p_input, p_es );
}
break;
case DVD_SPU_ES:
if( main_GetIntVariable( INPUT_DVD_SUBTITLE_VAR, -1 )
== ((p_es->i_id & 0x1F00) >> 8) )
{
input_SelectES( p_input, p_es );
}
break;
case LPCM_AUDIO_ES:
/* FIXME ! */
break;
}
}
}
#endif
#ifdef STATS
input_DumpStream( p_input );
#endif
vlc_mutex_unlock( &p_input->stream.stream_lock );
}
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;
vlc_mutex_unlock( &p_input->stream.stream_lock );
}
}
/*****************************************************************************
* DVDEnd: frees unused data
*****************************************************************************/
static void DVDEnd( input_thread_t * p_input )
{
free( p_input->stream.p_demux_data );
free( p_input->p_plugin_data );
}
/*****************************************************************************
* SafeRead: reads a chunk of stream and correctly detects errors
*****************************************************************************/
static __inline__ int SafeRead( input_thread_t * p_input, byte_t * p_buffer,
size_t i_len )
{
thread_dvd_data_t * p_method;
int i_nb;
p_method = (thread_dvd_data_t *)p_input->p_plugin_data;
i_nb = read( p_input->i_handle, p_buffer, i_len );
switch( i_nb )
{
case 0:
/* End of File */
return( 1 );
case -1:
intf_ErrMsg( "Read failed (%s)", strerror(errno) );
return( -1 );
default:
break;
}
vlc_mutex_lock( &p_input->stream.stream_lock );
p_input->stream.i_tell += i_nb;
vlc_mutex_unlock( &p_input->stream.stream_lock );
return( 0 );
}
/*****************************************************************************
* DVDRead: reads data packets
*****************************************************************************
* Returns -1 in case of error, 0 if everything went well, and 1 in case of
* EOF.
*****************************************************************************/
static int DVDRead( input_thread_t * p_input,
data_packet_t * pp_packets[INPUT_READ_ONCE] )
{
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;
p_method = (thread_dvd_data_t *)p_input->p_plugin_data;
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 )) )
{
return( i_error );
}
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_dummy,i_nb;
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 = read( p_input->i_handle, &i_dummy, 1 )) != 0 )
{
i_startcode |= i_dummy;
fprintf(stderr, "tut :%d %d\n", i_dummy, i_nb );
}
else
{
fprintf(stderr, "poc\n" );
return( 1 );
}
}
/* Packet found. */
*(u32 *)p_header = U32_AT(&i_startcode);
if( (i_error = SafeRead( p_input, p_header + 4, 2 )) )
{
return( i_error );
}
}
if( U32_AT(p_header) != 0x1BA )
{
/* That's the case for all packets, except pack header. */
i_packet_size = U16_AT(&p_header[4]);
}
else
{
/* Pack header. */
if( (p_header[4] & 0xC0) == 0x40 )
{
/* MPEG-2 */
i_packet_size = 8;
}
else if( (p_header[4] & 0xF0) == 0x20 )
{
/* MPEG-1 */
i_packet_size = 6;
}
else
{
intf_ErrMsg( "Unable to determine stream type" );
return( -1 );
}
}
/* Fetch a packet of the appropriate size. */
if( (p_data = NewPacket( p_input, i_packet_size + 6 )) == NULL )
{
intf_ErrMsg( "Out of memory" );
return( -1 );
}
/* 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 )) )
{
return( i_error );
}
/* 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 );
}
}
}
/* Give the packet to the other input stages. */
pp_packets[i_packet] = p_data;
}
return( 0 );
}
/*****************************************************************************
* DVDRewind : reads a stream backward
*****************************************************************************/
static int DVDRewind( input_thread_t * p_input )
{
return( -1 );
}
/*****************************************************************************
* DVDSeek : Goes to a given position on the stream
*****************************************************************************/
static int DVDSeek( input_thread_t * p_input, off_t i_off )
{
return( -1 );
}
/*
* Packet management utilities
*/
/*****************************************************************************
* NewPacket: allocates a data packet
*****************************************************************************/
static struct data_packet_s * NewPacket( void * p_garbage,
size_t i_size )
{
data_packet_t * p_data;
/* Safety check */
if( i_size > INPUT_MAX_PACKET_SIZE )
{
intf_ErrMsg( "Packet too big (%d)", i_size );
return NULL;
}
if( (p_data = (data_packet_t *)malloc( sizeof(data_packet_t) )) == NULL )
{
intf_DbgMsg( "Out of memory" );
return NULL;
}
if( (p_data->p_buffer = (byte_t *)malloc( i_size )) == NULL )
{
intf_DbgMsg( "Out of memory" );
free( p_data );
return NULL;
}
/* Initialize data */
p_data->p_next = NULL;
p_data->b_discard_payload = 0;
p_data->p_payload_start = p_data->p_buffer;
p_data->p_payload_end = p_data->p_buffer + i_size;
return( p_data );
}
/*****************************************************************************
* NewPES: allocates a pes packet
*****************************************************************************/
static pes_packet_t * NewPES( void * p_garbage )
{
pes_packet_t * p_pes;
if( (p_pes = (pes_packet_t *)malloc( sizeof(pes_packet_t) )) == NULL )
{
intf_DbgMsg( "Out of memory" );
return NULL;
}
p_pes->b_messed_up = p_pes->b_data_alignment = p_pes->b_discontinuity =
p_pes->i_pts = p_pes->i_dts = 0;
p_pes->i_pes_size = 0;
p_pes->p_first = NULL;
return( p_pes );
}
/*****************************************************************************
* DeletePacket: deletes a data packet
*****************************************************************************/
static void DeletePacket( void * p_garbage,
data_packet_t * p_data )
{
ASSERT(p_data);
ASSERT(p_data->p_buffer);
free( p_data->p_buffer );
free( p_data );
}
/*****************************************************************************
* DeletePES: deletes a PES packet and associated data packets
*****************************************************************************/
static void DeletePES( void * p_garbage, pes_packet_t * p_pes )
{
data_packet_t * p_data;
data_packet_t * p_next;
p_data = p_pes->p_first;
while( p_data != NULL )
{
p_next = p_data->p_next;
free( p_data->p_buffer );
free( p_data );
p_data = p_next;
}
free( p_pes );
}
/*****************************************************************************
* DVDKludge: fakes a DVD plugin (FIXME)
*****************************************************************************/
input_capabilities_t * DVDKludge( void )
{
input_capabilities_t * p_plugin;
p_plugin = (input_capabilities_t *)malloc( sizeof(input_capabilities_t) );
p_plugin->pf_probe = DVDProbe;
p_plugin->pf_init = DVDInit;
p_plugin->pf_end = DVDEnd;
p_plugin->pf_read = DVDRead;
p_plugin->pf_demux = input_DemuxPS; /* FIXME: use i_p_config_t ! */
p_plugin->pf_new_packet = NewPacket;
p_plugin->pf_new_pes = NewPES;
p_plugin->pf_delete_packet = DeletePacket;
p_plugin->pf_delete_pes = DeletePES;
p_plugin->pf_rewind = DVDRewind;
p_plugin->pf_seek = DVDSeek;
return( p_plugin );
}
/*****************************************************************************
* input_dvd.h: thread structure of the DVD plugin
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
*
* Author: 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.
*****************************************************************************/
/*****************************************************************************
* thread_dvd_data_t: extension of input_thread_t for DVD specificity
*****************************************************************************/
typedef struct thread_dvd_data_s
{
/* Structure that contains all information of the DVD */
struct ifo_s ifo;
} thread_dvd_data_t;
......@@ -202,6 +202,23 @@ void intf_Run( intf_thread_t *p_intf )
p_intf->p_input = input_CreateThread( p_input_config, NULL );
}
}
/* DVD mode */
else if( p_main->b_dvd )
{
if( (p_input_config =
(input_config_t *)malloc( sizeof(input_config_t) )) == NULL )
{
intf_ErrMsg( "intf error: cannot create input_config_t" );
}
else
{
p_input_config->i_method = INPUT_METHOD_DVD;
p_input_config->p_source = main_GetPszVariable( INPUT_DVD_DEVICE_VAR, INPUT_DVD_DEVICE_DEFAULT );
p_input_config->p_default_aout = p_main->p_aout;
p_input_config->p_default_vout = p_intf->p_vout;
p_intf->p_input = input_CreateThread( p_input_config, NULL );
}
}
/* Or if a file was specified */
else if( p_main->p_playlist->p_list != NULL )
{
......
......@@ -85,6 +85,7 @@
#define OPT_SERVER 171
#define OPT_PORT 172
#define OPT_BROADCAST 173
#define OPT_DVD 174
#define OPT_SYNCHRO 180
......@@ -132,6 +133,7 @@ static const struct option longopts[] =
{ "server", 1, 0, OPT_SERVER },
{ "port", 1, 0, OPT_PORT },
{ "broadcast", 0, 0, OPT_BROADCAST },
{ "dvd", 0, 0, OPT_DVD },
/* Synchro options */
{ "synchro", 1, 0, OPT_SYNCHRO },
......@@ -458,6 +460,7 @@ static void SetDefaultConfiguration( void )
p_main->b_audio = 1;
p_main->b_video = 1;
p_main->b_vlans = 0;
p_main->b_dvd = 0;
}
/*****************************************************************************
......@@ -589,6 +592,9 @@ static int GetConfiguration( int i_argc, char *ppsz_argv[], char *ppsz_env[] )
case OPT_BROADCAST: /* --broadcast */
main_PutIntVariable( INPUT_BROADCAST_VAR, 1 );
break;
case OPT_DVD: /* --dvd */
p_main->b_dvd = 1;
break;
/* Synchro options */
case OPT_SYNCHRO:
......@@ -658,6 +664,7 @@ static void Usage( int i_fashion )
"\n --server <host> \tvideo server address"
"\n --port <port> \tvideo server port"
"\n --broadcast \tlisten to a broadcast"
"\n --dvd \tread dvd"
"\n"
"\n --synchro <type> \tforce synchro algorithm"
"\n"
......@@ -705,7 +712,9 @@ static void Usage( int i_fashion )
"\n " INPUT_IFACE_VAR "=<interface> \tnetwork interface"
"\n " INPUT_BROADCAST_VAR "={1|0} \tbroadcast mode"
"\n " INPUT_VLAN_SERVER_VAR "=<hostname> \tvlan server"
"\n " INPUT_VLAN_PORT_VAR "=<port> \tvlan server port" );
"\n " INPUT_VLAN_PORT_VAR "=<port> \tvlan server port"
"\n " INPUT_DVD_DEVICE_VAR "=<device> \tDVD device"
);
/* Synchro parameters */
intf_Msg( "\nSynchro parameters:"
......
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