/*==============================================================================

FICHIER     : [dvdcopy.c]

DATE        : 2005/12/0001 22:04:33

CREATEUR    : [Linux!jef]

COMMENTAIRE :
		Released under GPL license, see gnu.org
 * encoding     UTF8 !-UTF8-!
================================================================================
	COPY sans garder les menus
==============================================================================*/
#define __USE_LARGEFILE64
#define _LARGEFILE64_SOURCE
#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/stat.h>

#include <gnome.h>

#define CTEST(x)		/***/

#include "support.h"

#include "dvdformat.h"
#include "dvdinfo.h"
#include "dvdtools.h"
#include "message.h"
#include "gconfig.h"
#include "interface.h"
#include "globals.h"
#include "systools.h"
#include "uitools.h"
#include "avancement.h"
#include "dvdcopy.h"
#include "const.h"
#include "profile.h"

#define IsValidAudioTrack( pgc, t )		(( pgc->audio_control[t] >> 8) != 0 )
#define IsValidSubpTrack( pgc, t )		(( pgc->subp_control[t] >> 24) != 0 )

#define BCD2INT( v )		(((v & 0xf0) >> 3) * 5 + (v & 0x0f))

// static char *_AudioFormat[7] = { "AC3", "?", "MPEG1", "MPEG2", "LPCM ", "SDDS ", "DTS" };
// static char *_AudioType[5] = { "", "Normal", "Impaired", "Director's comments", "Alternate director's comments" };
/*
static char *SubpType[16] = {
	"", "Normal", "Large", "Children", "reserved", "Normal_CC",
	"Large_CC", "Children_CC",
	"reserved", "Forced", "reserved", "reserved", "reserved", "Director",
	"Large_Director", "Children_Director"
};
*/

static char * AspectRatio[4] = {"4:3", "16:9", "\"?:?\"", "16:9"};

static char TitreDvd[128];

/*@$#[dvdcopy.c] static proto. AutoProtoSigV1.1. date: 2009/06/04 21:09:17 */
#include "proto.h"
#ifdef __cplusplus
extern "C" {
#endif
static char *_AudioFormat(int format);
static char *_AudioType(int type);
static char *_SubType(int type);
static int NrOfSubp(vtsi_mat_t *vtsi_mat, pgc_t *pgc);
static gint VideoSortString(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer userdata);
static gint VideoSortStringNBR(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer userdata);
static int SubpId(unsigned int control);
static int AudioId(unsigned int control);
static void AudioCheckToggled(GtkCellRendererToggle *cell, gchar *path_str, gpointer data);
static void SubCheckToggled(GtkCellRendererToggle *cell, gchar *path_str, gpointer data);
static gint AudioSortString(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer userdata);
static gint AudioSortStringNBR(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer userdata);
static gint SubSortString(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer userdata);
static gint SubSortStringNBR(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer userdata);
static unsigned long GetSector(int chapitre, pgc_t *pgc);
static unsigned short SubCode(int noPisteVideo, int noSubtitle);
static double DefaultRequantFactor(int noPisteVideo, AudioMap_t *audioMap, SubMap_t *subMap, int useMenuF);
#ifdef __cplusplus
}
#endif
/*@$% end of AutoProtoSigV1.1 (Dont remove this line) []*/

/***************************************************************************//**
 *	_AUDIOFORMAT-
 * @date	2009/06/04 20:45:14
 * @author	jef-Linux
 * @brief
 *	Pas d'explication
 * @details
 *	Pas de details
 * @param[in]	Pas de detail
 * @param[out]	Pas de detail
*******************************************************************************/
static char * _AudioFormat( int format )
{
	switch( format ) {
		case 0 :	return( _("AC3") );
		case 1 : 	return( _("?") );
		case 2 :	return( _("MPEG1") );
		case 3 :	return( _("MPEG2") );
		case 4 :	return( _("LPCM") );
		case 5 :	return( _("SDDS") );
		case 6 :	return( _("DTS") );
	}
	return( _("?") );
}

/***************************************************************************//**
 *	_AUDIOTYPE-
 * @date	2009/06/04 20:48:42
 * @author	jef-Linux
 * @brief
 *	Pas d'explication
 * @details
 *	Pas de details
 * @param[in]	Pas de detail
 * @param[out]	Pas de detail
*******************************************************************************/
static char * _AudioType( int type )
{
	switch( type ) {
		case 0 :	return( "" );
		case 1 :	return( _("Normal") );
		case 2 :	return( _("Impaired") );
		case 3 :	return( _("Director's comments") );
		case 4 :	return( _("Alternate director's comments" ) );
	}
	return( "" );
}

/***************************************************************************//**
 *	_SUBTYPE-
 * @date	2009/06/04 20:55:44
 * @author	jef-Linux
 * @brief
 *	Pas d'explication
 * @details
 *	Pas de details
 * @param[in]	Pas de detail
 * @param[out]	Pas de detail
*******************************************************************************/
static char * _SubType( int type )
{
	switch( type ) {
		case 0 : return( "" );
		case 1 : return( _("Normal") );
		case 2 : return( _("Large") );
		case 3 : return( _("Enfants") );
		case 4 : return( _("Reserved") );
		case 5 : return( _("Légende normale") );
		case 6 : return( _("Légende large") );
		case 7 : return( _("Légende enfants") );
		case 8 : return( _("reserved") );
		case 9 : return( _("Forcé") );
		case 10 : return( _("reserved") );
		case 11 : return( _("reserved") );
		case 12 : return( _("reserved") );
		case 13 : return( _("Réalisateur") );
		case 14 : return( _("Réalisateur large") );
		case 15 : return( _("Réalisateur enfants") );
	}
	return( "" );
}
/*------------------------------------------------------------------------------
	NROFSUBP-
Linux!jef 2006/01/25 21:43:53
------------------------------------------------------------------------------*/

static int NrOfSubp( vtsi_mat_t * vtsi_mat, pgc_t * pgc )
{
	int i;
	int count = 0;

	for( i = 0; i < vtsi_mat->nr_of_vts_subp_streams; i++ ) {
		if( IsValidSubpTrack( pgc, i ) )	count++;
	}
	return( count );
}

/*------------------------------------------------------------------------------
	SORTSTRING-
Linux!jef 2007/01/30 21:46:59
------------------------------------------------------------------------------*/

static gint VideoSortString( GtkTreeModel *model, GtkTreeIter  *a, GtkTreeIter *b, gpointer userdata)
{
	gint sortcol = GPOINTER_TO_INT(userdata);
	gint ret = 0;
	gchar *name1, *name2;

	switch (sortcol) {
		case VIDEO_COL5_LANG:
		case VIDEO_COL7_VIDEO:
			gtk_tree_model_get(model, a, sortcol, &name1, -1);
			gtk_tree_model_get(model, b, sortcol, &name2, -1);
			if( name1 == NULL || name2 == NULL ) {
				if( name1 == NULL && name2 == NULL )	break;
				ret = (name1 == NULL) ? -1 : 1;
			}
			else
				ret = g_utf8_collate( name1, name2 );
			g_free( name1 );
			g_free( name2 );
			break;
	}
	return( ret );
}

/*------------------------------------------------------------------------------
	SORTSTRINGNBR-
Linux!jef 2007/01/30 21:46:59
------------------------------------------------------------------------------*/

static gint VideoSortStringNBR( GtkTreeModel *model, GtkTreeIter  *a, GtkTreeIter *b, gpointer userdata)
{
	gint sortcol = GPOINTER_TO_INT(userdata);
	gint ret = 0;
	gchar *name1, *name2;

	switch (sortcol) {
		case VIDEO_COL2_PISTE :
		case VIDEO_COL4_CHAPITRE:
		case VIDEO_COL6_SUB:
			gtk_tree_model_get(model, a, sortcol, &name1, -1);
			gtk_tree_model_get(model, b, sortcol, &name2, -1);
			if( name1 == NULL || name2 == NULL ) {
				if( name1 == NULL && name2 == NULL )	break;
				ret = (name1 == NULL) ? -1 : 1;
			}
			else {
				ret = atoi( name1 ) - atoi( name2 );
				if( ret < 0 )	ret = -1;
				if( ret > 0 )	ret = 1;
			}
			g_free( name1 );
			g_free( name2 );
			break;
		case VIDEO_COL3_DUREE :
			gtk_tree_model_get(model, a, sortcol, &name1, -1);
			gtk_tree_model_get(model, b, sortcol, &name2, -1);
			if( name1 == NULL || name2 == NULL ) {
				if( name1 == NULL && name2 == NULL )	break;
				ret = (name1 == NULL) ? -1 : 1;
			}
			else {
				int d1 = StringDuree2Sec( name1 );
				int d2 = StringDuree2Sec( name2 );
				if( d1 > d2 )	ret = 1;
				if( d1 < d2 )	ret = -1;
// fprintf(stderr,"(%s/%d)(%s/%d)=%d\n", name1,d1, name2,d2, ret );
			}
			g_free( name1 );
			g_free( name2 );
			break;
	}
	return( ret );
}

/*------------------------------------------------------------------------------
	SCANDVD-
Linux!jef 2005/12/02 21:55:34
------------------------------------------------------------------------------*/

int ScanDvd( GtkWidget * forme )
{
	GtkWidget * item;
	int i,j;
	pgcit_t *vts_pgcit;   vtsi_mat_t *vtsi_mat;
	vmgi_mat_t *vmgi_mat;
	video_attr_t *video_attr;
	int title_set_nr;
	int vts_ttn;
	pgc_t *pgc;
	char string[1024];
	GtkTreeStore *treestore;
	GtkTreeIter   iter;
	GtkTreeViewColumn   *col;
	GtkCellRenderer     *renderer;
	unsigned long maxSec = 0;
	GtkTreeIter longest;
	int noPiste = 0;

	/* Close old data before starting new */
	DvdClose();

	OpenAnalyse();

	if(DvdOpen( Device ) < 0 ) {
		CloseAnalyse();
		MessageBoxError( _("Lecture de la structure impossible !") );
		return( -1 );
	}

	if( GetDVDTitleUsingLibDVD( TitreDvd ) < 0 ) {
		CloseAnalyse();
		MessageBoxError( _("Lecture du titre de %s impossible!"), Device );
		return( -1 );
	}

	CloseAnalyse();

	item = lookup_widget(GTK_WIDGET(forme), "titre" );
	g_assert( item );
	gtk_entry_set_text( GTK_ENTRY(item), TitreDvd );
	gtk_widget_show( item );


	item = lookup_widget(GTK_WIDGET(forme), "PistesVideo" );
	g_assert( item );

/* Permits theme decoration */
	gtk_tree_view_set_rules_hint( GTK_TREE_VIEW(item), TRUE );

/* Erase old columns */
	for( i = VIDEO_NCOLS-1; i >=0; i-- ) {
		col = gtk_tree_view_get_column( GTK_TREE_VIEW(item), i );
		if( col )	gtk_tree_view_remove_column(GTK_TREE_VIEW(item), col);
	}

	treestore = gtk_tree_store_new(	VIDEO_NCOLS,
					G_TYPE_STRING,
					G_TYPE_STRING,
					G_TYPE_STRING,
					G_TYPE_STRING,
					G_TYPE_STRING,
					G_TYPE_STRING,
					G_TYPE_INT );
	g_assert( treestore );

/* La piste */
	renderer = gtk_cell_renderer_text_new();

	col = gtk_tree_view_column_new_with_attributes(
			_("Piste"),
			renderer,
			"text",
			VIDEO_COL2_PISTE,
			NULL);
	gtk_tree_view_append_column(GTK_TREE_VIEW(item), col);
	gtk_tree_view_column_set_sort_column_id( col, VIDEO_COL2_PISTE );

/* La duree */
	renderer = gtk_cell_renderer_text_new();

	col = gtk_tree_view_column_new_with_attributes(
			_("Dur\303\251e"),
			renderer,
			"text",
			VIDEO_COL3_DUREE,
			NULL);
	gtk_tree_view_append_column(GTK_TREE_VIEW(item), col);
	gtk_tree_view_column_set_sort_column_id( col, VIDEO_COL3_DUREE );

/* Les chapitres */
	renderer = gtk_cell_renderer_text_new();

	col = gtk_tree_view_column_new_with_attributes(
			_("Chapitres"),
			renderer,
			"text",
			VIDEO_COL4_CHAPITRE,
			NULL);
	gtk_tree_view_append_column(GTK_TREE_VIEW(item), col);
	gtk_tree_view_column_set_sort_column_id( col, VIDEO_COL4_CHAPITRE );

/* Les langues */
	renderer = gtk_cell_renderer_text_new();

	col = gtk_tree_view_column_new_with_attributes(
			_("Langues"),
			renderer,
			"text",
			VIDEO_COL5_LANG,
			NULL);
	gtk_tree_view_append_column(GTK_TREE_VIEW(item), col);
	gtk_tree_view_column_set_sort_column_id( col, VIDEO_COL5_LANG );

/* Les subs */
	renderer = gtk_cell_renderer_text_new();

	col = gtk_tree_view_column_new_with_attributes(
			_("Sous-titres"),
			renderer,
			"text",
			VIDEO_COL6_SUB,
			NULL);
	gtk_tree_view_append_column(GTK_TREE_VIEW(item), col);
	gtk_tree_view_column_set_sort_column_id( col, VIDEO_COL6_SUB );

/* Les format video */
	renderer = gtk_cell_renderer_text_new();

	col = gtk_tree_view_column_new_with_attributes(
			_("Format"),
			renderer,
			"text",
			VIDEO_COL7_VIDEO,
			NULL);
	gtk_tree_view_append_column(GTK_TREE_VIEW(item), col);
	gtk_tree_view_column_set_sort_column_id( col, VIDEO_COL7_VIDEO );

	vmgi_mat = Ifo_zero->vmgi_mat;
	RazPistes();

	DBG('c',fprintf(stderr,"#title_sets: %d NrTitles: %d ifo_zero->tt_srpt->nr_of_srpts: %d\n", vmgi_mat->vmg_nr_of_title_sets, NrTitles, Ifo_zero->tt_srpt->nr_of_srpts););
	for( j = 0; j < Ifo_zero->tt_srpt->nr_of_srpts; j++ ) {
		ifo_handle_t * ifo = Ifo[Ifo_zero->tt_srpt->title[j].title_set_nr];
		Piste_t * piste = GetPiste(j);

		DBG('c',fprintf(stderr,"title%d ifo: %p ifo#: %d\n", j, ifo, Ifo_zero->tt_srpt->title[j].title_set_nr ););
		if( !ifo )	continue;

		vtsi_mat = ifo->vtsi_mat;
		vts_pgcit = ifo->vts_pgcit;

/* HUM HUM */
//		piste->vts = j+1;
		piste->vts = Ifo_zero->tt_srpt->title[j].title_set_nr;

		piste->ifo = ifo;
		piste->vtsi_mat = vtsi_mat;
		piste->vts_pgcit = vts_pgcit;

		if( vtsi_mat && vts_pgcit ) {
			int k;
			char langues[100];
			audio_attr_t *audio_attr;
			unsigned long sec;
			int h,m,s;
			vts_ptt_srpt_t * vts_ptt_srpt;

			video_attr = &vtsi_mat->vts_video_attr;
			vts_ttn = Ifo_zero->tt_srpt->title[j].vts_ttn;
			title_set_nr = Ifo_zero->tt_srpt->title[j].title_set_nr;
			vts_ptt_srpt = ifo->vts_ptt_srpt;
			DBG('c',fprintf(stderr,"vts_ttn: %d nr_of_srpts: %d\n", vts_ttn, vts_ptt_srpt->nr_of_srpts););
			pgc = vts_pgcit->pgci_srp[Ifo[title_set_nr]->vts_ptt_srpt->title[vts_ttn - 1].ptt[0].pgcn - 1].pgc;

			DBG('c',fprintf(stderr,"Piste: %d nr_of_pgci_srp: %d ifo: %p Pgc: %p Audio#: %d\n", j + 1, vts_pgcit->nr_of_pgci_srp, ifo, pgc, vtsi_mat->nr_of_vts_audio_streams););
			*langues = 0;
			{
				DBG('c',fprintf(stderr,"#cells: %d\n", pgc->nr_of_cells ););
				for( k = 0; k < vtsi_mat->nr_of_vts_audio_streams;k++ ) {
					char lang_code[3];

					if( IsValidAudioTrack( pgc, k ) ) {
						audio_attr = &vtsi_mat->vts_audio_attr[k];
						if( audio_attr->lang_code != 0xFFFF ) {
							DBG('c',fprintf(stderr,"Audio code 0x%x\n", audio_attr->lang_code ););
							sprintf( lang_code, "%c%c", audio_attr->lang_code >> 8,audio_attr->lang_code & 0xff);
							if( !strstr( langues, lang_code ) ) {
								if( *langues )	strcat( langues, "," );
								strcat( langues, lang_code );
							}
						}
					}
					else {
						DBG('c',fprintf(stderr,"Unavailable audio track %d\n", k ););
					}
				}
				sec = BCD2INT( pgc->playback_time.hour ) * 3600;
				sec += BCD2INT( pgc->playback_time.minute ) * 60;
				sec += BCD2INT( pgc->playback_time.second );
				DBG('c',fprintf(stderr,"sec=%s\n", Duree2String( sec ) ););
				piste->pgcs[piste->nrPgc++] = pgc;
				piste->duree += sec;
				piste->sectors += GetSector( -1, pgc );
				piste->nrSubp = NrOfSubp( vtsi_mat, piste->pgcs[0] );
/* Verify track duration and filter if == 0 */
				if( piste->duree == 0 )	continue;
			}
/* Check if pgc seems valid */
			if( CheckPgc( pgc ) < 0 ) {
				DBG( 'c', fprintf( stderr, "Check pgc failed !\n" ););
				DBG( 'c', DumpPgc( pgc ) );
				continue;
			}
/*
			else {
				DBG( 'c', fprintf( stderr, "Good pgc!\n" ););
				DBG( 'c', DumpPgc( pgc ) );
			}
*/
			sec = piste->duree;
			h = sec / 3600;
			sec -= h * 3600;
			m = sec / 60;
			sec -= m * 60;
			s = sec;

			gtk_tree_store_append(treestore, &iter, NULL );

			sprintf( string, _("%d"), j + 1 );
			gtk_tree_store_set( treestore, &iter, VIDEO_COL2_PISTE, string, -1 );

//			sprintf( string, _("%02d h %02d m %02d s"),h,m,s );
			HMS2String( h, m, s, string );
			gtk_tree_store_set( treestore, &iter, VIDEO_COL3_DUREE, string, -1 );

			sprintf( string, _("%d"), Ifo_zero->tt_srpt->title[j].nr_of_ptts );
			gtk_tree_store_set( treestore, &iter, VIDEO_COL4_CHAPITRE, string, -1 );

			sprintf( string, _("%s"), langues );
			gtk_tree_store_set( treestore, &iter, VIDEO_COL5_LANG, string, -1 );

			sprintf( string, _("%d"), piste->nrSubp );
			gtk_tree_store_set( treestore, &iter, VIDEO_COL6_SUB, string, -1 );

			sprintf( string, _("%s"), AspectRatio[video_attr->display_aspect_ratio]);
			gtk_tree_store_set( treestore, &iter, VIDEO_COL7_VIDEO, string, -1 );

			gtk_tree_store_set( treestore, &iter, VIDEO_COL8_NO, j, -1 );

			if( piste->sectors > maxSec ) {
				maxSec = piste->sectors;
				longest = iter;
				noPiste = j;
			}
		}
		else {
			DBG('c',fprintf(stderr,"Piste%d: no vtsi_mat\n", j+1););
		}
	}
	DBG('c',fprintf(stderr,"Scan end.\n"););

	gtk_tree_view_set_model(GTK_TREE_VIEW(item), GTK_TREE_MODEL(treestore));

	gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(item)), GTK_SELECTION_SINGLE );

/* Permits sorting */
	 gtk_tree_sortable_set_sort_func(	GTK_TREE_SORTABLE( GTK_TREE_MODEL( treestore ) ),
						VIDEO_COL2_PISTE,
						VideoSortStringNBR,
						(gpointer)VIDEO_COL2_PISTE,
						NULL);
	 gtk_tree_sortable_set_sort_func(	GTK_TREE_SORTABLE( GTK_TREE_MODEL( treestore ) ),
						VIDEO_COL3_DUREE,
						VideoSortStringNBR,
						(gpointer)VIDEO_COL3_DUREE,
						NULL);
	 gtk_tree_sortable_set_sort_func(	GTK_TREE_SORTABLE( GTK_TREE_MODEL( treestore ) ),
						VIDEO_COL4_CHAPITRE,
						VideoSortStringNBR,
						(gpointer)VIDEO_COL4_CHAPITRE,
						NULL);
	 gtk_tree_sortable_set_sort_func(	GTK_TREE_SORTABLE( GTK_TREE_MODEL( treestore ) ),
						VIDEO_COL5_LANG,
						VideoSortString,
						(gpointer)VIDEO_COL5_LANG,
						NULL);
	 gtk_tree_sortable_set_sort_func(	GTK_TREE_SORTABLE( GTK_TREE_MODEL( treestore ) ),
						VIDEO_COL6_SUB,
						VideoSortStringNBR,
						(gpointer)VIDEO_COL6_SUB,
						NULL);
	 gtk_tree_sortable_set_sort_func(	GTK_TREE_SORTABLE( GTK_TREE_MODEL( treestore ) ),
						VIDEO_COL7_VIDEO,
						VideoSortString,
						(gpointer)VIDEO_COL7_VIDEO,
						NULL);
/* Pre-select longest track */
	if( maxSec) {
		GtkTreeSelection *selection;

		selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(item));
		gtk_tree_selection_select_iter( selection, &longest );
		ScanPiste( forme, noPiste );
	}

	gtk_widget_show_all( item );
	g_object_unref(treestore);

	return( 0 );
}
/*------------------------------------------------------------------------------
	UPDDEFFACTOR-
Linux!jef 2005/12/17 01:03:12
------------------------------------------------------------------------------*/

void UpdDefFactor( GtkWidget * forme, int noPisteVideo, AudioMap_t * audioMap, SubMap_t * subMap )
{
	GtkWidget * item;
	double dFactor;
	double pct;
	int useMenuF = ConfigGetInt( KEY_USEMENU, 0 );

	dFactor =  DefaultRequantFactor( noPisteVideo, audioMap, subMap, useMenuF );
	item = lookup_widget(GTK_WIDGET(forme), "Qualite" );
	g_assert( item );
	pct = (1.0 / dFactor ) * 100.0;
// fprintf(stderr,"dFactor=%f qualite=%f\n", dFactor, pct );
	gtk_range_set_value( GTK_RANGE( item ), pct );
	gtk_widget_show_now( item );
	GtkFlush();
}

/*------------------------------------------------------------------------------
	GETMENUSIZE-
Linux!jef 2005/12/27 21:17:23
------------------------------------------------------------------------------*/

long long GetMenuSize()
{
	int menuSizes[MAX_VTS];
	int ts;
	int i;
	vmgi_mat_t * vmgi_mat;
	vtsi_mat_t * vtsi_mat;
	pgcit_t * vts_pgcit;
	pgc_t * pgc;
	long long menuSize;

	vmgi_mat = Ifo_zero->vmgi_mat;
	memset( menuSizes, 0, sizeof(menuSizes));

	menuSizes[0] = vmgi_mat->vmg_last_sector;

	for( ts = 1; ts <= Ifo_zero->vts_atrt->nr_of_vtss; ts++ ) {
		if( !Ifo[ts] )	continue;

		vtsi_mat   = Ifo[ts]->vtsi_mat;
		vts_pgcit  = Ifo[ts]->vts_pgcit;
// fprintf(stderr,"%p %p nr: %d\n", vtsi_mat, vts_pgcit,vts_pgcit->nr_of_pgci_srp );
	        for( i = 0; i < vts_pgcit->nr_of_pgci_srp; i++) {
			pgc = vts_pgcit->pgci_srp[i].pgc;
// fprintf(stderr,"pgc%d: %p\n", i, pgc );
			if( vtsi_mat && (pgc->nr_of_cells >0)) {
				menuSizes[ts] = vtsi_mat->vtstt_vobs + vtsi_mat->vtsi_last_sector +1;
			}
	        }
	}
// fprintf(stderr,"here\n");
	menuSize = 0;
	for( i = 0; i < MAX_VTS; i++ )	menuSize += (long long)menuSizes[i];
	return( menuSize * SECTOR_SIZE );
}
/*------------------------------------------------------------------------------
	SUBPID-
Linux!jef 2006/02/02 22:33:20
------------------------------------------------------------------------------*/

static int SubpId( unsigned int control )
{
	unsigned char subpc;
	int id = 0;

	if( control & 0x80000000 ) {
/* Take wide sub if present */
		subpc = ( control >>16 ) & 0x1F;
		if( subpc )	return( (int)subpc );
/* Take 4/3 sub if present */
		subpc = ( control >> 24 ) & 0x1F;
		if( subpc )	return( (int)subpc );
/* Take letterbox sub if present */
		subpc = ( control >> 8 ) & 0x1F;
		if( subpc )	return( (int)subpc );
/* Take pan&scan sub if present */
		subpc = control & 0x1F;
		if( subpc )	return( (int)subpc );
	}
#if 0
	subpc = control>>24;
	if ((subpc & 0x80)==0x80) {
		id = 0;

		if( (subpc &0x1F) !=0 )	id = (subpc & 0x1F);
		subpc = control>>16;
		if( (subpc &0x1F) !=0 ) id = (subpc & 0x1F);
		subpc = control>>8;
		if( (subpc &0x1F) !=0 ) id = (subpc & 0x1F);
		subpc = control;
		if( (subpc &0x1F) !=0 ) id = (subpc & 0x1F);
	}
#endif
	return( id );
}
/*------------------------------------------------------------------------------
	GETSUBID-
Linux!jef 2006/02/02 22:41:39
------------------------------------------------------------------------------*/

int GetSubId( int noPisteVideo, int noPisteSub )
{
//	ifo_handle_t * ifo = Ifo[Ifo_zero->tt_srpt->title[noPisteVideo].title_set_nr];
	Piste_t * piste = GetPiste(noPisteVideo);
//	ifo_handle_t * ifo = piste->ifo;
	pgcit_t *vts_pgcit;
	int title_set_nr;
	int vts_ttn;
	pgc_t *pgc;

//	vts_pgcit = ifo->vts_pgcit;
	vts_pgcit = piste->vts_pgcit;
	vts_ttn = Ifo_zero->tt_srpt->title[noPisteVideo].vts_ttn;
	title_set_nr = Ifo_zero->tt_srpt->title[noPisteVideo].title_set_nr;
//	pgc = vts_pgcit->pgci_srp[Ifo[title_set_nr]->vts_ptt_srpt->title[vts_ttn - 1].ptt[0].pgcn - 1].pgc;
	pgc = piste->pgcs[0];

	return( SubpId( pgc->subp_control[noPisteSub] ) );
}


/*------------------------------------------------------------------------------
	AUDIOPID-
Linux!jef 2006/02/02 22:33:20
------------------------------------------------------------------------------*/

static int AudioId( unsigned int control )
{
	return( (control >> 8) & 0x07 );
}

/*------------------------------------------------------------------------------
	GETSUBID-
Linux!jef 2006/02/02 22:41:39
------------------------------------------------------------------------------*/

int GetAudioId( int noPisteVideo, int noPisteAudio )
{
	Piste_t * piste = GetPiste( noPisteVideo );
	pgcit_t *vts_pgcit;
	int title_set_nr;
	int vts_ttn;
	pgc_t *pgc;

//	vts_pgcit = Ifo[Ifo_zero->tt_srpt->title[noPisteVideo].title_set_nr]->vts_pgcit;
	vts_pgcit = piste->vts_pgcit;
	vts_ttn = Ifo_zero->tt_srpt->title[noPisteVideo].vts_ttn;
	title_set_nr = Ifo_zero->tt_srpt->title[noPisteVideo].title_set_nr;
//	pgc = vts_pgcit->pgci_srp[Ifo[title_set_nr]->vts_ptt_srpt->title[vts_ttn - 1].ptt[0].pgcn - 1].pgc;
	pgc = piste->pgcs[0];

	return( AudioId( pgc->audio_control[noPisteAudio ] ) );

}
/*------------------------------------------------------------------------------
	AUDIOCHECKTOGGLED-
Linux!jef 2007/01/17 21:59:17
------------------------------------------------------------------------------*/

static void AudioCheckToggled( GtkCellRendererToggle *cell, gchar * path_str, gpointer data)
{
	GtkTreeModel *model = (GtkTreeModel *)data;
	GtkTreePath *path = gtk_tree_path_new_from_string (path_str);
	GtkTreeIter iter;
	gboolean toggle_item;
	gchar * langCode;
	gchar * audioPref = ConfigGetString( KEY_AUDIO, "" );
	gchar * audioFormat;
	gchar * audioChannels;
	char audioTag[50];

// fprintf(stderr,"BLIP %p (%s)!\n", model, path_str );
/* get toggled iter */
	gtk_tree_model_get_iter( model, &iter, path);
	gtk_tree_model_get( model, &iter, AUDIO_COL1_CHECK, &toggle_item, -1);
	gtk_tree_model_get( model, &iter, AUDIO_COL7_LANGCODE, &langCode, -1);
	gtk_tree_model_get( model, &iter, AUDIO_COL4_FORMAT, &audioFormat, -1);
	gtk_tree_model_get( model, &iter, AUDIO_COL6_CANAUX, &audioChannels, -1);

/* Build audio tag to correctly select audio track */
	sprintf( audioTag, "%s.%s.%s",
				langCode,
				audioFormat,
				audioChannels );

/* do something with the value */
	toggle_item ^= 1;
	DBG('p',fprintf(stderr,"AudioPref=(%s) AudioTag(%s)\n", audioPref, audioTag ););
	if( toggle_item ) {
		DBG('p',fprintf(stderr,"AudioTag (%s) selected\n", audioTag ););
		audioPref = AddString2List( audioPref, audioTag );
	}
	else {
		DBG('p',fprintf(stderr,"AudioTag (%s) unselected\n", audioTag ););
		audioPref = RemoveStringFromList( audioPref, audioTag );
	}
	DBG('p',fprintf(stderr,"AudioPref=(%s)\n", audioPref ););
	SetConfigString( KEY_AUDIO, audioPref );
	free( audioPref );
/* set new value */
	gtk_tree_store_set(GTK_TREE_STORE (model), &iter, AUDIO_COL1_CHECK, toggle_item, -1);
/* clean up */
	gtk_tree_path_free( path );
	g_free( langCode );
}

/*------------------------------------------------------------------------------
	SUBCHECKTOGGLED-
Linux!jef 2007/01/17 21:59:17
------------------------------------------------------------------------------*/

static void SubCheckToggled( GtkCellRendererToggle *cell, gchar * path_str, gpointer data)
{
	GtkTreeModel *model = (GtkTreeModel *)data;
	GtkTreePath *path = gtk_tree_path_new_from_string (path_str);
	GtkTreeIter iter;
	gboolean toggle_item;
	gchar * langCode;
	gchar * subPref = ConfigGetString( KEY_SUBTITLE, "" );

// fprintf(stderr,"BLIP %p (%s)!\n", model, path_str );
/* get toggled iter */
	gtk_tree_model_get_iter( model, &iter, path);
	gtk_tree_model_get( model, &iter, SUB_COL1_CHECK, &toggle_item, -1);
	gtk_tree_model_get( model, &iter, SUB_COL5_LANGCODE, &langCode, -1);
/* do something with the value */
	toggle_item ^= 1;
	CTEST(fprintf(stderr,"SubPref=(%s)\n", subPref ););
	if( toggle_item ) {
		CTEST(fprintf(stderr,"LangCode (%s) selected\n", langCode ););
		subPref = AddString2List( subPref, langCode );
	}
	else {
		CTEST(fprintf(stderr,"LangCode (%s) unselected\n", langCode ););
		subPref = RemoveStringFromList( subPref, langCode );
	}
	CTEST(fprintf(stderr,"SubPref=(%s)\n", subPref ););
	SetConfigString( KEY_SUBTITLE, subPref );
	free( subPref );
/* set new value */
	gtk_tree_store_set (GTK_TREE_STORE (model), &iter, SUB_COL1_CHECK, toggle_item, -1);
/* clean up */
	gtk_tree_path_free (path);
	g_free( langCode );
}

/*------------------------------------------------------------------------------
	SORTSTRING-
Linux!jef 2007/01/30 21:46:59
------------------------------------------------------------------------------*/

static gint AudioSortString( GtkTreeModel *model, GtkTreeIter  *a, GtkTreeIter *b, gpointer userdata)
{
	gint sortcol = GPOINTER_TO_INT(userdata);
	gint ret = 0;
	gchar *name1, *name2;

	switch (sortcol) {
		case AUDIO_COL3_LANG:
		case AUDIO_COL4_FORMAT :
			gtk_tree_model_get(model, a, sortcol, &name1, -1);
			gtk_tree_model_get(model, b, sortcol, &name2, -1);
			if( name1 == NULL || name2 == NULL ) {
				if( name1 == NULL && name2 == NULL )	break;
				ret = (name1 == NULL) ? -1 : 1;
			}
			else
				ret = g_utf8_collate( name1, name2 );
			g_free( name1 );
			g_free( name2 );
			break;
	}
	return( ret );
}

/*------------------------------------------------------------------------------
	SORTSTRINGNBR-
Linux!jef 2007/01/30 21:46:59
------------------------------------------------------------------------------*/

static gint AudioSortStringNBR( GtkTreeModel *model, GtkTreeIter  *a, GtkTreeIter *b, gpointer userdata)
{
	gint sortcol = GPOINTER_TO_INT(userdata);
	gint ret = 0;
	gchar *name1, *name2;

	switch (sortcol) {
		case AUDIO_COL2_PISTE:
		case AUDIO_COL6_CANAUX:
			gtk_tree_model_get(model, a, sortcol, &name1, -1);
			gtk_tree_model_get(model, b, sortcol, &name2, -1);
			if( name1 == NULL || name2 == NULL ) {
				if( name1 == NULL && name2 == NULL )	break;
				ret = (name1 == NULL) ? -1 : 1;
			}
			else {
				ret = atoi( name1 ) - atoi( name2 );
				if( ret < 0 )	ret = -1;
				if( ret > 0 )	ret = 1;
			}
			g_free( name1 );
			g_free( name2 );
			break;
	}
	return( ret );
}

/*------------------------------------------------------------------------------
	SORTSTRING-
Linux!jef 2007/01/30 21:46:59
------------------------------------------------------------------------------*/

static gint SubSortString( GtkTreeModel *model, GtkTreeIter  *a, GtkTreeIter *b, gpointer userdata)
{
	gint sortcol = GPOINTER_TO_INT(userdata);
	gint ret = 0;
	gchar *name1, *name2;

	switch (sortcol) {
		case SUB_COL3_LANG:
		case SUB_COL4_EXT :
			gtk_tree_model_get(model, a, sortcol, &name1, -1);
			gtk_tree_model_get(model, b, sortcol, &name2, -1);
			if( name1 == NULL || name2 == NULL ) {
				if( name1 == NULL && name2 == NULL )	break;
				ret = (name1 == NULL) ? -1 : 1;
			}
			else
				ret = g_utf8_collate( name1, name2 );
			g_free( name1 );
			g_free( name2 );
			break;
	}
	return( ret );
}

/*------------------------------------------------------------------------------
	SORTSTRINGNBR-
Linux!jef 2007/01/30 21:46:59
------------------------------------------------------------------------------*/

static gint SubSortStringNBR( GtkTreeModel *model, GtkTreeIter  *a, GtkTreeIter *b, gpointer userdata)
{
	gint sortcol = GPOINTER_TO_INT(userdata);
	gint ret = 0;
	gchar *name1, *name2;

	switch (sortcol) {
		case SUB_COL2_PISTE:
			gtk_tree_model_get(model, a, sortcol, &name1, -1);
			gtk_tree_model_get(model, b, sortcol, &name2, -1);
			if( name1 == NULL || name2 == NULL ) {
				if( name1 == NULL && name2 == NULL )	break;
				ret = (name1 == NULL) ? -1 : 1;
			}
			else {
				ret = atoi( name1 ) - atoi( name2 );
				if( ret < 0 )	ret = -1;
				if( ret > 0 )	ret = 1;
			}
			g_free( name1 );
			g_free( name2 );
			break;
	}
	return( ret );
}

/*------------------------------------------------------------------------------
	SCANPISTE-
Linux!jef 2005/12/05 20:43:40
------------------------------------------------------------------------------*/

int ScanPiste( GtkWidget * forme, int noPisteVideo )
{
	GtkWidget * item;
	int i,k;
	pgcit_t *vts_pgcit;
	vtsi_mat_t *vtsi_mat;
	vmgi_mat_t *vmgi_mat;
	audio_attr_t *audio_attr;
	video_attr_t *video_attr;
	subp_attr_t *subp_attr;
	int title_set_nr;
	int vts_ttn;
	pgc_t *pgc;
	char langues[100];
	char string[1024];
	gchar * audioPref;
	GtkTreeStore *treestore;
	GtkTreeIter   iter;
	GtkTreeViewColumn   *col;
	GtkTreeViewColumn   *colCheck;
	GtkCellRenderer     *renderer;
	GtkCellRenderer     *renderCheck = NULL;
	GtkTreeModel * model;
	gchar * subPref;
	int subFound = 0;
	AudioMap_t audioMap;
	SubMap_t subMap;
	Piste_t * piste = GetPiste( noPisteVideo );
	Profile_t * p = GetProfile( GetFormat() );

	g_assert( p );
// fprintf(stderr,"%s-%d\n",__FILE__,__LINE__);
	memset( &audioMap, 0, sizeof(audioMap));
	memset( &subMap, 0, sizeof(subMap));

	audioPref = ConfigGetString( KEY_AUDIO, "fr" );
	subPref = ConfigGetString( KEY_SUBTITLE, "fr" );
/* Pistes Audio */
	item = lookup_widget(GTK_WIDGET(forme), "PistesAudio" );
	g_assert( item );

/* Permits theme decoration */
	gtk_tree_view_set_rules_hint( GTK_TREE_VIEW(item), TRUE );

/* Erase old columns */
	for( i = AUDIO_NCOLS-1; i >=0; i-- ) {
		col = gtk_tree_view_get_column( GTK_TREE_VIEW(item), i );
		if( col )	gtk_tree_view_remove_column(GTK_TREE_VIEW(item), col);
	}

	treestore = gtk_tree_store_new(	AUDIO_NCOLS,
					G_TYPE_BOOLEAN,
					G_TYPE_STRING,
					G_TYPE_STRING,
					G_TYPE_STRING,
					G_TYPE_STRING,
					G_TYPE_STRING,
					G_TYPE_STRING,
					G_TYPE_INT );

	g_assert( treestore );

	renderCheck = gtk_cell_renderer_toggle_new();
	g_object_set( renderCheck, "xalign", 0.0, NULL);
	colCheck = gtk_tree_view_column_new_with_attributes(
			"",
			renderCheck,
			"active",
			AUDIO_COL1_CHECK,
			NULL);
/* Ajout de la colonne à la vue */
	gtk_tree_view_append_column(GTK_TREE_VIEW(item), colCheck);

/* La piste */
	renderer = gtk_cell_renderer_text_new();
	col = gtk_tree_view_column_new_with_attributes(
			_("Piste"),
			renderer,
			"text",
			AUDIO_COL2_PISTE,
			NULL);
	gtk_tree_view_append_column(GTK_TREE_VIEW(item), col);
	gtk_tree_view_column_set_sort_column_id( col, AUDIO_COL2_PISTE );
/* La langue */
	renderer = gtk_cell_renderer_text_new();
	col = gtk_tree_view_column_new_with_attributes(
			_("Langue"),
			renderer,
			"text",
			AUDIO_COL3_LANG,
			NULL);
	gtk_tree_view_append_column(GTK_TREE_VIEW(item), col);
	gtk_tree_view_column_set_sort_column_id( col, AUDIO_COL3_LANG );
/* Le format */
	renderer = gtk_cell_renderer_text_new();
	col = gtk_tree_view_column_new_with_attributes(
			_("Format"),
			renderer,
			"text",
			AUDIO_COL4_FORMAT,
			NULL);
	gtk_tree_view_append_column(GTK_TREE_VIEW(item), col);
	gtk_tree_view_column_set_sort_column_id( col, AUDIO_COL4_FORMAT );

/* Extension */
	renderer = gtk_cell_renderer_text_new();
	col = gtk_tree_view_column_new_with_attributes(
			_("Extension"),
			renderer,
			"text",
			AUDIO_COL5_EXTENSION,
			NULL);
	gtk_tree_view_append_column(GTK_TREE_VIEW(item), col);
	gtk_tree_view_column_set_sort_column_id( col, AUDIO_COL5_EXTENSION );

/* Les canaux */
	renderer = gtk_cell_renderer_text_new();
	col = gtk_tree_view_column_new_with_attributes(
			_("Canaux"),
			renderer,
			"text",
			AUDIO_COL6_CANAUX,
			NULL);
	gtk_tree_view_append_column(GTK_TREE_VIEW(item), col);
	gtk_tree_view_column_set_sort_column_id( col, AUDIO_COL6_CANAUX );

//	vtsi_mat = Ifo[Ifo_zero->tt_srpt->title[noPisteVideo].title_set_nr]->vtsi_mat;
//	vts_pgcit = Ifo[Ifo_zero->tt_srpt->title[noPisteVideo].title_set_nr]->vts_pgcit;
	vtsi_mat = piste->vtsi_mat;
	vts_pgcit = piste->vts_pgcit;

	video_attr = &vtsi_mat->vts_video_attr;
	vts_ttn = Ifo_zero->tt_srpt->title[noPisteVideo].vts_ttn;
	vmgi_mat = Ifo_zero->vmgi_mat;
	title_set_nr = Ifo_zero->tt_srpt->title[noPisteVideo].title_set_nr;
//	pgc = vts_pgcit->pgci_srp[Ifo[title_set_nr]->vts_ptt_srpt->title[vts_ttn - 1].ptt[0].pgcn - 1].pgc;
	pgc = piste->pgcs[0];

	*langues = 0;

	for( k = 0; k < vtsi_mat->nr_of_vts_audio_streams;k++ ) {
		char lang_code[3];
		char audio_tag[50];

		if( IsValidAudioTrack( pgc, k ) ) {
			audio_attr = &vtsi_mat->vts_audio_attr[k];
			sprintf( lang_code, "%c%c", audio_attr->lang_code >> 8,audio_attr->lang_code & 0xff);

			DBG('c',fprintf(stderr,"Audio%d=0x%x %s (0x%x) Id: %d Channels: %d\n",k, pgc->subp_control[k], DvdLangCode2String( lang_code ), audio_attr->lang_code, AudioId(pgc->audio_control[k]), audio_attr->channels + 1 ););

			gtk_tree_store_append(treestore, &iter, NULL );
			sprintf( string, _("%d"), k+1 );
			gtk_tree_store_set( treestore, &iter, AUDIO_COL2_PISTE, string, -1 );

			sprintf( string, _("%s"), DvdLangCode2String( lang_code ) );
			gtk_tree_store_set( treestore, &iter, AUDIO_COL3_LANG, string, -1 );

			sprintf( string, "%s", _AudioFormat(audio_attr->audio_format) );
			gtk_tree_store_set( treestore, &iter, AUDIO_COL4_FORMAT, string, -1 );

			sprintf( string, "%s", _AudioType(audio_attr->code_extension) );
			gtk_tree_store_set( treestore, &iter, AUDIO_COL5_EXTENSION, string, -1 );

			sprintf( string, _("%d"), audio_attr->channels + 1 );
			gtk_tree_store_set( treestore, &iter, AUDIO_COL6_CANAUX, string, -1 );

			gtk_tree_store_set( treestore, &iter, AUDIO_COL7_LANGCODE, lang_code, -1 );

			gtk_tree_store_set( treestore, &iter, AUDIO_COL8_NO, k, -1 );

/* Build audio tag to correctly select audio track */
			sprintf( audio_tag, "%s.%s.%d",
						lang_code,
						_AudioFormat(audio_attr->audio_format),
						audio_attr->channels + 1 );

			if( strstr( audioPref, audio_tag ) ) {
				gtk_tree_store_set( treestore, &iter, AUDIO_COL1_CHECK, 1, -1 );
				audioMap.audioTracks[k] = 1;
			}
		}
	}

	gtk_tree_view_set_model(GTK_TREE_VIEW(item), GTK_TREE_MODEL(treestore));

/* Permits sorting */
	 gtk_tree_sortable_set_sort_func(	GTK_TREE_SORTABLE( GTK_TREE_MODEL( treestore ) ),
						AUDIO_COL2_PISTE,
						AudioSortStringNBR,
						(gpointer)AUDIO_COL2_PISTE,
						NULL);
	 gtk_tree_sortable_set_sort_func(	GTK_TREE_SORTABLE( GTK_TREE_MODEL( treestore ) ),
						AUDIO_COL3_LANG,
						AudioSortString,
						(gpointer)AUDIO_COL3_LANG,
						NULL);

	 gtk_tree_sortable_set_sort_func(	GTK_TREE_SORTABLE( GTK_TREE_MODEL( treestore ) ),
						AUDIO_COL4_FORMAT,
						AudioSortString,
						(gpointer)AUDIO_COL4_FORMAT,
						NULL);

	 gtk_tree_sortable_set_sort_func(	GTK_TREE_SORTABLE( GTK_TREE_MODEL( treestore ) ),
						AUDIO_COL6_CANAUX,
						AudioSortStringNBR,
						(gpointer)AUDIO_COL6_CANAUX,
						NULL);


	if( renderCheck ) {
		model = gtk_tree_view_get_model(GTK_TREE_VIEW(item));
		g_assert( model );
		g_signal_connect( renderCheck, "toggled", G_CALLBACK(AudioCheckToggled), model);
	}

/*	if( ConfigGetInt( KEY_USEMENU, 0 ) ) {
		gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(item)), GTK_SELECTION_MULTIPLE );
	}
	else
		gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(item)), GTK_SELECTION_SINGLE );
*/
	gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(item)), GTK_SELECTION_NONE );

	gtk_widget_show_all( item );
	g_object_unref(treestore);
/* Sous titres */
	item = lookup_widget(GTK_WIDGET(forme), "SousTitres" );
	g_assert( item );

/* Permits theme decoration */
	gtk_tree_view_set_rules_hint( GTK_TREE_VIEW(item), TRUE );

/* Erase old columns */
	for( i = AUDIO_NCOLS-1; i >=0; i-- ) {
		col = gtk_tree_view_get_column( GTK_TREE_VIEW(item), i );
		if( col )	gtk_tree_view_remove_column(GTK_TREE_VIEW(item), col);
	}

	treestore = gtk_tree_store_new(	SUB_NCOLS,
					G_TYPE_BOOLEAN,
					G_TYPE_STRING,
					G_TYPE_STRING,
					G_TYPE_STRING,
					G_TYPE_STRING,
					G_TYPE_INT );
	g_assert( treestore );

	renderCheck = gtk_cell_renderer_toggle_new();
	g_object_set( renderCheck, "xalign", 0.0, NULL);
	colCheck = gtk_tree_view_column_new_with_attributes(
			"",
			renderCheck,
			"active",
			SUB_COL1_CHECK,
			NULL);
/* Ajout de la colonne à la vue */
	gtk_tree_view_append_column(GTK_TREE_VIEW(item), colCheck);

/* La piste */
	renderer = gtk_cell_renderer_text_new();
	col = gtk_tree_view_column_new_with_attributes(
			_("Piste"),
			renderer,
			"text",
			SUB_COL2_PISTE,
			NULL);
	gtk_tree_view_append_column(GTK_TREE_VIEW(item), col);
	gtk_tree_view_column_set_sort_column_id( col, SUB_COL2_PISTE );
/* La langue */
	renderer = gtk_cell_renderer_text_new();
	col = gtk_tree_view_column_new_with_attributes(
			_("Langue"),
			renderer,
			"text",
			SUB_COL3_LANG,
			NULL);
	gtk_tree_view_append_column(GTK_TREE_VIEW(item), col);
	gtk_tree_view_column_set_sort_column_id( col, SUB_COL3_LANG );
/* L'extension */
	renderer = gtk_cell_renderer_text_new();
	col = gtk_tree_view_column_new_with_attributes(
			_("Ext"),
			renderer,
			"text",
			SUB_COL4_EXT,
			NULL);
	gtk_tree_view_append_column(GTK_TREE_VIEW(item), col);
	gtk_tree_view_column_set_sort_column_id( col, SUB_COL4_EXT );

//	vtsi_mat = Ifo[Ifo_zero->tt_srpt->title[noPisteVideo].title_set_nr]->vtsi_mat;
//	vts_pgcit = Ifo[Ifo_zero->tt_srpt->title[noPisteVideo].title_set_nr]->vts_pgcit;
	video_attr = &vtsi_mat->vts_video_attr;
	vts_ttn = Ifo_zero->tt_srpt->title[noPisteVideo].vts_ttn;
	vmgi_mat = Ifo_zero->vmgi_mat;
	title_set_nr = Ifo_zero->tt_srpt->title[noPisteVideo].title_set_nr;
//	pgc = vts_pgcit->pgci_srp[Ifo[title_set_nr]->vts_ptt_srpt->title[vts_ttn - 1].ptt[0].pgcn - 1].pgc;
	*langues = 0;

	for( k = 0; k < vtsi_mat->nr_of_vts_subp_streams; k++ ) {
		char lang_code[3];

		if( IsValidSubpTrack( pgc, k ) ) {
			subp_attr = &vtsi_mat->vts_subp_attr[k];
			sprintf (lang_code, "%c%c", subp_attr->lang_code >> 8, subp_attr->lang_code & 0xff);
			if (!lang_code[0]) {
				strcpy (lang_code, "xx");
			}
			gtk_tree_store_append(treestore, &iter, NULL );

			sprintf( string, _("%d"), k+1 );
			gtk_tree_store_set( treestore, &iter, SUB_COL2_PISTE, string, -1 );

			sprintf( string, _("%s"), DvdLangCode2String( lang_code ) );
			gtk_tree_store_set( treestore, &iter, SUB_COL3_LANG, string, -1 );

			sprintf( string, "%s", _SubType( subp_attr->code_extension ) );
			gtk_tree_store_set( treestore, &iter, SUB_COL4_EXT, string, -1 );

			gtk_tree_store_set( treestore, &iter, SUB_COL5_LANGCODE, lang_code, -1 );

			gtk_tree_store_set( treestore, &iter, SUB_COL6_NO, k, -1 );

			DBG('c',fprintf(stderr,"Subp%d=0x%x %s ID: %d EXT:%d LEXT: 0x%x\n",k, pgc->subp_control[k], DvdLangCode2String( lang_code ), SubpId(pgc->subp_control[k]), subp_attr->code_extension, subp_attr->lang_extension ););
			if( strstr( subPref, lang_code ) ) {
				gtk_tree_store_set( treestore, &iter, SUB_COL1_CHECK, 1, -1 );
				subMap.subTracks[k] = 1;
				subFound++;
			}
		}
	}
/* Add a empty subtitle track */
//	gtk_tree_store_append(treestore, &iter, NULL );
//	gtk_tree_store_set( treestore, &iter, SUB_COL2_PISTE, _("AUCUN"), -1 );
/* And the default selected if none */
//	if( !subFound ) {
//		gtk_tree_store_set( treestore, &iter, SUB_COL1_CHECK, 1, -1 );
//	}

	gtk_tree_view_set_model(GTK_TREE_VIEW(item), GTK_TREE_MODEL(treestore));
	gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(item)), GTK_SELECTION_NONE );

/* Permits sorting */
	 gtk_tree_sortable_set_sort_func(	GTK_TREE_SORTABLE( GTK_TREE_MODEL( treestore ) ),
						SUB_COL2_PISTE,
						SubSortStringNBR,
						(gpointer)SUB_COL2_PISTE,
						NULL);
	 gtk_tree_sortable_set_sort_func(	GTK_TREE_SORTABLE( GTK_TREE_MODEL( treestore ) ),
						SUB_COL3_LANG,
						SubSortString,
						(gpointer)SUB_COL3_LANG,
						NULL);
	 gtk_tree_sortable_set_sort_func(	GTK_TREE_SORTABLE( GTK_TREE_MODEL( treestore ) ),
						SUB_COL4_EXT,
						SubSortString,
						(gpointer)SUB_COL4_EXT,
						NULL);


	model = gtk_tree_view_get_model(GTK_TREE_VIEW(item));
	g_assert( model );
	g_signal_connect( renderCheck, "toggled", G_CALLBACK(SubCheckToggled), model);

	gtk_widget_show_all( item );
	g_object_unref(treestore);

	UpdDefFactor( forme, noPisteVideo, &audioMap, &subMap );

	return( 0 );
}
/*------------------------------------------------------------------------------
	GETSECTOR-
Linux!jef 2005/12/07 22:17:13
------------------------------------------------------------------------------*/

static unsigned long GetSector( chapitre, pgc )
int chapitre;
pgc_t * pgc;
{
	int i;
	int cell = 0;
	unsigned int total = 0;

	DBG('b',fprintf(stderr,"%s:> #programs: %d\n",__FUNCTION__, pgc->nr_of_programs););
	for( i = 0; i < pgc->nr_of_programs; i++ ) {
		DBG('b',fprintf(stderr,"%s: Chapitre: %d Start=%d\n", __FUNCTION__, i+1, pgc->program_map[i] ););
	}

{
	int j;

	for( j = 0; j < pgc->nr_of_cells; j++ ) {
		cell_playback_t * cell_playback = &pgc->cell_playback[j];
		unsigned int secSize;

		secSize	= cell_playback->last_sector - cell_playback->first_sector + 1;

		DBG('b',fprintf(stderr,"%s: cell %d block_type=%d block_mode=%d secSize=%s from: %u to: %u\n", __FUNCTION__, j, cell_playback->block_type, cell_playback->block_mode, LLSize2Giga((long long)secSize * SECTOR_SIZE), cell_playback->first_sector,cell_playback->last_sector ););
	}
}

	for( i = 0; i < pgc->nr_of_programs; i++ ) {
		unsigned int sectors = 0;
		int next;

		if( i == (pgc->nr_of_programs - 1))
			next = pgc->nr_of_cells + 1;
		else
			next = pgc->program_map[i + 1];
		DBG('b',fprintf(stderr,"%s: first=%d next: %d start=%d\n", __FUNCTION__, cell, next, pgc->program_map[i] ););
		while( cell < next - 1 ) {
			unsigned int secSize;
			cell_playback_t * cell_playback = &pgc->cell_playback[cell];

/* cell cannot index > nr_of_cells */
			if( cell >= pgc->nr_of_cells )	break;

			secSize	= cell_playback->last_sector - cell_playback->first_sector + 1;
//			DBG('b',fprintf(stderr,"%s: block_type=%d block_mode=%d secSize=%s from: %u to: %u\n", __FUNCTION__, cell_playback->block_type, cell_playback->block_mode, LLSize2Giga((long long)secSize * SECTOR_SIZE), cell_playback->first_sector,cell_playback->last_sector ););
#if IGNORE_ANGLE
			if( cell_playback->block_type == 1  ) { /* Angle block start */
				unsigned int start = cell_playback->first_sector;
				unsigned int end;

				while( cell_playback->block_type == 1 && cell_playback->block_mode != 3 ) {
					cell++;
					cell_playback = &pgc->cell_playback[cell];
				}
				end = cell_playback->last_sector;
				secSize = end - start + 1;
				DBG('b',fprintf(stderr,"%s: angle secSize=%s from: %u to: %u\n", __FUNCTION__, LLSize2Giga((long long)secSize * SECTOR_SIZE), cell_playback->first_sector,cell_playback->last_sector ););
				sectors += secSize;
				goto ignore;
			}
#endif
			DBG('b',fprintf(stderr,"%s: prg=%d cell: %d secSize=%s from: %u to: %u\n", __FUNCTION__, i, cell, LLSize2Giga((long long)secSize * SECTOR_SIZE), cell_playback->first_sector,cell_playback->last_sector ););
			sectors += secSize;
#if IGNORE_ANGLE
ignore:;
#endif
			cell++;
		}
		DBG('b',fprintf(stderr,"%s: Chapter %d size=%s\n", __FUNCTION__, i, LLSize2Giga((long long)sectors * SECTOR_SIZE) ););
		total += sectors;
		if ((i + 1) == chapitre ) {
			DBG('b',fprintf(stderr,"%s: total=%s\n", __FUNCTION__, LLSize2Giga((long long)sectors * SECTOR_SIZE) ););
			return( sectors );
		}
	}
	DBG('b',fprintf(stderr,"%s: total=%s (%d sectors)\n", __FUNCTION__, LLSize2Giga((long long)total * SECTOR_SIZE), total ););
	return( total );
}
/*------------------------------------------------------------------------------
	TOTALAUDIOSIZE-
Linux!jef 2006/01/30 23:39:05
------------------------------------------------------------------------------*/

long long TotalAudioSize( int noPisteVideo, int * pDuree )
{
	Piste_t * piste = GetPiste( noPisteVideo );
	pgcit_t *vts_pgcit;
	vtsi_mat_t *vtsi_mat;
	vmgi_mat_t *vmgi_mat;
	audio_attr_t *audio_attr;
	video_attr_t *video_attr;
	int title_set_nr;
	int vts_ttn;
	pgc_t *pgc;
	long long totalAudioSize = 0;
	int audioKBPS;
	int duree = 0;
	int i,j;

	vtsi_mat = piste->vtsi_mat;
	vts_pgcit = piste->vts_pgcit;

	video_attr = &vtsi_mat->vts_video_attr;
	vts_ttn = Ifo_zero->tt_srpt->title[noPisteVideo].vts_ttn;
	vmgi_mat = Ifo_zero->vmgi_mat;
	title_set_nr = Ifo_zero->tt_srpt->title[noPisteVideo].title_set_nr;
	for( j = 0; j < piste->nrPgc; j++ ) {
		pgc = piste->pgcs[j];

		duree += ( BCD2INT( pgc->playback_time.hour ) * 3600) +
			( BCD2INT( pgc->playback_time.minute ) * 60 ) +
			BCD2INT( pgc->playback_time.second );

		for( i = 0; i < vtsi_mat->nr_of_vts_audio_streams; i++ ) {
			if( IsValidAudioTrack( pgc, i ) ) {
				audio_attr = &vtsi_mat->vts_audio_attr[i];

				if((audio_attr->channels + 1) == 2)
					audioKBPS = 64 * 2;
			        else
			        	audioKBPS = 64 * 6;
			        totalAudioSize += ((long long)audioKBPS * (long long)duree * 1000LL) / 8LL;
			}
		}
	}
	if( pDuree )	*pDuree = duree;
	return( totalAudioSize );
}
/*------------------------------------------------------------------------------
	AUDIOSIZE-
Linux!jef 2006/01/30 23:44:00
------------------------------------------------------------------------------*/
long long AudioSize( int noPisteVideo, int noPisteAudio )
{
	Piste_t * piste = GetPiste( noPisteVideo );
	pgcit_t *vts_pgcit;   vtsi_mat_t *vtsi_mat;
	vmgi_mat_t *vmgi_mat;
	audio_attr_t *audio_attr;
	int audioKBPS;
	int duree = 0;
	long long size = 0;
	int j;

	vtsi_mat = piste->vtsi_mat;
	vts_pgcit = piste->vts_pgcit;
	vmgi_mat = Ifo_zero->vmgi_mat;

	for( j = 0; j < piste->nrPgc; j++ ) {
		pgc_t *pgc = piste->pgcs[j];

		if( IsValidAudioTrack( pgc, noPisteAudio ) ) {
			duree = ( BCD2INT( pgc->playback_time.hour ) * 3600) +
				( BCD2INT( pgc->playback_time.minute ) * 60 ) +
				BCD2INT( pgc->playback_time.second );
			audio_attr = &vtsi_mat->vts_audio_attr[noPisteAudio];
			if((audio_attr->channels + 1) == 2)
				audioKBPS = 64 * 2;
		        else
		        	audioKBPS = 64 * 6;
		        size += ((long long)audioKBPS * (long long)duree * 1000LL) / 8LL;
			DBG('c',fprintf(stderr,"%s: pisteAudio %d KPS: %d duree: %d size: %lld\n", __FUNCTION__, noPisteAudio, audioKBPS, duree, size ););
		}
	}
	return( size );
}
/*------------------------------------------------------------------------------
	SUBLANG-
Linux!jef 2005/12/16 22:07:24
------------------------------------------------------------------------------*/

static unsigned short SubCode( int noPisteVideo, int noSubtitle )
{
	vtsi_mat_t *vtsi_mat;
	subp_attr_t *subp_attr;

	vtsi_mat = Ifo[Ifo_zero->tt_srpt->title[noPisteVideo].title_set_nr]->vtsi_mat;

	subp_attr = &vtsi_mat->vts_subp_attr[noSubtitle];
	return( subp_attr->lang_code & 0xFFFF );
}


/*------------------------------------------------------------------------------
	DEFAULTREQUANTFACTOR-
Linux!jef 2005/12/16 23:37:02
------------------------------------------------------------------------------*/

static double DefaultRequantFactor( int noPisteVideo, AudioMap_t * audioMap, SubMap_t * subMap, int useMenuF )
{
	Piste_t * piste = GetPiste( noPisteVideo );
	pgcit_t *vts_pgcit;
	vtsi_mat_t *vtsi_mat;
	vmgi_mat_t *vmgi_mat;
	audio_attr_t *audio_attr;
	video_attr_t *video_attr;
	int title_set_nr;
	int vts_ttn;
//	pgc_t *pgc;
	long long totalSectors;
	long long totalSize;
	long long totalAudioSize = 0;
	long long menuSize = 0;
	int audioKBPS;
	int duree;
	long long audioSize;
	int i;
	double factor;

	DBG('c',fprintf(stderr,"%s: noPisteVideo: %d\n", __FUNCTION__, noPisteVideo ););
//	vtsi_mat = Ifo[Ifo_zero->tt_srpt->title[noPisteVideo].title_set_nr]->vtsi_mat;
//	vts_pgcit = Ifo[Ifo_zero->tt_srpt->title[noPisteVideo].title_set_nr]->vts_pgcit;
	vtsi_mat = piste->vtsi_mat;
	vts_pgcit = piste->vts_pgcit;

	video_attr = &vtsi_mat->vts_video_attr;
	vts_ttn = Ifo_zero->tt_srpt->title[noPisteVideo].vts_ttn;
	vmgi_mat = Ifo_zero->vmgi_mat;
	title_set_nr = Ifo_zero->tt_srpt->title[noPisteVideo].title_set_nr;
//	pgc = vts_pgcit->pgci_srp[Ifo[title_set_nr]->vts_ptt_srpt->title[vts_ttn - 1].ptt[0].pgcn - 1].pgc;
//	pgc = Pistes[noPisteVideo].pgc;

	totalSectors = piste->sectors; // GetSector( -1, pgc );

	totalSize = totalSectors * SECTOR_SIZE;

	if( totalSize < GetWantedBytes() ) {
		DBG('c',fprintf(stderr,"%s: totalSize: %lld < %lld(DVDSize)\n", __FUNCTION__, totalSize, GetWantedBytes()););
		return( 1.0 );
	}

	totalAudioSize = TotalAudioSize( noPisteVideo, &duree );

	DBG('c',fprintf(stderr,"totalAudioSize: %lld duree: %d secondes\n", totalAudioSize, duree ););
	DBG('c',fprintf(stderr,"DureeVideo: %s\n", Duree2String( duree ) ););
	audioSize = 0;
	for( i = 0; i < MAX_AUDIO_TRACK; i++ ) {
		if( audioMap->audioTracks[i] ) {
			long long size;

			audio_attr = &vtsi_mat->vts_audio_attr[i];
			if((audio_attr->channels + 1) == 2)
				audioKBPS = 64 * 2;
		        else
		        	audioKBPS = 64 * 6;

			size = ((long long)audioKBPS * (long long)duree * 1000LL) / 8LL;
			audioSize += size;
			DBG('c',fprintf(stderr,"%s: pisteAudio %d KPS: %d size: %s ", __FUNCTION__, i, audioKBPS, LLSize2Giga(size) ););
			DBG('c',fprintf(stderr,"audioSize: %s\n", LLSize2Giga( audioSize ) ););
		}
	}

	if( useMenuF )	menuSize = GetMenuSize();

	DBG('c',fprintf(stderr,"%s: totalSize: %s ", __FUNCTION__, LLSize2Giga(totalSize) ););
	DBG('c',fprintf(stderr,"totalAudioSize: %s\n", LLSize2Giga(totalAudioSize) ););
	DBG('c',fprintf(stderr,"%s: menuSize: %s\n", __FUNCTION__, LLSize2Giga(menuSize) ););

	DBG('c',fprintf(stderr,"%s: Video2Requant: %s\n", __FUNCTION__, LLSize2Giga( totalSize - totalAudioSize ) ););
	DBG('c',fprintf(stderr,"%s: VideoSizeAllocated: %s\n", __FUNCTION__, LLSize2Giga( GetWantedBytes() - audioSize - menuSize ) ););

	factor = (double)(totalSize - totalAudioSize) / (double) (GetWantedBytes() - audioSize - menuSize );

	factor = factor + (factor / (double) 100 * (double) 3);    // 3 % Reserve

/* Pour eviter de compter plusieurs fois le meme subpicture */
	{
		unsigned short lastCode = -1;

		for( i = 0; i < MAX_SUB_TRACK; i++ ) {
			if( subMap->subTracks[i] ) {
				unsigned short subCode = SubCode( noPisteVideo, i );
				if( subCode != lastCode )	factor = factor + (factor / (double) 100);   // 1 % Reserve pour soustitre
				lastCode = subCode;
			}
		}
	}
	factor = factor + (factor / (double) 200); // 0.5 % Overhead
	if (factor < 1)		factor = 1;
	DBG('c',fprintf(stderr,"%s: factor: %f\n", __FUNCTION__, factor ););

	return( factor );
}


/*------------------------------------------------------------------------------
	VISUDVDSTRUCT-
Linux!jef 2005/12/17 00:18:59
------------------------------------------------------------------------------*/

void VisuDvdPiste( int noPisteVideo )
{
	char * player = ConfigGetString( KEY_PLAYER, "xine" );
	char sysCmd[1024];
	int res;

	if( !strcmp( player, "xine" )) {
		sprintf( sysCmd, "xine dvd:/%s", Device);
		res = system( sysCmd );
		return;
	}
	if( !strcmp( player, "mplayer" )) {
		sprintf( sysCmd, "mplayer -dvd-device %s dvd://%d", Device, noPisteVideo + 1 );
		res = system( sysCmd );
		return;
	}
	if( !strcmp( player, "vlc" )) {
		sprintf( sysCmd, "vlc dvd://%s@%d:1", Device, noPisteVideo + 1 );
		res = system( sysCmd );
		return;
	}
	sprintf( sysCmd, "%s %s", player, Device );
	res  = system( sysCmd );
}


/*------------------------------------------------------------------------------
	VISUDVDSTRUCT-
Linux!jef 2005/12/17 00:18:59
------------------------------------------------------------------------------*/

void VisuDvdStruct( path )
char * path;
{
	char * player = ConfigGetString( KEY_PLAYER, "xine" );
	char sysCmd[1024];
	int res;

	if( !strcmp( player, "xine" )) {
		sprintf( sysCmd, "xine \"dvd://%s\"", path );
		DBG('c',fprintf(stderr,"%s: executing (%s)\n", __FUNCTION__, sysCmd ););
		res = system( sysCmd );
		return;
	}
	if( !strcmp( player, "mplayer" )) {
		sprintf( sysCmd, "mplayer -dvd-device \"%s\" dvd://1", path );
		DBG('c',fprintf(stderr,"%s: executing (%s)\n", __FUNCTION__, sysCmd ););
		res = system( sysCmd );
		return;
	}
	if( !strcmp( player, "vlc" )) {
		sprintf( sysCmd, "vlc \"dvd://%s@0:1\"", path );
		DBG('c',fprintf(stderr,"%s: executing (%s)\n", __FUNCTION__, sysCmd ););
		res = system( sysCmd );
		return;
	}
}

/*------------------------------------------------------------------------------
	EXECUTEMKISOFS-
Linux!jef 2005/12/20 22:17:17
------------------------------------------------------------------------------*/

int ExecuteMkIsoFs( char * sysCmd )
{
	FILE * fp;
	char line[1024];
	int res = 0;
	int status;

	InitAvancement( 0 );
/* re-direct stderr */
	strcat( sysCmd, " 2>&1" );
	DBG('c',fprintf(stderr,"%s: executing (%s)\n", __FUNCTION__, sysCmd ););
	fp = popen( sysCmd, "r" );
	if( !fp )	 return( -1 );
	while( 1 )
	{
		char * p, * s;

		if( !fgets( line, sizeof(line), fp ) )	break;
		if( !*line )	continue;
		s = line;
		while( *s == ' ' || *s == '\t' )	s++;
// fprintf(stderr,"line(%s)\n", s );
		p = strchr( s, '%' );
		if( p ) {
			double pct;

			*p = 0;
/* locale troubles . => , */
			pct = atof( s );
			pct /= 100.0;
//fprintf(stderr,"pct: %f\n", pct );
			if( AvancementUi2( pct ) < 0 ) {
				res = -1;
				break;
			}
		}
	}
	status = pclose( fp );
	if( !res && status ) {
		DBG('c',fprintf(stderr,"%s: retCode=%d\n", __FUNCTION__, status ););
		return( -1 );
	}
	return( res );
}
