From 5bf8706d1f6536cd89207b777161ab83195ddb20 Mon Sep 17 00:00:00 2001 From: wm4 Date: Sat, 8 Dec 2012 13:59:49 +0100 Subject: sub: remove vobsub reader in favor of ffmpeg vobsub demuxer ffmpeg recently added a demuxer that can read vobsubs (pairs of .sub and .idx files). Get rid of the internal vobsub reader, and use the ffmpeg demuxer instead. Sneak in an unrelated manpage change (autosub default). --- DOCS/man/en/changes.rst | 1 + DOCS/man/en/options.rst | 19 +- Makefile | 1 - core/cfg-mplayer.h | 5 - core/command.c | 1 - core/mp_core.h | 10 - core/mplayer.c | 125 ++---- core/mplayer.h | 2 - demux/demux.c | 10 + sub/find_subfiles.c | 53 +-- sub/find_subfiles.h | 1 - sub/spudec.c | 28 +- sub/vobsub.c | 980 ------------------------------------------------ sub/vobsub.h | 43 --- 14 files changed, 74 insertions(+), 1205 deletions(-) delete mode 100644 sub/vobsub.c delete mode 100644 sub/vobsub.h diff --git a/DOCS/man/en/changes.rst b/DOCS/man/en/changes.rst index c2cceddcfc..82066cb75c 100644 --- a/DOCS/man/en/changes.rst +++ b/DOCS/man/en/changes.rst @@ -112,6 +112,7 @@ Command line switches -sub-fuzziness --autosub-match -subfont-text-scale --sub-scale -spugauss --sub-gauss + -vobsub --sub (pass the .idx file) =================================== =================================== input.conf and slave commands diff --git a/DOCS/man/en/options.rst b/DOCS/man/en/options.rst index 1e24d2b071..4f2acc5793 100644 --- a/DOCS/man/en/options.rst +++ b/DOCS/man/en/options.rst @@ -205,6 +205,8 @@ :fuzzy: Load all subs containing movie name. :all: Load all subs in the current and ``--sub-paths`` directories. + (Default: exact.) + --autosync= Gradually adjusts the A/V sync based on audio delay measurements. Specifying ``--autosync=0``, the default, will cause frame timing to be @@ -779,10 +781,6 @@ *NOTE*: This option only works if the underlying media supports seeking (i.e. not with stdin, pipe, etc). ---ifo= - Indicate the VOBsub IFO file that will be used to load palette and frame - size for VOBsub subtitles. - --ignore-start Matters with the builtin AVI demuxer only, which is not enabled by default. Ignore the specified starting time for streams in AVI files. This @@ -1692,7 +1690,7 @@ --sid= Display the subtitle stream specified by (0-31). ``auto`` selects the default, ``no`` disables subtitles. - See also ``--slang``, ``--vobsubid``, ``--no-sub``. + See also ``--slang``, ``--no-sub``. --slang= Specify a priority list of subtitle languages to use. Different container @@ -1883,7 +1881,9 @@ Open the given file with a demuxer, and use its subtitle streams. Same as ``--audiofile``, but for subtitle streams. - Use ``--sub`` for normal text subtitle files. + *NOTE*: use ``--sub`` for subtitle files. This option is useless, unless + you want to force libavformat subtitle parsers instead of libass or + internal subtitle parsers. --subfps= Specify the framerate of the subtitle file (default: movie fps). @@ -2210,13 +2210,6 @@ configuration files specifying a list of fallbacks may make sense. See `video_outputs` for details and descriptions of available drivers. ---vobsub= - Specify a VOBsub file to use for subtitles. Has to be the full pathname - without extension, i.e. without the ``.idx``, ``.ifo`` or ``.sub``. - ---vobsubid=<0-31> - Specify the VOBsub subtitle ID. - --volstep=<0-100> Set the step size of mixer volume changes in percent of the whole range (default: 3). diff --git a/Makefile b/Makefile index e5808bc3c4..16299e3744 100644 --- a/Makefile +++ b/Makefile @@ -225,7 +225,6 @@ SOURCES = talloc.c \ sub/sub.c \ sub/subassconvert.c \ sub/subreader.c \ - sub/vobsub.c \ video/csputils.c \ video/fmt-conversion.c \ video/image_writer.c \ diff --git a/core/cfg-mplayer.h b/core/cfg-mplayer.h index 310405dee2..6534672223 100644 --- a/core/cfg-mplayer.h +++ b/core/cfg-mplayer.h @@ -498,8 +498,6 @@ const m_option_t common_opts[] = { {"subfps", &sub_fps, CONF_TYPE_FLOAT, 0, 0.0, 10.0, NULL}, OPT_MAKE_FLAGS("autosub", sub_auto, 0), {"sub-forced-only", &forced_subs_only, CONF_TYPE_FLAG, 0, 0, 1, NULL}, - // specify IFO file for VOBSUB subtitle - {"ifo", &spudec_ifo, CONF_TYPE_STRING, 0, 0, 0, NULL}, // enable Closed Captioning display {"overlapsub", &suboverlap_enabled, CONF_TYPE_FLAG, 0, 0, 2, NULL}, {"sub-no-text-pp", &sub_no_text_pp, CONF_TYPE_FLAG, 0, 0, 1, NULL}, @@ -649,9 +647,6 @@ const m_option_t mplayer_opts[]={ OPT_INTRANGE("osd-duration", osd_duration, 0, 0, 3600000), OPT_MAKE_FLAGS("osd-fractions", osd_fractions, 0), - OPT_STRING("vobsub", vobsub_name, 0), - {"vobsubid", &vobsub_id, CONF_TYPE_INT, CONF_RANGE, 0, 31, NULL}, - {"sstep", &step_sec, CONF_TYPE_DOUBLE, CONF_MIN, 0, 0, NULL}, OPT_CHOICE("framedrop", frame_dropping, 0, diff --git a/core/command.c b/core/command.c index 7f2940fbaa..1e4ccd88bc 100644 --- a/core/command.c +++ b/core/command.c @@ -52,7 +52,6 @@ #include "video/decode/dec_video.h" #include "audio/decode/dec_audio.h" #include "osdep/strsep.h" -#include "sub/vobsub.h" #include "sub/spudec.h" #include "core/path.h" #include "sub/ass_mp.h" diff --git a/core/mp_core.h b/core/mp_core.h index f633f3481f..92803d2dd0 100644 --- a/core/mp_core.h +++ b/core/mp_core.h @@ -35,7 +35,6 @@ #define INITIALIZED_GETCH2 8 #define INITIALIZED_SPUDEC 32 #define INITIALIZED_STREAM 64 -#define INITIALIZED_VOBSUB 256 #define INITIALIZED_DEMUXER 512 #define INITIALIZED_ACODEC 1024 #define INITIALIZED_VCODEC 2048 @@ -43,12 +42,6 @@ #define INITIALIZED_ALL 0xFFFF -#define SUB_SOURCE_SUBS 0 -#define SUB_SOURCE_VOBSUB 1 -#define SUB_SOURCE_DEMUX 2 -#define SUB_SOURCES 3 - - enum stop_play_reason { KEEP_PLAYING = 0, // must be 0, numeric values of others do not matter AT_END_OF_FILE, // file has ended normally, prepare to play next @@ -120,9 +113,6 @@ struct track { // External text subtitle using non-libass subtitle renderer. struct sub_data *subdata; - - // External image subtitle (data is in vo_vobsub). 0 if not set. - int vobsub_id_plus_one; }; typedef struct MPContext { diff --git a/core/mplayer.c b/core/mplayer.c index 81302f284f..5ef73de0f7 100644 --- a/core/mplayer.c +++ b/core/mplayer.c @@ -92,7 +92,6 @@ #include "core/codec-cfg.h" #include "sub/spudec.h" -#include "sub/vobsub.h" #include "osdep/getch2.h" #include "osdep/timer.h" @@ -217,8 +216,6 @@ char **video_fm_list; // override video codec family // use this to allow dvdnav to follow -slang across stream resets, // in particular the subtitle ID for a language changes int dvdsub_lang_id; -int vobsub_id = -1; -static char *spudec_ifo = NULL; int forced_subs_only = 0; // A-V sync: @@ -246,6 +243,9 @@ int use_filedir_conf; static void reset_subtitles(struct MPContext *mpctx); static void reinit_subs(struct MPContext *mpctx); +static struct track *open_external_file(struct MPContext *mpctx, char *filename, + char *demuxer_name, int stream_cache, + enum stream_type filter); static float get_relative_time(struct MPContext *mpctx) { @@ -605,13 +605,6 @@ void uninit_player(struct MPContext *mpctx, unsigned int mask) getch2_disable(); } - if (mask & INITIALIZED_VOBSUB) { - mpctx->initialized_flags &= ~INITIALIZED_VOBSUB; - if (vo_vobsub) - vobsub_close(vo_vobsub); - vo_vobsub = NULL; - } - if (mask & INITIALIZED_SPUDEC) { mpctx->initialized_flags &= ~INITIALIZED_SPUDEC; spudec_free(vo_spudec); @@ -1001,6 +994,10 @@ struct track *mp_add_subtitles(struct MPContext *mpctx, char *filename, if (!sh && !subd) { + struct track *ext = open_external_file(mpctx, filename, NULL, 0, + STREAM_SUB); + if (ext) + return ext; mp_tmsg(MSGT_CPLAYER, noerr ? MSGL_WARN : MSGL_ERR, "Cannot load subtitles: %s\n", filename); return NULL; @@ -1030,13 +1027,6 @@ void init_vo_spudec(struct MPContext *mpctx) if (!mpctx->sh_video) return; - if (spudec_ifo) { - unsigned int palette[16]; - if (vobsub_parse_ifo(NULL, spudec_ifo, palette, &width, &height, - 1, -1, NULL) >= 0) - vo_spudec = spudec_new_scaled(palette, width, height, NULL, 0); - } - width = mpctx->sh_video->disp_w; height = mpctx->sh_video->disp_h; @@ -1796,26 +1786,14 @@ static void update_subtitles(struct MPContext *mpctx, double refpts_tl) } // DVD sub: - if ((track->vobsub_id_plus_one || type == 'v') - && !(sh_sub && sh_sub->active)) - { + if (type == 'v' && !(sh_sub && sh_sub->active)) { int timestamp; // Get a sub packet from the demuxer (or the vobsub.c thing, which // should be a demuxer, but isn't). while (1) { // Vobsub len = 0; - if (track->vobsub_id_plus_one) { - if (curpts_s >= 0) { - len = vobsub_get_packet(vo_vobsub, curpts_s, - (void **)&packet, ×tamp); - if (len > 0) - mp_dbg(MSGT_CPLAYER, MSGL_V, "\rVOB sub: len=%d " - "v_pts=%5.3f v_timer=%5.3f sub=%5.3f ts=%d \n", - len, refpts_s, sh_video->timer, - timestamp / 90000.0, timestamp); - } - } else { + { // DVD sub assert(d_sub->sh == sh_sub); len = ds_get_packet_sub(d_sub, (unsigned char **)&packet); @@ -1843,7 +1821,7 @@ static void update_subtitles(struct MPContext *mpctx, double refpts_tl) // PGS subtitles. if (!vo_spudec) vo_spudec = spudec_new(NULL); - if (track->vobsub_id_plus_one || timestamp >= 0) + if (timestamp >= 0) spudec_assemble(vo_spudec, packet, len, timestamp); } } else if (d_sub && (is_text_sub(type) || (sh_sub && sh_sub->active))) { @@ -1854,6 +1832,9 @@ static void update_subtitles(struct MPContext *mpctx, double refpts_tl) while (d_sub->first) { double subpts_s = ds_get_next_pts(d_sub); if (subpts_s > curpts_s) { + mp_dbg(MSGT_CPLAYER, MSGL_V, + "Sub early: c_pts=%5.3f s_pts=%5.3f\n", + curpts_s, subpts_s); // Libass handled subs can be fed to it in advance if (!opts->ass_enabled || !is_text_sub(type)) break; @@ -1874,10 +1855,8 @@ static void update_subtitles(struct MPContext *mpctx, double refpts_tl) } if (sh_sub && sh_sub->active) { sub_decode(sh_sub, mpctx->osd, packet, len, subpts_s, duration); - continue; - } - // is_text_sub() case - if (subpts_s != MP_NOPTS_VALUE) { + } else if (subpts_s != MP_NOPTS_VALUE) { + // text sub if (duration < 0) sub_clear_text(&mpctx->subs, MP_NOPTS_VALUE); if (type == 'a') { // ssa/ass subs without libass => convert to plaintext @@ -2000,8 +1979,6 @@ static void reinit_subs(struct MPContext *mpctx) init_demux_stream(mpctx, STREAM_SUB); - vobsub_id = -1; - if (!track) return; @@ -2023,9 +2000,7 @@ static void reinit_subs(struct MPContext *mpctx) mpctx->initialized_flags |= INITIALIZED_SUB; - if (track->vobsub_id_plus_one) { - vobsub_id = track->vobsub_id_plus_one - 1; - } else if (track->subdata || track->sh_sub) { + if (track->subdata || track->sh_sub) { #ifdef CONFIG_ASS if (opts->ass_enabled && track->sh_sub) sub_init(track->sh_sub, mpctx->osd); @@ -2717,7 +2692,7 @@ static void seek_reset(struct MPContext *mpctx, bool reset_ao, bool reset_ac) mpctx->delay = 0; mpctx->time_frame = 0; // Not all demuxers set d_video->pts during seek, so this value - // (which is used by at least vobsub code below) may be completely + // (which was used by at least vobsub code below) may be completely // wrong (probably 0). mpctx->sh_video->pts = mpctx->sh_video->ds->pts + mpctx->video_offset; mpctx->video_pts = mpctx->sh_video->pts; @@ -2733,10 +2708,6 @@ static void seek_reset(struct MPContext *mpctx, bool reset_ao, bool reset_ac) reset_subtitles(mpctx); - if (vo_vobsub && mpctx->sh_video) { - vobsub_seek(vo_vobsub, mpctx->sh_video->pts); - } - mpctx->restart_playback = true; mpctx->hrseek_active = false; mpctx->hrseek_framedrop = false; @@ -3600,7 +3571,6 @@ static int match_lang(char **langs, char *lang) * Sort tracks based on the following criteria, and pick the first: * 0) track matches tid (always wins) * 1) track is external - * 1.5) track is external and vobsub and has higher vobsub ID * 2) earlier match in lang list * 3) track is marked default * 4) lower track number @@ -3618,8 +3588,6 @@ static bool compare_track(struct track *t1, struct track *t2, char **langs) return l1 > l2; if (t1->default_track != t2->default_track) return t1->default_track; - if (t1->vobsub_id_plus_one != t2->vobsub_id_plus_one) - return t1->vobsub_id_plus_one >= t2->vobsub_id_plus_one; return t1->user_tid <= t2->user_tid; } static struct track *select_track(struct MPContext *mpctx, @@ -3680,45 +3648,6 @@ static void init_input(struct MPContext *mpctx) stream_set_interrupt_callback(mp_input_check_interrupt, mpctx->input); } -static void open_vobsubs_from_options(struct MPContext *mpctx) -{ - if (mpctx->opts.vobsub_name) { - vo_vobsub = vobsub_open(mpctx->opts.vobsub_name, spudec_ifo, 1, &vo_spudec); - if (vo_vobsub == NULL) - mp_tmsg(MSGT_CPLAYER, MSGL_ERR, "Cannot load subtitles: %s\n", - mpctx->opts.vobsub_name); - } else if (mpctx->opts.sub_auto) { - char **vob = find_vob_subtitles(&mpctx->opts, mpctx->filename); - for (int i = 0; i < MP_TALLOC_ELEMS(vob); i++) { - vo_vobsub = vobsub_open(vob[i], spudec_ifo, 0, &vo_spudec); - if (vo_vobsub) - break; - } - talloc_free(vob); - } - if (vo_vobsub) { - mpctx->initialized_flags |= INITIALIZED_VOBSUB; - // TODO: let frontend do the selection - vobsub_set_from_lang(vo_vobsub, mpctx->opts.sub_lang); - mp_property_do("sub-forced-only", M_PROPERTY_SET, &forced_subs_only, - mpctx); - - for (int i = 0; i < vobsub_get_indexes_count(vo_vobsub); i++) { - int id = vobsub_get_id_by_index(vo_vobsub, i); - struct track *track = talloc_ptrtype(NULL, track); - *track = (struct track) { - .type = STREAM_SUB, - .user_tid = find_new_tid(mpctx, STREAM_SUB), - .demuxer_id = -1, - .lang = talloc_strdup(track, vobsub_get_id(vo_vobsub, id)), - .is_external = true, - .vobsub_id_plus_one = id + 1, - }; - MP_TARRAY_APPEND(mpctx, mpctx->tracks, mpctx->num_tracks, track); - } - } -} - static void open_subtitles_from_options(struct MPContext *mpctx) { // after reading video params we should load subtitles because @@ -3738,13 +3667,13 @@ static void open_subtitles_from_options(struct MPContext *mpctx) } } -static void open_external_file(struct MPContext *mpctx, char *filename, - char *demuxer_name, int stream_cache, - enum stream_type filter) +static struct track *open_external_file(struct MPContext *mpctx, char *filename, + char *demuxer_name, int stream_cache, + enum stream_type filter) { struct MPOpts *opts = &mpctx->opts; if (!filename) - return; + return NULL; int format = 0; struct stream *stream = open_stream(filename, &mpctx->opts, &format); if (!stream) @@ -3767,7 +3696,7 @@ static void open_external_file(struct MPContext *mpctx, char *filename, free_stream(stream); goto err_out; } - int num_added = 0; + struct track *first = NULL; for (int n = 0; n < demuxer->num_streams; n++) { struct sh_stream *stream = demuxer->streams[n]; if (stream->type == filter) { @@ -3775,19 +3704,22 @@ static void open_external_file(struct MPContext *mpctx, char *filename, t->is_external = true; t->title = talloc_strdup(t, filename); t->external_filename = talloc_strdup(t, filename); - num_added++; + first = t; } } - if (num_added == 0) { + if (!first) { + free_demuxer(demuxer); mp_msg(MSGT_CPLAYER, MSGL_WARN, "No streams added from file %s.\n", filename); + goto err_out; } MP_TARRAY_APPEND(NULL, mpctx->sources, mpctx->num_sources, demuxer); - return; + return first; err_out: mp_msg(MSGT_CPLAYER, MSGL_ERR, "Can not open external file %s.\n", filename); + return false; } static void open_audiofiles_from_options(struct MPContext *mpctx) @@ -4048,7 +3980,6 @@ goto_enable_cache: ; add_subtitle_fonts_from_sources(mpctx); open_subtitles_from_options(mpctx); - open_vobsubs_from_options(mpctx); open_audiofiles_from_options(mpctx); open_subfiles_from_options(mpctx); diff --git a/core/mplayer.h b/core/mplayer.h index 004c770901..0471a3137d 100644 --- a/core/mplayer.h +++ b/core/mplayer.h @@ -31,8 +31,6 @@ extern float audio_delay; extern double force_fps; -extern int vobsub_id; - struct MPContext; struct MPOpts; struct subtitle; diff --git a/demux/demux.c b/demux/demux.c index f765b2ae87..41b74b20c4 100644 --- a/demux/demux.c +++ b/demux/demux.c @@ -459,6 +459,16 @@ void free_demuxer(demuxer_t *demuxer) void ds_add_packet(demux_stream_t *ds, demux_packet_t *dp) { + // demux API can't handle 0-sized packets, but at least some vobsubs + // generate them. Skipping them seems to work fine. Not skipping them will + // stop demuxing with external vobsubs. See FATE sub/vobsub.{idx,sub} at + // pts=185.91. + if (dp->len == 0 && ds->stream_type == STREAM_SUB) { + mp_dbg(MSGT_DEMUXER, MSGL_INFO, "Discarding empty subtitle packet.\n"); + free_demux_packet(dp); + return; + } + // append packet to DS stream: ++ds->packs; ds->bytes += dp->len; diff --git a/sub/find_subfiles.c b/sub/find_subfiles.c index 502fc911dc..95004b564f 100644 --- a/sub/find_subfiles.c +++ b/sub/find_subfiles.c @@ -87,7 +87,7 @@ static void append_dir_subtitles(struct MPOpts *opts, struct bstr path, const char *fname, int limit_fuzziness) { - char *sub_exts[] = {"utf", "utf8", "utf-8", "sub", "srt", "smi", "rt", "txt", "ssa", "aqt", "jss", "js", "ass", NULL}; + char *sub_exts[] = {"utf", "utf8", "utf-8", "idx", "sub", "srt", "smi", "rt", "txt", "ssa", "aqt", "jss", "js", "ass", NULL}; void *tmpmem = talloc_new(NULL); FILE *f; assert(strlen(fname) < 1e6); @@ -117,20 +117,6 @@ static void append_dir_subtitles(struct MPOpts *opts, struct bstr tmp_fname_ext = get_ext(dename); struct bstr tmp_fname_trim = bstr_strip(tmp_fname_noext); - // If it's a .sub, check if there is a .idx with the same name. If - // there is one, it's certainly a vobsub so we skip it. - if (bstrcasecmp(tmp_fname_ext, bstr0("sub")) == 0) { - char *idxname = talloc_asprintf(tmpmem2, "%.*s.idx", - (int)tmp_fname_noext.len, - de->d_name); - char *idx = mp_path_join(tmpmem2, path, bstr0(idxname)); - f = fopen(idx, "rt"); - if (f) { - fclose(f); - goto next_sub; - } - } - // does it end with a subtitle extension? #ifdef CONFIG_ICONV #ifdef CONFIG_ENCA @@ -183,7 +169,7 @@ static void append_dir_subtitles(struct MPOpts *opts, if (prio) { prio += prio; #ifdef CONFIG_ICONV - if (i < 3) // prefer UTF-8 coded + if (i < 4) // prefer UTF-8 coded, or idx over sub (vobsubs) prio++; #endif char *subpath = mp_path_join(*slist, path, dename); @@ -241,38 +227,3 @@ char **find_text_subtitles(struct MPOpts *opts, const char *fname) talloc_free(slist); return subnames; } - -char **find_vob_subtitles(struct MPOpts *opts, const char *fname) -{ - char **vobs = talloc_array_ptrtype(NULL, vobs, 1); - int n = 0; - - // Potential vobsub in the media directory - struct bstr bname = bstr0(mp_basename(fname)); - int pdot = bstrrchr(bname, '.'); - if (pdot >= 0) - bname.len = pdot; - vobs[n++] = mp_path_join(vobs, mp_dirname(fname), bname); - - // Potential vobsubs in directories specified by sub-paths option - if (opts->sub_paths) { - for (int i = 0; opts->sub_paths[i]; i++) { - char *path = mp_path_join(NULL, mp_dirname(fname), - bstr0(opts->sub_paths[i])); - MP_GROW_ARRAY(vobs, n); - vobs[n++] = mp_path_join(vobs, bstr0(path), bname); - talloc_free(path); - } - } - - // Potential vobsub in ~/.mplayer/sub - char *mp_subdir = get_path("sub/"); - if (mp_subdir) { - MP_GROW_ARRAY(vobs, n); - vobs[n++] = mp_path_join(vobs, bstr0(mp_subdir), bname); - } - - free(mp_subdir); - MP_RESIZE_ARRAY(NULL, vobs, n); - return vobs; -} diff --git a/sub/find_subfiles.h b/sub/find_subfiles.h index c93164c6f8..6d68d6140c 100644 --- a/sub/find_subfiles.h +++ b/sub/find_subfiles.h @@ -24,6 +24,5 @@ struct MPOpts; char **find_text_subtitles(struct MPOpts *opts, const char *fname); -char **find_vob_subtitles(struct MPOpts *opts, const char *fname); #endif /* MPLAYER_FINDFILES_H */ diff --git a/sub/spudec.c b/sub/spudec.c index 22f121e92c..59c3058251 100644 --- a/sub/spudec.c +++ b/sub/spudec.c @@ -43,7 +43,6 @@ #include "core/mp_msg.h" #include "spudec.h" -#include "vobsub.h" #include "sub.h" #include "core/mp_common.h" #include "video/csputils.h" @@ -659,6 +658,33 @@ void spudec_get_indexed(void *this, struct mp_osd_res *dim, } } +static unsigned int vobsub_palette_to_yuv(unsigned int pal) +{ + int r, g, b, y, u, v; + // Palette in idx file is not rgb value, it was calculated by wrong formula. + // Here's reversed formula of the one used to generate palette in idx file. + r = pal >> 16 & 0xff; + g = pal >> 8 & 0xff; + b = pal & 0xff; + y = av_clip_uint8( 0.1494 * r + 0.6061 * g + 0.2445 * b); + u = av_clip_uint8( 0.6066 * r - 0.4322 * g - 0.1744 * b + 128); + v = av_clip_uint8(-0.08435 * r - 0.3422 * g + 0.4266 * b + 128); + y = y * 219 / 255 + 16; + return y << 16 | u << 8 | v; +} + +static unsigned int vobsub_rgb_to_yuv(unsigned int rgb) +{ + int r, g, b, y, u, v; + r = rgb >> 16 & 0xff; + g = rgb >> 8 & 0xff; + b = rgb & 0xff; + y = ( 0.299 * r + 0.587 * g + 0.114 * b) * 219 / 255 + 16.5; + u = (-0.16874 * r - 0.33126 * g + 0.5 * b) * 224 / 255 + 128.5; + v = ( 0.5 * r - 0.41869 * g - 0.08131 * b) * 224 / 255 + 128.5; + return y << 16 | u << 8 | v; +} + static void spudec_parse_extradata(spudec_handle_t *this, uint8_t *extradata, int extradata_len) { diff --git a/sub/vobsub.c b/sub/vobsub.c deleted file mode 100644 index 5ae7e6cf1a..0000000000 --- a/sub/vobsub.c +++ /dev/null @@ -1,980 +0,0 @@ -/* - * Some code freely inspired from VobSub , - * with kind permission from Gabest - * - * This file is part of MPlayer. - * - * MPlayer 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. - * - * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "config.h" -#include "core/mp_common.h" -#include "vobsub.h" -#include "spudec.h" -#include "core/mp_msg.h" -#include "core/path.h" -#include "libavutil/common.h" -#include "libavutil/intreadwrite.h" - -extern int vobsub_id; -// Record the original -vobsubid set by commandline, since vobsub_id will be -// overridden if slang match any of vobsub streams. -static int vobsubid = -2; - -typedef FILE rar_stream_t; -#define rar_open fopen -#define rar_close fclose -#define rar_eof feof -#define rar_tell ftell -#define rar_seek fseek -#define rar_getc getc -#define rar_read fread - -/**********************************************************************/ - -static ssize_t vobsub_getline(char **lineptr, size_t *n, rar_stream_t *stream) -{ - size_t res = 0; - int c; - if (*lineptr == NULL) { - *lineptr = malloc(4096); - if (*lineptr) - *n = 4096; - } else if (*n == 0) { - char *tmp = realloc(*lineptr, 4096); - if (tmp) { - *lineptr = tmp; - *n = 4096; - } - } - if (*lineptr == NULL || *n == 0) - return -1; - - for (c = rar_getc(stream); c != EOF; c = rar_getc(stream)) { - if (res + 1 >= *n) { - char *tmp = realloc(*lineptr, *n * 2); - if (tmp == NULL) - return -1; - *lineptr = tmp; - *n *= 2; - } - (*lineptr)[res++] = c; - if (c == '\n') { - (*lineptr)[res] = 0; - return res; - } - } - if (res == 0) - return -1; - (*lineptr)[res] = 0; - return res; -} - -/********************************************************************** - * MPEG parsing - **********************************************************************/ - -typedef struct { - rar_stream_t *stream; - unsigned int pts; - int aid; - unsigned char *packet; - unsigned int packet_reserve; - unsigned int packet_size; - int padding_was_here; - int merge; -} mpeg_t; - -static mpeg_t *mpeg_open(const char *filename) -{ - mpeg_t *res = malloc(sizeof(mpeg_t)); - int err = res == NULL; - if (!err) { - res->pts = 0; - res->aid = -1; - res->packet = NULL; - res->packet_size = 0; - res->packet_reserve = 0; - res->padding_was_here = 1; - res->merge = 0; - res->stream = rar_open(filename, "rb"); - err = res->stream == NULL; - if (err) - perror("fopen Vobsub file failed"); - if (err) - free(res); - } - return err ? NULL : res; -} - -static void mpeg_free(mpeg_t *mpeg) -{ - free(mpeg->packet); - if (mpeg->stream) - rar_close(mpeg->stream); - free(mpeg); -} - -static int mpeg_eof(mpeg_t *mpeg) -{ - return rar_eof(mpeg->stream); -} - -static off_t mpeg_tell(mpeg_t *mpeg) -{ - return rar_tell(mpeg->stream); -} - -static int mpeg_run(mpeg_t *mpeg) -{ - unsigned int len, idx, version; - int c; - /* Goto start of a packet, it starts with 0x000001?? */ - const unsigned char wanted[] = { 0, 0, 1 }; - unsigned char buf[5]; - - mpeg->aid = -1; - mpeg->packet_size = 0; - if (rar_read(buf, 4, 1, mpeg->stream) != 1) - return -1; - while (memcmp(buf, wanted, sizeof(wanted)) != 0) { - c = rar_getc(mpeg->stream); - if (c < 0) - return -1; - memmove(buf, buf + 1, 3); - buf[3] = c; - } - switch (buf[3]) { - case 0xb9: /* System End Code */ - break; - case 0xba: /* Packet start code */ - c = rar_getc(mpeg->stream); - if (c < 0) - return -1; - if ((c & 0xc0) == 0x40) - version = 4; - else if ((c & 0xf0) == 0x20) - version = 2; - else { - mp_msg(MSGT_VOBSUB, MSGL_ERR, "VobSub: Unsupported MPEG version: 0x%02x\n", c); - return -1; - } - if (version == 4) { - if (rar_seek(mpeg->stream, 9, SEEK_CUR)) - return -1; - } else if (version == 2) { - if (rar_seek(mpeg->stream, 7, SEEK_CUR)) - return -1; - } else - abort(); - if (!mpeg->padding_was_here) - mpeg->merge = 1; - break; - case 0xbd: /* packet */ - if (rar_read(buf, 2, 1, mpeg->stream) != 1) - return -1; - mpeg->padding_was_here = 0; - len = buf[0] << 8 | buf[1]; - idx = mpeg_tell(mpeg); - c = rar_getc(mpeg->stream); - if (c < 0) - return -1; - if ((c & 0xC0) == 0x40) { /* skip STD scale & size */ - if (rar_getc(mpeg->stream) < 0) - return -1; - c = rar_getc(mpeg->stream); - if (c < 0) - return -1; - } - if ((c & 0xf0) == 0x20) { /* System-1 stream timestamp */ - /* Do we need this? */ - abort(); - } else if ((c & 0xf0) == 0x30) { - /* Do we need this? */ - abort(); - } else if ((c & 0xc0) == 0x80) { /* System-2 (.VOB) stream */ - unsigned int pts_flags, hdrlen, dataidx; - c = rar_getc(mpeg->stream); - if (c < 0) - return -1; - pts_flags = c; - c = rar_getc(mpeg->stream); - if (c < 0) - return -1; - hdrlen = c; - dataidx = mpeg_tell(mpeg) + hdrlen; - if (dataidx > idx + len) { - mp_msg(MSGT_VOBSUB, MSGL_ERR, "Invalid header length: %d (total length: %d, idx: %d, dataidx: %d)\n", - hdrlen, len, idx, dataidx); - return -1; - } - if ((pts_flags & 0xc0) == 0x80) { - if (rar_read(buf, 5, 1, mpeg->stream) != 1) - return -1; - if (!(((buf[0] & 0xf0) == 0x20) && (buf[0] & 1) && (buf[2] & 1) && (buf[4] & 1))) { - mp_msg(MSGT_VOBSUB, MSGL_ERR, "vobsub PTS error: 0x%02x %02x%02x %02x%02x \n", - buf[0], buf[1], buf[2], buf[3], buf[4]); - mpeg->pts = 0; - } else - mpeg->pts = ((buf[0] & 0x0e) << 29 | buf[1] << 22 | (buf[2] & 0xfe) << 14 - | buf[3] << 7 | (buf[4] >> 1)); - } else /* if ((pts_flags & 0xc0) == 0xc0) */ { - /* what's this? */ - /* abort(); */ - } - rar_seek(mpeg->stream, dataidx, SEEK_SET); - mpeg->aid = rar_getc(mpeg->stream); - if (mpeg->aid < 0) { - mp_msg(MSGT_VOBSUB, MSGL_ERR, "Bogus aid %d\n", mpeg->aid); - return -1; - } - mpeg->packet_size = len - ((unsigned int) mpeg_tell(mpeg) - idx); - if (mpeg->packet_reserve < mpeg->packet_size) { - free(mpeg->packet); - mpeg->packet = malloc(mpeg->packet_size); - if (mpeg->packet) - mpeg->packet_reserve = mpeg->packet_size; - } - if (mpeg->packet == NULL) { - mp_msg(MSGT_VOBSUB, MSGL_FATAL, "malloc failure"); - mpeg->packet_reserve = 0; - mpeg->packet_size = 0; - return -1; - } - if (rar_read(mpeg->packet, mpeg->packet_size, 1, mpeg->stream) != 1) { - mp_msg(MSGT_VOBSUB, MSGL_ERR, "fread failure"); - mpeg->packet_size = 0; - return -1; - } - idx = len; - } - break; - case 0xbe: /* Padding */ - if (rar_read(buf, 2, 1, mpeg->stream) != 1) - return -1; - len = buf[0] << 8 | buf[1]; - if (len > 0 && rar_seek(mpeg->stream, len, SEEK_CUR)) - return -1; - mpeg->padding_was_here = 1; - break; - default: - if (0xc0 <= buf[3] && buf[3] < 0xf0) { - /* MPEG audio or video */ - if (rar_read(buf, 2, 1, mpeg->stream) != 1) - return -1; - len = buf[0] << 8 | buf[1]; - if (len > 0 && rar_seek(mpeg->stream, len, SEEK_CUR)) - return -1; - } else { - mp_msg(MSGT_VOBSUB, MSGL_ERR, "unknown header 0x%02X%02X%02X%02X\n", - buf[0], buf[1], buf[2], buf[3]); - return -1; - } - } - return 0; -} - -/********************************************************************** - * Packet queue - **********************************************************************/ - -typedef struct { - unsigned int pts100; - off_t filepos; - unsigned int size; - unsigned char *data; -} packet_t; - -typedef struct { - char *id; - packet_t *packets; - unsigned int packets_reserve; - unsigned int packets_size; - unsigned int current_index; -} packet_queue_t; - -static void packet_construct(packet_t *pkt) -{ - pkt->pts100 = 0; - pkt->filepos = 0; - pkt->size = 0; - pkt->data = NULL; -} - -static void packet_destroy(packet_t *pkt) -{ - free(pkt->data); -} - -static void packet_queue_construct(packet_queue_t *queue) -{ - queue->id = NULL; - queue->packets = NULL; - queue->packets_reserve = 0; - queue->packets_size = 0; - queue->current_index = 0; -} - -static void packet_queue_destroy(packet_queue_t *queue) -{ - if (queue->packets) { - while (queue->packets_size--) - packet_destroy(queue->packets + queue->packets_size); - free(queue->packets); - } - return; -} - -/* Make sure there is enough room for needed_size packets in the - packet queue. */ -static int packet_queue_ensure(packet_queue_t *queue, unsigned int needed_size) -{ - if (queue->packets_reserve < needed_size) { - if (queue->packets) { - packet_t *tmp = realloc(queue->packets, 2 * queue->packets_reserve * sizeof(packet_t)); - if (tmp == NULL) { - mp_msg(MSGT_VOBSUB, MSGL_FATAL, "realloc failure"); - return -1; - } - queue->packets = tmp; - queue->packets_reserve *= 2; - } else { - queue->packets = malloc(sizeof(packet_t)); - if (queue->packets == NULL) { - mp_msg(MSGT_VOBSUB, MSGL_FATAL, "malloc failure"); - return -1; - } - queue->packets_reserve = 1; - } - } - return 0; -} - -/* add one more packet */ -static int packet_queue_grow(packet_queue_t *queue) -{ - if (packet_queue_ensure(queue, queue->packets_size + 1) < 0) - return -1; - packet_construct(queue->packets + queue->packets_size); - ++queue->packets_size; - return 0; -} - -/* insert a new packet, duplicating pts from the current one */ -static int packet_queue_insert(packet_queue_t *queue) -{ - packet_t *pkts; - if (packet_queue_ensure(queue, queue->packets_size + 1) < 0) - return -1; - /* XXX packet_size does not reflect the real thing here, it will be updated a bit later */ - memmove(queue->packets + queue->current_index + 2, - queue->packets + queue->current_index + 1, - sizeof(packet_t) * (queue->packets_size - queue->current_index - 1)); - pkts = queue->packets + queue->current_index; - ++queue->packets_size; - ++queue->current_index; - packet_construct(pkts + 1); - pkts[1].pts100 = pkts[0].pts100; - pkts[1].filepos = pkts[0].filepos; - return 0; -} - -/********************************************************************** - * Vobsub - **********************************************************************/ - -typedef struct { - unsigned int palette[16]; - int delay; - unsigned int have_palette; - unsigned int orig_frame_width, orig_frame_height; - unsigned int origin_x, origin_y; - /* index */ - packet_queue_t *spu_streams; - unsigned int spu_streams_size; - unsigned int spu_streams_current; - unsigned int spu_valid_streams_size; -} vobsub_t; - -/* Make sure that the spu stream idx exists. */ -static int vobsub_ensure_spu_stream(vobsub_t *vob, unsigned int index) -{ - if (index >= vob->spu_streams_size) { - /* This is a new stream */ - if (vob->spu_streams) { - packet_queue_t *tmp = realloc(vob->spu_streams, (index + 1) * sizeof(packet_queue_t)); - if (tmp == NULL) { - mp_msg(MSGT_VOBSUB, MSGL_ERR, "vobsub_ensure_spu_stream: realloc failure"); - return -1; - } - vob->spu_streams = tmp; - } else { - vob->spu_streams = malloc((index + 1) * sizeof(packet_queue_t)); - if (vob->spu_streams == NULL) { - mp_msg(MSGT_VOBSUB, MSGL_ERR, "vobsub_ensure_spu_stream: malloc failure"); - return -1; - } - } - while (vob->spu_streams_size <= index) { - packet_queue_construct(vob->spu_streams + vob->spu_streams_size); - ++vob->spu_streams_size; - } - } - return 0; -} - -static int vobsub_add_id(vobsub_t *vob, const char *id, size_t idlen, - const unsigned int index) -{ - if (vobsub_ensure_spu_stream(vob, index) < 0) - return -1; - if (id && idlen) { - free(vob->spu_streams[index].id); - vob->spu_streams[index].id = malloc(idlen + 1); - if (vob->spu_streams[index].id == NULL) { - mp_msg(MSGT_VOBSUB, MSGL_FATAL, "vobsub_add_id: malloc failure"); - return -1; - } - vob->spu_streams[index].id[idlen] = 0; - memcpy(vob->spu_streams[index].id, id, idlen); - } - vob->spu_streams_current = index; - mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_VOBSUB_ID=%d\n", index); - if (id && idlen) - mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_VSID_%d_LANG=%s\n", index, vob->spu_streams[index].id); - mp_msg(MSGT_VOBSUB, MSGL_V, "[vobsub] subtitle (vobsubid): %d language %s\n", - index, vob->spu_streams[index].id); - return 0; -} - -static int vobsub_add_timestamp(vobsub_t *vob, off_t filepos, int ms) -{ - packet_queue_t *queue; - packet_t *pkt; - if (vob->spu_streams == 0) { - mp_msg(MSGT_VOBSUB, MSGL_WARN, "[vobsub] warning, binning some index entries. Check your index file\n"); - return -1; - } - queue = vob->spu_streams + vob->spu_streams_current; - if (packet_queue_grow(queue) >= 0) { - pkt = queue->packets + (queue->packets_size - 1); - pkt->filepos = filepos; - pkt->pts100 = ms < 0 ? UINT_MAX : (unsigned int)ms * 90; - return 0; - } - return -1; -} - -static int vobsub_parse_id(vobsub_t *vob, const char *line) -{ - // id: xx, index: n - size_t idlen; - const char *p, *q; - p = line; - while (isspace(*p)) - ++p; - q = p; - while (isalpha(*q)) - ++q; - idlen = q - p; - if (idlen == 0) - return -1; - ++q; - while (isspace(*q)) - ++q; - if (strncmp("index:", q, 6)) - return -1; - q += 6; - while (isspace(*q)) - ++q; - if (!isdigit(*q)) - return -1; - return vobsub_add_id(vob, p, idlen, atoi(q)); -} - -static int vobsub_parse_timestamp(vobsub_t *vob, const char *line) -{ - int h, m, s, ms; - int64_t filepos; - if (sscanf(line, " %02d:%02d:%02d:%03d, filepos: %09"SCNx64, - &h, &m, &s, &ms, &filepos) != 5) - return -1; - return vobsub_add_timestamp(vob, filepos, vob->delay + ms + 1000 * (s + 60 * (m + 60 * h))); -} - -static int vobsub_parse_origin(vobsub_t *vob, const char *line) -{ - // org: X,Y - unsigned x, y; - - if (sscanf(line, " %u,%u", &x, &y) == 2) { - vob->origin_x = x; - vob->origin_y = y; - return 0; - } - return -1; -} - -unsigned int vobsub_palette_to_yuv(unsigned int pal) -{ - int r, g, b, y, u, v; - // Palette in idx file is not rgb value, it was calculated by wrong formula. - // Here's reversed formula of the one used to generate palette in idx file. - r = pal >> 16 & 0xff; - g = pal >> 8 & 0xff; - b = pal & 0xff; - y = av_clip_uint8( 0.1494 * r + 0.6061 * g + 0.2445 * b); - u = av_clip_uint8( 0.6066 * r - 0.4322 * g - 0.1744 * b + 128); - v = av_clip_uint8(-0.08435 * r - 0.3422 * g + 0.4266 * b + 128); - y = y * 219 / 255 + 16; - return y << 16 | u << 8 | v; -} - -unsigned int vobsub_rgb_to_yuv(unsigned int rgb) -{ - int r, g, b, y, u, v; - r = rgb >> 16 & 0xff; - g = rgb >> 8 & 0xff; - b = rgb & 0xff; - y = ( 0.299 * r + 0.587 * g + 0.114 * b) * 219 / 255 + 16.5; - u = (-0.16874 * r - 0.33126 * g + 0.5 * b) * 224 / 255 + 128.5; - v = ( 0.5 * r - 0.41869 * g - 0.08131 * b) * 224 / 255 + 128.5; - return y << 16 | u << 8 | v; -} - -static int vobsub_parse_delay(vobsub_t *vob, const char *line) -{ - int h, m, s, ms; - int forward = 1; - if (*(line + 7) == '+') { - forward = 1; - line++; - } else if (*(line + 7) == '-') { - forward = -1; - line++; - } - mp_msg(MSGT_SPUDEC, MSGL_V, "forward=%d", forward); - h = atoi(line + 7); - mp_msg(MSGT_VOBSUB, MSGL_V, "h=%d,", h); - m = atoi(line + 10); - mp_msg(MSGT_VOBSUB, MSGL_V, "m=%d,", m); - s = atoi(line + 13); - mp_msg(MSGT_VOBSUB, MSGL_V, "s=%d,", s); - ms = atoi(line + 16); - mp_msg(MSGT_VOBSUB, MSGL_V, "ms=%d", ms); - vob->delay = (ms + 1000 * (s + 60 * (m + 60 * h))) * forward; - return 0; -} - -static int vobsub_set_lang(const char *line) -{ - if (vobsub_id == -1) - vobsub_id = atoi(line + 8); - return 0; -} - -static int vobsub_parse_one_line(vobsub_t *vob, rar_stream_t *fd, - unsigned char **extradata, - unsigned int *extradata_len) -{ - ssize_t line_size; - int res = -1; - size_t line_reserve = 0; - char *line = NULL; - do { - line_size = vobsub_getline(&line, &line_reserve, fd); - if (line_size < 0 || line_size > 1000000 || - *extradata_len+line_size > 10000000) { - break; - } - - *extradata = realloc(*extradata, *extradata_len+line_size+1); - memcpy(*extradata+*extradata_len, line, line_size); - *extradata_len += line_size; - (*extradata)[*extradata_len] = 0; - - if (*line == 0 || *line == '\r' || *line == '\n' || *line == '#') - continue; - else if (strncmp("langidx:", line, 8) == 0) - res = vobsub_set_lang(line); - else if (strncmp("delay:", line, 6) == 0) - res = vobsub_parse_delay(vob, line); - else if (strncmp("id:", line, 3) == 0) - res = vobsub_parse_id(vob, line + 3); - else if (strncmp("org:", line, 4) == 0) - res = vobsub_parse_origin(vob, line + 4); - else if (strncmp("timestamp:", line, 10) == 0) - res = vobsub_parse_timestamp(vob, line + 10); - else { - mp_msg(MSGT_VOBSUB, MSGL_V, "vobsub: ignoring %s", line); - continue; - } - if (res < 0) - mp_msg(MSGT_VOBSUB, MSGL_ERR, "ERROR in %s", line); - break; - } while (1); - free(line); - return res; -} - -int vobsub_parse_ifo(void* this, const char *const name, unsigned int *palette, - unsigned int *width, unsigned int *height, int force, - int sid, char *langid) -{ - vobsub_t *vob = this; - int res = -1; - rar_stream_t *fd = rar_open(name, "rb"); - if (fd == NULL) { - if (force) - mp_msg(MSGT_VOBSUB, MSGL_WARN, "VobSub: Can't open IFO file\n"); - } else { - // parse IFO header - unsigned char block[0x800]; - const char *const ifo_magic = "DVDVIDEO-VTS"; - if (rar_read(block, sizeof(block), 1, fd) != 1) { - if (force) - mp_msg(MSGT_VOBSUB, MSGL_ERR, "VobSub: Can't read IFO header\n"); - } else if (memcmp(block, ifo_magic, strlen(ifo_magic) + 1)) - mp_msg(MSGT_VOBSUB, MSGL_ERR, "VobSub: Bad magic in IFO header\n"); - else { - unsigned pgci_sector = AV_RB32(block + 0xcc); - int standard = (block[0x200] & 0x30) >> 4; - int resolution = (block[0x201] & 0x0c) >> 2; - *height = standard ? 576 : 480; - *width = 0; - switch (resolution) { - case 0x0: - *width = 720; - break; - case 0x1: - *width = 704; - break; - case 0x2: - *width = 352; - break; - case 0x3: - *width = 352; - *height /= 2; - break; - default: - mp_msg(MSGT_VOBSUB, MSGL_WARN, "Vobsub: Unknown resolution %d \n", resolution); - } - if (langid && 0 <= sid && sid < 32) { - unsigned char *tmp = block + 0x256 + sid * 6 + 2; - langid[0] = tmp[0]; - langid[1] = tmp[1]; - langid[2] = 0; - } - if (rar_seek(fd, pgci_sector * sizeof(block), SEEK_SET) - || rar_read(block, sizeof(block), 1, fd) != 1) - mp_msg(MSGT_VOBSUB, MSGL_ERR, "VobSub: Can't read IFO PGCI\n"); - else { - unsigned idx; - unsigned pgc_offset = AV_RB32(block + 0xc); - pgc_offset = FFMIN(pgc_offset, sizeof(block) - 0xa4 - 4*16); - for (idx = 0; idx < 16; ++idx) { - unsigned char *p = block + pgc_offset + 0xa4 + 4 * idx; - palette[idx] = AV_RB32(p); - } - if (vob) - vob->have_palette = 1; - res = 0; - } - } - rar_close(fd); - } - return res; -} - -void *vobsub_open(const char *const name, const char *const ifo, - const int force, void** spu) -{ - unsigned char *extradata = NULL; - unsigned int extradata_len = 0; - vobsub_t *vob = calloc(1, sizeof(vobsub_t)); - if (spu) - *spu = NULL; - if (vobsubid == -2) - vobsubid = vobsub_id; - if (vob) { - char *buf; - buf = malloc(strlen(name) + 5); - if (buf) { - rar_stream_t *fd; - mpeg_t *mpg; - /* read in the info file */ - if (!ifo) { - strcpy(buf, name); - strcat(buf, ".ifo"); - vobsub_parse_ifo(vob, buf, vob->palette, &vob->orig_frame_width, &vob->orig_frame_height, force, -1, NULL); - } else - vobsub_parse_ifo(vob, ifo, vob->palette, &vob->orig_frame_width, &vob->orig_frame_height, force, -1, NULL); - /* read in the index */ - strcpy(buf, name); - strcat(buf, ".idx"); - fd = rar_open(buf, "rb"); - if (fd == NULL) { - if (force) - mp_msg(MSGT_VOBSUB, MSGL_ERR, "VobSub: Can't open IDX file\n"); - else { - free(buf); - free(vob); - return NULL; - } - } else { - while (vobsub_parse_one_line(vob, fd, &extradata, &extradata_len) >= 0) - /* NOOP */ ; - rar_close(fd); - } - if (spu) - *spu = spudec_new_scaled(vob->palette, vob->orig_frame_width, vob->orig_frame_height, extradata, extradata_len); - free(extradata); - - /* read the indexed mpeg_stream */ - strcpy(buf, name); - strcat(buf, ".sub"); - mpg = mpeg_open(buf); - if (mpg == NULL) { - if (force) - mp_msg(MSGT_VOBSUB, MSGL_ERR, "VobSub: Can't open SUB file\n"); - else { - free(buf); - free(vob); - return NULL; - } - } else { - long last_pts_diff = 0; - while (!mpeg_eof(mpg)) { - off_t pos = mpeg_tell(mpg); - if (mpeg_run(mpg) < 0) { - if (!mpeg_eof(mpg)) - mp_msg(MSGT_VOBSUB, MSGL_ERR, "VobSub: mpeg_run error\n"); - break; - } - if (mpg->packet_size) { - if ((mpg->aid & 0xe0) == 0x20) { - unsigned int sid = mpg->aid & 0x1f; - if (vobsub_ensure_spu_stream(vob, sid) >= 0) { - packet_queue_t *queue = vob->spu_streams + sid; - /* get the packet to fill */ - if (queue->packets_size == 0 && packet_queue_grow(queue) < 0) - abort(); - while (queue->current_index + 1 < queue->packets_size - && queue->packets[queue->current_index + 1].filepos <= pos) - ++queue->current_index; - if (queue->current_index < queue->packets_size) { - packet_t *pkt; - if (queue->packets[queue->current_index].data) { - /* insert a new packet and fix the PTS ! */ - packet_queue_insert(queue); - queue->packets[queue->current_index].pts100 = - mpg->pts + last_pts_diff; - } - pkt = queue->packets + queue->current_index; - if (pkt->pts100 != UINT_MAX) { - if (queue->packets_size > 1) - last_pts_diff = pkt->pts100 - mpg->pts; - else - pkt->pts100 = mpg->pts; - if (mpg->merge && queue->current_index > 0) { - packet_t *last = &queue->packets[queue->current_index - 1]; - pkt->pts100 = last->pts100; - } - mpg->merge = 0; - /* FIXME: should not use mpg_sub internal informations, make a copy */ - pkt->data = mpg->packet; - pkt->size = mpg->packet_size; - mpg->packet = NULL; - mpg->packet_reserve = 0; - mpg->packet_size = 0; - } - } - } else - mp_msg(MSGT_VOBSUB, MSGL_WARN, "don't know what to do with subtitle #%u\n", sid); - } - } - } - vob->spu_streams_current = vob->spu_streams_size; - while (vob->spu_streams_current-- > 0) { - vob->spu_streams[vob->spu_streams_current].current_index = 0; - if (vobsubid == vob->spu_streams_current || - vob->spu_streams[vob->spu_streams_current].packets_size > 0) - ++vob->spu_valid_streams_size; - } - mpeg_free(mpg); - } - free(buf); - } - } - return vob; -} - -void vobsub_close(void *this) -{ - vobsub_t *vob = this; - if (vob->spu_streams) { - while (vob->spu_streams_size--) - packet_queue_destroy(vob->spu_streams + vob->spu_streams_size); - free(vob->spu_streams); - } - free(vob); -} - -unsigned int vobsub_get_indexes_count(void *vobhandle) -{ - vobsub_t *vob = vobhandle; - return vob->spu_valid_streams_size; -} - -char *vobsub_get_id(void *vobhandle, unsigned int index) -{ - vobsub_t *vob = vobhandle; - return (index < vob->spu_streams_size) ? vob->spu_streams[index].id : NULL; -} - -int vobsub_get_id_by_index(void *vobhandle, unsigned int index) -{ - vobsub_t *vob = vobhandle; - int i, j; - if (vob == NULL) - return -1; - for (i = 0, j = 0; i < vob->spu_streams_size; ++i) - if (i == vobsubid || vob->spu_streams[i].packets_size > 0) { - if (j == index) - return i; - ++j; - } - return -1; -} - -int vobsub_get_index_by_id(void *vobhandle, int id) -{ - vobsub_t *vob = vobhandle; - int i, j; - if (vob == NULL || id < 0 || id >= vob->spu_streams_size) - return -1; - if (id != vobsubid && !vob->spu_streams[id].packets_size) - return -1; - for (i = 0, j = 0; i < id; ++i) - if (i == vobsubid || vob->spu_streams[i].packets_size > 0) - ++j; - return j; -} - -int vobsub_set_from_lang(void *vobhandle, char **lang) -{ - int i; - vobsub_t *vob= vobhandle; - if (!lang) - goto end; - for (int n = 0; lang[n]; n++) { - for (i = 0; i < vob->spu_streams_size; i++) - if (vob->spu_streams[i].id) - if ((strncmp(vob->spu_streams[i].id, lang[n], 2) == 0)) { - vobsub_id = i; - mp_msg(MSGT_VOBSUB, MSGL_INFO, "Selected VOBSUB language: %d language: %s\n", i, vob->spu_streams[i].id); - return 0; - } - } -end: - mp_msg(MSGT_VOBSUB, MSGL_WARN, "No matching VOBSUB language found!\n"); - return -1; -} - -/// make sure we seek to the first packet of packets having same pts values. -static void vobsub_queue_reseek(packet_queue_t *queue, unsigned int pts100) -{ - int reseek_count = 0; - unsigned int lastpts = 0; - - if (queue->current_index > 0 - && (queue->packets[queue->current_index].pts100 == UINT_MAX - || queue->packets[queue->current_index].pts100 > pts100)) { - // possible pts seek previous, try to check it. - int i = 1; - while (queue->current_index >= i - && queue->packets[queue->current_index-i].pts100 == UINT_MAX) - ++i; - if (queue->current_index >= i - && queue->packets[queue->current_index-i].pts100 > pts100) - // pts seek previous confirmed, reseek from beginning - queue->current_index = 0; - } - while (queue->current_index < queue->packets_size - && queue->packets[queue->current_index].pts100 <= pts100) { - lastpts = queue->packets[queue->current_index].pts100; - ++queue->current_index; - ++reseek_count; - } - while (reseek_count-- && --queue->current_index) { - if (queue->packets[queue->current_index-1].pts100 != UINT_MAX && - queue->packets[queue->current_index-1].pts100 != lastpts) - break; - } -} - -int vobsub_get_packet(void *vobhandle, float pts, void** data, int* timestamp) -{ - vobsub_t *vob = vobhandle; - unsigned int pts100 = 90000 * pts; - if (vob->spu_streams && 0 <= vobsub_id && (unsigned) vobsub_id < vob->spu_streams_size) { - packet_queue_t *queue = vob->spu_streams + vobsub_id; - - vobsub_queue_reseek(queue, pts100); - - while (queue->current_index < queue->packets_size) { - packet_t *pkt = queue->packets + queue->current_index; - if (pkt->pts100 != UINT_MAX) - if (pkt->pts100 <= pts100) { - ++queue->current_index; - *data = pkt->data; - *timestamp = pkt->pts100; - return pkt->size; - } else - break; - else - ++queue->current_index; - } - } - return -1; -} - -void vobsub_seek(void * vobhandle, float pts) -{ - vobsub_t * vob = vobhandle; - packet_queue_t * queue; - int seek_pts100 = pts * 90000; - - if (vob->spu_streams && 0 <= vobsub_id && (unsigned) vobsub_id < vob->spu_streams_size) { - /* do not seek if we don't know the id */ - if (vobsub_get_id(vob, vobsub_id) == NULL) - return; - queue = vob->spu_streams + vobsub_id; - queue->current_index = 0; - vobsub_queue_reseek(queue, seek_pts100); - } -} diff --git a/sub/vobsub.h b/sub/vobsub.h deleted file mode 100644 index 0851e90c14..0000000000 --- a/sub/vobsub.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * This file is part of MPlayer. - * - * MPlayer 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. - * - * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef MPLAYER_VOBSUB_H -#define MPLAYER_VOBSUB_H - -void *vobsub_open(const char *subname, const char *const ifo, const int force, void** spu); -void vobsub_reset(void *vob); -int vobsub_parse_ifo(void* this, const char *const name, unsigned int *palette, unsigned int *width, unsigned int *height, int force, int sid, char *langid); -int vobsub_get_packet(void *vobhandle, float pts,void** data, int* timestamp); -void vobsub_close(void *this); -unsigned int vobsub_get_indexes_count(void * /* vobhandle */); -char *vobsub_get_id(void * /* vobhandle */, unsigned int /* index */); - -/// Get vobsub id by its index in the valid streams. -int vobsub_get_id_by_index(void *vobhandle, unsigned int index); -/// Get index in the valid streams by vobsub id. -int vobsub_get_index_by_id(void *vobhandle, int id); - -/// Convert palette value in idx file to yuv. -unsigned int vobsub_palette_to_yuv(unsigned int pal); -/// Convert rgb value to yuv. -unsigned int vobsub_rgb_to_yuv(unsigned int rgb); - -int vobsub_set_from_lang(void *vobhandle, char **lang); -void vobsub_seek(void * vobhandle, float pts); - -#endif /* MPLAYER_VOBSUB_H */ -- cgit v1.2.3