sub.c
来自「VLC媒体播放程序」· C语言 代码 · 共 1,224 行 · 第 1/3 页
C
1,224 行
/***************************************************************************** * sub.c: subtitle demux for external subtitle files ***************************************************************************** * Copyright (C) 1999-2004 VideoLAN * $Id: sub.c,v 1.52 2004/02/22 15:59:53 fenrir Exp $ * * Authors: Laurent Aimar <fenrir@via.ecp.fr> * Derk-Jan Hartman <hartman at videolan dot org> * * 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 <stdlib.h>#include <errno.h>#include <sys/types.h>#include <ctype.h>#include <vlc/vlc.h>#include <vlc/input.h>#include "vlc_video.h"#include <codecs.h>#include "sub.h"#if (!defined( WIN32 ) || defined(__MINGW32__))# include <dirent.h>#endif#define DVD_VIDEO_LB_LEN 2048static int Open ( vlc_object_t *p_this );static int sub_open ( subtitle_demux_t *p_sub, input_thread_t *p_input, char *psz_name, mtime_t i_microsecperframe );static int sub_demux( subtitle_demux_t *p_sub, mtime_t i_maxdate );static int sub_seek ( subtitle_demux_t *p_sub, mtime_t i_date );static void sub_close( subtitle_demux_t *p_sub );static void sub_fix( subtitle_demux_t *p_sub );static char *ppsz_sub_type[] = { "auto", "microdvd", "subrip", "ssa1", "ssa2-4", "vplayer", "sami", "vobsub" };/***************************************************************************** * Module descriptor *****************************************************************************/#define SUB_DELAY_LONGTEXT \ "Delay subtitles (in 1/10s)"#define SUB_FPS_LONGTEXT \ "Override frames per second. " \ "It will only work with MicroDVD subtitles."#define SUB_TYPE_LONGTEXT \ "One from \"microdvd\", \"subrip\", \"ssa1\", \"ssa2-4\", \"vplayer\" " \ "\"sami\" (auto for autodetection, it should always work)."vlc_module_begin(); set_description( _("Text subtitles demux") ); set_capability( "subtitle demux", 12 ); add_float( "sub-fps", 25.0, NULL, N_("Frames per second"), SUB_FPS_LONGTEXT, VLC_TRUE ); add_integer( "sub-delay", 0, NULL, N_("Delay subtitles (in 1/10s)"), SUB_DELAY_LONGTEXT, VLC_TRUE ); add_string( "sub-type", "auto", NULL, "Subtitles fileformat", SUB_TYPE_LONGTEXT, VLC_TRUE ); change_string_list( ppsz_sub_type, 0, 0 ); set_callbacks( Open, NULL );vlc_module_end();/***************************************************************************** * Module initializer *****************************************************************************/static int Open ( vlc_object_t *p_this ){ subtitle_demux_t *p_sub = (subtitle_demux_t*)p_this; p_sub->pf_open = sub_open; p_sub->pf_demux = sub_demux; p_sub->pf_seek = sub_seek; p_sub->pf_close = sub_close; /* Initialize the variables */ var_Create( p_this, "sub-fps", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT ); var_Create( p_this, "sub-delay", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT ); var_Create( p_this, "sub-type", VLC_VAR_STRING | VLC_VAR_DOINHERIT ); return VLC_SUCCESS;}#define MAX_TRY 256#define MAX_LINE 2048#define FREE( p ) if( p ) { free( p); (p) = NULL; }typedef struct{ int i_line_count; int i_line; char **line;} text_t;static int text_load( text_t *txt, char *psz_name ){ FILE *f; int i_line_max; /* init txt */ i_line_max = 100; txt->i_line_count = 0; txt->i_line = 0; txt->line = calloc( i_line_max, sizeof( char * ) ); /* open file */ if( !( f = fopen( psz_name, "rb" ) ) ) { return VLC_EGENERIC; } /* load the complete file */ for( ;; ) { char buffer[8096]; char *p; if( fgets( buffer, 8096, f ) <= 0) { break; } while( ( p = strchr( buffer, '\r' ) ) ) { *p = '\0'; } while( ( p = strchr( buffer, '\n' ) ) ) { *p = '\0'; } txt->line[txt->i_line_count++] = strdup( buffer ); if( txt->i_line_count >= i_line_max ) { i_line_max += 100; txt->line = realloc( txt->line, i_line_max * sizeof( char*) ); } } fclose( f ); if( txt->i_line_count <= 0 ) { FREE( txt->line ); return( VLC_EGENERIC ); } return( VLC_SUCCESS );}static void text_unload( text_t *txt ){ int i; for( i = 0; i < txt->i_line_count; i++ ) { FREE( txt->line[i] ); } FREE( txt->line ); txt->i_line = 0; txt->i_line_count = 0;}static char *text_get_line( text_t *txt ){ if( txt->i_line >= txt->i_line_count ) { return( NULL ); } return( txt->line[txt->i_line++] );}static void text_previous_line( text_t *txt ){ if( txt->i_line > 0 ) { txt->i_line--; }}static void text_rewind( text_t *txt ){ txt->i_line = 0;}static int sub_MicroDvdRead( subtitle_demux_t *p_sub, text_t *txt, subtitle_t *p_subtitle, mtime_t i_microsecperframe );static int sub_SubRipRead ( subtitle_demux_t *p_sub, text_t *txt, subtitle_t *p_subtitle, mtime_t i_microsecperframe );static int sub_SSARead ( subtitle_demux_t *p_sub, text_t *txt, subtitle_t *p_subtitle, mtime_t i_microsecperframe );static int sub_Vplayer ( subtitle_demux_t *p_sub, text_t *txt, subtitle_t *p_subtitle, mtime_t i_microsecperframe );static int sub_Sami ( subtitle_demux_t *p_sub, text_t *txt, subtitle_t *p_subtitle, mtime_t i_microsecperframe );static int sub_VobSubIDX ( subtitle_demux_t *p_sub, text_t *txt, subtitle_t *p_subtitle, mtime_t i_microsecperframe );static int DemuxVobSub ( subtitle_demux_t *, block_t * );static struct{ char *psz_type_name; int i_type; char *psz_name; int (*pf_read_subtitle) ( subtitle_demux_t *, text_t *, subtitle_t*, mtime_t );} sub_read_subtitle_function [] ={ { "microdvd", SUB_TYPE_MICRODVD, "MicroDVD", sub_MicroDvdRead }, { "subrip", SUB_TYPE_SUBRIP, "SubRIP", sub_SubRipRead }, { "ssa1", SUB_TYPE_SSA1, "SSA-1", sub_SSARead }, { "ssa2-4", SUB_TYPE_SSA2_4, "SSA-2/3/4",sub_SSARead }, { "vplayer", SUB_TYPE_VPLAYER, "VPlayer", sub_Vplayer }, { "sami", SUB_TYPE_SAMI, "SAMI", sub_Sami }, { "vobsub", SUB_TYPE_VOBSUB, "VobSub", sub_VobSubIDX }, { NULL, SUB_TYPE_UNKNOWN, "Unknown", NULL }};static char * local_stristr( char *psz_big, char *psz_little){ char *p_pos = psz_big; if (!psz_big || !psz_little || !*psz_little) return psz_big; while (*p_pos) { if (toupper(*p_pos) == toupper(*psz_little)) { char * psz_cur1 = p_pos + 1; char * psz_cur2 = psz_little + 1; while (*psz_cur1 && *psz_cur2 && toupper(*psz_cur1) == toupper(*psz_cur2)) { psz_cur1++; psz_cur2++; } if (!*psz_cur2) return p_pos; } p_pos++; } return NULL;}/***************************************************************************** * sub_open: Open a subtitle file and add subtitle ES *****************************************************************************/static int sub_open( subtitle_demux_t *p_sub, input_thread_t *p_input, char *psz_name, mtime_t i_microsecperframe ){ text_t txt; vlc_value_t val; es_format_t fmt; int i, i_sub_type, i_max; int (*pf_read_subtitle)( subtitle_demux_t *, text_t *, subtitle_t *, mtime_t ) = NULL; p_sub->i_sub_type = SUB_TYPE_UNKNOWN; p_sub->p_es = NULL; p_sub->i_subtitles = 0; p_sub->subtitle = NULL; p_sub->p_vobsub_file = 0; p_sub->p_input = p_input; if( !psz_name || !*psz_name ) { msg_Err( p_sub, "no subtitle file specified" ); return VLC_EGENERIC; } /* *** load the file *** */ if( text_load( &txt, psz_name ) ) { msg_Err( p_sub, "cannot open `%s' subtitle file", psz_name ); return VLC_EGENERIC; } msg_Dbg( p_sub, "opened `%s'", psz_name ); var_Get( p_sub, "sub-fps", &val ); if( val.i_int >= 1.0 ) { i_microsecperframe = (mtime_t)( (float)1000000 / val.f_float ); } else if( val.f_float <= 0 ) { i_microsecperframe = 40000; /* default: 25fps */ } var_Get( p_sub, "sub-type", &val); if( val.psz_string && *val.psz_string ) { int i; for( i = 0; ; i++ ) { if( sub_read_subtitle_function[i].psz_type_name == NULL ) { i_sub_type = SUB_TYPE_UNKNOWN; break; } if( !strcmp( sub_read_subtitle_function[i].psz_type_name, val.psz_string ) ) { i_sub_type = sub_read_subtitle_function[i].i_type; break; } } } else { i_sub_type = SUB_TYPE_UNKNOWN; } FREE( val.psz_string ); /* *** Now try to autodetect subtitle format *** */ if( i_sub_type == SUB_TYPE_UNKNOWN ) { int i_try; char *s; msg_Dbg( p_input, "trying to autodetect file format" ); for( i_try = 0; i_try < MAX_TRY; i_try++ ) { int i_dummy; if( ( s = text_get_line( &txt ) ) == NULL ) { break; } if( local_stristr( s, "<SAMI>" ) ) { i_sub_type = SUB_TYPE_SAMI; break; } else if( sscanf( s, "{%d}{%d}", &i_dummy, &i_dummy ) == 2 || sscanf( s, "{%d}{}", &i_dummy ) == 1) { i_sub_type = SUB_TYPE_MICRODVD; break; } else if( sscanf( s, "%d:%d:%d,%d --> %d:%d:%d,%d", &i_dummy,&i_dummy,&i_dummy,&i_dummy, &i_dummy,&i_dummy,&i_dummy,&i_dummy ) == 8 ) { i_sub_type = SUB_TYPE_SUBRIP; break; } else if( sscanf( s, "!: This is a Sub Station Alpha v%d.x script.", &i_dummy ) == 1) { if( i_dummy <= 1 ) { i_sub_type = SUB_TYPE_SSA1; } else { i_sub_type = SUB_TYPE_SSA2_4; /* I hope this will work */ } break; } else if( local_stristr( s, "This is a Sub Station Alpha v4 script" ) ) { i_sub_type = SUB_TYPE_SSA2_4; /* I hope this will work */ break; } else if( !strncasecmp( s, "Dialogue: Marked", 16 ) ) { i_sub_type = SUB_TYPE_SSA2_4; /* could be wrong */ break; } else if( sscanf( s, "%d:%d:%d:", &i_dummy, &i_dummy, &i_dummy ) == 3 || sscanf( s, "%d:%d:%d ", &i_dummy, &i_dummy, &i_dummy ) == 3 ) { i_sub_type = SUB_TYPE_VPLAYER; break; } else if( local_stristr( s, "# VobSub index file" ) ) { i_sub_type = SUB_TYPE_VOBSUB; break; } } text_rewind( &txt ); } /* *** Load this file in memory *** */ for( i = 0; ; i++ ) { if( sub_read_subtitle_function[i].i_type == SUB_TYPE_UNKNOWN )
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?