Commit ee0906d2 authored by Benjamin Adolphi's avatar Benjamin Adolphi Committed by Thomas Guillem

input/subtitles: refactor subtitles_Detect

This function fills now a list of input_item_slave. Subtitles are not sorted in
input.c.
Signed-off-by: Thomas Guillem's avatarThomas Guillem <thomas@gllm.fr>
parent 3d227df7
...@@ -924,6 +924,26 @@ static void StartTitle( input_thread_t * p_input ) ...@@ -924,6 +924,26 @@ static void StartTitle( input_thread_t * p_input )
p_input->p->b_fast_seek = var_GetBool( p_input, "input-fast-seek" ); p_input->p->b_fast_seek = var_GetBool( p_input, "input-fast-seek" );
} }
static int SlaveCompare(const void *a, const void *b)
{
const input_item_slave_t *p_slave0 = *((const input_item_slave_t **) a);
const input_item_slave_t *p_slave1 = *((const input_item_slave_t **) b);
if( p_slave0 == NULL || p_slave1 == NULL )
{
/* Put NULL (or rejected) subs at the end */
return p_slave0 == NULL ? 1 : p_slave1 == NULL ? -1 : 0;
}
if( p_slave0->i_priority > p_slave1->i_priority )
return -1;
if( p_slave0->i_priority < p_slave1->i_priority )
return 1;
return 0;
}
static void LoadSubtitles( input_thread_t *p_input ) static void LoadSubtitles( input_thread_t *p_input )
{ {
/* Load subtitles */ /* Load subtitles */
...@@ -960,23 +980,44 @@ static void LoadSubtitles( input_thread_t *p_input ) ...@@ -960,23 +980,44 @@ static void LoadSubtitles( input_thread_t *p_input )
if( var_GetBool( p_input, "sub-autodetect-file" ) ) if( var_GetBool( p_input, "sub-autodetect-file" ) )
{ {
/* Add local subtitles */
input_item_slave_t **pp_slaves;
int i_slaves;
TAB_INIT( i_slaves, pp_slaves );
char *psz_autopath = var_GetNonEmptyString( p_input, "sub-autodetect-path" ); char *psz_autopath = var_GetNonEmptyString( p_input, "sub-autodetect-path" );
char **ppsz_subs = subtitles_Detect( p_input, psz_autopath,
p_input->p->p_item->psz_uri );
free( psz_autopath );
for( int i = 0; ppsz_subs && ppsz_subs[i]; i++ ) if( subtitles_Detect( p_input, psz_autopath, p_input->p->p_item->psz_uri,
&pp_slaves, &i_slaves ) == VLC_SUCCESS )
{ {
if( !psz_subtitle || strcmp( psz_subtitle, ppsz_subs[i] ) ) /* check that we did not add the subtitle through sub-file */
for( int i = 0; i < i_slaves; i++ )
{ {
i_flags |= SUB_CANFAIL; input_item_slave_t *p_curr = pp_slaves[i];
input_SubtitleFileAdd( p_input, ppsz_subs[i], i_flags, false ); if( p_curr != NULL && psz_subtitle != NULL
i_flags = SUB_NOFLAG; && !strcmp( psz_subtitle, p_curr->psz_uri ) )
{
/* reject current sub */
input_item_slave_Delete( p_curr );
pp_slaves[i] = NULL;
}
} }
}
free( psz_autopath );
qsort( pp_slaves, i_slaves, sizeof(input_item_slave_t*), SlaveCompare );
free( ppsz_subs[i] ); /* add all detected subtitles */
for( int i = 0; i < i_slaves && pp_slaves[i] != NULL; i++ )
{
const char *psz_uri = pp_slaves[i]->psz_uri;
i_flags |= SUB_CANFAIL;
input_SubtitleAdd( p_input, psz_uri, i_flags );
i_flags = SUB_NOFLAG;
input_item_slave_Delete( pp_slaves[i] );
} }
free( ppsz_subs );
TAB_CLEAN( i_slaves, pp_slaves );
} }
free( psz_subtitle ); free( psz_subtitle );
......
...@@ -249,7 +249,7 @@ void input_ControlVarTitle( input_thread_t *, int i_title ); ...@@ -249,7 +249,7 @@ void input_ControlVarTitle( input_thread_t *, int i_title );
void input_ConfigVarInit ( input_thread_t * ); void input_ConfigVarInit ( input_thread_t * );
/* Subtitles */ /* Subtitles */
char **subtitles_Detect( input_thread_t *, char* path, const char *fname ); int subtitles_Detect( input_thread_t *, char *, const char *, input_item_slave_t ***, int * );
int subtitles_Filter( const char *); int subtitles_Filter( const char *);
/* input.c */ /* input.c */
......
...@@ -41,24 +41,10 @@ ...@@ -41,24 +41,10 @@
#include "input_internal.h" #include "input_internal.h"
/**
* We are not going to autodetect more subtitle files than this.
*/
#define MAX_SUBTITLE_FILES 128
/** /**
* The possible extensions for subtitle files we support * The possible extensions for subtitle files we support
*/ */
static const char sub_exts[][6] = { static const char *const sub_exts[] = { SLAVE_SPU_EXTENSIONS, "" };
"idx", "sub", "srt",
"ssa", "ass", "smi",
"utf", "utf8", "utf-8",
"rt", "aqt", "txt",
"usf", "jss", "cdg",
"psb", "mpsub","mpl2",
"pjs", "dks", "stl",
"vtt", "sbv", ""
};
static void strcpy_trim( char *d, const char *s ) static void strcpy_trim( char *d, const char *s )
{ {
...@@ -130,39 +116,6 @@ static int whiteonly( const char *s ) ...@@ -130,39 +116,6 @@ static int whiteonly( const char *s )
return 1; return 1;
} }
enum
{
SUB_PRIORITY_NONE = 0,
SUB_PRIORITY_MATCH_NONE = 1,
SUB_PRIORITY_MATCH_RIGHT = 2,
SUB_PRIORITY_MATCH_LEFT = 3,
SUB_PRIORITY_MATCH_ALL = 4,
};
typedef struct
{
int priority;
char *psz_fname;
char *psz_ext;
} vlc_subfn_t;
static int compare_sub_priority( const void *a, const void *b )
{
const vlc_subfn_t *p0 = a;
const vlc_subfn_t *p1 = b;
if( p0->priority > p1->priority )
return -1;
if( p0->priority < p1->priority )
return 1;
#ifdef HAVE_STRCOLL
return strcoll( p0->psz_fname, p1->psz_fname);
#else
return strcmp( p0->psz_fname, p1->psz_fname);
#endif
}
/* /*
* Check if a file ends with a subtitle extension * Check if a file ends with a subtitle extension
*/ */
...@@ -226,7 +179,6 @@ static char **paths_to_list( const char *psz_dir, char *psz_path ) ...@@ -226,7 +179,6 @@ static char **paths_to_list( const char *psz_dir, char *psz_path )
return subdirs; return subdirs;
} }
/** /**
* Detect subtitle files. * Detect subtitle files.
* *
...@@ -238,37 +190,36 @@ static char **paths_to_list( const char *psz_dir, char *psz_path ) ...@@ -238,37 +190,36 @@ static char **paths_to_list( const char *psz_dir, char *psz_path )
* \ingroup Demux * \ingroup Demux
* \param p_this the calling \ref input_thread_t * \param p_this the calling \ref input_thread_t
* \param psz_path a list of subdirectories (separated by a ',') to look in. * \param psz_path a list of subdirectories (separated by a ',') to look in.
* \param psz_name the complete filename to base the search on. * \param psz_name_org the complete filename to base the search on.
* \return a NULL terminated array of filenames with detected possible subtitles. * \param pp_slaves an initialized input item slave list to append detected subtitles to
* The array contains max MAX_SUBTITLE_FILES items and you need to free it after use. * \param p_slaves pointer to the size of the slave list
* \return VLC_SUCCESS if ok
*/ */
char **subtitles_Detect( input_thread_t *p_this, char *psz_path, int subtitles_Detect( input_thread_t *p_this, char *psz_path, const char *psz_name_org,
const char *psz_name_org ) input_item_slave_t ***ppp_slaves, int *p_slaves )
{ {
int i_fuzzy = var_GetInteger( p_this, "sub-autodetect-fuzzy" ); int i_fuzzy = var_GetInteger( p_this, "sub-autodetect-fuzzy" );
if ( i_fuzzy == 0 ) if ( i_fuzzy == 0 )
return NULL; return VLC_EGENERIC;
int j, i_result2, i_sub_count, i_fname_len; int j, i_fname_len;
input_item_slave_t **pp_slaves = *ppp_slaves;
int i_slaves = *p_slaves;
char *f_fname_noext = NULL, *f_fname_trim = NULL; char *f_fname_noext = NULL, *f_fname_trim = NULL;
char **subdirs; /* list of subdirectories to look in */ char **subdirs; /* list of subdirectories to look in */
vlc_subfn_t *result = NULL; /* unsorted results */
char **result2; /* sorted results */
if( !psz_name_org ) if( !psz_name_org )
return NULL; return VLC_EGENERIC;
char *psz_fname = vlc_uri2path( psz_name_org ); char *psz_fname = vlc_uri2path( psz_name_org );
if( !psz_fname ) if( !psz_fname )
return NULL; return VLC_EGENERIC;
/* extract filename & dirname from psz_fname */ /* extract filename & dirname from psz_fname */
char *f_dir = strdup( psz_fname ); char *f_dir = strdup( psz_fname );
if( f_dir == NULL ) if( f_dir == 0 )
{ {
free( psz_fname ); free( psz_fname );
return NULL; return VLC_ENOMEM;
} }
const char *f_fname = strrchr( psz_fname, DIR_SEP_CHAR ); const char *f_fname = strrchr( psz_fname, DIR_SEP_CHAR );
...@@ -276,7 +227,7 @@ char **subtitles_Detect( input_thread_t *p_this, char *psz_path, ...@@ -276,7 +227,7 @@ char **subtitles_Detect( input_thread_t *p_this, char *psz_path,
{ {
free( f_dir ); free( f_dir );
free( psz_fname ); free( psz_fname );
return NULL; return VLC_EGENERIC;
} }
f_fname++; /* Skip the '/' */ f_fname++; /* Skip the '/' */
f_dir[f_fname - psz_fname] = 0; /* keep dir separator in f_dir */ f_dir[f_fname - psz_fname] = 0; /* keep dir separator in f_dir */
...@@ -291,15 +242,14 @@ char **subtitles_Detect( input_thread_t *p_this, char *psz_path, ...@@ -291,15 +242,14 @@ char **subtitles_Detect( input_thread_t *p_this, char *psz_path,
free( f_fname_noext ); free( f_fname_noext );
free( f_fname_trim ); free( f_fname_trim );
free( psz_fname ); free( psz_fname );
return NULL; return VLC_ENOMEM;
} }
strcpy_strip_ext( f_fname_noext, f_fname ); strcpy_strip_ext( f_fname_noext, f_fname );
strcpy_trim( f_fname_trim, f_fname_noext ); strcpy_trim( f_fname_trim, f_fname_noext );
result = calloc( MAX_SUBTITLE_FILES+1, sizeof(vlc_subfn_t) ); /* We check it later (simplify code) */
subdirs = paths_to_list( f_dir, psz_path ); subdirs = paths_to_list( f_dir, psz_path );
for( j = -1, i_sub_count = 0; (j == -1) || ( j >= 0 && subdirs != NULL && subdirs[j] != NULL ); j++ ) for( j = -1; (j == -1) || ( j >= 0 && subdirs != NULL && subdirs[j] != NULL ); j++ )
{ {
const char *psz_dir = (j < 0) ? f_dir : subdirs[j]; const char *psz_dir = (j < 0) ? f_dir : subdirs[j];
if( psz_dir == NULL || ( j >= 0 && !strcmp( psz_dir, f_dir ) ) ) if( psz_dir == NULL || ( j >= 0 && !strcmp( psz_dir, f_dir ) ) )
...@@ -313,7 +263,7 @@ char **subtitles_Detect( input_thread_t *p_this, char *psz_path, ...@@ -313,7 +263,7 @@ char **subtitles_Detect( input_thread_t *p_this, char *psz_path,
msg_Dbg( p_this, "looking for a subtitle file in %s", psz_dir ); msg_Dbg( p_this, "looking for a subtitle file in %s", psz_dir );
const char *psz_name; const char *psz_name;
while( (psz_name = vlc_readdir( dir )) && i_sub_count < MAX_SUBTITLE_FILES ) while( (psz_name = vlc_readdir( dir )) )
{ {
if( psz_name[0] == '.' || !subtitles_Filter( psz_name ) ) if( psz_name[0] == '.' || !subtitles_Filter( psz_name ) )
continue; continue;
...@@ -322,7 +272,7 @@ char **subtitles_Detect( input_thread_t *p_this, char *psz_path, ...@@ -322,7 +272,7 @@ char **subtitles_Detect( input_thread_t *p_this, char *psz_path,
char tmp_fname_trim[strlen( psz_name ) + 1]; char tmp_fname_trim[strlen( psz_name ) + 1];
char tmp_fname_ext[strlen( psz_name ) + 1]; char tmp_fname_ext[strlen( psz_name ) + 1];
const char *tmp; const char *tmp;
int i_prio = SUB_PRIORITY_NONE; int i_prio = 0;
/* retrieve various parts of the filename */ /* retrieve various parts of the filename */
strcpy_strip_ext( tmp_fname_noext, psz_name ); strcpy_strip_ext( tmp_fname_noext, psz_name );
...@@ -332,7 +282,7 @@ char **subtitles_Detect( input_thread_t *p_this, char *psz_path, ...@@ -332,7 +282,7 @@ char **subtitles_Detect( input_thread_t *p_this, char *psz_path,
if( !strcmp( tmp_fname_trim, f_fname_trim ) ) if( !strcmp( tmp_fname_trim, f_fname_trim ) )
{ {
/* matches the movie name exactly */ /* matches the movie name exactly */
i_prio = SUB_PRIORITY_MATCH_ALL; i_prio = SLAVE_PRIORITY_MATCH_ALL;
} }
else if( (tmp = strstr( tmp_fname_trim, f_fname_trim )) ) else if( (tmp = strstr( tmp_fname_trim, f_fname_trim )) )
{ {
...@@ -341,40 +291,49 @@ char **subtitles_Detect( input_thread_t *p_this, char *psz_path, ...@@ -341,40 +291,49 @@ char **subtitles_Detect( input_thread_t *p_this, char *psz_path,
if( whiteonly( tmp ) ) if( whiteonly( tmp ) )
{ {
/* chars in front of the movie name */ /* chars in front of the movie name */
i_prio = SUB_PRIORITY_MATCH_RIGHT; i_prio = SLAVE_PRIORITY_MATCH_RIGHT;
} }
else else
{ {
/* chars after (and possibly in front of) /* chars after (and possibly in front of)
* the movie name */ * the movie name */
i_prio = SUB_PRIORITY_MATCH_LEFT; i_prio = SLAVE_PRIORITY_MATCH_LEFT;
} }
} }
else if( j == -1 ) else if( j == -1 )
{ {
/* doesn't contain the movie name, prefer files in f_dir over subdirs */ /* doesn't contain the movie name, prefer files in f_dir over subdirs */
i_prio = SUB_PRIORITY_MATCH_NONE; i_prio = SLAVE_PRIORITY_MATCH_NONE;
} }
if( i_prio >= i_fuzzy ) if( i_prio >= i_fuzzy )
{ {
struct stat st; struct stat st;
char *path; char *path;
if( asprintf( &path, "%s"DIR_SEP"%s", psz_dir, psz_name ) < 0 ) size_t i_len = strlen( psz_dir );
const char *psz_format;
if( psz_dir[i_len - 1] == DIR_SEP_CHAR )
psz_format = "%s%s";
else
psz_format = "%s"DIR_SEP"%s";
if( asprintf( &path, psz_format, psz_dir, psz_name ) < 0 )
continue; continue;
if( strcmp( path, psz_fname ) if( strcmp( path, psz_fname )
&& vlc_stat( path, &st ) == 0 && vlc_stat( path, &st ) == 0
&& S_ISREG( st.st_mode ) && result ) && S_ISREG( st.st_mode ) )
{ {
msg_Dbg( p_this, msg_Dbg( p_this,
"autodetected subtitle: %s with priority %d", "autodetected subtitle: %s with priority %d",
path, i_prio ); path, i_prio );
result[i_sub_count].priority = i_prio; char *psz_uri = vlc_path2uri( path, NULL );
result[i_sub_count].psz_fname = path; input_item_slave_t *p_sub = psz_uri != NULL ?
path = NULL; input_item_slave_New( psz_uri, SLAVE_TYPE_SPU, i_prio )
result[i_sub_count].psz_ext = strdup(tmp_fname_ext); : NULL;
i_sub_count++; if( p_sub )
INSERT_ELEM( pp_slaves, i_slaves, i_slaves, p_sub );
free( psz_uri );
} }
free( path ); free( path );
} }
...@@ -392,52 +351,53 @@ char **subtitles_Detect( input_thread_t *p_this, char *psz_path, ...@@ -392,52 +351,53 @@ char **subtitles_Detect( input_thread_t *p_this, char *psz_path,
free( f_fname_noext ); free( f_fname_noext );
free( psz_fname ); free( psz_fname );
if( !result ) for( int i = 0; i < i_slaves; i++ )
return NULL;
qsort( result, i_sub_count, sizeof(vlc_subfn_t), compare_sub_priority );
result2 = calloc( i_sub_count + 1, sizeof(char*) );
for( j = 0, i_result2 = 0; j < i_sub_count && result2 != NULL; j++ )
{ {
bool b_reject = false; input_item_slave_t *p_sub = pp_slaves[i];
if( !result[j].psz_fname || !result[j].psz_ext ) /* memory out */ bool b_reject = false;
break; char *psz_ext = strrchr( p_sub->psz_uri, '.' );
if( !psz_ext )
continue;
psz_ext++;
if( !strcasecmp( result[j].psz_ext, "sub" ) ) if( !strcasecmp( psz_ext, "sub" ) )
{ {
int i; for( int j = 0; j < i_slaves; j++ )
for( i = 0; i < i_sub_count; i++ )
{ {
if( result[i].psz_fname && result[i].psz_ext && input_item_slave_t *p_sub_inner = pp_slaves[j];
!strncasecmp( result[j].psz_fname, result[i].psz_fname,
strlen( result[j].psz_fname) - 3 ) && /* check that the filenames without extension match */
!strcasecmp( result[i].psz_ext, "idx" ) ) if( strncasecmp( p_sub->psz_uri, p_sub_inner->psz_uri,
strlen( p_sub->psz_uri ) - 3 ) )
continue;
char *psz_ext_inner = strrchr( p_sub_inner->psz_uri, '.' );
if( !psz_ext_inner )
continue;
psz_ext_inner++;
/* check that we have an idx file */
if( !strcasecmp( psz_ext_inner, "idx" ) )
{
b_reject = true;
break; break;
}
} }
if( i < i_sub_count )
b_reject = true;
} }
else if( !strcasecmp( result[j].psz_ext, "cdg" ) ) else if( !strcasecmp( psz_ext, "cdg" ) )
{ {
if( result[j].priority < SUB_PRIORITY_MATCH_ALL ) if( p_sub->i_priority < SLAVE_PRIORITY_MATCH_ALL )
b_reject = true; b_reject = true;
} }
if( b_reject )
/* */ {
if( !b_reject ) pp_slaves[i] = NULL;
result2[i_result2++] = strdup( result[j].psz_fname ); input_item_slave_Delete( p_sub );
} }
for( j = 0; j < i_sub_count; j++ )
{
free( result[j].psz_fname );
free( result[j].psz_ext );
} }
free( result );
return result2; *ppp_slaves = pp_slaves; /* in case of realloc */
*p_slaves = i_slaves;
return VLC_SUCCESS;
} }
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