diff options
author | Uoti Urpala <uau@glyph.nonexistent.invalid> | 2011-01-26 20:42:15 +0200 |
---|---|---|
committer | Uoti Urpala <uau@glyph.nonexistent.invalid> | 2011-01-26 20:42:15 +0200 |
commit | f50f34245efa1012855a693558680bcfb7c348e5 (patch) | |
tree | 76e8fc186a96fdc1106b5c634d5937e514a06037 | |
parent | ec55a188e4d0232acd50fcabc0a3db3be2b9538e (diff) | |
parent | c9026cb3210205b07e2e068467a18ee40f9259a3 (diff) |
Merge branch 'sub'
* sub:
sub/OSD: move some related files to sub/
subtitles: options: enable -ass by default
subtitles: change default libass rendering style
demux_mkv, chapters: change millisecond arithmetic to ns
cleanup: rename ass_* functions to mp_ass_*
subs: use correct font aspect ratio for libass + converted subs
cleanup: some random minor code simplification and cleanup
vf_vo: fix EOSD change detection bug
sd_ass: remove subreader use, support plaintext markup
subtitles: style support for common SubRip tags and MicroDVD
core: ordered chapters: fix bad subtitle parameter
subs/demux: don't try to enable sub track when creating it
subtitles/demux: store duration instead of endpts in demux packets
subtitles: add framework for subtitle decoders
options: add special -leak-report option
subtitles: remove code trying to handle text subs with libavcodec
cleanup: move MP_NOPTS_VALUE definition to mpcommon.h
subtitles: move global ass_track to struct osd_state
core: move most mpcommon.c contents to mplayer.c
core: move global "subdata" and "vo_sub_last" to mpctx
subtitles: remove sub_last_pts hack
options: move -noconfig to option struct, simplify
-rw-r--r-- | DOCS/man/en/mplayer.1 | 24 | ||||
-rw-r--r-- | Makefile | 32 | ||||
-rw-r--r-- | TOOLS/subrip.c | 4 | ||||
-rw-r--r-- | cfg-common.h | 3 | ||||
-rw-r--r-- | cfg-mplayer.h | 1 | ||||
-rw-r--r-- | command.c | 71 | ||||
-rw-r--r-- | defaultopts.c | 6 | ||||
-rw-r--r-- | libmenu/menu.c | 4 | ||||
-rw-r--r-- | libmenu/menu_cmdlist.c | 2 | ||||
-rw-r--r-- | libmenu/menu_console.c | 2 | ||||
-rw-r--r-- | libmenu/menu_list.c | 2 | ||||
-rw-r--r-- | libmenu/menu_txt.c | 2 | ||||
-rw-r--r-- | libmenu/vf_menu.c | 4 | ||||
-rw-r--r-- | libmpcodecs/vf.h | 9 | ||||
-rw-r--r-- | libmpcodecs/vf_ass.c | 50 | ||||
-rw-r--r-- | libmpcodecs/vf_expand.c | 2 | ||||
-rw-r--r-- | libmpcodecs/vf_vo.c | 78 | ||||
-rw-r--r-- | libmpdemux/demux_lavf.c | 10 | ||||
-rw-r--r-- | libmpdemux/demux_mkv.c | 64 | ||||
-rw-r--r-- | libmpdemux/demux_mov.c | 2 | ||||
-rw-r--r-- | libmpdemux/demux_ogg.c | 4 | ||||
-rw-r--r-- | libmpdemux/demux_ty.c | 2 | ||||
-rw-r--r-- | libmpdemux/demux_ty_osd.c | 4 | ||||
-rw-r--r-- | libmpdemux/demuxer.c | 38 | ||||
-rw-r--r-- | libmpdemux/demuxer.h | 6 | ||||
-rw-r--r-- | libmpdemux/stheader.h | 5 | ||||
-rw-r--r-- | libmpdemux/video.c | 2 | ||||
-rw-r--r-- | libvo/old_vo_wrapper.c | 2 | ||||
-rw-r--r-- | libvo/vesa_lvo.c | 2 | ||||
-rw-r--r-- | libvo/video_out.h | 7 | ||||
-rw-r--r-- | libvo/vo_aa.c | 4 | ||||
-rw-r--r-- | libvo/vo_caca.c | 2 | ||||
-rw-r--r-- | libvo/vo_corevideo.m | 2 | ||||
-rw-r--r-- | libvo/vo_dfbmga.c | 2 | ||||
-rw-r--r-- | libvo/vo_dga.c | 2 | ||||
-rw-r--r-- | libvo/vo_direct3d.c | 4 | ||||
-rw-r--r-- | libvo/vo_directfb2.c | 2 | ||||
-rw-r--r-- | libvo/vo_directx.c | 2 | ||||
-rw-r--r-- | libvo/vo_dxr2.c | 2 | ||||
-rw-r--r-- | libvo/vo_dxr3.c | 2 | ||||
-rw-r--r-- | libvo/vo_fbdev.c | 2 | ||||
-rw-r--r-- | libvo/vo_fbdev2.c | 2 | ||||
-rw-r--r-- | libvo/vo_gl.c | 6 | ||||
-rw-r--r-- | libvo/vo_gl2.c | 2 | ||||
-rw-r--r-- | libvo/vo_kva.c | 2 | ||||
-rw-r--r-- | libvo/vo_mga.c | 2 | ||||
-rw-r--r-- | libvo/vo_quartz.c | 2 | ||||
-rw-r--r-- | libvo/vo_s3fb.c | 2 | ||||
-rw-r--r-- | libvo/vo_sdl.c | 2 | ||||
-rw-r--r-- | libvo/vo_svga.c | 2 | ||||
-rw-r--r-- | libvo/vo_tdfxfb.c | 2 | ||||
-rw-r--r-- | libvo/vo_vdpau.c | 8 | ||||
-rw-r--r-- | libvo/vo_vesa.c | 2 | ||||
-rw-r--r-- | libvo/vo_wii.c | 2 | ||||
-rw-r--r-- | libvo/vo_x11.c | 2 | ||||
-rw-r--r-- | libvo/vo_xmga.c | 2 | ||||
-rw-r--r-- | libvo/vo_xv.c | 2 | ||||
-rw-r--r-- | libvo/vo_xvmc.c | 2 | ||||
-rw-r--r-- | libvo/vo_xvr100.c | 2 | ||||
-rw-r--r-- | libvo/vo_yuv4mpeg.c | 2 | ||||
-rw-r--r-- | libvo/vosub_vidix.c | 2 | ||||
-rw-r--r-- | m_option.c | 2 | ||||
-rw-r--r-- | mp_core.h | 9 | ||||
-rw-r--r-- | mpcommon.c | 345 | ||||
-rw-r--r-- | mpcommon.h | 30 | ||||
-rw-r--r-- | mplayer.c | 391 | ||||
-rw-r--r-- | mplayer.h | 5 | ||||
-rw-r--r-- | options.h | 1 | ||||
-rw-r--r-- | stream/stream_dvdnav.c | 2 | ||||
-rw-r--r-- | sub/ass_mp.c (renamed from ass_mp.c) | 56 | ||||
-rw-r--r-- | sub/ass_mp.h (renamed from ass_mp.h) | 19 | ||||
-rw-r--r-- | sub/av_sub.c (renamed from av_sub.c) | 47 | ||||
-rw-r--r-- | sub/av_sub.h (renamed from av_sub.h) | 4 | ||||
-rw-r--r-- | sub/dec_sub.c | 72 | ||||
-rw-r--r-- | sub/dec_sub.h | 14 | ||||
-rw-r--r-- | sub/find_sub.c (renamed from find_sub.c) | 6 | ||||
-rw-r--r-- | sub/font_load.c (renamed from libvo/font_load.c) | 0 | ||||
-rw-r--r-- | sub/font_load.h (renamed from libvo/font_load.h) | 0 | ||||
-rw-r--r-- | sub/font_load_ft.c (renamed from libvo/font_load_ft.c) | 0 | ||||
-rw-r--r-- | sub/osd_font.h (renamed from libvo/osd_font.h) | 0 | ||||
-rw-r--r-- | sub/sd.h | 16 | ||||
-rw-r--r-- | sub/sd_ass.c | 154 | ||||
-rw-r--r-- | sub/spudec.c (renamed from spudec.c) | 3 | ||||
-rw-r--r-- | sub/spudec.h (renamed from spudec.h) | 0 | ||||
-rw-r--r-- | sub/sub.c (renamed from libvo/sub.c) | 2 | ||||
-rw-r--r-- | sub/sub.h (renamed from libvo/sub.h) | 6 | ||||
-rw-r--r-- | sub/sub_cc.c (renamed from sub_cc.c) | 2 | ||||
-rw-r--r-- | sub/sub_cc.h (renamed from sub_cc.h) | 0 | ||||
-rw-r--r-- | sub/subassconvert.c | 502 | ||||
-rw-r--r-- | sub/subassconvert.h | 27 | ||||
-rw-r--r-- | sub/subreader.c (renamed from subreader.c) | 154 | ||||
-rw-r--r-- | sub/subreader.h (renamed from subreader.h) | 4 | ||||
-rw-r--r-- | sub/unrar_exec.c (renamed from unrar_exec.c) | 0 | ||||
-rw-r--r-- | sub/unrar_exec.h (renamed from unrar_exec.h) | 0 | ||||
-rw-r--r-- | sub/vobsub.c (renamed from vobsub.c) | 0 | ||||
-rw-r--r-- | sub/vobsub.h (renamed from vobsub.h) | 0 |
96 files changed, 1625 insertions, 768 deletions
diff --git a/DOCS/man/en/mplayer.1 b/DOCS/man/en/mplayer.1 index cc5f912053..ae13cac060 100644 --- a/DOCS/man/en/mplayer.1 +++ b/DOCS/man/en/mplayer.1 @@ -2088,14 +2088,17 @@ FIXME: Document this. Also see \-vf expand. . .TP -.B \-ass (FreeType only) -Turn on SSA/ASS subtitle rendering. -With this option, libass will be used for SSA/ASS -external subtitles and Matroska tracks. +.B \-ass, \-noass (FreeType only) +Use libass to render all text subtitles. +This enables support for the native styling of SSA/ASS subtitles, +and also support for some styling features in other subtitle formats by +conversion to ASS markup. +Enabled by default if the player was compiled with libass support. .br .I NOTE: -Unlike normal OSD, libass uses fontconfig by default. To disable it, use -\-nofontconfig. +Some of the other subtitle options were written for the old non-libass +subtitle rendering system and may not work the same way or at all with +libass rendering enabled. . .TP .B \-ass\-border\-color <value> @@ -2272,13 +2275,8 @@ With Fontconfig, this option determines the Fontconfig font pattern. .PD 1 . .TP -.B \-fontconfig (fontconfig only) -Enables the usage of fontconfig managed fonts. -.br -.I NOTE: -By default fontconfig is used for libass-rendered subtitles and not used for -OSD. With \-fontconfig it is used for both libass and OSD, with \-nofontconfig -it is not used at all. +.B \-fontconfig, \-nofontconfig (fontconfig only) +Enables the use of fontconfig managed fonts. Enabled by default. . .TP .B \-forcedsubsonly @@ -27,7 +27,7 @@ SRCS_AUDIO_INPUT-$(ALSA1X) += stream/ai_alsa1x.c SRCS_AUDIO_INPUT-$(ALSA9) += stream/ai_alsa.c SRCS_AUDIO_INPUT-$(OSS) += stream/ai_oss.c SRCS_COMMON-$(AUDIO_INPUT) += $(SRCS_AUDIO_INPUT-yes) -SRCS_COMMON-$(BITMAP_FONT) += libvo/font_load.c +SRCS_COMMON-$(BITMAP_FONT) += sub/font_load.c SRCS_COMMON-$(CDDA) += stream/stream_cdda.c \ stream/cdinfo.c SRCS_COMMON-$(CDDB) += stream/stream_cddb.c @@ -101,7 +101,6 @@ SRCS_COMMON-$(FASTMEMCPY) += libvo/aclib.c SRCS_COMMON-$(FFMPEG) += libmpcodecs/vf_pp.c \ av_opts.c \ libaf/af_lavcac3enc.c \ - av_sub.c \ libaf/af_lavcresample.c \ libmpcodecs/ad_ffmpeg.c \ libmpcodecs/vd_ffmpeg.c \ @@ -111,6 +110,7 @@ SRCS_COMMON-$(FFMPEG) += libmpcodecs/vf_pp.c \ libmpcodecs/vf_uspp.c \ libmpdemux/demux_lavf.c \ stream/stream_ffmpeg.c \ + sub/av_sub.c \ # Requires a new enough libavutil that installs eval.h SRCS_COMMON-$(FFMPEG_EVAL_API) += libmpcodecs/vf_geq.c \ @@ -122,7 +122,7 @@ SRCS_COMMON-$(FFMPEG_INTERNALS) += libmpcodecs/vf_fspp.c \ libmpcodecs/vf_qp.c \ libmpcodecs/vf_spp.c \ -SRCS_COMMON-$(FREETYPE) += libvo/font_load_ft.c +SRCS_COMMON-$(FREETYPE) += sub/font_load_ft.c SRCS_COMMON-$(FTP) += stream/stream_ftp.c SRCS_COMMON-$(GIF) += libmpdemux/demux_gif.c SRCS_COMMON-$(HAVE_POSIX_SELECT) += libmpcodecs/vf_bmovl.c @@ -130,8 +130,9 @@ SRCS_COMMON-$(HAVE_SYS_MMAN_H) += libaf/af_export.c osdep/mmap_anon.c SRCS_COMMON-$(JPEG) += libmpcodecs/vd_ijpg.c SRCS_COMMON-$(LADSPA) += libaf/af_ladspa.c SRCS_COMMON-$(LIBA52) += libmpcodecs/ad_liba52.c -SRCS_COMMON-$(LIBASS) += ass_mp.c \ - libmpcodecs/vf_ass.c \ +SRCS_COMMON-$(LIBASS) += libmpcodecs/vf_ass.c \ + sub/ass_mp.c \ + sub/sd_ass.c \ SRCS_COMMON-$(LIBBLURAY) += stream/stream_bluray.c SRCS_COMMON-$(LIBBS2B) += libaf/af_bs2b.c @@ -268,7 +269,7 @@ SRCS_COMMON-$(TV_DSHOW) += stream/tvi_dshow.c \ SRCS_COMMON-$(TV_V4L1) += stream/tvi_v4l.c stream/audio_in.c SRCS_COMMON-$(TV_V4L2) += stream/tvi_v4l2.c stream/audio_in.c -SRCS_COMMON-$(UNRAR_EXEC) += unrar_exec.c +SRCS_COMMON-$(UNRAR_EXEC) += sub/unrar_exec.c SRCS_COMMON-$(VCD) += stream/stream_vcd.c SRCS_COMMON-$(VORBIS) += libmpcodecs/ad_libvorbis.c \ libmpdemux/demux_ogg.c @@ -327,7 +328,6 @@ SRCS_COMMON = asxparser.c \ cpudetect.c \ defaultopts.c \ edl.c \ - find_sub.c \ fmt-conversion.c \ m_config.c \ m_option.c \ @@ -338,12 +338,8 @@ SRCS_COMMON = asxparser.c \ path.c \ playtree.c \ playtreeparser.c \ - spudec.c \ - sub_cc.c \ subopt-helper.c \ - subreader.c \ talloc.c \ - vobsub.c \ libaf/af.c \ libaf/af_center.c \ libaf/af_channels.c \ @@ -503,7 +499,6 @@ SRCS_COMMON = asxparser.c \ libmpdemux/yuv4mpeg.c \ libmpdemux/yuv4mpeg_ratio.c \ libvo/osd.c \ - libvo/sub.c \ osdep/findfiles.c \ osdep/numcores.c \ osdep/$(GETCH) \ @@ -515,6 +510,14 @@ SRCS_COMMON = asxparser.c \ stream/stream_mf.c \ stream/stream_null.c \ stream/url.c \ + sub/sub.c \ + sub/sub_cc.c \ + sub/dec_sub.c \ + sub/find_sub.c \ + sub/spudec.c \ + sub/subassconvert.c \ + sub/subreader.c \ + sub/vobsub.c \ $(SRCS_COMMON-yes) @@ -687,6 +690,7 @@ DIRS = . \ stream/freesdp \ stream/librtsp \ stream/realrtsp \ + sub \ tremor \ TOOLS \ vidix \ @@ -913,8 +917,8 @@ toolsclean: TOOLS/bmovl-test$(EXESUF): -lSDL_image -TOOLS/subrip$(EXESUF): vobsub.o spudec.o unrar_exec.o libvo/aclib.o \ - libswscale/libswscale.a libavutil/libavutil.a $(TEST_OBJS) +TOOLS/subrip$(EXESUF): sub/vobsub.o sub/spudec.o sub/unrar_exec.o \ + libvo/aclib.o \ libswscale/libswscale.a libavutil/libavutil.a $(TEST_OBJS) TOOLS/vfw2menc$(EXESUF): -lwinmm -lole32 diff --git a/TOOLS/subrip.c b/TOOLS/subrip.c index 85ee1c78e0..fb9395c413 100644 --- a/TOOLS/subrip.c +++ b/TOOLS/subrip.c @@ -31,8 +31,8 @@ #include <sys/types.h> #include <sys/wait.h> #include "libvo/video_out.h" -#include "vobsub.h" -#include "spudec.h" +#include "sub/vobsub.h" +#include "sub/spudec.h" /* linking hacks */ char *mplayer_version; diff --git a/cfg-common.h b/cfg-common.h index 7f4123cc56..e56d87b3de 100644 --- a/cfg-common.h +++ b/cfg-common.h @@ -379,7 +379,8 @@ const m_option_t common_opts[] = { {"priority", &proc_priority, CONF_TYPE_STRING, 0, 0, 0, NULL}, #endif {"codecpath", &codec_path, CONF_TYPE_STRING, 0, 0, 0, NULL}, - {"noconfig", (void *) noconfig_opts, CONF_TYPE_SUBCONFIG, CONF_GLOBAL|CONF_NOCFG|CONF_PRE_PARSE, 0, 0, NULL}, + OPT_CHOICE("noconfig", noconfig, CONF_GLOBAL | CONF_NOCFG | CONF_PRE_PARSE, + ({"off", 0}, {"user", 1}, {"system", 2}, {"all", 3})), // ------------------------- stream options -------------------- diff --git a/cfg-mplayer.h b/cfg-mplayer.h index ff5dd8a2c8..003e7f9c54 100644 --- a/cfg-mplayer.h +++ b/cfg-mplayer.h @@ -294,6 +294,7 @@ const m_option_t mplayer_opts[]={ {"lircconf", &lirc_configfile, CONF_TYPE_STRING, CONF_GLOBAL, 0, 0, NULL}, #endif + {"leak-report", "", CONF_TYPE_PRINT, 0, 0, 0, (void*)1}, // these should be removed when gmplayer is forgotten {"gui", "Internal GUI was removed. Use some other frontend instead.\n", CONF_TYPE_PRINT, 0, 0, 0, NULL}, {"nogui", "Internal GUI was removed, -nogui is no longer valid.\n", CONF_TYPE_PRINT, 0, 0, 0, NULL}, @@ -31,7 +31,8 @@ #include "libmpdemux/stheader.h" #include "codec-cfg.h" #include "mplayer.h" -#include "libvo/sub.h" +#include "sub/sub.h" +#include "sub/dec_sub.h" #include "m_option.h" #include "m_property.h" #include "m_config.h" @@ -40,7 +41,7 @@ #include "libmpcodecs/vd.h" #include "mp_osd.h" #include "libvo/video_out.h" -#include "libvo/font_load.h" +#include "sub/font_load.h" #include "playtree.h" #include "libao2/audio_out.h" #include "mpcommon.h" @@ -48,10 +49,10 @@ #include "libmpcodecs/dec_video.h" #include "libmpcodecs/dec_audio.h" #include "libmpcodecs/dec_teletext.h" -#include "vobsub.h" -#include "spudec.h" +#include "sub/vobsub.h" +#include "sub/spudec.h" #include "path.h" -#include "ass_mp.h" +#include "sub/ass_mp.h" #include "stream/tv.h" #include "stream/stream_radio.h" #include "stream/pvr.h" @@ -193,15 +194,16 @@ static void log_sub(struct MPContext *mpctx) char *fname; FILE *f; int i; + struct subtitle *vo_sub_last = mpctx->vo_sub_last; - if (subdata == NULL || vo_sub_last == NULL) + if (mpctx->subdata == NULL || vo_sub_last == NULL) return; fname = get_path("subtitle_log"); f = fopen(fname, "a"); if (!f) return; fprintf(f, "----------------------------------------------------------\n"); - if (subdata->sub_uses_time) { + if (mpctx->subdata->sub_uses_time) { fprintf(f, "N: %s S: %02ld:%02ld:%02ld.%02ld E: %02ld:%02ld:%02ld.%02ld\n", mpctx->filename, vo_sub_last->start / 360000, @@ -1522,7 +1524,6 @@ static int mp_property_sub(m_option_t *prop, int action, void *arg, demux_stream_t *const d_sub = mpctx->d_sub; int source = -1, reset_spu = 0; int source_pos = -1; - char *sub_name; update_global_sub_size(mpctx); const int global_sub_size = mpctx->global_sub_size; @@ -1541,13 +1542,15 @@ static int mp_property_sub(m_option_t *prop, int action, void *arg, return M_PROPERTY_ERROR; *(char **) arg = malloc(64); (*(char **) arg)[63] = 0; - sub_name = 0; - if (subdata) - sub_name = subdata->filename; + char *sub_name = NULL; + if (mpctx->subdata) + sub_name = mpctx->subdata->filename; #ifdef CONFIG_ASS - if (ass_track && ass_track->name) - sub_name = ass_track->name; + if (mpctx->osd->ass_track) + sub_name = mpctx->osd->ass_track->name; #endif + if (!sub_name && mpctx->subdata) + sub_name = mpctx->subdata->filename; if (sub_name) { const char *tmp = mp_basename(sub_name); @@ -1644,7 +1647,7 @@ static int mp_property_sub(m_option_t *prop, int action, void *arg, mpctx->global_sub_pos, source); mpctx->set_of_sub_pos = -1; - subdata = NULL; + mpctx->subdata = NULL; vobsub_id = -1; opts->sub_id = -1; @@ -1653,21 +1656,25 @@ static int mp_property_sub(m_option_t *prop, int action, void *arg, reset_spu = 1; d_sub->id = -2; } -#ifdef CONFIG_ASS - ass_track = 0; -#endif + mpctx->osd->ass_track = NULL; + uninit_player(mpctx, INITIALIZED_SUB); if (source == SUB_SOURCE_VOBSUB) { vobsub_id = vobsub_get_id_by_index(vo_vobsub, source_pos); } else if (source == SUB_SOURCE_SUBS) { mpctx->set_of_sub_pos = source_pos; #ifdef CONFIG_ASS - if (opts->ass_enabled && mpctx->set_of_ass_tracks[mpctx->set_of_sub_pos]) - ass_track = mpctx->set_of_ass_tracks[mpctx->set_of_sub_pos]; - else + if (opts->ass_enabled + && mpctx->set_of_ass_tracks[mpctx->set_of_sub_pos]) { + mpctx->osd->ass_track = + mpctx->set_of_ass_tracks[mpctx->set_of_sub_pos]; + mpctx->osd->ass_track_changed = true; + mpctx->osd->vsfilter_aspect = + mpctx->track_was_native_ass[mpctx->set_of_sub_pos]; + } else #endif { - subdata = mpctx->set_of_subtitles[mpctx->set_of_sub_pos]; + mpctx->subdata = mpctx->set_of_subtitles[mpctx->set_of_sub_pos]; vo_osd_changed(OSDTYPE_SUBTITLE); } } else if (source == SUB_SOURCE_DEMUX) { @@ -1690,10 +1697,10 @@ static int mp_property_sub(m_option_t *prop, int action, void *arg, sh_sub_t *sh = d_sub->sh; if (sh->type == 'v') init_vo_spudec(mpctx); -#ifdef CONFIG_ASS - else if (opts->ass_enabled) - ass_track = sh->ass_track; -#endif + else { + sub_init(sh, mpctx->osd); + mpctx->initialized_flags |= INITIALIZED_SUB; + } } else { d_sub->id = -2; d_sub->sh = NULL; @@ -1710,7 +1717,7 @@ static int mp_property_sub(m_option_t *prop, int action, void *arg, } #endif - update_subtitles(mpctx, &mpctx->opts, mpctx->sh_video, 0, 0, d_sub, 1); + update_subtitles(mpctx, 0, 0, true); return M_PROPERTY_OK; } @@ -2692,10 +2699,8 @@ static void remove_subtitle_range(MPContext *mpctx, int start, int count) if (mpctx->set_of_sub_pos >= start && mpctx->set_of_sub_pos < end) { mpctx->global_sub_pos = -2; - subdata = NULL; -#ifdef CONFIG_ASS - ass_track = NULL; -#endif + mpctx->subdata = NULL; + mpctx->osd->ass_track = NULL; mp_input_queue_cmd(mpctx->input, mp_input_parse_cmd("sub_select")); } else if (mpctx->set_of_sub_pos >= end) { mpctx->set_of_sub_pos -= count; @@ -2931,11 +2936,11 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd) case MP_CMD_SUB_STEP: if (sh_video) { int movement = cmd->args[0].v.i; - step_sub(subdata, mpctx->video_pts, movement); + step_sub(mpctx->subdata, mpctx->video_pts, movement); #ifdef CONFIG_ASS - if (ass_track) + if (mpctx->osd->ass_track) sub_delay += - ass_step_sub(ass_track, + ass_step_sub(mpctx->osd->ass_track, (mpctx->video_pts + sub_delay) * 1000 + .5, movement) / 1000.; #endif diff --git a/defaultopts.c b/defaultopts.c index e9c2d85dce..d49841a731 100644 --- a/defaultopts.c +++ b/defaultopts.c @@ -46,6 +46,10 @@ void set_default_mplayer_options(struct MPOpts *opts) .movie_aspect = -1., .flip = -1, .vd_use_slices = 1, +#ifdef CONFIG_ASS + .ass_enabled = 1, +#endif + .lavc_param = { .workaround_bugs = 1, // autodetect .error_resilience = 2, @@ -60,8 +64,6 @@ void set_default_mplayer_options(struct MPOpts *opts) .use_lircc = 1, #ifdef CONFIG_APPLE_REMOTE .use_ar = 1, -#else - .use_ar = 0, #endif .default_bindings = 1, } diff --git a/libmenu/menu.c b/libmenu/menu.c index 8a9cb28872..f537cd1671 100644 --- a/libmenu/menu.c +++ b/libmenu/menu.c @@ -26,8 +26,8 @@ #include <unistd.h> #include "libvo/osd.h" -#include "libvo/font_load.h" -#include "libvo/sub.h" +#include "sub/font_load.h" +#include "sub/sub.h" #include "osdep/keycodes.h" #include "asxparser.h" #include "stream/stream.h" diff --git a/libmenu/menu_cmdlist.c b/libmenu/menu_cmdlist.c index 5b7812be5e..14026d04c4 100644 --- a/libmenu/menu_cmdlist.c +++ b/libmenu/menu_cmdlist.c @@ -33,7 +33,7 @@ #include "menu.h" #include "menu_list.h" -#include "libvo/font_load.h" +#include "sub/font_load.h" #include "input/input.h" diff --git a/libmenu/menu_console.c b/libmenu/menu_console.c index dd706b65cb..eb8595e9ab 100644 --- a/libmenu/menu_console.c +++ b/libmenu/menu_console.c @@ -38,7 +38,7 @@ #include "m_option.h" #include "menu.h" -#include "libvo/font_load.h" +#include "sub/font_load.h" #include "osdep/keycodes.h" #include "input/input.h" #include "osdep/timer.h" diff --git a/libmenu/menu_list.c b/libmenu/menu_list.c index 28264ce04c..37f10d123e 100644 --- a/libmenu/menu_list.c +++ b/libmenu/menu_list.c @@ -29,7 +29,7 @@ #include "m_struct.h" #include "menu.h" -#include "libvo/font_load.h" +#include "sub/font_load.h" #include "osdep/keycodes.h" #define IMPL 1 diff --git a/libmenu/menu_txt.c b/libmenu/menu_txt.c index 308d9547c0..0170320884 100644 --- a/libmenu/menu_txt.c +++ b/libmenu/menu_txt.c @@ -30,7 +30,7 @@ #include "m_option.h" #include "menu.h" -#include "libvo/font_load.h" +#include "sub/font_load.h" #include "osdep/keycodes.h" struct menu_priv_s { diff --git a/libmenu/vf_menu.c b/libmenu/vf_menu.c index 1a5d003e94..994c7134ea 100644 --- a/libmenu/vf_menu.c +++ b/libmenu/vf_menu.c @@ -32,8 +32,8 @@ #include "libvo/fastmemcpy.h" #include "libvo/video_out.h" -#include "libvo/font_load.h" -#include "libvo/sub.h" +#include "sub/font_load.h" +#include "sub/sub.h" #include "input/input.h" #include "m_struct.h" #include "menu.h" diff --git a/libmpcodecs/vf.h b/libmpcodecs/vf.h index 0d10abd6c6..58cfaaf787 100644 --- a/libmpcodecs/vf.h +++ b/libmpcodecs/vf.h @@ -20,6 +20,7 @@ #define MPLAYER_VF_H #include "mp_image.h" +#include "mpcommon.h" struct MPOpts; struct vf_instance; @@ -107,8 +108,8 @@ typedef struct vf_seteq_s #define VFCTRL_DRAW_EOSD 16 /* Render EOSD */ #define VFCTRL_SET_DEINTERLACE 18 /* Set deinterlacing status */ #define VFCTRL_GET_DEINTERLACE 19 /* Get deinterlacing status */ -/* Hack to make the OSD state object available to vf_expand which accesses - * the OSD state outside of normal OSD draw time. */ +/* Hack to make the OSD state object available to vf_expand and vf_ass which + * access OSD/subtitle state outside of normal OSD draw time. */ #define VFCTRL_SET_OSD_OBJ 20 #define VFCTRL_REDRAW_OSD 21 /* Change user-visible OSD immediately */ #define VFCTRL_SET_YUV_COLORSPACE 22 @@ -116,10 +117,6 @@ typedef struct vf_seteq_s #include "vfcap.h" -//FIXME this should be in a common header, but i dunno which -#define MP_NOPTS_VALUE (-1LL<<63) //both int64_t and double should be able to represent this exactly - - // functions: void vf_mpi_clear(mp_image_t* mpi,int x0,int y0,int w,int h); mp_image_t* vf_get_image(vf_instance_t* vf, unsigned int outfmt, int mp_imgtype, int mp_imgflag, int w, int h); diff --git a/libmpcodecs/vf_ass.c b/libmpcodecs/vf_ass.c index 2678986025..4047316a50 100644 --- a/libmpcodecs/vf_ass.c +++ b/libmpcodecs/vf_ass.c @@ -33,13 +33,14 @@ #include "img_format.h" #include "mp_image.h" #include "vf.h" +#include "sub/sub.h" #include "libvo/fastmemcpy.h" #include "m_option.h" #include "m_struct.h" -#include "ass_mp.h" +#include "sub/ass_mp.h" #define _r(c) ((c)>>24) #define _g(c) (((c)>>16)&0xFF) @@ -59,7 +60,9 @@ static const struct vf_priv_s { // 0 = insert always int auto_insert; - ASS_Renderer *ass_priv; + struct osd_state *osd; + ASS_Renderer *renderer_realaspect; + ASS_Renderer *renderer_vsfilter; unsigned char *planes[3]; struct line_limits { @@ -68,9 +71,7 @@ static const struct vf_priv_s { } *line_limits; } vf_priv_dflt; -extern ASS_Track *ass_track; extern float sub_delay; -extern int sub_visibility; static int config(struct vf_instance *vf, int width, int height, int d_width, int d_height, @@ -92,9 +93,14 @@ static int config(struct vf_instance *vf, vf->priv->planes[2] = malloc(vf->priv->outw * vf->priv->outh); vf->priv->line_limits = malloc((vf->priv->outh + 1) / 2 * sizeof(*vf->priv->line_limits)); - if (vf->priv->ass_priv) { - ass_configure(vf->priv->ass_priv, vf->priv->outw, vf->priv->outh, 0); - ass_set_aspect_ratio(vf->priv->ass_priv, 1, 1); + if (vf->priv->renderer_realaspect) { + mp_ass_configure(vf->priv->renderer_realaspect, + vf->priv->outw, vf->priv->outh, 0); + mp_ass_configure(vf->priv->renderer_vsfilter, + vf->priv->outw, vf->priv->outh, 0); + ass_set_aspect_ratio(vf->priv->renderer_realaspect, + (double)width / height * d_height / d_width, 1); + ass_set_aspect_ratio(vf->priv->renderer_vsfilter, 1, 1); } return vf_next_config(vf, vf->priv->outw, vf->priv->outh, d_width, @@ -351,9 +357,12 @@ static int render_frame(struct vf_instance *vf, mp_image_t *mpi, static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts) { ASS_Image *images = 0; - if (sub_visibility && vf->priv->ass_priv && ass_track + ASS_Renderer *renderer = vf->priv->osd->vsfilter_aspect ? + vf->priv->renderer_vsfilter : vf->priv->renderer_realaspect; + if (sub_visibility && renderer && vf->priv->osd->ass_track && (pts != MP_NOPTS_VALUE)) - images = ass_mp_render_frame(vf->priv->ass_priv, ass_track, + images = mp_ass_render_frame(renderer, + vf->priv->osd->ass_track, (pts + sub_delay) * 1000 + .5, NULL); prepare_image(vf, mpi); @@ -377,14 +386,23 @@ static int query_format(struct vf_instance *vf, unsigned int fmt) static int control(vf_instance_t *vf, int request, void *data) { switch (request) { + case VFCTRL_SET_OSD_OBJ: + vf->priv->osd = data; + break; case VFCTRL_INIT_EOSD: - vf->priv->ass_priv = ass_renderer_init((ASS_Library *)data); - if (!vf->priv->ass_priv) + vf->priv->renderer_realaspect = ass_renderer_init((ASS_Library *)data); + if (!vf->priv->renderer_realaspect) + return CONTROL_FALSE; + vf->priv->renderer_vsfilter = ass_renderer_init((ASS_Library *)data); + if (!vf->priv->renderer_vsfilter) { + ass_renderer_done(vf->priv->renderer_realaspect); return CONTROL_FALSE; - ass_configure_fonts(vf->priv->ass_priv); + } + mp_ass_configure_fonts(vf->priv->renderer_realaspect); + mp_ass_configure_fonts(vf->priv->renderer_vsfilter); return CONTROL_TRUE; case VFCTRL_DRAW_EOSD: - if (vf->priv->ass_priv) + if (vf->priv->renderer_realaspect) return CONTROL_TRUE; break; } @@ -393,8 +411,10 @@ static int control(vf_instance_t *vf, int request, void *data) static void uninit(struct vf_instance *vf) { - if (vf->priv->ass_priv) - ass_renderer_done(vf->priv->ass_priv); + if (vf->priv->renderer_realaspect) { + ass_renderer_done(vf->priv->renderer_realaspect); + ass_renderer_done(vf->priv->renderer_vsfilter); + } free(vf->priv->planes[1]); free(vf->priv->planes[2]); free(vf->priv->line_limits); diff --git a/libmpcodecs/vf_expand.c b/libmpcodecs/vf_expand.c index 57226acb93..95580b9f26 100644 --- a/libmpcodecs/vf_expand.c +++ b/libmpcodecs/vf_expand.c @@ -35,7 +35,7 @@ #include "libavutil/avutil.h" #ifdef OSD_SUPPORT -#include "libvo/sub.h" +#include "sub/sub.h" #include "libvo/osd.h" #endif diff --git a/libmpcodecs/vf_vo.c b/libmpcodecs/vf_vo.c index 0e8563d5a6..8bbaf465b3 100644 --- a/libmpcodecs/vf_vo.c +++ b/libmpcodecs/vf_vo.c @@ -29,21 +29,19 @@ #include "libvo/video_out.h" -#ifdef CONFIG_ASS -#include "ass_mp.h" -extern ASS_Track *ass_track; -#endif +#include "sub/ass_mp.h" +#include "sub/sub.h" //===========================================================================// -extern int sub_visibility; extern float sub_delay; struct vf_priv_s { struct vo *vo; #ifdef CONFIG_ASS - ASS_Renderer *ass_priv; - int prev_visibility; + ASS_Renderer *renderer_realaspect; + ASS_Renderer *renderer_vsfilter; + bool prev_visibility; double scale_ratio; #endif }; @@ -86,8 +84,12 @@ static int config(struct vf_instance *vf, #ifdef CONFIG_ASS vf->priv->scale_ratio = (double) d_width / d_height * height / width; - if (vf->priv->ass_priv) - ass_configure(vf->priv->ass_priv, width, height, !!(vf->default_caps & VFCAP_EOSD_UNSCALED)); + if (vf->priv->renderer_realaspect) { + mp_ass_configure(vf->priv->renderer_realaspect, width, height, + vf->default_caps & VFCAP_EOSD_UNSCALED); + mp_ass_configure(vf->priv->renderer_vsfilter, width, height, + vf->default_caps & VFCAP_EOSD_UNSCALED); + } #endif return 1; @@ -133,33 +135,55 @@ static int control(struct vf_instance *vf, int request, void* data) #ifdef CONFIG_ASS case VFCTRL_INIT_EOSD: { - vf->priv->ass_priv = ass_renderer_init((ASS_Library*)data); - if (!vf->priv->ass_priv) return CONTROL_FALSE; - ass_configure_fonts(vf->priv->ass_priv); - vf->priv->prev_visibility = 0; + vf->priv->renderer_realaspect = ass_renderer_init(data); + if (!vf->priv->renderer_realaspect) + return CONTROL_FALSE; + vf->priv->renderer_vsfilter = ass_renderer_init(data); + if (!vf->priv->renderer_vsfilter) { + ass_renderer_done(vf->priv->renderer_realaspect); + return CONTROL_FALSE; + } + mp_ass_configure_fonts(vf->priv->renderer_realaspect); + mp_ass_configure_fonts(vf->priv->renderer_vsfilter); + vf->priv->prev_visibility = false; return CONTROL_TRUE; } case VFCTRL_DRAW_EOSD: { + struct osd_state *osd = data; mp_eosd_images_t images = {NULL, 2}; double pts = video_out->next_pts; - if (!video_out->config_ok || !vf->priv->ass_priv) return CONTROL_FALSE; - if (sub_visibility && vf->priv->ass_priv && ass_track && (pts != MP_NOPTS_VALUE)) { - mp_eosd_res_t res; - memset(&res, 0, sizeof(res)); + ASS_Renderer *renderer; + double scale; + if (osd->vsfilter_aspect) { + renderer = vf->priv->renderer_vsfilter; + scale = vf->priv->scale_ratio; + } else { + renderer = vf->priv->renderer_realaspect; + scale = 1; + } + if (!video_out->config_ok || !renderer) + return CONTROL_FALSE; + if (osd->ass_track_changed) + vf->priv->prev_visibility = false; + osd->ass_track_changed = false; + if (sub_visibility && osd->ass_track && (pts != MP_NOPTS_VALUE)) { + struct mp_eosd_res res = {0}; if (vo_control(video_out, VOCTRL_GET_EOSD_RES, &res) == VO_TRUE) { - ass_set_frame_size(vf->priv->ass_priv, res.w, res.h); - ass_set_margins(vf->priv->ass_priv, res.mt, res.mb, res.ml, res.mr); - ass_set_aspect_ratio(vf->priv->ass_priv, vf->priv->scale_ratio, 1); + ass_set_frame_size(renderer, res.w, res.h); + ass_set_margins(renderer, res.mt, res.mb, res.ml, res.mr); + ass_set_aspect_ratio(renderer, scale, 1); } - images.imgs = ass_mp_render_frame(vf->priv->ass_priv, ass_track, (pts+sub_delay) * 1000 + .5, &images.changed); + images.imgs = mp_ass_render_frame(renderer, + osd->ass_track, + (pts+sub_delay) * 1000 + .5, + &images.changed); if (!vf->priv->prev_visibility) images.changed = 2; - vf->priv->prev_visibility = 1; + vf->priv->prev_visibility = true; } else - vf->priv->prev_visibility = 0; - vf->priv->prev_visibility = sub_visibility; + vf->priv->prev_visibility = false; return vo_control(video_out, VOCTRL_DRAW_EOSD, &images) == VO_TRUE; } #endif @@ -223,8 +247,10 @@ static void uninit(struct vf_instance *vf) * to get rid of numbered-mpi references that will now be invalid. */ vo_seek_reset(video_out); #ifdef CONFIG_ASS - if (vf->priv->ass_priv) - ass_renderer_done(vf->priv->ass_priv); + if (vf->priv->renderer_realaspect) { + ass_renderer_done(vf->priv->renderer_realaspect); + ass_renderer_done(vf->priv->renderer_vsfilter); + } #endif free(vf->priv); } diff --git a/libmpdemux/demux_lavf.c b/libmpdemux/demux_lavf.c index 7f665a86bb..6a32240ebd 100644 --- a/libmpdemux/demux_lavf.c +++ b/libmpdemux/demux_lavf.c @@ -36,7 +36,7 @@ #include "demuxer.h" #include "stheader.h" #include "m_option.h" -#include "libvo/sub.h" +#include "sub/sub.h" #include "libavformat/avformat.h" #include "libavformat/avio.h" @@ -588,8 +588,8 @@ static demuxer_t* demux_open_lavf(demuxer_t *demuxer){ for(i=0; i < avfc->nb_chapters; i++) { AVChapter *c = avfc->chapters[i]; - uint64_t start = av_rescale_q(c->start, c->time_base, (AVRational){1,1000}); - uint64_t end = av_rescale_q(c->end, c->time_base, (AVRational){1,1000}); + uint64_t start = av_rescale_q(c->start, c->time_base, (AVRational){1,1000000000}); + uint64_t end = av_rescale_q(c->end, c->time_base, (AVRational){1,1000000000}); t = av_metadata_get(c->metadata, "title", NULL, 0); demuxer_add_chapter(demuxer, t ? BSTR(t->value) : BSTR(NULL), start, end); } @@ -756,11 +756,11 @@ static int demux_lavf_fill_buffer(demuxer_t *demux, demux_stream_t *dsds){ if(ts != AV_NOPTS_VALUE){ dp->pts = ts * av_q2d(priv->avfc->streams[id]->time_base); priv->last_pts= dp->pts * AV_TIME_BASE; - // always set endpts for subtitles, even if PKT_FLAG_KEY is not set, + // always set duration for subtitles, even if PKT_FLAG_KEY is not set, // otherwise they will stay on screen to long if e.g. ASS is demuxed from mkv if((ds == demux->sub || (pkt.flags & PKT_FLAG_KEY)) && pkt.convergence_duration > 0) - dp->endpts = dp->pts + pkt.convergence_duration * av_q2d(priv->avfc->streams[id]->time_base); + dp->duration = pkt.convergence_duration * av_q2d(priv->avfc->streams[id]->time_base); } dp->pos=demux->filepos; dp->flags= !!(pkt.flags&PKT_FLAG_KEY); diff --git a/libmpdemux/demux_mkv.c b/libmpdemux/demux_mkv.c index 2414b01b4b..7432b59d46 100644 --- a/libmpdemux/demux_mkv.c +++ b/libmpdemux/demux_mkv.c @@ -41,11 +41,7 @@ #include "mp_msg.h" -#include "vobsub.h" -#include "subreader.h" -#include "libvo/sub.h" - -#include "ass_mp.h" +#include "sub/sub.h" #include "libavutil/common.h" @@ -184,7 +180,7 @@ typedef struct mkv_demuxer { } *cluster_positions; int num_cluster_pos; - int64_t skip_to_timecode; + uint64_t skip_to_timecode; int v_skip_to_keyframe, a_skip_to_keyframe; int num_audio_tracks; @@ -786,8 +782,8 @@ static int demux_mkv_read_chapters(struct demuxer *demuxer) if (!ca->n_chapter_time_start) mp_msg(MSGT_DEMUX, warn_level, "[mkv] Chapter lacks start time\n"); - chapter.start = ca->chapter_time_start / 1000000; - chapter.end = ca->chapter_time_end / 1000000; + chapter.start = ca->chapter_time_start; + chapter.end = ca->chapter_time_end; if (ca->n_chapter_display) { if (ca->n_chapter_display > 1) @@ -824,14 +820,14 @@ static int demux_mkv_read_chapters(struct demuxer *demuxer) mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] Chapter %u from %02d:%02d:%02d.%03d " "to %02d:%02d:%02d.%03d, %.*s\n", i, - (int) (chapter.start / 60 / 60 / 1000), - (int) ((chapter.start / 60 / 1000) % 60), - (int) ((chapter.start / 1000) % 60), - (int) (chapter.start % 1000), - (int) (chapter.end / 60 / 60 / 1000), - (int) ((chapter.end / 60 / 1000) % 60), - (int) ((chapter.end / 1000) % 60), - (int) (chapter.end % 1000), + (int) (chapter.start / 60 / 60 / 1000000000), + (int) ((chapter.start / 60 / 1000000000) % 60), + (int) ((chapter.start / 1000000000) % 60), + (int) (chapter.start % 1000000000), + (int) (chapter.end / 60 / 60 / 1000000000), + (int) ((chapter.end / 60 / 1000000000) % 60), + (int) ((chapter.end / 1000000000) % 60), + (int) (chapter.end % 1000000000), BSTR_P(name)); if (idx == selected_edition){ @@ -1883,13 +1879,13 @@ static void handle_subtitles(demuxer_t *demuxer, mkv_track_t *track, sub_utf8 = 1; dp = new_demux_packet(size); memcpy(dp->buffer, block, size); - dp->pts = timecode / 1000.0; - dp->endpts = (timecode + block_duration) / 1000.0; + dp->pts = timecode / 1e9; + dp->duration = block_duration / 1e9; ds_add_packet(demuxer->sub, dp); } static void handle_realvideo(demuxer_t *demuxer, mkv_track_t *track, - uint8_t *buffer, uint32_t size, int block_bref) + uint8_t *buffer, uint32_t size, int64_t block_bref) { mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv; demux_packet_t *dp; @@ -1915,7 +1911,7 @@ static void handle_realvideo(demuxer_t *demuxer, mkv_track_t *track, } static void handle_realaudio(demuxer_t *demuxer, mkv_track_t *track, - uint8_t *buffer, uint32_t size, int block_bref) + uint8_t *buffer, uint32_t size, int64_t block_bref) { mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv; int sps = track->sub_packet_size; @@ -2028,7 +2024,7 @@ static int handle_block(demuxer_t *demuxer, uint8_t *block, uint64_t length, mkv_track_t *track = NULL; demux_stream_t *ds = NULL; uint64_t old_length; - int64_t tc; + uint64_t tc; uint32_t *lace_size; uint8_t laces, flags; int i, num, tmp, use_this_block = 1; @@ -2048,10 +2044,8 @@ static int handle_block(demuxer_t *demuxer, uint8_t *block, uint64_t length, return 0; block += old_length - length; - tc = (time * mkv_d->tc_scale + mkv_d->cluster_tc) / 1000000.0 + 0.5; - if (tc < 0) - tc = 0; - current_pts = tc / 1000.0; + tc = time * mkv_d->tc_scale + mkv_d->cluster_tc; + current_pts = tc / 1e9; for (i = 0; i < mkv_d->num_tracks; i++) if (mkv_d->tracks[i]->tnum == num) { @@ -2080,7 +2074,7 @@ static int handle_block(demuxer_t *demuxer, uint8_t *block, uint64_t length, sh_audio_t *sh = (sh_audio_t *) ds->sh; if (block_duration != 0) { - sh->i_bps = length * 1000 / block_duration; + sh->i_bps = length * 1e9 / block_duration; track->fix_i_bps = 0; } else if (track->qt_last_a_pts == 0.0) track->qt_last_a_pts = current_pts; @@ -2186,8 +2180,7 @@ static int demux_mkv_fill_buffer(demuxer_t *demuxer, demux_stream_t *ds) free(block); return 0; } - block_duration = - block_duration * mkv_d->tc_scale / 1000000.0 + 0.5; + block_duration *= mkv_d->tc_scale; break; case MATROSKA_ID_BLOCK: @@ -2387,7 +2380,7 @@ static struct mkv_index *seek_with_cues(struct demuxer *demuxer, int seek_id, * target time after the last entry - then still seek to the first/last * entry if that's further in the direction wanted than mkv_d->last_pts. */ - int64_t min_diff = target_timecode - mkv_d->last_pts * 1000; + int64_t min_diff = target_timecode - (int64_t)(mkv_d->last_pts * 1e9 + 0.5); if (flags & SEEK_BACKWARD) min_diff = -min_diff; min_diff = FFMAX(min_diff, 1); @@ -2395,8 +2388,7 @@ static struct mkv_index *seek_with_cues(struct demuxer *demuxer, int seek_id, if (seek_id < 0 || mkv_d->indexes[i].tnum == seek_id) { int64_t diff = target_timecode - - (int64_t) (mkv_d->indexes[i].timecode * - mkv_d->tc_scale / 1000000.0 + 0.5); + (int64_t) (mkv_d->indexes[i].timecode * mkv_d->tc_scale); if (flags & SEEK_BACKWARD) diff = -diff; if (diff <= 0) { @@ -2442,9 +2434,8 @@ static void demux_mkv_seek(demuxer_t *demuxer, float rel_seek_secs, if (!(flags & SEEK_ABSOLUTE)) /* relative seek */ rel_seek_secs += mkv_d->last_pts; - int64_t target_timecode = rel_seek_secs * 1000.0; - if (target_timecode < 0) - target_timecode = 0; + rel_seek_secs = FFMAX(rel_seek_secs, 0); + int64_t target_timecode = rel_seek_secs * 1e9 + 0.5; if (mkv_d->indexes == NULL) { /* no index was found */ if (seek_creating_index(demuxer, rel_seek_secs, flags) < 0) @@ -2462,7 +2453,8 @@ static void demux_mkv_seek(demuxer_t *demuxer, float rel_seek_secs, if (flags & SEEK_FORWARD) mkv_d->skip_to_timecode = target_timecode; else - mkv_d->skip_to_timecode = index ? index->timecode : 0; + mkv_d->skip_to_timecode = index ? index->timecode * mkv_d->tc_scale + : 0; mkv_d->a_skip_to_keyframe = 1; demux_mkv_fill_buffer(demuxer, NULL); @@ -2496,7 +2488,7 @@ static void demux_mkv_seek(demuxer_t *demuxer, float rel_seek_secs, if (demuxer->video->id >= 0) mkv_d->v_skip_to_keyframe = 1; - mkv_d->skip_to_timecode = index->timecode; + mkv_d->skip_to_timecode = index->timecode * mkv_d->tc_scale; mkv_d->a_skip_to_keyframe = 1; demux_mkv_fill_buffer(demuxer, NULL); diff --git a/libmpdemux/demux_mov.c b/libmpdemux/demux_mov.c index 3175ae34bd..5ecb076698 100644 --- a/libmpdemux/demux_mov.c +++ b/libmpdemux/demux_mov.c @@ -64,7 +64,7 @@ #include "libavutil/common.h" #include "ffmpeg_files/intreadwrite.h" -#include "libvo/sub.h" +#include "sub/sub.h" #include "demux_mov.h" #include "qtpalette.h" diff --git a/libmpdemux/demux_ogg.c b/libmpdemux/demux_ogg.c index 1883c36cd1..3ba2627414 100644 --- a/libmpdemux/demux_ogg.c +++ b/libmpdemux/demux_ogg.c @@ -166,8 +166,8 @@ typedef struct ogg_demuxer { //-------- subtitle support - should be moved to decoder layer, and queue // - subtitles up in demuxer buffer... -#include "subreader.h" -#include "libvo/sub.h" +#include "sub/subreader.h" +#include "sub/sub.h" #define OGG_SUB_MAX_LINE 128 static subtitle ogg_sub; diff --git a/libmpdemux/demux_ty.c b/libmpdemux/demux_ty.c index 5d6958a970..4309ad1387 100644 --- a/libmpdemux/demux_ty.c +++ b/libmpdemux/demux_ty.c @@ -44,7 +44,7 @@ #include "demux_ty_osd.h" #include "parse_es.h" #include "stheader.h" -#include "sub_cc.h" +#include "sub/sub_cc.h" #include "libavutil/avstring.h" #include "ffmpeg_files/intreadwrite.h" diff --git a/libmpdemux/demux_ty_osd.c b/libmpdemux/demux_ty_osd.c index 0d419b0813..983c243f98 100644 --- a/libmpdemux/demux_ty_osd.c +++ b/libmpdemux/demux_ty_osd.c @@ -23,8 +23,8 @@ //#include "stheader.h" //#include "mp3_hdr.h" //#include "subreader.h" -#include "sub_cc.h" -#include "libvo/sub.h" +#include "sub/sub_cc.h" +#include "sub/sub.h" #include "demux_ty_osd.h" //#include "dvdauth.h" diff --git a/libmpdemux/demuxer.c b/libmpdemux/demuxer.c index 056822e1ab..6607f2399f 100644 --- a/libmpdemux/demuxer.c +++ b/libmpdemux/demuxer.c @@ -43,8 +43,6 @@ #include "libmpcodecs/dec_teletext.h" #include "libmpcodecs/vd_ffmpeg.h" -#include "ass_mp.h" - #ifdef CONFIG_FFMPEG #include "libavcodec/avcodec.h" #if MP_INPUT_BUFFER_PADDING_SIZE < FF_INPUT_BUFFER_PADDING_SIZE @@ -188,7 +186,7 @@ struct demux_packet *new_demux_packet(size_t len) dp->len = len; dp->next = NULL; dp->pts = MP_NOPTS_VALUE; - dp->endpts = MP_NOPTS_VALUE; + dp->duration = -1; dp->stream_pts = MP_NOPTS_VALUE; dp->pos = 0; dp->flags = 0; @@ -351,10 +349,6 @@ sh_sub_t *new_sh_sub_sid(demuxer_t *demuxer, int id, int sid) sh->opts = demuxer->opts; mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_SUBTITLE_ID=%d\n", sid); } - if (sid == demuxer->opts->sub_id) { - demuxer->sub->id = id; - demuxer->sub->sh = demuxer->s_streams[id]; - } return demuxer->s_streams[id]; } @@ -373,10 +367,6 @@ static void free_sh_sub(sh_sub_t *sh) { mp_msg(MSGT_DEMUXER, MSGL_DBG2, "DEMUXER: freeing sh_sub at %p\n", sh); free(sh->extradata); -#ifdef CONFIG_ASS - if (sh->ass_track) - ass_free_track(sh->ass_track); -#endif free(sh->lang); #ifdef CONFIG_FFMPEG clear_parser((sh_common_t *)sh); @@ -1076,20 +1066,6 @@ static struct demuxer *demux_open_stream(struct MPOpts *opts, sh_video->fps, sh_video->i_bps * 0.008f, sh_video->i_bps / 1024.0f); } -#ifdef CONFIG_ASS - if (opts->ass_enabled && ass_library) { - for (int i = 0; i < MAX_S_STREAMS; ++i) { - sh_sub_t *sh = demuxer->s_streams[i]; - if (sh && sh->type == 'a') { - sh->ass_track = ass_new_track(ass_library); - if (sh->ass_track && sh->extradata) - ass_process_codec_private(sh->ass_track, sh->extradata, - sh->extradata_len); - } else if (sh && sh->type != 'v') - sh->ass_track = ass_default_track(ass_library); - } - } -#endif return demuxer; } @@ -1418,9 +1394,9 @@ int demuxer_add_chapter(demuxer_t *demuxer, struct bstr name, talloc_strdup(demuxer->chapters, mp_gtext("unknown")); mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_CHAPTER_ID=%d\n", demuxer->num_chapters); - mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_CHAPTER_%d_START=%"PRIu64"\n", demuxer->num_chapters, start); + mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_CHAPTER_%d_START=%"PRIu64"\n", demuxer->num_chapters, start / 1000000); if (end) - mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_CHAPTER_%d_END=%"PRIu64"\n", demuxer->num_chapters, end); + mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_CHAPTER_%d_END=%"PRIu64"\n", demuxer->num_chapters, end / 1000000); if (name.start) mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_CHAPTER_%d_NAME=%.*s\n", demuxer->num_chapters, BSTR_P(name)); @@ -1473,7 +1449,7 @@ int demuxer_seek_chapter(demuxer_t *demuxer, int chapter, double *seek_pts, if (chapter < 0) chapter = 0; - *seek_pts = demuxer->chapters[chapter].start / 1000.0; + *seek_pts = demuxer->chapters[chapter].start / 1e9; if (chapter_name) *chapter_name = talloc_strdup(NULL, demuxer->chapters[chapter].name); @@ -1490,7 +1466,7 @@ int demuxer_get_current_chapter(demuxer_t *demuxer, double time_now) &chapter) == STREAM_UNSUPPORTED) chapter = -2; } else { - uint64_t now = time_now * 1000 + 0.5; + uint64_t now = time_now * 1e9 + 0.5; for (chapter = demuxer->num_chapters - 1; chapter >= 0; --chapter) { if (demuxer->chapters[chapter].start <= now) break; @@ -1533,8 +1509,8 @@ float demuxer_chapter_time(demuxer_t *demuxer, int chapter, float *end) if (demuxer->num_chapters && demuxer->chapters && chapter >= 0 && chapter < demuxer->num_chapters) { if (end) - *end = demuxer->chapters[chapter].end / 1000.0; - return demuxer->chapters[chapter].start / 1000.0; + *end = demuxer->chapters[chapter].end / 1e9; + return demuxer->chapters[chapter].start / 1e9; } return -1.0; } diff --git a/libmpdemux/demuxer.h b/libmpdemux/demuxer.h index 742e42aa74..e66b8f8a12 100644 --- a/libmpdemux/demuxer.h +++ b/libmpdemux/demuxer.h @@ -27,6 +27,7 @@ #include "stream/stream.h" #include "bstr.h" +#include "mpcommon.h" struct MPOpts; @@ -96,9 +97,6 @@ struct MPOpts; // A virtual demuxer type for the network code #define DEMUXER_TYPE_PLAYLIST (2<<16) - -#define MP_NOPTS_VALUE (-1LL<<63) //both int64_t and double should be able to represent this exactly - enum timestamp_type { TIMESTAMP_TYPE_PTS, TIMESTAMP_TYPE_SORT, @@ -129,7 +127,7 @@ enum timestamp_type { typedef struct demux_packet { int len; double pts; - double endpts; + double duration; double stream_pts; off_t pos; // position in index (AVI) or file (MPG) unsigned char* buffer; diff --git a/libmpdemux/stheader.h b/libmpdemux/stheader.h index 4bb2da3ac7..dc84518abc 100644 --- a/libmpdemux/stheader.h +++ b/libmpdemux/stheader.h @@ -19,6 +19,8 @@ #ifndef MPLAYER_STHEADER_H #define MPLAYER_STHEADER_H +#include <stdbool.h> + #include "aviheader.h" #include "ms_hdr.h" struct MPOpts; @@ -135,9 +137,10 @@ typedef struct sh_sub { SH_COMMON int sid; char type; // t = text, v = VobSub, a = SSA/ASS + bool active; // after track switch decoder may stay initialized, not active unsigned char* extradata; // extra header data passed from demuxer int extradata_len; - struct ass_track *ass_track; // for SSA/ASS streams (type == 'a') + const struct sd_functions *sd_driver; } sh_sub_t; // demuxer.c: diff --git a/libmpdemux/video.c b/libmpdemux/video.c index bda6e661ae..400a995d57 100644 --- a/libmpdemux/video.c +++ b/libmpdemux/video.c @@ -38,7 +38,7 @@ #include "mpeg_hdr.h" /* sub_cc (closed captions)*/ -#include "sub_cc.h" +#include "sub/sub_cc.h" /* biCompression constant */ #define BI_RGB 0L diff --git a/libvo/old_vo_wrapper.c b/libvo/old_vo_wrapper.c index bdbc8b8349..a99511d831 100644 --- a/libvo/old_vo_wrapper.c +++ b/libvo/old_vo_wrapper.c @@ -20,7 +20,7 @@ #include <stdint.h> #include "old_vo_wrapper.h" #include "video_out.h" -#include "sub.h" +#include "sub/sub.h" struct vo *global_vo; struct osd_state *global_osd; diff --git a/libvo/vesa_lvo.c b/libvo/vesa_lvo.c index 4f4c796250..f5cbab4757 100644 --- a/libvo/vesa_lvo.c +++ b/libvo/vesa_lvo.c @@ -39,7 +39,7 @@ #include "fastmemcpy.h" #include "osd.h" #include "video_out.h" -#include "sub.h" +#include "sub/sub.h" #include "libmpcodecs/vfcap.h" #define WIDTH_ALIGN 32 /* should be 16 for rage:422 and 32 for rage:420 */ diff --git a/libvo/video_out.h b/libvo/video_out.h index 36a161aaf5..5fac7dd02d 100644 --- a/libvo/video_out.h +++ b/libvo/video_out.h @@ -26,11 +26,8 @@ #include <inttypes.h> #include <stdbool.h> -//#include "font_load.h" #include "libmpcodecs/img_format.h" -//#include "vidix/vidix.h" - -#define MP_NOPTS_VALUE (-1LL<<63) +#include "mpcommon.h" #define VO_EVENT_EXPOSE 1 #define VO_EVENT_RESIZE 2 @@ -80,7 +77,7 @@ struct voctrl_get_equalizer_args { #define VOCTRL_BORDER 27 #define VOCTRL_DRAW_EOSD 28 #define VOCTRL_GET_EOSD_RES 29 -typedef struct { +typedef struct mp_eosd_res { int w, h; // screen dimensions, including black borders int mt, mb, ml, mr; // borders (top, bottom, left, right) } mp_eosd_res_t; diff --git a/libvo/vo_aa.c b/libvo/vo_aa.c index 3e55803982..99e313d399 100644 --- a/libvo/vo_aa.c +++ b/libvo/vo_aa.c @@ -39,8 +39,8 @@ #include "aspect.h" #include "libswscale/swscale.h" #include "libmpcodecs/vf_scale.h" -#include "font_load.h" -#include "sub.h" +#include "sub/font_load.h" +#include "sub/sub.h" #include "osdep/keycodes.h" #include <aalib.h> diff --git a/libvo/vo_caca.c b/libvo/vo_caca.c index 75e862ef91..2a5ebad4e7 100644 --- a/libvo/vo_caca.c +++ b/libvo/vo_caca.c @@ -35,7 +35,7 @@ #include "config.h" #include "video_out.h" #include "video_out_internal.h" -#include "sub.h" +#include "sub/sub.h" #include "osdep/keycodes.h" #include "mp_msg.h" diff --git a/libvo/vo_corevideo.m b/libvo/vo_corevideo.m index 585898a076..a964de7e57 100644 --- a/libvo/vo_corevideo.m +++ b/libvo/vo_corevideo.m @@ -40,7 +40,7 @@ #include "mp_msg.h" #include "m_option.h" #include "mp_fifo.h" -#include "libvo/sub.h" +#include "sub/sub.h" #include "subopt-helper.h" #include "input/input.h" diff --git a/libvo/vo_dfbmga.c b/libvo/vo_dfbmga.c index a0a9d07760..b83f3c5e52 100644 --- a/libvo/vo_dfbmga.c +++ b/libvo/vo_dfbmga.c @@ -31,7 +31,7 @@ #include "video_out.h" #include "video_out_internal.h" #include "fastmemcpy.h" -#include "sub.h" +#include "sub/sub.h" #include "mp_msg.h" #include "aspect.h" #include "mp_fifo.h" diff --git a/libvo/vo_dga.c b/libvo/vo_dga.c index 879831761d..94d42774a8 100644 --- a/libvo/vo_dga.c +++ b/libvo/vo_dga.c @@ -333,7 +333,7 @@ static void check_events(void) //--------------------------------------------------------- -#include "sub.h" +#include "sub/sub.h" static void draw_osd(void) { diff --git a/libvo/vo_direct3d.c b/libvo/vo_direct3d.c index 384dcb477b..65f5a6c2d1 100644 --- a/libvo/vo_direct3d.c +++ b/libvo/vo_direct3d.c @@ -30,8 +30,8 @@ #include "aspect.h" #include "w32_common.h" #include "libavutil/common.h" -#include "font_load.h" -#include "sub.h" +#include "sub/font_load.h" +#include "sub/sub.h" static const vo_info_t info = { diff --git a/libvo/vo_directfb2.c b/libvo/vo_directfb2.c index 1fb5577075..c011d20225 100644 --- a/libvo/vo_directfb2.c +++ b/libvo/vo_directfb2.c @@ -33,7 +33,7 @@ #include "video_out.h" #include "video_out_internal.h" #include "fastmemcpy.h" -#include "sub.h" +#include "sub/sub.h" #include "mp_msg.h" #include "aspect.h" #include "subopt-helper.h" diff --git a/libvo/vo_directx.c b/libvo/vo_directx.c index b80f0bdc01..494d6c8424 100644 --- a/libvo/vo_directx.c +++ b/libvo/vo_directx.c @@ -37,7 +37,7 @@ #include "aspect.h" #include "geometry.h" #include "mp_fifo.h" -#include "sub.h" +#include "sub/sub.h" #ifndef WM_XBUTTONDOWN # define WM_XBUTTONDOWN 0x020B diff --git a/libvo/vo_dxr2.c b/libvo/vo_dxr2.c index 00d5d2f3c0..71c402cd9a 100644 --- a/libvo/vo_dxr2.c +++ b/libvo/vo_dxr2.c @@ -34,7 +34,7 @@ #include "video_out_internal.h" #include "mp_msg.h" #include "m_option.h" -#include "sub.h" +#include "sub/sub.h" #include "path.h" #include "libmpdemux/mpeg_packetizer.h" #include "x11_common.h" diff --git a/libvo/vo_dxr3.c b/libvo/vo_dxr3.c index 3494e25f00..8f7b471306 100644 --- a/libvo/vo_dxr3.c +++ b/libvo/vo_dxr3.c @@ -42,7 +42,7 @@ #include "video_out_internal.h" #include "aspect.h" #include "spuenc.h" -#include "sub.h" +#include "sub/sub.h" #ifdef CONFIG_X11 #include "x11_common.h" #endif diff --git a/libvo/vo_fbdev.c b/libvo/vo_fbdev.c index 991673a9cd..2d422af269 100644 --- a/libvo/vo_fbdev.c +++ b/libvo/vo_fbdev.c @@ -39,7 +39,7 @@ #include "video_out.h" #include "video_out_internal.h" #include "fastmemcpy.h" -#include "sub.h" +#include "sub/sub.h" #include "geometry.h" #ifdef CONFIG_VIDIX #include "vosub_vidix.h" diff --git a/libvo/vo_fbdev2.c b/libvo/vo_fbdev2.c index a4929afe13..612b145464 100644 --- a/libvo/vo_fbdev2.c +++ b/libvo/vo_fbdev2.c @@ -34,7 +34,7 @@ #include "video_out.h" #include "video_out_internal.h" #include "fastmemcpy.h" -#include "sub.h" +#include "sub/sub.h" #include "mp_msg.h" static const vo_info_t info = { diff --git a/libvo/vo_gl.c b/libvo/vo_gl.c index 8ffd82b6fd..c062614d3a 100644 --- a/libvo/vo_gl.c +++ b/libvo/vo_gl.c @@ -31,13 +31,13 @@ #include "subopt-helper.h" #include "video_out.h" #include "video_out_internal.h" -#include "font_load.h" -#include "sub.h" +#include "sub/font_load.h" +#include "sub/sub.h" #include "gl_common.h" #include "aspect.h" #include "fastmemcpy.h" -#include "ass_mp.h" +#include "sub/ass_mp.h" #ifdef CONFIG_GL_SDL #ifdef CONFIG_SDL_SDL_H diff --git a/libvo/vo_gl2.c b/libvo/vo_gl2.c index 14137f76a6..957125069b 100644 --- a/libvo/vo_gl2.c +++ b/libvo/vo_gl2.c @@ -29,7 +29,7 @@ #include "subopt-helper.h" #include "video_out.h" #include "video_out_internal.h" -#include "sub.h" +#include "sub/sub.h" #include "gl_common.h" #include "aspect.h" diff --git a/libvo/vo_kva.c b/libvo/vo_kva.c index 7994fe9143..155a779e4e 100644 --- a/libvo/vo_kva.c +++ b/libvo/vo_kva.c @@ -47,7 +47,7 @@ #include "input/input.h" #include "input/mouse.h" #include "subopt-helper.h" -#include "sub.h" +#include "sub/sub.h" #include "cpudetect.h" #include "libswscale/swscale.h" diff --git a/libvo/vo_mga.c b/libvo/vo_mga.c index d398ec001a..df99251847 100644 --- a/libvo/vo_mga.c +++ b/libvo/vo_mga.c @@ -34,7 +34,7 @@ #include <linux/fb.h> #include "drivers/mga_vid.h" -#include "sub.h" +#include "sub/sub.h" #include "aspect.h" static const vo_info_t info = diff --git a/libvo/vo_quartz.c b/libvo/vo_quartz.c index 07edf2538d..65797c988b 100644 --- a/libvo/vo_quartz.c +++ b/libvo/vo_quartz.c @@ -48,7 +48,7 @@ #include "m_option.h" #include "mp_fifo.h" #include "mpbswap.h" -#include "sub.h" +#include "sub/sub.h" #include "input/input.h" #include "input/mouse.h" diff --git a/libvo/vo_s3fb.c b/libvo/vo_s3fb.c index 5b884b75b8..a0d54e0ca9 100644 --- a/libvo/vo_s3fb.c +++ b/libvo/vo_s3fb.c @@ -44,7 +44,7 @@ #include "video_out.h" #include "video_out_internal.h" #include "aspect.h" -#include "sub.h" +#include "sub/sub.h" static const vo_info_t info = { diff --git a/libvo/vo_sdl.c b/libvo/vo_sdl.c index 9715dd98fb..be6e741295 100644 --- a/libvo/vo_sdl.c +++ b/libvo/vo_sdl.c @@ -63,7 +63,7 @@ #include "video_out_internal.h" #include "fastmemcpy.h" -#include "sub.h" +#include "sub/sub.h" #include "aspect.h" #include "libmpcodecs/vfcap.h" diff --git a/libvo/vo_svga.c b/libvo/vo_svga.c index c74cf61089..d44821df05 100644 --- a/libvo/vo_svga.c +++ b/libvo/vo_svga.c @@ -59,7 +59,7 @@ TODO: #include "vosub_vidix.h" #endif -#include "sub.h" +#include "sub/sub.h" #include "mp_msg.h" //#include "mp_image.h" diff --git a/libvo/vo_tdfxfb.c b/libvo/vo_tdfxfb.c index b9255eaf8f..6e14f600b7 100644 --- a/libvo/vo_tdfxfb.c +++ b/libvo/vo_tdfxfb.c @@ -62,7 +62,7 @@ #include "video_out_internal.h" #include "drivers/3dfx.h" #include "aspect.h" -#include "sub.h" +#include "sub/sub.h" static const vo_info_t info = { diff --git a/libvo/vo_vdpau.c b/libvo/vo_vdpau.c index f8748b5574..210fe797dc 100644 --- a/libvo/vo_vdpau.c +++ b/libvo/vo_vdpau.c @@ -41,7 +41,7 @@ #include "video_out.h" #include "x11_common.h" #include "aspect.h" -#include "sub.h" +#include "sub/sub.h" #include "subopt-helper.h" #include "libmpcodecs/vfcap.h" #include "libmpcodecs/mp_image.h" @@ -49,12 +49,12 @@ #include "libavcodec/vdpau.h" -#include "font_load.h" +#include "sub/font_load.h" #include "libavutil/common.h" #include "libavutil/mathematics.h" -#include "ass_mp.h" +#include "sub/ass_mp.h" #define WRAP_ADD(x, a, m) ((a) < 0 \ ? ((x)+(a)+(m) < (m) ? (x)+(a)+(m) : (x)+(a)) \ @@ -1803,7 +1803,7 @@ static int control(struct vo *vo, uint32_t request, void *data) draw_eosd(vo); return VO_TRUE; case VOCTRL_GET_EOSD_RES: { - mp_eosd_res_t *r = data; + struct mp_eosd_res *r = data; r->w = vo->dwidth; r->h = vo->dheight; r->ml = r->mr = vc->border_x; diff --git a/libvo/vo_vesa.c b/libvo/vo_vesa.c index 8c367586ee..698b9f033a 100644 --- a/libvo/vo_vesa.c +++ b/libvo/vo_vesa.c @@ -48,7 +48,7 @@ #include "video_out_internal.h" #include "fastmemcpy.h" -#include "sub.h" +#include "sub/sub.h" #include "libavutil/common.h" #include "mpbswap.h" #include "aspect.h" diff --git a/libvo/vo_wii.c b/libvo/vo_wii.c index 148e641bdb..b7c07fc6cb 100644 --- a/libvo/vo_wii.c +++ b/libvo/vo_wii.c @@ -51,7 +51,7 @@ #include "config.h" #include "video_out.h" #include "video_out_internal.h" -#include "sub.h" +#include "sub/sub.h" #include "mp_msg.h" static const vo_info_t info = { diff --git a/libvo/vo_x11.c b/libvo/vo_x11.c index bdf561cb53..ec85c7b747 100644 --- a/libvo/vo_x11.c +++ b/libvo/vo_x11.c @@ -46,7 +46,7 @@ static int gXErrorFlag; static int CompletionType = -1; #endif -#include "sub.h" +#include "sub/sub.h" #include "libswscale/swscale.h" #include "libmpcodecs/vf_scale.h" diff --git a/libvo/vo_xmga.c b/libvo/vo_xmga.c index 9072c8b3a2..cc6cd1cd0e 100644 --- a/libvo/vo_xmga.c +++ b/libvo/vo_xmga.c @@ -46,7 +46,7 @@ #endif #include "x11_common.h" -#include "sub.h" +#include "sub/sub.h" #include "aspect.h" #ifdef SHOW_TIME diff --git a/libvo/vo_xv.c b/libvo/vo_xv.c index 63221782e2..67d1cffb95 100644 --- a/libvo/vo_xv.c +++ b/libvo/vo_xv.c @@ -56,7 +56,7 @@ Buffer allocation: #include "x11_common.h" #include "fastmemcpy.h" -#include "sub.h" +#include "sub/sub.h" #include "aspect.h" #include "subopt-helper.h" diff --git a/libvo/vo_xvmc.c b/libvo/vo_xvmc.c index 252a2cf87f..21a279beaa 100644 --- a/libvo/vo_xvmc.c +++ b/libvo/vo_xvmc.c @@ -45,7 +45,7 @@ #include "libavcodec/avcodec.h" #include "libavcodec/xvmc.h" -#include "sub.h" +#include "sub/sub.h" #include "aspect.h" #include "subopt-helper.h" diff --git a/libvo/vo_xvr100.c b/libvo/vo_xvr100.c index 7a82c436fb..fcd3b35b54 100644 --- a/libvo/vo_xvr100.c +++ b/libvo/vo_xvr100.c @@ -48,7 +48,7 @@ #include "aspect.h" #include "geometry.h" #include "fastmemcpy.h" -#include "sub.h" +#include "sub/sub.h" #include "mp_msg.h" diff --git a/libvo/vo_yuv4mpeg.c b/libvo/vo_yuv4mpeg.c index 5901cce2c2..67013eaa90 100644 --- a/libvo/vo_yuv4mpeg.c +++ b/libvo/vo_yuv4mpeg.c @@ -51,7 +51,7 @@ #include "mp_msg.h" -#include "sub.h" +#include "sub/sub.h" #include "fastmemcpy.h" #include "libavutil/rational.h" diff --git a/libvo/vosub_vidix.c b/libvo/vosub_vidix.c index b06306e98b..f4add7db4c 100644 --- a/libvo/vosub_vidix.c +++ b/libvo/vosub_vidix.c @@ -41,7 +41,7 @@ #include "fastmemcpy.h" #include "osd.h" #include "video_out.h" -#include "sub.h" +#include "sub/sub.h" #include "vosub_vidix.h" #include "old_vo_wrapper.h" diff --git a/m_option.c b/m_option.c index a0f01e6344..3cca348b1e 100644 --- a/m_option.c +++ b/m_option.c @@ -970,7 +970,7 @@ static int parse_print(const m_option_t* opt,const char *name, const char *param if(opt->priv == NULL) return M_OPT_EXIT; - return 1; + return 0; } const m_option_type_t m_option_type_print = { @@ -23,7 +23,7 @@ #include "options.h" #include "mixer.h" -#include "subreader.h" +#include "sub/subreader.h" // definitions used internally by the core player code @@ -37,6 +37,7 @@ #define INITIALIZED_DEMUXER 512 #define INITIALIZED_ACODEC 1024 #define INITIALIZED_VCODEC 2048 +#define INITIALIZED_SUB 4096 #define INITIALIZED_ALL 0xFFFF @@ -88,6 +89,9 @@ typedef struct MPContext { struct mp_fifo *key_fifo; struct input_ctx *input; struct osd_state *osd; + struct sub_data *subdata; // current sub_data style subtitles if any + // last sub_data style sub line if any, used by log_sub() only + struct subtitle *vo_sub_last; bool add_osd_seek_info; // if nonzero, hide current OSD contents when GetTimerMS() reaches this @@ -194,6 +198,7 @@ typedef struct MPContext { // parsed by libass or NULL if format unsupported struct ass_track *set_of_ass_tracks[MAX_SUBTITLE_FILES]; sub_data* set_of_subtitles[MAX_SUBTITLE_FILES]; + bool track_was_native_ass[MAX_SUBTITLE_FILES]; int file_format; @@ -243,5 +248,7 @@ double get_current_time(struct MPContext *mpctx); int get_percent_pos(struct MPContext *mpctx); int get_current_chapter(struct MPContext *mpctx); char *chapter_display_name(struct MPContext *mpctx, int chapter); +void update_subtitles(struct MPContext *mpctx, double refpts, + double sub_offset, bool reset); #endif /* MPLAYER_MP_CORE_H */ diff --git a/mpcommon.c b/mpcommon.c index f1b1828c1f..47c056a08e 100644 --- a/mpcommon.c +++ b/mpcommon.c @@ -16,351 +16,6 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#if defined(__MINGW32__) || defined(__CYGWIN__) -#include <windows.h> -#endif -#include <stdlib.h> -#include <stdbool.h> - -#include "mpcommon.h" -#include "options.h" -#include "stream/stream.h" -#include "libmpdemux/demuxer.h" -#include "libmpdemux/stheader.h" -#include "mplayer.h" -#include "libvo/sub.h" -#include "libvo/video_out.h" -#include "cpudetect.h" -#include "mp_msg.h" -#include "spudec.h" #include "version.h" -#include "vobsub.h" -#include "av_sub.h" -#include "libmpcodecs/dec_teletext.h" -#include "ffmpeg_files/intreadwrite.h" -#include "m_option.h" - -double sub_last_pts = -303; - -#ifdef CONFIG_ASS -#include "ass_mp.h" -ASS_Track *ass_track = 0; // current track to render -#endif - -sub_data* subdata = NULL; -subtitle* vo_sub_last = NULL; const char *mplayer_version = "MPlayer " VERSION; - -void print_version(const char* name) -{ - mp_msg(MSGT_CPLAYER, MSGL_INFO, MP_TITLE, name); - - /* Test for CPU capabilities (and corresponding OS support) for optimizing */ - GetCpuCaps(&gCpuCaps); -#if ARCH_X86 - mp_msg(MSGT_CPLAYER, MSGL_V, - "CPUflags: MMX: %d MMX2: %d 3DNow: %d 3DNowExt: %d SSE: %d SSE2: %d SSSE3: %d\n", - gCpuCaps.hasMMX, gCpuCaps.hasMMX2, - gCpuCaps.has3DNow, gCpuCaps.has3DNowExt, - gCpuCaps.hasSSE, gCpuCaps.hasSSE2, gCpuCaps.hasSSSE3); -#if CONFIG_RUNTIME_CPUDETECT - mp_tmsg(MSGT_CPLAYER,MSGL_V, "Compiled with runtime CPU detection.\n"); -#else - mp_tmsg(MSGT_CPLAYER,MSGL_V, "Compiled for x86 CPU with extensions:"); -if (HAVE_MMX) - mp_msg(MSGT_CPLAYER,MSGL_V," MMX"); -if (HAVE_MMX2) - mp_msg(MSGT_CPLAYER,MSGL_V," MMX2"); -if (HAVE_AMD3DNOW) - mp_msg(MSGT_CPLAYER,MSGL_V," 3DNow"); -if (HAVE_AMD3DNOWEXT) - mp_msg(MSGT_CPLAYER,MSGL_V," 3DNowExt"); -if (HAVE_SSE) - mp_msg(MSGT_CPLAYER,MSGL_V," SSE"); -if (HAVE_SSE2) - mp_msg(MSGT_CPLAYER,MSGL_V," SSE2"); -if (HAVE_SSSE3) - mp_msg(MSGT_CPLAYER,MSGL_V," SSSE3"); -if (HAVE_CMOV) - mp_msg(MSGT_CPLAYER,MSGL_V," CMOV"); - mp_msg(MSGT_CPLAYER,MSGL_V,"\n"); -#endif /* CONFIG_RUNTIME_CPUDETECT */ -#endif /* ARCH_X86 */ -} - -static bool is_text_sub(int type) -{ - return type == 't' || type == 'm' || type == 'a'; -} - -static bool is_av_sub(int type) -{ - return type == 'b' || type == 'p' || type == 'x'; -} - -void update_subtitles(struct MPContext *mpctx, struct MPOpts *opts, - sh_video_t *sh_video, double refpts, double sub_offset, - demux_stream_t *d_dvdsub, int reset) -{ - double curpts = refpts + sub_delay; - unsigned char *packet=NULL; - int len; - int type = d_dvdsub->sh ? ((sh_sub_t *)d_dvdsub->sh)->type : 'v'; - static subtitle subs; - if (reset) { - sub_clear_text(&subs, MP_NOPTS_VALUE); - if (vo_sub) { - set_osd_subtitle(mpctx, NULL); - } - if (vo_spudec) { - spudec_reset(vo_spudec); - vo_osd_changed(OSDTYPE_SPU); - } -#ifdef CONFIG_FFMPEG - if (is_av_sub(type)) - reset_avsub(d_dvdsub->sh); -#endif - return; - } - // find sub - if (subdata) { - if (sub_fps==0) sub_fps = sh_video ? sh_video->fps : 25; - current_module = "find_sub"; - if (refpts > sub_last_pts || refpts < sub_last_pts-1.0) { - find_sub(mpctx, subdata, curpts * - (subdata->sub_uses_time ? 100. : sub_fps)); - if (vo_sub) vo_sub_last = vo_sub; - // FIXME! frame counter... - sub_last_pts = refpts; - } - } - - // DVD sub: - if (vobsub_id >= 0 || type == 'v') { - int timestamp; - current_module = "spudec"; - /* Get a sub packet from the DVD or a vobsub */ - while(1) { - // Vobsub - len = 0; - if (vo_vobsub) { - if (curpts >= 0) { - len = vobsub_get_packet(vo_vobsub, curpts, - (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,sh_video->timer,timestamp / 90000.0,timestamp); - } - } - } else { - // DVD sub - len = ds_get_packet_sub(d_dvdsub, (unsigned char**)&packet); - if (len > 0) { - // XXX This is wrong, sh_video->pts can be arbitrarily - // much behind demuxing position. Unfortunately using - // d_video->pts which would have been the simplest - // improvement doesn't work because mpeg specific hacks - // in video.c set d_video->pts to 0. - float x = d_dvdsub->pts - refpts; - if (x > -20 && x < 20) // prevent missing subs on pts reset - timestamp = 90000*d_dvdsub->pts; - else timestamp = 90000*curpts; - mp_dbg(MSGT_CPLAYER, MSGL_V, "\rDVD sub: len=%d " - "v_pts=%5.3f s_pts=%5.3f ts=%d \n", len, - refpts, d_dvdsub->pts, timestamp); - } - } - if (len<=0 || !packet) break; - // create it only here, since with some broken demuxers we might - // type = v but no DVD sub and we currently do not change the - // "original frame size" ever after init, leading to wrong-sized - // PGS subtitles. - if (!vo_spudec) - vo_spudec = spudec_new(NULL); - if (vo_vobsub || timestamp >= 0) - spudec_assemble(vo_spudec, packet, len, timestamp); - } - } else if (is_text_sub(type) || is_av_sub(type) || type == 'd') { - if (type == 'd' && !d_dvdsub->demuxer->teletext) { - tt_stream_props tsp = {0}; - void *ptr = &tsp; - if (teletext_control(NULL, TV_VBI_CONTROL_START, &ptr) == VBI_CONTROL_TRUE) - d_dvdsub->demuxer->teletext = ptr; - } - if (d_dvdsub->non_interleaved) - ds_get_next_pts(d_dvdsub); - - int orig_type = type; - while (d_dvdsub->first) { - double subpts = ds_get_next_pts(d_dvdsub) + sub_offset; - type = orig_type; - if (subpts > curpts) { - // Libass handled subs can be fed to it in advance - if (!opts->ass_enabled || !is_text_sub(type)) - break; - // Try to avoid demuxing whole file at once - if (d_dvdsub->non_interleaved && subpts > curpts + 1) - break; - } - double endpts = d_dvdsub->first->endpts + sub_offset; - len = ds_get_packet_sub(d_dvdsub, &packet); - if (is_av_sub(type)) { -#ifdef CONFIG_FFMPEG - type = decode_avsub(d_dvdsub->sh, &packet, &len, &subpts, &endpts); - if (type <= 0) -#endif - continue; - } - if (type == 'm') { - if (len < 2) continue; - len = FFMIN(len - 2, AV_RB16(packet)); - packet += 2; - } - if (type == 'd') { - if (d_dvdsub->demuxer->teletext) { - uint8_t *p = packet; - p++; - len--; - while (len >= 46) { - int sublen = p[1]; - if (p[0] == 2 || p[0] == 3) - teletext_control(d_dvdsub->demuxer->teletext, - TV_VBI_CONTROL_DECODE_DVB, p + 2); - p += sublen + 2; - len -= sublen + 2; - } - } - continue; - } -#ifdef CONFIG_ASS - if (opts->ass_enabled) { - sh_sub_t* sh = d_dvdsub->sh; - ass_track = sh ? sh->ass_track : NULL; - if (!ass_track) continue; - if (type == 'a') { // ssa/ass subs with libass - ass_process_chunk(ass_track, packet, len, - (long long)(subpts*1000 + 0.5), - (long long)((endpts-subpts)*1000 + 0.5)); - } else { // plaintext subs with libass - if (subpts != MP_NOPTS_VALUE) { - subtitle tmp_subs = {0}; - if (endpts == MP_NOPTS_VALUE) endpts = subpts + 3; - sub_add_text(&tmp_subs, packet, len, endpts); - tmp_subs.start = subpts * 100; - tmp_subs.end = endpts * 100; - ass_process_subtitle(ass_track, &tmp_subs); - sub_clear_text(&tmp_subs, MP_NOPTS_VALUE); - } - } - continue; - } -#endif - if (subpts != MP_NOPTS_VALUE) { - if (endpts == MP_NOPTS_VALUE) - sub_clear_text(&subs, MP_NOPTS_VALUE); - if (type == 'a') { // ssa/ass subs without libass => convert to plaintext - int i; - unsigned char* p = packet; - for (i=0; i < 8 && *p != '\0'; p++) - if (*p == ',') - i++; - if (*p == '\0') /* Broken line? */ - continue; - len -= p - packet; - packet = p; - } - sub_add_text(&subs, packet, len, endpts); - set_osd_subtitle(mpctx, &subs); - } - if (d_dvdsub->non_interleaved) - ds_get_next_pts(d_dvdsub); - } - if (!opts->ass_enabled) - if (sub_clear_text(&subs, curpts)) - set_osd_subtitle(mpctx, &subs); - } - if (vo_spudec) { - spudec_heartbeat(vo_spudec, 90000*curpts); - if (spudec_changed(vo_spudec)) - vo_osd_changed(OSDTYPE_SPU); - } - - current_module=NULL; -} - -void update_teletext(sh_video_t *sh_video, demuxer_t *demuxer, int reset) -{ - int page_changed; - - if (!demuxer->teletext) - return; - - //Also forcing page update when such ioctl is not supported or call error occured - if(teletext_control(demuxer->teletext,TV_VBI_CONTROL_IS_CHANGED,&page_changed)!=VBI_CONTROL_TRUE) - page_changed=1; - - if(!page_changed) - return; - - if(teletext_control(demuxer->teletext,TV_VBI_CONTROL_GET_VBIPAGE,&vo_osd_teletext_page)!=VBI_CONTROL_TRUE) - vo_osd_teletext_page=NULL; - if(teletext_control(demuxer->teletext,TV_VBI_CONTROL_GET_HALF_PAGE,&vo_osd_teletext_half)!=VBI_CONTROL_TRUE) - vo_osd_teletext_half=0; - if(teletext_control(demuxer->teletext,TV_VBI_CONTROL_GET_MODE,&vo_osd_teletext_mode)!=VBI_CONTROL_TRUE) - vo_osd_teletext_mode=0; - if(teletext_control(demuxer->teletext,TV_VBI_CONTROL_GET_FORMAT,&vo_osd_teletext_format)!=VBI_CONTROL_TRUE) - vo_osd_teletext_format=0; - vo_osd_changed(OSDTYPE_TELETEXT); - - teletext_control(demuxer->teletext,TV_VBI_CONTROL_MARK_UNCHANGED,NULL); -} - -int select_audio(demuxer_t* demuxer, int audio_id, char* audio_lang) -{ - if (audio_id == -1) - audio_id = demuxer_audio_track_by_lang_and_default(demuxer, audio_lang); - if (audio_id != -1) // -1 (automatic) is the default behaviour of demuxers - demuxer_switch_audio(demuxer, audio_id); - if (audio_id == -2) { // some demuxers don't yet know how to switch to no sound - demuxer->audio->id = -2; - demuxer->audio->sh = NULL; - } - return demuxer->audio->id; -} - -bool attachment_is_font(struct demux_attachment *att) -{ - if (!att->name || !att->type || !att->data || !att->data_size) - return false; - // match against MIME types - if (strcmp(att->type, "application/x-truetype-font") == 0 - || strcmp(att->type, "application/x-font") == 0) - return true; - // fallback: match against file extension - if (strlen(att->name) > 4) { - char *ext = att->name + strlen(att->name) - 4; - if (strcasecmp(ext, ".ttf") == 0 || strcasecmp(ext, ".ttc") == 0 - || strcasecmp(ext, ".otf") == 0) - return true; - } - return false; -} - -/* Parse -noconfig common to both programs */ -int disable_system_conf=0; -int disable_user_conf=0; - -/* Disable all configuration files */ -static void noconfig_all(void) -{ - disable_system_conf = 1; - disable_user_conf = 1; -} - -const m_option_t noconfig_opts[] = { - {"all", noconfig_all, CONF_TYPE_FUNC, CONF_GLOBAL|CONF_NOCFG|CONF_PRE_PARSE, 0, 0, NULL}, - {"system", &disable_system_conf, CONF_TYPE_FLAG, CONF_GLOBAL|CONF_NOCFG|CONF_PRE_PARSE, 0, 1, NULL}, - {"user", &disable_user_conf, CONF_TYPE_FLAG, CONF_GLOBAL|CONF_NOCFG|CONF_PRE_PARSE, 0, 1, NULL}, - {NULL, NULL, 0, 0, 0, 0, NULL} -}; - diff --git a/mpcommon.h b/mpcommon.h index d34be23e32..82b860bd87 100644 --- a/mpcommon.h +++ b/mpcommon.h @@ -19,35 +19,9 @@ #ifndef MPLAYER_MPCOMMON_H #define MPLAYER_MPCOMMON_H -#include <stdbool.h> - -struct subtitle; - -extern double sub_last_pts; -extern struct ass_track *ass_track; -extern struct subtitle *vo_sub_last; - -extern int disable_system_conf; -extern int disable_user_conf; +// both int64_t and double should be able to represent this exactly +#define MP_NOPTS_VALUE (-1LL<<63) extern const char *mplayer_version; -struct MPContext; -struct demuxer; -struct demux_stream; -struct demux_attachment; -struct sh_video; -struct MPOpts; - -void print_version(const char* name); -void update_subtitles(struct MPContext *mpctx, struct MPOpts *opts, - struct sh_video *sh_video, double refpts, - double sub_offset, struct demux_stream *d_dvdsub, - int reset); -void update_teletext(struct sh_video *sh_video, struct demuxer *demuxer, - int reset); -int select_audio(struct demuxer *demuxer, int audio_id, char *audio_lang); -void set_osd_subtitle(struct MPContext *mpctx, struct subtitle *subs); -bool attachment_is_font(struct demux_attachment *att); - #endif /* MPLAYER_MPCOMMON_H */ @@ -71,13 +71,19 @@ #include "libavutil/avstring.h" -#include "subreader.h" +#include "sub/subreader.h" +#include "sub/dec_sub.h" #include "mp_osd.h" #include "libvo/video_out.h" -#include "libvo/font_load.h" -#include "libvo/sub.h" +#include "sub/font_load.h" +#include "sub/sub.h" +#include "ffmpeg_files/intreadwrite.h" +#include "sub/av_sub.h" +#include "libmpcodecs/dec_teletext.h" +#include "cpudetect.h" +#include "version.h" #ifdef CONFIG_X11 #include "libvo/x11_common.h" @@ -89,8 +95,8 @@ #include "edl.h" -#include "spudec.h" -#include "vobsub.h" +#include "sub/spudec.h" +#include "sub/vobsub.h" #include "osdep/getch2.h" #include "osdep/timer.h" @@ -328,7 +334,7 @@ char *vobsub_name=NULL; int subcc_enabled=0; int suboverlap_enabled = 1; -#include "ass_mp.h" +#include "sub/ass_mp.h" char* current_module=NULL; // for debugging @@ -595,6 +601,15 @@ static void mp_dvdnav_context_free(MPContext *ctx){ } #endif +static void uninit_subs(struct demuxer *demuxer) +{ + for (int i = 0; i < MAX_S_STREAMS; i++) { + struct sh_sub *sh = demuxer->s_streams[i]; + if (sh && sh->initialized) + sub_uninit(sh); + } +} + void uninit_player(struct MPContext *mpctx, unsigned int mask){ mask &= mpctx->initialized_flags; @@ -608,6 +623,12 @@ void uninit_player(struct MPContext *mpctx, unsigned int mask){ mpctx->mixer.afilter = NULL; } + if (mask & INITIALIZED_SUB) { + mpctx->initialized_flags &= ~INITIALIZED_SUB; + if (mpctx->d_sub->sh) + sub_switchoff(mpctx->d_sub->sh, mpctx->osd); + } + if(mask&INITIALIZED_VCODEC){ mpctx->initialized_flags&=~INITIALIZED_VCODEC; current_module="uninit_vcodec"; @@ -624,6 +645,7 @@ void uninit_player(struct MPContext *mpctx, unsigned int mask){ if (mpctx->num_sources) { mpctx->demuxer = mpctx->sources[0].demuxer; for (int i = 1; i < mpctx->num_sources; i++) { + uninit_subs(mpctx->sources[i].demuxer); free_stream(mpctx->sources[i].stream); free_demuxer(mpctx->sources[i].demuxer); } @@ -640,6 +662,7 @@ void uninit_player(struct MPContext *mpctx, unsigned int mask){ mpctx->video_offset = 0; if(mpctx->demuxer){ mpctx->stream=mpctx->demuxer->stream; + uninit_subs(mpctx->demuxer); free_demuxer(mpctx->demuxer); } mpctx->demuxer=NULL; @@ -868,9 +891,10 @@ static int cfg_include(m_option_t *conf, char *filename) static void parse_cfgfiles(struct MPContext *mpctx, m_config_t* conf) { + struct MPOpts *opts = &mpctx->opts; char *conffile; int conffile_fd; -if (!disable_system_conf && + if (!(opts->noconfig & 2) && m_config_parse_config_file(conf, MPLAYER_CONFDIR "/mplayer.conf") < 0) exit_player(mpctx, EXIT_NONE); if ((conffile = get_path("")) == NULL) { @@ -890,7 +914,7 @@ if ((conffile = get_path("")) == NULL) { write(conffile_fd, default_config, strlen(default_config)); close(conffile_fd); } - if (!disable_user_conf && + if (!(opts->noconfig & 1) && m_config_parse_config_file(conf, conffile) < 0) exit_player(mpctx, EXIT_NONE); free(conffile); @@ -1067,31 +1091,30 @@ void add_subtitles(struct MPContext *mpctx, char *filename, float fps, int noerr struct MPOpts *opts = &mpctx->opts; sub_data *subd = NULL; struct ass_track *asst = NULL; + bool is_native_ass = false; - if (filename == NULL || mpctx->set_of_sub_size >= MAX_SUBTITLE_FILES) { + if (filename == NULL || mpctx->set_of_sub_size >= MAX_SUBTITLE_FILES) return; - } #ifdef CONFIG_ASS if (opts->ass_enabled) { #ifdef CONFIG_ICONV - asst = ass_read_stream(ass_library, filename, sub_cp); + asst = mp_ass_read_stream(ass_library, filename, sub_cp); #else - asst = ass_read_stream(ass_library, filename, 0); + asst = mp_ass_read_stream(ass_library, filename, 0); #endif + is_native_ass = asst; if (!asst) { - subd = sub_read_file(filename, fps); + subd = sub_read_file(filename, fps, &mpctx->opts); if (subd) { - asst = ass_read_subdata(ass_library, subd, fps); - if (asst) { - sub_free(subd); - subd = NULL; - } + asst = mp_ass_read_subdata(ass_library, subd, fps); + sub_free(subd); + subd = NULL; } } } else #endif - subd = sub_read_file(filename, fps); + subd = sub_read_file(filename, fps, &mpctx->opts); if (!asst && !subd) { @@ -1102,6 +1125,7 @@ void add_subtitles(struct MPContext *mpctx, char *filename, float fps, int noerr mpctx->set_of_ass_tracks[mpctx->set_of_sub_size] = asst; mpctx->set_of_subtitles[mpctx->set_of_sub_size] = subd; + mpctx->track_was_native_ass[mpctx->set_of_sub_size] = is_native_ass; mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_FILE_SUB_ID=%d\n", mpctx->set_of_sub_size); mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_FILE_SUB_FILENAME=%s\n", filename_recode(filename)); @@ -1795,6 +1819,209 @@ double playing_audio_pts(struct MPContext *mpctx) mpctx->audio_out->get_delay(); } +static bool is_av_sub(int type) +{ + return type == 'b' || type == 'p' || type == 'x'; +} + +void update_subtitles(struct MPContext *mpctx, double refpts, + double sub_offset, bool reset) +{ + struct MPOpts *opts = &mpctx->opts; + struct sh_video *sh_video = mpctx->sh_video; + struct demux_stream *d_sub = mpctx->d_sub; + double curpts = refpts + sub_delay; + unsigned char *packet=NULL; + int len; + struct sh_sub *sh_sub = d_sub->sh; + int type = sh_sub ? sh_sub->type : 'v'; + static subtitle subs; + if (reset) { + if (sh_sub) + sub_reset(sh_sub, mpctx->osd); + sub_clear_text(&subs, MP_NOPTS_VALUE); + if (vo_sub) + set_osd_subtitle(mpctx, NULL); + if (vo_spudec) { + spudec_reset(vo_spudec); + vo_osd_changed(OSDTYPE_SPU); + } +#ifdef CONFIG_FFMPEG + if (is_av_sub(type)) + reset_avsub(sh_sub); +#endif + return; + } + // find sub + if (mpctx->subdata) { + if (sub_fps==0) sub_fps = sh_video ? sh_video->fps : 25; + current_module = "find_sub"; + find_sub(mpctx, mpctx->subdata, curpts * + (mpctx->subdata->sub_uses_time ? 100. : sub_fps)); + if (vo_sub) + mpctx->vo_sub_last = vo_sub; + } + + // DVD sub: + if (vobsub_id >= 0 || type == 'v') { + int timestamp; + current_module = "spudec"; + /* Get a sub packet from the DVD or a vobsub */ + while(1) { + // Vobsub + len = 0; + if (vo_vobsub) { + if (curpts >= 0) { + len = vobsub_get_packet(vo_vobsub, curpts, + (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,sh_video->timer,timestamp / 90000.0,timestamp); + } + } + } else { + // DVD sub + len = ds_get_packet_sub(d_sub, (unsigned char**)&packet); + if (len > 0) { + // XXX This is wrong, sh_video->pts can be arbitrarily + // much behind demuxing position. Unfortunately using + // d_video->pts which would have been the simplest + // improvement doesn't work because mpeg specific hacks + // in video.c set d_video->pts to 0. + float x = d_sub->pts - refpts; + if (x > -20 && x < 20) // prevent missing subs on pts reset + timestamp = 90000*d_sub->pts; + else timestamp = 90000*curpts; + mp_dbg(MSGT_CPLAYER, MSGL_V, "\rDVD sub: len=%d " + "v_pts=%5.3f s_pts=%5.3f ts=%d \n", len, + refpts, d_sub->pts, timestamp); + } + } + if (len<=0 || !packet) break; + // create it only here, since with some broken demuxers we might + // type = v but no DVD sub and we currently do not change the + // "original frame size" ever after init, leading to wrong-sized + // PGS subtitles. + if (!vo_spudec) + vo_spudec = spudec_new(NULL); + if (vo_vobsub || timestamp >= 0) + spudec_assemble(vo_spudec, packet, len, timestamp); + } + } else if (is_text_sub(type) || is_av_sub(type) || type == 'd') { + if (type == 'd' && !d_sub->demuxer->teletext) { + tt_stream_props tsp = {0}; + void *ptr = &tsp; + if (teletext_control(NULL, TV_VBI_CONTROL_START, &ptr) == VBI_CONTROL_TRUE) + d_sub->demuxer->teletext = ptr; + } + if (d_sub->non_interleaved) + ds_get_next_pts(d_sub); + + while (d_sub->first) { + double subpts = ds_get_next_pts(d_sub) + sub_offset; + if (subpts > curpts) { + // Libass handled subs can be fed to it in advance + if (!opts->ass_enabled || !is_text_sub(type)) + break; + // Try to avoid demuxing whole file at once + if (d_sub->non_interleaved && subpts > curpts + 1) + break; + } + double duration = d_sub->first->duration; + len = ds_get_packet_sub(d_sub, &packet); + if (is_av_sub(type)) { +#ifdef CONFIG_FFMPEG + decode_avsub(sh_sub, packet, len, subpts, duration); +#endif + continue; + } + if (type == 'm') { + if (len < 2) continue; + len = FFMIN(len - 2, AV_RB16(packet)); + packet += 2; + } + if (type == 'd') { + if (d_sub->demuxer->teletext) { + uint8_t *p = packet; + p++; + len--; + while (len >= 46) { + int sublen = p[1]; + if (p[0] == 2 || p[0] == 3) + teletext_control(d_sub->demuxer->teletext, + TV_VBI_CONTROL_DECODE_DVB, p + 2); + p += sublen + 2; + len -= sublen + 2; + } + } + continue; + } + if (sh_sub && sh_sub->active) { + sub_decode(sh_sub, mpctx->osd, packet, len, subpts, duration); + continue; + } + if (subpts != MP_NOPTS_VALUE) { + if (duration < 0) + sub_clear_text(&subs, MP_NOPTS_VALUE); + if (type == 'a') { // ssa/ass subs without libass => convert to plaintext + int i; + unsigned char* p = packet; + for (i=0; i < 8 && *p != '\0'; p++) + if (*p == ',') + i++; + if (*p == '\0') /* Broken line? */ + continue; + len -= p - packet; + packet = p; + } + double endpts = MP_NOPTS_VALUE; + if (subpts != MP_NOPTS_VALUE && duration >= 0) + endpts = subpts + duration; + sub_add_text(&subs, packet, len, endpts); + set_osd_subtitle(mpctx, &subs); + } + if (d_sub->non_interleaved) + ds_get_next_pts(d_sub); + } + if (!opts->ass_enabled) + if (sub_clear_text(&subs, curpts)) + set_osd_subtitle(mpctx, &subs); + } + if (vo_spudec) { + spudec_heartbeat(vo_spudec, 90000*curpts); + if (spudec_changed(vo_spudec)) + vo_osd_changed(OSDTYPE_SPU); + } + + current_module=NULL; +} + +static void update_teletext(sh_video_t *sh_video, demuxer_t *demuxer, int reset) +{ + int page_changed; + + if (!demuxer->teletext) + return; + + //Also forcing page update when such ioctl is not supported or call error occured + if(teletext_control(demuxer->teletext,TV_VBI_CONTROL_IS_CHANGED,&page_changed)!=VBI_CONTROL_TRUE) + page_changed=1; + + if(!page_changed) + return; + + if(teletext_control(demuxer->teletext,TV_VBI_CONTROL_GET_VBIPAGE,&vo_osd_teletext_page)!=VBI_CONTROL_TRUE) + vo_osd_teletext_page=NULL; + if(teletext_control(demuxer->teletext,TV_VBI_CONTROL_GET_HALF_PAGE,&vo_osd_teletext_half)!=VBI_CONTROL_TRUE) + vo_osd_teletext_half=0; + if(teletext_control(demuxer->teletext,TV_VBI_CONTROL_GET_MODE,&vo_osd_teletext_mode)!=VBI_CONTROL_TRUE) + vo_osd_teletext_mode=0; + if(teletext_control(demuxer->teletext,TV_VBI_CONTROL_GET_FORMAT,&vo_osd_teletext_format)!=VBI_CONTROL_TRUE) + vo_osd_teletext_format=0; + vo_osd_changed(OSDTYPE_TELETEXT); + + teletext_control(demuxer->teletext,TV_VBI_CONTROL_MARK_UNCHANGED,NULL); +} + static int check_framedrop(struct MPContext *mpctx, double frame_time) { struct MPOpts *opts = &mpctx->opts; // check for frame-drop: @@ -2735,7 +2962,7 @@ static void reinit_decoders(struct MPContext *mpctx) { reinit_video_chain(mpctx); reinit_audio_chain(mpctx); - mp_property_do("sub", M_PROPERTY_SET, &mpctx->global_sub_pos, mpctx); + mp_property_do("sub", M_PROPERTY_SET, &(int){mpctx->global_sub_pos}, mpctx); } static void seek_reset(struct MPContext *mpctx) @@ -2756,9 +2983,8 @@ static void seek_reset(struct MPContext *mpctx) // be completely wrong (probably 0). mpctx->sh_video->pts = mpctx->d_video->pts + mpctx->video_offset; mpctx->video_pts = mpctx->sh_video->pts; - update_subtitles(mpctx, &mpctx->opts, mpctx->sh_video, - mpctx->sh_video->pts, mpctx->video_offset, - mpctx->d_sub, 1); + update_subtitles(mpctx, mpctx->sh_video->pts, mpctx->video_offset, + true); update_teletext(mpctx->sh_video, mpctx->demuxer, 1); } @@ -2769,8 +2995,8 @@ static void seek_reset(struct MPContext *mpctx) mpctx->sh_audio->a_buffer_len = 0; mpctx->sh_audio->a_out_buffer_len = 0; if (!mpctx->sh_video) - update_subtitles(mpctx, &mpctx->opts, NULL, mpctx->sh_audio->pts, - mpctx->video_offset, mpctx->d_sub, 1); + update_subtitles(mpctx, mpctx->sh_audio->pts, + mpctx->video_offset, true); } if (vo_vobsub && mpctx->sh_video) { @@ -2797,7 +3023,7 @@ static bool timeline_set_part(struct MPContext *mpctx, int i) mpctx->video_offset = n->start - n->source_start; if (n->source == p->source) return false; - uninit_player(mpctx, INITIALIZED_VCODEC | (mpctx->opts.fixed_vo && mpctx->opts.video_id != -2 ? 0 : INITIALIZED_VO) | INITIALIZED_AO | INITIALIZED_ACODEC); + uninit_player(mpctx, INITIALIZED_VCODEC | (mpctx->opts.fixed_vo && mpctx->opts.video_id != -2 ? 0 : INITIALIZED_VO) | INITIALIZED_AO | INITIALIZED_ACODEC | INITIALIZED_SUB); mpctx->demuxer = n->source->demuxer; mpctx->d_video = mpctx->demuxer->video; mpctx->d_audio = mpctx->demuxer->audio; @@ -3108,8 +3334,7 @@ static void run_playloop(struct MPContext *mpctx) if (end_at.type == END_AT_TIME && end_at.pos < a_pos) mpctx->stop_play = PT_NEXT_ENTRY; - update_subtitles(mpctx, &mpctx->opts, NULL, a_pos, mpctx->video_offset, - mpctx->d_sub, 0); + update_subtitles(mpctx, a_pos, mpctx->video_offset, false); update_osd_msg(mpctx); } else { @@ -3180,12 +3405,11 @@ static void run_playloop(struct MPContext *mpctx) if (!frame_time_remaining && blit_frame) { struct sh_video *sh_video = mpctx->sh_video; mpctx->video_pts = sh_video->pts; - update_subtitles(mpctx, &mpctx->opts, sh_video, sh_video->pts, - mpctx->video_offset, mpctx->d_sub, 0); + update_subtitles(mpctx, sh_video->pts, mpctx->video_offset, false); update_teletext(sh_video, mpctx->demuxer, 0); update_osd_msg(mpctx); struct vf_instance *vf = sh_video->vfilter; - vf->control(vf, VFCTRL_DRAW_EOSD, NULL); + vf->control(vf, VFCTRL_DRAW_EOSD, mpctx->osd); vf->control(vf, VFCTRL_DRAW_OSD, mpctx->osd); vo_osd_changed(0); @@ -3509,11 +3733,12 @@ static void build_ordered_chapter_timeline(struct MPContext *mpctx) * specify chapter end times that are one frame too early; * we don't want to try seeking over a one frame gap. */ int64_t join_diff = c->start - starttime - prev_part_offset; - if (part_count == 0 || FFABS(join_diff) > opts->chapter_merge_threshold + if (part_count == 0 + || FFABS(join_diff) > opts->chapter_merge_threshold * 1000000 || sources + j != timeline[part_count - 1].source) { timeline[part_count].source = sources + j; - timeline[part_count].start = starttime / 1000.; - timeline[part_count].source_start = c->start / 1000.; + timeline[part_count].start = starttime / 1e9; + timeline[part_count].source_start = c->start / 1e9; prev_part_offset = c->start - starttime; part_count++; } else if (part_count > 0 && join_diff) { @@ -3523,12 +3748,12 @@ static void build_ordered_chapter_timeline(struct MPContext *mpctx) "offset %d ms.\n", i, (int) join_diff); starttime += join_diff; } - chapters[num_chapters].start = starttime / 1000.; + chapters[num_chapters].start = starttime / 1e9; chapters[num_chapters].name = talloc_strdup(chapters, c->name); starttime += c->end - c->start; num_chapters++; } - timeline[part_count].start = starttime / 1000.; + timeline[part_count].start = starttime / 1e9; if (!part_count) { // None of the parts come from the file itself??? @@ -3543,7 +3768,7 @@ static void build_ordered_chapter_timeline(struct MPContext *mpctx) timeline[part_count].start); if (missing_time) mp_msg(MSGT_CPLAYER, MSGL_ERR, "There are %.3f seconds missing " - "from the timeline!\n", missing_time / 1000.); + "from the timeline!\n", missing_time / 1e9); mp_msg(MSGT_CPLAYER, MSGL_V, "Source files:\n"); for (int i = 0; i < num_sources; i++) mp_msg(MSGT_CPLAYER, MSGL_V, "%d: %s\n", i, @@ -3574,12 +3799,80 @@ static int read_keys(void *ctx, int fd) return mplayer_get_key(ctx, 0); } +static bool attachment_is_font(struct demux_attachment *att) +{ + if (!att->name || !att->type || !att->data || !att->data_size) + return false; + // match against MIME types + if (strcmp(att->type, "application/x-truetype-font") == 0 + || strcmp(att->type, "application/x-font") == 0) + return true; + // fallback: match against file extension + if (strlen(att->name) > 4) { + char *ext = att->name + strlen(att->name) - 4; + if (strcasecmp(ext, ".ttf") == 0 || strcasecmp(ext, ".ttc") == 0 + || strcasecmp(ext, ".otf") == 0) + return true; + } + return false; +} + +static int select_audio(demuxer_t *demuxer, int audio_id, char *audio_lang) +{ + if (audio_id == -1) + audio_id = demuxer_audio_track_by_lang_and_default(demuxer, audio_lang); + if (audio_id != -1) // -1 (automatic) is the default behaviour of demuxers + demuxer_switch_audio(demuxer, audio_id); + if (audio_id == -2) { // some demuxers don't yet know how to switch to no sound + demuxer->audio->id = -2; + demuxer->audio->sh = NULL; + } + return demuxer->audio->id; +} + +static void print_version(const char* name) +{ + mp_msg(MSGT_CPLAYER, MSGL_INFO, MP_TITLE, name); + + /* Test for CPU capabilities (and corresponding OS support) for optimizing */ + GetCpuCaps(&gCpuCaps); +#if ARCH_X86 + mp_msg(MSGT_CPLAYER, MSGL_V, + "CPUflags: MMX: %d MMX2: %d 3DNow: %d 3DNowExt: %d SSE: %d SSE2: %d SSSE3: %d\n", + gCpuCaps.hasMMX, gCpuCaps.hasMMX2, + gCpuCaps.has3DNow, gCpuCaps.has3DNowExt, + gCpuCaps.hasSSE, gCpuCaps.hasSSE2, gCpuCaps.hasSSSE3); +#if CONFIG_RUNTIME_CPUDETECT + mp_tmsg(MSGT_CPLAYER,MSGL_V, "Compiled with runtime CPU detection.\n"); +#else + mp_tmsg(MSGT_CPLAYER,MSGL_V, "Compiled for x86 CPU with extensions:"); +if (HAVE_MMX) + mp_msg(MSGT_CPLAYER,MSGL_V," MMX"); +if (HAVE_MMX2) + mp_msg(MSGT_CPLAYER,MSGL_V," MMX2"); +if (HAVE_AMD3DNOW) + mp_msg(MSGT_CPLAYER,MSGL_V," 3DNow"); +if (HAVE_AMD3DNOWEXT) + mp_msg(MSGT_CPLAYER,MSGL_V," 3DNowExt"); +if (HAVE_SSE) + mp_msg(MSGT_CPLAYER,MSGL_V," SSE"); +if (HAVE_SSE2) + mp_msg(MSGT_CPLAYER,MSGL_V," SSE2"); +if (HAVE_SSSE3) + mp_msg(MSGT_CPLAYER,MSGL_V," SSSE3"); +if (HAVE_CMOV) + mp_msg(MSGT_CPLAYER,MSGL_V," CMOV"); + mp_msg(MSGT_CPLAYER,MSGL_V,"\n"); +#endif /* CONFIG_RUNTIME_CPUDETECT */ +#endif /* ARCH_X86 */ +} /* This preprocessor directive is a hack to generate a mplayer-nomain.o object * file for some tools to link against. */ #ifndef DISABLE_MAIN int main(int argc,char* argv[]){ - + if (argc > 1 && !strcmp(argv[1], "-leak-report")) + talloc_enable_leak_report(); char * mem_ptr; @@ -3798,7 +4091,7 @@ if(!codecs_file || !parse_codec_cfg(codecs_file)){ #endif #ifdef CONFIG_ASS - ass_library = ass_init(); + ass_library = mp_ass_init(); #endif #ifdef HAVE_RTC @@ -4413,14 +4706,14 @@ if(vo_spudec==NULL && mpctx->sub_counts[SUB_SOURCE_SUBS] = mpctx->set_of_sub_size; if (select_subtitle(mpctx)) { - if(subdata) + if(mpctx->subdata) switch (stream_dump_type) { - case 3: list_sub_file(subdata); break; - case 4: dump_mpsub(subdata, mpctx->sh_video->fps); break; - case 6: dump_srt(subdata, mpctx->sh_video->fps); break; - case 7: dump_microdvd(subdata, mpctx->sh_video->fps); break; - case 8: dump_jacosub(subdata, mpctx->sh_video->fps); break; - case 9: dump_sami(subdata, mpctx->sh_video->fps); break; + case 3: list_sub_file(mpctx->subdata); break; + case 4: dump_mpsub(mpctx->subdata, mpctx->sh_video->fps); break; + case 6: dump_srt(mpctx->subdata, mpctx->sh_video->fps); break; + case 7: dump_microdvd(mpctx->subdata, mpctx->sh_video->fps); break; + case 8: dump_jacosub(mpctx->subdata, mpctx->sh_video->fps); break; + case 9: dump_sami(mpctx->subdata, mpctx->sh_video->fps); break; } } @@ -4643,10 +4936,10 @@ if(mpctx->set_of_sub_size > 0) { } mpctx->set_of_sub_size = 0; } -vo_sub_last = vo_sub=NULL; -subdata=NULL; +mpctx->vo_sub_last = vo_sub=NULL; +mpctx->subdata=NULL; #ifdef CONFIG_ASS -ass_track = NULL; +mpctx->osd->ass_track = NULL; if(ass_library) ass_clear_fonts(ass_library); #endif @@ -19,6 +19,8 @@ #ifndef MPLAYER_MPLAYER_H #define MPLAYER_MPLAYER_H +#include <stdlib.h> + #include "mp_msg.h" extern char* current_module; @@ -57,5 +59,8 @@ static inline void exit_player_bad(const char *how) } struct MPContext; +struct subtitle; + +void set_osd_subtitle(struct MPContext *mpctx, struct subtitle *subs); #endif /* MPLAYER_MPLAYER_H */ @@ -39,6 +39,7 @@ typedef struct MPOpts { int ordered_chapters; int chapter_merge_threshold; int quiet; + int noconfig; float stream_cache_min_percent; float stream_cache_seek_min_percent; int chapterrange[2]; diff --git a/stream/stream_dvdnav.c b/stream/stream_dvdnav.c index bbd2b2085b..21522f8b6b 100644 --- a/stream/stream_dvdnav.c +++ b/stream/stream_dvdnav.c @@ -33,7 +33,7 @@ #include "stream_dvdnav.h" #include "libvo/video_out.h" #include "libavutil/common.h" -#include "spudec.h" +#include "sub/spudec.h" #include "m_option.h" #include "m_struct.h" #include "stream_dvd_common.h" diff --git a/ass_mp.c b/sub/ass_mp.c index 31acb521b8..98602ace03 100644 --- a/ass_mp.c +++ b/sub/ass_mp.c @@ -22,6 +22,7 @@ #include <string.h> #include <stdlib.h> #include <stdarg.h> +#include <stdbool.h> #include <ass/ass.h> #include <ass/ass_types.h> @@ -69,9 +70,7 @@ extern char *sub_cp; static char *sub_cp = 0; #endif -void process_force_style(ASS_Track *track); - -ASS_Track *ass_default_track(ASS_Library *library) +ASS_Track *mp_ass_default_track(ASS_Library *library) { ASS_Track *track = ass_new_track(library); @@ -84,13 +83,9 @@ ASS_Track *ass_default_track(ASS_Library *library) ass_read_styles(track, ass_styles_file, sub_cp); if (track->n_styles == 0) { - ASS_Style *style; - int sid; - double fs; - uint32_t c1, c2; - - sid = ass_alloc_style(track); - style = track->styles + sid; + track->Kerning = true; + int sid = ass_alloc_style(track); + ASS_Style *style = track->styles + sid; style->Name = strdup("Default"); style->FontName = (font_fontconfig >= 0 && sub_font_name) ? strdup(sub_font_name) @@ -98,30 +93,34 @@ ASS_Track *ass_default_track(ASS_Library *library) && font_name) ? strdup(font_name) : strdup("Sans"); style->treat_fontname_as_pattern = 1; - fs = track->PlayResY * text_font_scale_factor / 100.; - // approximate autoscale coefficients + double fs = track->PlayResY * text_font_scale_factor / 100.; + /* The font size is always proportional to video height only; + * real -subfont-autoscale behavior is not implemented. + * Apply a correction that corresponds to about 4:3 aspect ratio + * video to get a size somewhat closer to what non-libass rendering + * would produce with the same text_font_scale_factor + * and subtitle_autoscale. + */ if (subtitle_autoscale == 2) fs *= 1.3; else if (subtitle_autoscale == 3) - fs *= 1.4; - style->FontSize = fs; + fs *= 1.7; + uint32_t c1 = 0xFFFFFF00; + uint32_t c2 = 0x00000000; if (ass_color) c1 = strtoll(ass_color, NULL, 16); - else - c1 = 0xFFFF0000; if (ass_border_color) c2 = strtoll(ass_border_color, NULL, 16); - else - c2 = 0x00000000; + style->FontSize = fs; style->PrimaryColour = c1; style->SecondaryColour = c1; style->OutlineColour = c2; style->BackColour = 0x00000000; style->BorderStyle = 1; style->Alignment = 2; - style->Outline = 2; + style->Outline = fs / 16; style->MarginL = 10; style->MarginR = 10; style->MarginV = 5; @@ -154,7 +153,7 @@ static int check_duplicate_plaintext_event(ASS_Track *track) * note: assumes that subtitle is _not_ fps-based; caller must manually correct * Start and Duration in other case. **/ -int ass_process_subtitle(ASS_Track *track, subtitle *sub) +static int ass_process_subtitle(ASS_Track *track, subtitle *sub) { int eid; ASS_Event *event; @@ -210,13 +209,13 @@ int ass_process_subtitle(ASS_Track *track, subtitle *sub) * \param fps video framerate * \return newly allocated ASS_Track, filled with subtitles from subdata */ -ASS_Track *ass_read_subdata(ASS_Library *library, sub_data *subdata, - double fps) +ASS_Track *mp_ass_read_subdata(ASS_Library *library, sub_data *subdata, + double fps) { ASS_Track *track; int i; - track = ass_default_track(library); + track = mp_ass_default_track(library); track->name = subdata->filename ? strdup(subdata->filename) : 0; for (i = 0; i < subdata->sub_num; ++i) { @@ -231,7 +230,8 @@ ASS_Track *ass_read_subdata(ASS_Library *library, sub_data *subdata, return track; } -ASS_Track *ass_read_stream(ASS_Library *library, const char *fname, char *charset) +ASS_Track *mp_ass_read_stream(ASS_Library *library, const char *fname, + char *charset) { int i; char *buf = NULL; @@ -280,7 +280,7 @@ ASS_Track *ass_read_stream(ASS_Library *library, const char *fname, char *charse return track; } -void ass_configure(ASS_Renderer *priv, int w, int h, int unscaled) +void mp_ass_configure(ASS_Renderer *priv, int w, int h, bool unscaled) { int hinting; ass_set_frame_size(priv, w, h); @@ -295,7 +295,7 @@ void ass_configure(ASS_Renderer *priv, int w, int h, int unscaled) ass_set_line_spacing(priv, ass_line_spacing); } -void ass_configure_fonts(ASS_Renderer *priv) +void mp_ass_configure_fonts(ASS_Renderer *priv) { char *dir, *path, *family; dir = get_path("fonts"); @@ -327,7 +327,7 @@ static void message_callback(int level, const char *format, va_list va, void *ct mp_msg(MSGT_ASS, level, "\n"); } -ASS_Library *ass_init(void) +ASS_Library *mp_ass_init(void) { ASS_Library *priv; char *path = get_path("fonts"); @@ -342,7 +342,7 @@ ASS_Library *ass_init(void) int ass_force_reload = 0; // flag set if global ass-related settings were changed -ASS_Image *ass_mp_render_frame(ASS_Renderer *priv, ASS_Track *track, +ASS_Image *mp_ass_render_frame(ASS_Renderer *priv, ASS_Track *track, long long now, int *detect_change) { if (ass_force_reload) { diff --git a/ass_mp.h b/sub/ass_mp.h index 0694426898..965b063403 100644 --- a/ass_mp.h +++ b/sub/ass_mp.h @@ -22,6 +22,7 @@ #define MPLAYER_ASS_MP_H #include <stdint.h> +#include <stdbool.h> #include "config.h" #include "subreader.h" @@ -43,18 +44,18 @@ extern char *ass_border_color; extern char *ass_styles_file; extern int ass_hinting; -ASS_Track *ass_default_track(ASS_Library *library); -int ass_process_subtitle(ASS_Track *track, subtitle *sub); -ASS_Track *ass_read_subdata(ASS_Library *library, sub_data *subdata, - double fps); -ASS_Track *ass_read_stream(ASS_Library *library, const char *fname, char *charset); +ASS_Track *mp_ass_default_track(ASS_Library *library); +ASS_Track *mp_ass_read_subdata(ASS_Library *library, sub_data *subdata, + double fps); +ASS_Track *mp_ass_read_stream(ASS_Library *library, const char *fname, + char *charset); -void ass_configure(ASS_Renderer *priv, int w, int h, int hinting); -void ass_configure_fonts(ASS_Renderer *priv); -ASS_Library *ass_init(void); +void mp_ass_configure(ASS_Renderer *priv, int w, int h, bool unscaled); +void mp_ass_configure_fonts(ASS_Renderer *priv); +ASS_Library *mp_ass_init(void); extern int ass_force_reload; -ASS_Image *ass_mp_render_frame(ASS_Renderer *priv, ASS_Track *track, +ASS_Image *mp_ass_render_frame(ASS_Renderer *priv, ASS_Track *track, long long now, int *detect_change); #else /* CONFIG_ASS */ diff --git a/av_sub.c b/sub/av_sub.c index e850e2ffa2..a68fbce083 100644 --- a/av_sub.c +++ b/sub/av_sub.c @@ -19,7 +19,7 @@ #include <libavcodec/avcodec.h> #include "libmpdemux/stheader.h" -#include "libvo/sub.h" +#include "sub.h" #include "spudec.h" #include "av_sub.h" @@ -35,12 +35,11 @@ void reset_avsub(struct sh_sub *sh) * Decode a subtitle packet via libavcodec. * \return < 0 on error, > 0 if further processing is needed */ -int decode_avsub(struct sh_sub *sh, uint8_t **data, int *size, - double *pts, double *endpts) +int decode_avsub(struct sh_sub *sh, uint8_t *data, int size, + double pts, double duration) { AVCodecContext *ctx = sh->context; enum CodecID cid = CODEC_ID_NONE; - int new_type = 0; int res; int got_sub; AVSubtitle sub; @@ -56,11 +55,11 @@ int decode_avsub(struct sh_sub *sh, uint8_t **data, int *size, } av_init_packet(&pkt); - pkt.data = *data; - pkt.size = *size; - pkt.pts = *pts * 1000; - if (*pts != MP_NOPTS_VALUE && *endpts != MP_NOPTS_VALUE) - pkt.convergence_duration = (*endpts - *pts) * 1000; + pkt.data = data; + pkt.size = size; + pkt.pts = pts * 1000; + if (duration >= 0) + pkt.convergence_duration = duration * 1000; if (!ctx) { AVCodec *sub_codec; avcodec_init(); @@ -78,13 +77,16 @@ int decode_avsub(struct sh_sub *sh, uint8_t **data, int *size, res = avcodec_decode_subtitle2(ctx, &sub, &got_sub, &pkt); if (res < 0) return res; - if (*pts != MP_NOPTS_VALUE) { + if (pts != MP_NOPTS_VALUE) { if (sub.end_display_time > sub.start_display_time) - *endpts = *pts + sub.end_display_time / 1000.0; - *pts += sub.start_display_time / 1000.0; + duration = (sub.end_display_time - sub.start_display_time) / 1000.0; + pts += sub.start_display_time / 1000.0; } + double endpts = MP_NOPTS_VALUE; + if (pts != MP_NOPTS_VALUE && duration >= 0) + endpts = pts + duration; if (got_sub && vo_spudec && sub.num_rects == 0) - spudec_set_paletted(vo_spudec, NULL, 0, NULL, 0, 0, 0, 0, *pts, *endpts); + spudec_set_paletted(vo_spudec, NULL, 0, NULL, 0, 0, 0, 0, pts, endpts); if (got_sub && sub.num_rects > 0) { switch (sub.rects[0]->type) { case SUBTITLE_BITMAP: @@ -98,19 +100,14 @@ int decode_avsub(struct sh_sub *sh, uint8_t **data, int *size, sub.rects[0]->y, sub.rects[0]->w, sub.rects[0]->h, - *pts, - *endpts); + pts, + endpts); vo_osd_changed(OSDTYPE_SPU); break; - case SUBTITLE_TEXT: - *data = strdup(sub.rects[0]->text); - *size = strlen(*data); - new_type = 't'; - break; - case SUBTITLE_ASS: - *data = strdup(sub.rects[0]->ass); - *size = strlen(*data); - new_type = 'a'; + default: + mp_msg(MSGT_SUBREADER, MSGL_ERR, "sd_avsub: unsupported subtitle " + "type from libavcodec\n"); + res = -1; break; } } @@ -118,5 +115,5 @@ int decode_avsub(struct sh_sub *sh, uint8_t **data, int *size, if (got_sub) avsubtitle_free(&sub); #endif - return new_type; + return res; } diff --git a/av_sub.h b/sub/av_sub.h index 690ed6c1f1..af3edc4d34 100644 --- a/av_sub.h +++ b/sub/av_sub.h @@ -24,7 +24,7 @@ struct sh_sub; void reset_avsub(struct sh_sub *sh); -int decode_avsub(struct sh_sub *sh, uint8_t **data, int *size, - double *pts, double *endpts); +int decode_avsub(struct sh_sub *sh, uint8_t *data, int size, + double pts, double endpts); #endif /* MPLAYER_AV_SUB_H */ diff --git a/sub/dec_sub.c b/sub/dec_sub.c new file mode 100644 index 0000000000..6a6d1d77e5 --- /dev/null +++ b/sub/dec_sub.c @@ -0,0 +1,72 @@ +/* + * 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 <stdlib.h> +#include <stdbool.h> +#include <assert.h> + +#include "config.h" +#include "libmpdemux/stheader.h" +#include "sd.h" +#include "dec_sub.h" +#include "options.h" + +extern const struct sd_functions sd_ass; + +void sub_init(struct sh_sub *sh, struct osd_state *osd) +{ + struct MPOpts *opts = sh->opts; + +#ifdef CONFIG_ASS + if (opts->ass_enabled && is_text_sub(sh->type)) + sh->sd_driver = &sd_ass; +#endif + if (sh->sd_driver) { + sh->sd_driver->init(sh, osd); + sh->initialized = true; + sh->active = true; + } +} + +void sub_decode(struct sh_sub *sh, struct osd_state *osd, void *data, + int data_len, double pts, double duration) +{ + if (sh->active && sh->sd_driver->decode) + sh->sd_driver->decode(sh, osd, data, data_len, pts, duration); +} + +void sub_reset(struct sh_sub *sh, struct osd_state *osd) +{ + if (sh->active && sh->sd_driver->reset) + sh->sd_driver->reset(sh, osd); +} + +void sub_switchoff(struct sh_sub *sh, struct osd_state *osd) +{ + if (sh->active && sh->sd_driver->switch_off) + sh->sd_driver->switch_off(sh, osd); + sh->active = false; +} + +void sub_uninit(struct sh_sub *sh) +{ + assert (!sh->active); + if (sh->initialized && sh->sd_driver->uninit) + sh->sd_driver->uninit(sh); + sh->initialized = false; +} diff --git a/sub/dec_sub.h b/sub/dec_sub.h new file mode 100644 index 0000000000..d6fbef25f0 --- /dev/null +++ b/sub/dec_sub.h @@ -0,0 +1,14 @@ +struct sh_sub; +struct osd_state; + +static inline bool is_text_sub(int type) +{ + return type == 't' || type == 'm' || type == 'a'; +} + +void sub_decode(struct sh_sub *sh, struct osd_state *osd, void *data, + int data_len, double pts, double duration); +void sub_init(struct sh_sub *sh, struct osd_state *osd); +void sub_reset(struct sh_sub *sh, struct osd_state *osd); +void sub_switchoff(struct sh_sub *sh, struct osd_state *osd); +void sub_uninit(struct sh_sub *sh); diff --git a/find_sub.c b/sub/find_sub.c index d0ea3c0016..97c232b1db 100644 --- a/find_sub.c +++ b/sub/find_sub.c @@ -23,11 +23,12 @@ #include <stdio.h> #include "libvo/video_out.h" -#include "libvo/sub.h" +#include "sub.h" #include "subreader.h" #include "mp_msg.h" #include "mpcommon.h" +#include "mplayer.h" static int current_sub=0; @@ -36,9 +37,6 @@ static int nosub_range_start=-1; static int nosub_range_end=-1; static const sub_data *last_sub_data = NULL; -extern float sub_delay; -extern float sub_fps; - void step_sub(sub_data *subd, float pts, int movement) { subtitle *subs; int key; diff --git a/libvo/font_load.c b/sub/font_load.c index e9980b8e41..e9980b8e41 100644 --- a/libvo/font_load.c +++ b/sub/font_load.c diff --git a/libvo/font_load.h b/sub/font_load.h index 7efe067aaf..7efe067aaf 100644 --- a/libvo/font_load.h +++ b/sub/font_load.h diff --git a/libvo/font_load_ft.c b/sub/font_load_ft.c index 41a0f886cb..41a0f886cb 100644 --- a/libvo/font_load_ft.c +++ b/sub/font_load_ft.c diff --git a/libvo/osd_font.h b/sub/osd_font.h index 6be45bc1fa..6be45bc1fa 100644 --- a/libvo/osd_font.h +++ b/sub/osd_font.h diff --git a/sub/sd.h b/sub/sd.h new file mode 100644 index 0000000000..d5aea5c1a6 --- /dev/null +++ b/sub/sd.h @@ -0,0 +1,16 @@ +#ifndef MPLAYER_SD_H +#define MPLAYER_SD_H + +struct osd_state; +struct sh_sub; + +struct sd_functions { + void (*init)(struct sh_sub *sh, struct osd_state *osd); + void (*decode)(struct sh_sub *sh, struct osd_state *osd, + void *data, int data_len, double pts, double duration); + void (*reset)(struct sh_sub *sh, struct osd_state *osd); + void (*switch_off)(struct sh_sub *sh, struct osd_state *osd); + void (*uninit)(struct sh_sub *sh); +}; + +#endif diff --git a/sub/sd_ass.c b/sub/sd_ass.c new file mode 100644 index 0000000000..ba5710611e --- /dev/null +++ b/sub/sd_ass.c @@ -0,0 +1,154 @@ +/* + * 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 <stdlib.h> +#include <ass/ass.h> +#include <assert.h> +#include <string.h> + +#include "talloc.h" + +#include "mpcommon.h" +#include "libmpdemux/stheader.h" +#include "sub.h" +#include "ass_mp.h" +#include "sd.h" +#include "subassconvert.h" + +struct sd_ass_priv { + struct ass_track *ass_track; + bool incomplete_event; +}; + +static void free_last_event(ASS_Track *track) +{ + assert(track->n_events > 0); + ass_free_event(track, track->n_events - 1); + track->n_events--; +} + +static void init(struct sh_sub *sh, struct osd_state *osd) +{ + struct sd_ass_priv *ctx; + + if (sh->initialized) { + ctx = sh->context; + } else { + ctx = talloc_zero(NULL, struct sd_ass_priv); + sh->context = ctx; + if (sh->type == 'a') { + ctx->ass_track = ass_new_track(ass_library); + if (sh->extradata) + ass_process_codec_private(ctx->ass_track, sh->extradata, + sh->extradata_len); + } else + ctx->ass_track = mp_ass_default_track(ass_library); + } + + assert(osd->ass_track == NULL); + osd->ass_track = ctx->ass_track; + osd->vsfilter_aspect = sh->type == 'a'; + osd->ass_track_changed = true; +} + +static void decode(struct sh_sub *sh, struct osd_state *osd, void *data, + int data_len, double pts, double duration) +{ + unsigned char *text = data; + struct sd_ass_priv *ctx = sh->context; + ASS_Track *track = ctx->ass_track; + + if (sh->type == 'a') { // ssa/ass subs + ass_process_chunk(track, data, data_len, + (long long)(pts*1000 + 0.5), + (long long)(duration*1000 + 0.5)); + return; + } + // plaintext subs + if (pts == MP_NOPTS_VALUE) { + mp_msg(MSGT_SUBREADER, MSGL_WARN, "Subtitle without pts, ignored\n"); + return; + } + long long ipts = pts * 1000 + 0.5; + long long iduration = duration * 1000 + 0.5; + if (ctx->incomplete_event) { + ctx->incomplete_event = false; + ASS_Event *event = track->events + track->n_events - 1; + if (ipts <= event->Start) + free_last_event(track); + else + event->Duration = ipts - event->Start; + } + // Note: we rely on there being guaranteed 0 bytes after data packets + int len = strlen(text); + if (len < 5) { + // Some tracks use a whitespace (but not empty) packet to mark end + // of previous subtitle. + for (int i = 0; i < len; i++) + if (!strchr(" \f\n\r\t\v", text[i])) + goto not_all_whitespace; + return; + } + not_all_whitespace:; + char buf[500]; + subassconvert_subrip(text, buf, sizeof(buf)); + for (int i = 0; i < track->n_events; i++) + if (track->events[i].Start == ipts + && (duration <= 0 || track->events[i].Duration == iduration) + && strcmp(track->events[i].Text, buf) == 0) + return; // We've already added this subtitle + if (duration <= 0) { + iduration = 10000; + ctx->incomplete_event = true; + } + int eid = ass_alloc_event(track); + ASS_Event *event = track->events + eid; + event->Start = ipts; + event->Duration = iduration; + event->Text = strdup(buf); +} + +static void reset(struct sh_sub *sh, struct osd_state *osd) +{ + struct sd_ass_priv *ctx = sh->context; + if (ctx->incomplete_event) + free_last_event(ctx->ass_track); + ctx->incomplete_event = false; +} + +static void switch_off(struct sh_sub *sh, struct osd_state *osd) +{ + reset(sh, osd); + osd->ass_track = NULL; +} + +static void uninit(struct sh_sub *sh) +{ + struct sd_ass_priv *ctx = sh->context; + + ass_free_track(ctx->ass_track); + talloc_free(ctx); +} + +const struct sd_functions sd_ass = { + .init = init, + .decode = decode, + .reset = reset, + .switch_off = switch_off, + .uninit = uninit, +}; diff --git a/spudec.c b/sub/spudec.c index de7d443ffc..f48d47fd2a 100644 --- a/spudec.c +++ b/sub/spudec.c @@ -43,6 +43,7 @@ #include "libavutil/avutil.h" #include "ffmpeg_files/intreadwrite.h" #include "libswscale/swscale.h" +#include "mpcommon.h" /* Valid values for spu_aamode: 0: none (fastest, most ugly) @@ -1336,8 +1337,6 @@ void spudec_set_hw_spu(void *this, struct vo *hw_spu) vo_control(hw_spu, VOCTRL_SET_SPU_PALETTE, spu->global_palette); } -#define MP_NOPTS_VALUE (-1LL<<63) //both int64_t and double should be able to represent this exactly - /** * palette must contain at least 256 32-bit entries, otherwise crashes * are possible diff --git a/spudec.h b/sub/spudec.h index 2b3828c34c..2b3828c34c 100644 --- a/spudec.h +++ b/sub/spudec.h diff --git a/libvo/sub.c b/sub/sub.c index 58a777070e..62d79ca6f3 100644 --- a/libvo/sub.c +++ b/sub/sub.c @@ -35,7 +35,7 @@ #include "talloc.h" #include "mplayer.h" #include "mp_msg.h" -#include "video_out.h" +#include "libvo/video_out.h" #include "font_load.h" #include "sub.h" #include "spudec.h" diff --git a/libvo/sub.h b/sub/sub.h index d5a30e0b86..8309613ea6 100644 --- a/libvo/sub.h +++ b/sub/sub.h @@ -19,6 +19,8 @@ #ifndef MPLAYER_SUB_H #define MPLAYER_SUB_H +#include <stdbool.h> + typedef struct mp_osd_bbox_s { int x1,y1,x2,y2; } mp_osd_bbox_t; @@ -69,11 +71,13 @@ typedef struct mp_osd_obj_s { struct osd_state { unsigned char osd_text[128]; struct font_desc *sub_font; + struct ass_track *ass_track; + bool ass_track_changed; + bool vsfilter_aspect; }; #include "subreader.h" -extern sub_data* subdata; //currently used subtitles extern subtitle* vo_sub; extern void* vo_osd_teletext_page; diff --git a/sub_cc.c b/sub/sub_cc.c index 2422518355..f18fa28c54 100644 --- a/sub_cc.c +++ b/sub/sub_cc.c @@ -38,7 +38,7 @@ #include "subreader.h" #include "libvo/video_out.h" -#include "libvo/sub.h" +#include "sub.h" #define CC_MAX_LINE_LENGTH 64 diff --git a/sub_cc.h b/sub/sub_cc.h index f5f6924057..f5f6924057 100644 --- a/sub_cc.h +++ b/sub/sub_cc.h diff --git a/sub/subassconvert.c b/sub/subassconvert.c new file mode 100644 index 0000000000..773cb7f4d7 --- /dev/null +++ b/sub/subassconvert.c @@ -0,0 +1,502 @@ +/* + * Subtitles converter to SSA/ASS in order to allow special formatting + * + * 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 <string.h> +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.h> +#include <stdbool.h> + +#include "mp_msg.h" +#include "subassconvert.h" +#include "bstr.h" +#include "libavutil/common.h" + +struct line { + char *buf; + int bufsize; + int len; +}; + +#ifdef __GNUC__ +static void append_text(struct line *dst, char *fmt, ...) __attribute__ ((format(printf, 2, 3))); +#endif + +static void append_text(struct line *dst, char *fmt, ...) +{ + va_list va; + va_start(va, fmt); + int ret = vsnprintf(dst->buf + dst->len, dst->bufsize - dst->len, fmt, va); + if (ret < 0) + goto out; + dst->len += ret; + if (dst->len > dst->bufsize) + dst->len = dst->bufsize; + out: + va_end(va); +} + +static int indexof(const char *s, int c) +{ + char *f = strchr(s, c); + return f ? (f - s) : -1; +} + + + +/* + * SubRip + * + * Support basic tags (italic, bold, underline, strike-through) + * and font tag with size, color and face attributes. + * + */ + +struct font_tag { + int size; + uint32_t color; + struct bstr face; + bool has_size : 1; + bool has_color : 1; + bool has_face : 1; +}; + +static const struct tag_conv { + char *from; + char *to; +} subrip_basic_tags[] = { + {"<i>", "{\\i1}"}, {"</i>", "{\\i0}"}, + {"<b>", "{\\b1}"}, {"</b>", "{\\b0}"}, + {"<u>", "{\\u1}"}, {"</u>", "{\\u0}"}, + {"<s>", "{\\s1}"}, {"</s>", "{\\s0}"}, + {"{", "\\{"}, {"}", "\\}"}, + {"\n", "\\N"} +}; + +static const struct { + char *s; + uint32_t v; +} subrip_web_colors[] = { + /* 16 named HTML colors in BGR format */ + {"red", 0x0000ff}, {"blue", 0xff0000}, {"lime", 0x00ff00}, + {"aqua", 0xffff00}, {"purple", 0x800080}, {"yellow", 0x00ffff}, + {"fuchsia", 0xff00ff}, {"white", 0xffffff}, {"gray", 0x808080}, + {"maroon", 0x000080}, {"olive", 0x008080}, {"black", 0x000000}, + {"silver", 0xc0c0c0}, {"teal", 0x808000}, {"green", 0x008000}, + {"navy", 0x800000} +}; + +#define SUBRIP_MAX_STACKED_FONT_TAGS 16 + +void subassconvert_subrip(const char *orig, char *dest, int dest_buffer_size) +{ + /* line is not const to avoid warnings with strtol, etc. + * orig content won't be changed */ + char *line = (char *)orig; + struct line new_line = { + .buf = dest, + .bufsize = dest_buffer_size, + }; + struct font_tag font_stack[SUBRIP_MAX_STACKED_FONT_TAGS + 1]; + font_stack[0] = (struct font_tag){0}; // type with all defaults + int sp = 0; + + while (*line && new_line.len < new_line.bufsize - 1) { + char *orig_line = line; + + for (int i = 0; i < FF_ARRAY_ELEMS(subrip_basic_tags); i++) { + const struct tag_conv *tag = &subrip_basic_tags[i]; + int from_len = strlen(tag->from); + if (strncmp(line, tag->from, from_len) == 0) { + append_text(&new_line, "%s", tag->to); + line += from_len; + } + } + + if (strncmp(line, "</font>", 7) == 0) { + /* Closing font tag */ + line += 7; + + if (sp > 0) { + struct font_tag *tag = &font_stack[sp]; + struct font_tag *last_tag = &tag[-1]; + sp--; + + if (tag->has_size) { + if (!last_tag->has_size) + append_text(&new_line, "{\\fs}"); + else if (last_tag->size != tag->size) + append_text(&new_line, "{\\fs%d}", last_tag->size); + } + + if (tag->has_color) { + if (!last_tag->has_color) + append_text(&new_line, "{\\c}"); + else if (last_tag->color != tag->color) + append_text(&new_line, "{\\c&H%06X&}", last_tag->color); + } + + if (tag->has_face) { + if (!last_tag->has_face) + append_text(&new_line, "{\\fn}"); + else if (bstrcmp(last_tag->face, tag->face) != 0) + append_text(&new_line, "{\\fn%.*s}", + BSTR_P(last_tag->face)); + } + } + } else if (strncmp(line, "<font ", 6) == 0 + && sp + 1 < FF_ARRAY_ELEMS(font_stack)) { + /* Opening font tag */ + char *potential_font_tag_start = line; + int len_backup = new_line.len; + struct font_tag *tag = &font_stack[sp + 1]; + bool has_valid_attr = false; + + *tag = tag[-1]; // keep values from previous tag + line += 6; + + while (*line && *line != '>') { + if (strncmp(line, "size=\"", 6) == 0) { + line += 6; + tag->size = strtol(line, &line, 10); + if (*line != '"') + break; + append_text(&new_line, "{\\fs%d}", tag->size); + tag->has_size = true; + has_valid_attr = true; + } else if (strncmp(line, "color=\"", 7) == 0) { + line += 7; + if (*line == '#') { + // #RRGGBB format + line++; + tag->color = strtol(line, &line, 16) & 0x00ffffff; + if (*line != '"') + break; + tag->color = ((tag->color & 0xff) << 16) + | (tag->color & 0xff00) + | ((tag->color & 0xff0000) >> 16); + } else { + // Standard web colors + int len = indexof(line, '"'); + if (len <= 0) + break; + for (int i = 0; i < FF_ARRAY_ELEMS(subrip_web_colors); i++) { + char *color = subrip_web_colors[i].s; + if (strlen(color) == len + && strncasecmp(line, color, len) == 0) { + tag->color = subrip_web_colors[i].v; + goto foundcolor; + } + } + + /* We didn't find any matching color */ + mp_tmsg(MSGT_SUBREADER, MSGL_WARN, + "SubRip: unknown font color in subtitle: %s\n", orig); + append_text(&new_line, "{\\c}"); + line += len + 1; + continue; + + foundcolor: + line += len; + } + append_text(&new_line, "{\\c&H%06X&}", tag->color); + tag->has_color = true; + has_valid_attr = true; + } else if (strncmp(line, "face=\"", 6) == 0) { + /* Font face attribute */ + line += 6; + int len = indexof(line, '"'); + if (len <= 0) + break; + tag->face.start = line; + tag->face.len = len; + line += len; + append_text(&new_line, "{\\fn%.*s}", BSTR_P(tag->face)); + tag->has_face = true; + has_valid_attr = true; + } + line++; + } + + if (!has_valid_attr || *line != '>') { /* Not valid font tag */ + line = potential_font_tag_start; + new_line.len = len_backup; + } else { + sp++; + line++; + } + } + + /* Tag conversion code didn't match */ + if (line == orig_line) + new_line.buf[new_line.len++] = *line++; + } + new_line.buf[new_line.len] = 0; +} + + +/* + * MicroDVD + * + * Based on the specifications found here: + * https://trac.videolan.org/vlc/ticket/1825#comment:6 + */ + +struct microdvd_tag { + char key; + int persistent; + uint32_t data1; + uint32_t data2; + struct bstr data_string; +}; + +#define MICRODVD_PERSISTENT_OFF 0 +#define MICRODVD_PERSISTENT_ON 1 +#define MICRODVD_PERSISTENT_OPENED 2 + +// Color, Font, Size, cHarset, stYle, Position, cOordinate +#define MICRODVD_TAGS "cfshyYpo" + +static void microdvd_set_tag(struct microdvd_tag *tags, struct microdvd_tag tag) +{ + int tag_index = indexof(MICRODVD_TAGS, tag.key); + + if (tag_index < 0) + return; + memcpy(&tags[tag_index], &tag, sizeof(tag)); +} + +// italic, bold, underline, strike-through +#define MICRODVD_STYLES "ibus" + +static char *microdvd_load_tags(struct microdvd_tag *tags, char *s) +{ + while (*s == '{') { + char *start = s; + char tag_char = *(s + 1); + struct microdvd_tag tag = {0}; + + if (!tag_char || *(s + 2) != ':') + break; + s += 3; + + switch (tag_char) { + + /* Style */ + case 'Y': + tag.persistent = MICRODVD_PERSISTENT_ON; + case 'y': + while (*s && *s != '}') { + int style_index = indexof(MICRODVD_STYLES, *s); + + if (style_index >= 0) + tag.data1 |= (1 << style_index); + s++; + } + if (*s != '}') + break; + /* We must distinguish persistent and non-persistent styles + * to handle this kind of style tags: {y:ib}{Y:us} */ + tag.key = tag_char; + break; + + /* Color */ + case 'C': + tag.persistent = MICRODVD_PERSISTENT_ON; + case 'c': + tag.data1 = strtol(s, &s, 16) & 0x00ffffff; + if (*s != '}') + break; + tag.key = 'c'; + break; + + /* Font name */ + case 'F': + tag.persistent = MICRODVD_PERSISTENT_ON; + case 'f': + { + int len = indexof(s, '}'); + if (len < 0) + break; + tag.data_string.start = s; + tag.data_string.len = len; + s += len; + tag.key = 'f'; + break; + } + + /* Font size */ + case 'S': + tag.persistent = MICRODVD_PERSISTENT_ON; + case 's': + tag.data1 = strtol(s, &s, 10); + if (*s != '}') + break; + tag.key = 's'; + break; + + /* Charset */ + case 'H': + { + //TODO: not yet handled, just parsed. + int len = indexof(s, '}'); + if (len < 0) + break; + tag.data_string.start = s; + tag.data_string.len = len; + s += len; + tag.key = 'h'; + break; + } + + /* Position */ + case 'P': + tag.persistent = MICRODVD_PERSISTENT_ON; + tag.data1 = (*s++ == '1'); + if (*s != '}') + break; + tag.key = 'p'; + break; + + /* Coordinates */ + case 'o': + tag.persistent = MICRODVD_PERSISTENT_ON; + tag.data1 = strtol(s, &s, 10); + if (*s != ',') + break; + s++; + tag.data2 = strtol(s, &s, 10); + if (*s != '}') + break; + tag.key = 'o'; + break; + + default: /* Unknown tag, we consider it to be text */ + break; + } + + if (tag.key == 0) + return start; + + microdvd_set_tag(tags, tag); + s++; + } + return s; +} + +static void microdvd_open_tags(struct line *new_line, struct microdvd_tag *tags) +{ + for (int i = 0; i < sizeof(MICRODVD_TAGS) - 1; i++) { + if (tags[i].persistent == MICRODVD_PERSISTENT_OPENED) + continue; + switch (tags[i].key) { + case 'Y': + case 'y': + for (int sidx = 0; sidx < sizeof(MICRODVD_STYLES) - 1; sidx++) + if (tags[i].data1 & (1 << sidx)) + append_text(new_line, "{\\%c1}", MICRODVD_STYLES[sidx]); + break; + + case 'c': + append_text(new_line, "{\\c&H%06X&}", tags[i].data1); + break; + + case 'f': + append_text(new_line, "{\\fn%.*s}", BSTR_P(tags[i].data_string)); + break; + + case 's': + append_text(new_line, "{\\fs%d}", tags[i].data1); + break; + + case 'p': + if (tags[i].data1 == 0) + append_text(new_line, "{\\an8}"); + break; + + case 'o': + append_text(new_line, "{\\pos(%d,%d)}", + tags[i].data1, tags[i].data2); + break; + } + if (tags[i].persistent == MICRODVD_PERSISTENT_ON) + tags[i].persistent = MICRODVD_PERSISTENT_OPENED; + } +} + +static void microdvd_close_no_persistent_tags(struct line *new_line, + struct microdvd_tag *tags) +{ + int i; + + for (i = sizeof(MICRODVD_TAGS) - 2; i; i--) { + if (tags[i].persistent != MICRODVD_PERSISTENT_OFF) + continue; + switch (tags[i].key) { + + case 'y': + for (int sidx = sizeof(MICRODVD_STYLES) - 2; sidx >= 0; sidx--) + if (tags[i].data1 & (1 << sidx)) + append_text(new_line, "{\\%c0}", MICRODVD_STYLES[sidx]); + break; + + case 'c': + append_text(new_line, "{\\c}"); + break; + + case 'f': + append_text(new_line, "{\\fn}"); + break; + + case 's': + append_text(new_line, "{\\fs}"); + break; + } + tags[i].key = 0; + } +} + +void subassconvert_microdvd(const char *orig, char *dest, int dest_buffer_size) +{ + /* line is not const to avoid warnings with strtol, etc. + * orig content won't be changed */ + char *line = (char *)orig; + struct line new_line = { + .buf = dest, + .bufsize = dest_buffer_size, + }; + struct microdvd_tag tags[sizeof(MICRODVD_TAGS) - 1] = {{0}}; + + while (*line) { + line = microdvd_load_tags(tags, line); + microdvd_open_tags(&new_line, tags); + + while (*line && *line != '|') + new_line.buf[new_line.len++] = *line++; + + if (*line == '|') { + microdvd_close_no_persistent_tags(&new_line, tags); + append_text(&new_line, "\\N"); + line++; + } + } + new_line.buf[new_line.len] = 0; +} diff --git a/sub/subassconvert.h b/sub/subassconvert.h new file mode 100644 index 0000000000..e6a4425198 --- /dev/null +++ b/sub/subassconvert.h @@ -0,0 +1,27 @@ +/* + * Header for subtitles converter to SSA/ASS + * + * 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_SUBASSCONVERT_H +#define MPLAYER_SUBASSCONVERT_H + +void subassconvert_subrip(const char *orig, char *dest, int dest_buffer_size); +void subassconvert_microdvd(const char *orig, char *dest, int dest_buffer_size); + +#endif diff --git a/subreader.c b/sub/subreader.c index 3d422ddbdf..1f9294ec47 100644 --- a/subreader.c +++ b/sub/subreader.c @@ -32,6 +32,9 @@ #include "config.h" #include "mp_msg.h" #include "subreader.h" +#include "mpcommon.h" +#include "subassconvert.h" +#include "options.h" #include "stream/stream.h" #include "libavutil/common.h" #include "libavutil/avstring.h" @@ -53,6 +56,12 @@ int flip_hebrew = 1; ///flip subtitles using fribidi int fribidi_flip_commas = 0; ///flip comma when fribidi is used #endif +// Parameter struct for the format-specific readline functions +struct readline_args { + int utf16; + struct MPOpts *opts; +}; + /* Maximal length of line of a subtitle */ #define LINE_LEN 1000 static float mpsub_position=0; @@ -118,7 +127,10 @@ static void sami_add_line(subtitle *current, char *buffer, char **pos) { *pos = buffer; } -static subtitle *sub_read_line_sami(stream_t* st, subtitle *current, int utf16) { +static subtitle *sub_read_line_sami(stream_t* st, subtitle *current, + struct readline_args *args) +{ + int utf16 = args->utf16; static char line[LINE_LEN+1]; static char *s = NULL, *slacktime_s; char text[LINE_LEN+1], *p=NULL, *q; @@ -277,7 +289,10 @@ static char *sub_readtext(char *source, char **dest) { else return NULL; // last text field } -static subtitle *sub_read_line_microdvd(stream_t *st,subtitle *current, int utf16) { +static subtitle *sub_read_line_microdvd(stream_t *st,subtitle *current, + struct readline_args *args) +{ + int utf16 = args->utf16; char line[LINE_LEN+1]; char line2[LINE_LEN+1]; char *p, *next; @@ -292,7 +307,11 @@ static subtitle *sub_read_line_microdvd(stream_t *st,subtitle *current, int utf1 "{%ld}{%ld}%[^\r\n]", &(current->start), &(current->end), line2) < 3)); - p=line2; + if (args->opts->ass_enabled) { + subassconvert_microdvd(line2, line, LINE_LEN + 1); + p = line; + } else + p = line2; next=p, i=0; while ((next =sub_readtext (next, &(current->text[i])))) { @@ -305,7 +324,10 @@ static subtitle *sub_read_line_microdvd(stream_t *st,subtitle *current, int utf1 return current; } -static subtitle *sub_read_line_mpl2(stream_t *st,subtitle *current, int utf16) { +static subtitle *sub_read_line_mpl2(stream_t *st,subtitle *current, + struct readline_args *args) +{ + int utf16 = args->utf16; char line[LINE_LEN+1]; char line2[LINE_LEN+1]; char *p, *next; @@ -331,7 +353,10 @@ static subtitle *sub_read_line_mpl2(stream_t *st,subtitle *current, int utf16) { return current; } -static subtitle *sub_read_line_subrip(stream_t* st, subtitle *current, int utf16) { +static subtitle *sub_read_line_subrip(stream_t* st, subtitle *current, + struct readline_args *args) +{ + int utf16 = args->utf16; char line[LINE_LEN+1]; int a1,a2,a3,a4,b1,b2,b3,b4; char *p=NULL, *q=NULL; @@ -361,12 +386,75 @@ static subtitle *sub_read_line_subrip(stream_t* st, subtitle *current, int utf16 return current; } -static subtitle *sub_read_line_subviewer(stream_t *st,subtitle *current, int utf16) { +static subtitle *sub_ass_read_line_subviewer(stream_t *st, subtitle *current, + struct readline_args *args) +{ + int utf16 = args->utf16; + int a1, a2, a3, a4, b1, b2, b3, b4, j = 0; + + while (!current->text[0]) { + char line[LINE_LEN + 1], full_line[LINE_LEN + 1], sep; + int i; + + /* Parse SubRip header */ + if (!stream_read_line(st, line, LINE_LEN, utf16)) + return NULL; + if (sscanf(line, "%d:%d:%d%[,.:]%d --> %d:%d:%d%[,.:]%d", + &a1, &a2, &a3, &sep, &a4, &b1, &b2, &b3, &sep, &b4) < 10) + continue; + + current->start = a1 * 360000 + a2 * 6000 + a3 * 100 + a4 / 10; + current->end = b1 * 360000 + b2 * 6000 + b3 * 100 + b4 / 10; + + /* Concat lines */ + full_line[0] = 0; + for (i = 0; i < SUB_MAX_TEXT; i++) { + int blank = 1, len = 0; + char *p; + + if (!stream_read_line(st, line, LINE_LEN, utf16)) + break; + + for (p = line; *p != '\n' && *p != '\r' && *p; p++, len++) + if (*p != ' ' && *p != '\t') + blank = 0; + + if (blank) + break; + + *p = 0; + + if (!(j + 1 + len < sizeof(full_line) - 1)) + break; + + if (j != 0) + full_line[j++] = '\n'; + strcpy(&full_line[j], line); + j += len; + } + + /* Use the ASS/SSA converter to transform the whole lines */ + if (full_line[0]) { + char converted_line[LINE_LEN + 1]; + subassconvert_subrip(full_line, converted_line, LINE_LEN + 1); + current->text[0] = strdup(converted_line); + current->lines = 1; + } + } + return current; +} + +static subtitle *sub_read_line_subviewer(stream_t *st,subtitle *current, + struct readline_args *args) +{ + int utf16 = args->utf16; char line[LINE_LEN+1]; int a1,a2,a3,a4,b1,b2,b3,b4; char *p=NULL; int i,len; + if (args->opts->ass_enabled) + return sub_ass_read_line_subviewer(st, current, args); while (!current->text[0]) { if (!stream_read_line (st, line, LINE_LEN, utf16)) return NULL; if ((len=sscanf (line, "%d:%d:%d%[,.:]%d --> %d:%d:%d%[,.:]%d",&a1,&a2,&a3,(char *)&i,&a4,&b1,&b2,&b3,(char *)&i,&b4)) < 10) @@ -413,7 +501,10 @@ static subtitle *sub_read_line_subviewer(stream_t *st,subtitle *current, int utf return current; } -static subtitle *sub_read_line_subviewer2(stream_t *st,subtitle *current, int utf16) { +static subtitle *sub_read_line_subviewer2(stream_t *st,subtitle *current, + struct readline_args *args) +{ + int utf16 = args->utf16; char line[LINE_LEN+1]; int a1,a2,a3,a4; char *p=NULL; @@ -446,7 +537,10 @@ static subtitle *sub_read_line_subviewer2(stream_t *st,subtitle *current, int ut } -static subtitle *sub_read_line_vplayer(stream_t *st,subtitle *current, int utf16) { +static subtitle *sub_read_line_vplayer(stream_t *st,subtitle *current, + struct readline_args *args) +{ + int utf16 = args->utf16; char line[LINE_LEN+1]; int a1,a2,a3; char *p=NULL, *next,separator; @@ -492,7 +586,11 @@ static subtitle *sub_read_line_vplayer(stream_t *st,subtitle *current, int utf16 return current; } -static subtitle *sub_read_line_rt(stream_t *st,subtitle *current, int utf16) { +static subtitle *sub_read_line_rt(stream_t *st,subtitle *current, + struct readline_args *args) +{ + int utf16 = args->utf16; + //TODO: This format uses quite rich (sub/super)set of xhtml // I couldn't check it since DTD is not included. // WARNING: full XML parses can be required for proper parsing @@ -542,7 +640,9 @@ static subtitle *sub_read_line_rt(stream_t *st,subtitle *current, int utf16) { return current; } -static subtitle *sub_read_line_ssa(stream_t *st,subtitle *current, int utf16) { +static subtitle *sub_read_line_ssa(stream_t *st,subtitle *current, + struct readline_args *args) +{ /* * Sub Station Alpha v4 (and v2?) scripts have 9 commas before subtitle * other Sub Station Alpha scripts have only 8 commas before subtitle @@ -552,6 +652,7 @@ static subtitle *sub_read_line_ssa(stream_t *st,subtitle *current, int utf16) { * http://www.scriptclub.org is a good place to find more examples * http://www.eswat.demon.co.uk is where the SSA specs can be found */ + int utf16 = args->utf16; int comma; static int max_comma = 32; /* let's use 32 for the case that the */ /* amount of commas increase with newer SSA versions */ @@ -644,7 +745,10 @@ static void sub_pp_ssa(subtitle *sub) { * * by set, based on code by szabi (dunnowhat sub format ;-) */ -static subtitle *sub_read_line_pjs(stream_t *st,subtitle *current, int utf16) { +static subtitle *sub_read_line_pjs(stream_t *st,subtitle *current, + struct readline_args *args) +{ + int utf16 = args->utf16; char line[LINE_LEN+1]; char text[LINE_LEN+1], *s, *d; @@ -682,7 +786,10 @@ static subtitle *sub_read_line_pjs(stream_t *st,subtitle *current, int utf16) { return current; } -static subtitle *sub_read_line_mpsub(stream_t *st, subtitle *current, int utf16) { +static subtitle *sub_read_line_mpsub(stream_t *st, subtitle *current, + struct readline_args *args) +{ + int utf16 = args->utf16; char line[LINE_LEN+1]; float a,b; int num=0; @@ -727,7 +834,10 @@ static subtitle *sub_read_line_mpsub(stream_t *st, subtitle *current, int utf16) subtitle *previous_aqt_sub = NULL; #endif -static subtitle *sub_read_line_aqt(stream_t *st,subtitle *current, int utf16) { +static subtitle *sub_read_line_aqt(stream_t *st,subtitle *current, + struct readline_args *args) +{ + int utf16 = args->utf16; char line[LINE_LEN+1]; char *next; int i; @@ -784,7 +894,10 @@ static subtitle *sub_read_line_aqt(stream_t *st,subtitle *current, int utf16) { subtitle *previous_subrip09_sub = NULL; #endif -static subtitle *sub_read_line_subrip09(stream_t *st,subtitle *current, int utf16) { +static subtitle *sub_read_line_subrip09(stream_t *st,subtitle *current, + struct readline_args *args) +{ + int utf16 = args->utf16; char line[LINE_LEN+1]; int a1,a2,a3; char * next=NULL; @@ -836,8 +949,10 @@ static subtitle *sub_read_line_subrip09(stream_t *st,subtitle *current, int utf1 return current; } -static subtitle *sub_read_line_jacosub(stream_t* st, subtitle * current, int utf16) +static subtitle *sub_read_line_jacosub(stream_t* st, subtitle * current, + struct readline_args *args) { + int utf16 = args->utf16; char line1[LINE_LEN], line2[LINE_LEN], directive[LINE_LEN], *p, *q; unsigned a1, a2, a3, a4, b1, b2, b3, b4, comment = 0; static unsigned jacoTimeres = 30; @@ -1284,7 +1399,8 @@ static void adjust_subs_time(subtitle* sub, float subtime, float fps, int block, } struct subreader { - subtitle * (*read)(stream_t *st,subtitle *dest,int utf16); + subtitle * (*read)(stream_t *st, subtitle *dest, + struct readline_args *args); void (*post)(subtitle *dest); const char *name; }; @@ -1350,7 +1466,8 @@ const char* guess_cp(stream_t *st, const char *preferred_language, const char *f #undef MAX_GUESS_BUFFER_SIZE #endif -sub_data* sub_read_file (char *filename, float fps) { +sub_data* sub_read_file(char *filename, float fps, struct MPOpts *opts) +{ int utf16; stream_t* fd; int n_max, n_first, i, j, sub_first, sub_orig; @@ -1435,7 +1552,7 @@ sub_data* sub_read_file (char *filename, float fps) { sub = &first[sub_num]; #endif memset(sub, '\0', sizeof(subtitle)); - sub=srp->read(fd,sub,utf16); + sub=srp->read(fd, sub, &(struct readline_args){utf16, opts}); if(!sub) break; // EOF #ifdef CONFIG_ICONV if ((sub!=ERR) && sub_utf8 == 2) sub=subcp_recode(sub); @@ -2359,7 +2476,6 @@ void sub_add_text(subtitle *sub, const char *txt, int len, double endpts) { #endif } -#define MP_NOPTS_VALUE (-1LL<<63) /** * \brief remove outdated subtitle lines. * \param sub subtitle struct to modify diff --git a/subreader.h b/sub/subreader.h index b1aa07421b..9c7465d71a 100644 --- a/subreader.h +++ b/sub/subreader.h @@ -20,6 +20,7 @@ #define MPLAYER_SUBREADER_H #include <stdio.h> +#include <stdbool.h> #include "config.h" @@ -84,7 +85,8 @@ extern char *fribidi_charset; extern int flip_hebrew; extern int fribidi_flip_commas; -sub_data* sub_read_file (char *filename, float pts); +struct MPOpts; +sub_data* sub_read_file (char *filename, float pts, struct MPOpts *opts); subtitle* subcp_recode (subtitle *sub); // enca_fd is the file enca uses to determine the codepage. // setting to NULL disables enca. diff --git a/unrar_exec.c b/sub/unrar_exec.c index 6de8c59bef..6de8c59bef 100644 --- a/unrar_exec.c +++ b/sub/unrar_exec.c diff --git a/unrar_exec.h b/sub/unrar_exec.h index 5754083fd7..5754083fd7 100644 --- a/unrar_exec.h +++ b/sub/unrar_exec.h diff --git a/vobsub.c b/sub/vobsub.c index 08efa3acec..08efa3acec 100644 --- a/vobsub.c +++ b/sub/vobsub.c diff --git a/vobsub.h b/sub/vobsub.h index b076e4b6bc..b076e4b6bc 100644 --- a/vobsub.h +++ b/sub/vobsub.h |