From b44202b69fc4a1dd1659f7940c5f8846d316e0ff Mon Sep 17 00:00:00 2001 From: wm4 Date: Sun, 28 Apr 2013 21:12:11 +0200 Subject: sub: redo how -no-ass is handled The -no-ass switch used to disable any use of libass for text subtitles. This is not really the case anymore, because libass is now always involved when rendering text. The only remaining use of -no-ass is disabling styling or showing subtitles on the terminal. On the other hand, the old subtitle rendering path is a big reason why the subtitle code is still a big mess with an awful number of obscure special cases. In order to simplify it, remove the old subtitle rendering code, and always go through sd_ass.c. Basically, we use ASS_Track as central data structure for storing text subtitles instead of struct sub_data. This also makes libass mandatory for all text subs, even if they are printed to the terminal in -no-video mode. (We could add something like sd_text to avoid this, but it's not worth the trouble.) struct sub_data and subreader.c are still around, even its ASS/SSA reader. But struct sub_data is freed right after converting it to ASS_Track. The internal ASS reader actually can handle some obscure cases libass can't, like files encoded in UTF-16. --- core/command.c | 20 ++------ core/mp_core.h | 6 --- core/mplayer.c | 147 ++++++++++++++++++++------------------------------------- core/mplayer.h | 3 -- 4 files changed, 55 insertions(+), 121 deletions(-) (limited to 'core') diff --git a/core/command.c b/core/command.c index 3ee8f39c3d..7eb36be5f3 100644 --- a/core/command.c +++ b/core/command.c @@ -1307,7 +1307,6 @@ static int mp_property_sub_visibility(m_option_t *prop, int action, switch (action) { case M_PROPERTY_SET: opts->sub_visibility = *(int *)arg; - vo_osd_changed(OSDTYPE_SUBTITLE); if (vo_spudec) vo_osd_changed(OSDTYPE_SPU); return M_PROPERTY_OK; @@ -1991,26 +1990,18 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd) } case MP_CMD_SUB_STEP: +#ifdef CONFIG_ASS if (sh_video) { int movement = cmd->args[0].v.i; - struct track *track = mpctx->current_track[STREAM_SUB]; - bool available = false; - if (track && track->subdata) { - available = true; - step_sub(track->subdata, mpctx->video_pts, movement); - } -#ifdef CONFIG_ASS struct ass_track *ass_track = sub_get_ass_track(mpctx->osd); if (ass_track) { - available = true; + set_osd_tmsg(mpctx, OSD_MSG_SUB_DELAY, osdl, osd_duration, + "Sub delay: %d ms", ROUND(sub_delay * 1000)); sub_delay += ass_step_sub(ass_track, (mpctx->video_pts + sub_delay) * 1000 + .5, movement) / 1000.; } -#endif - if (available) - set_osd_tmsg(mpctx, OSD_MSG_SUB_DELAY, osdl, osd_duration, - "Sub delay: %d ms", ROUND(sub_delay * 1000)); } +#endif break; case MP_CMD_OSD: { @@ -2194,7 +2185,6 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd) if (tv_channel_list) { set_osd_tmsg(mpctx, OSD_MSG_TV_CHANNEL, osdl, osd_duration, "Channel: %s", tv_channel_current->name); - //vo_osd_changed(OSDTYPE_SUBTITLE); } } #ifdef CONFIG_PVR @@ -2232,7 +2222,6 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd) if (tv_channel_list) { set_osd_tmsg(mpctx, OSD_MSG_TV_CHANNEL, osdl, osd_duration, "Channel: %s", tv_channel_current->name); - //vo_osd_changed(OSDTYPE_SUBTITLE); } } #ifdef CONFIG_PVR @@ -2265,7 +2254,6 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd) if (tv_channel_list) { set_osd_tmsg(mpctx, OSD_MSG_TV_CHANNEL, osdl, osd_duration, "Channel: %s", tv_channel_current->name); - //vo_osd_changed(OSDTYPE_SUBTITLE); } } #ifdef CONFIG_PVR diff --git a/core/mp_core.h b/core/mp_core.h index 9e61c8ffa3..665588c5c0 100644 --- a/core/mp_core.h +++ b/core/mp_core.h @@ -22,8 +22,6 @@ #include #include "core/options.h" -#include "sub/subreader.h" -#include "sub/find_subfiles.h" #include "audio/mixer.h" #include "demux/demux.h" @@ -112,9 +110,6 @@ struct track { // External text subtitle using libass subtitle renderer. // The sh_sub is a dummy and doesn't belong to a demuxer. struct sh_sub *sh_sub; - - // External text subtitle using non-libass subtitle renderer. - struct sub_data *subdata; }; enum { @@ -129,7 +124,6 @@ typedef struct MPContext { struct osd_state *osd; struct mp_osd_msg *osd_msg_stack; char *terminal_osd_text; - subtitle subs; // subtitle list used when reading subtitles from demuxer int add_osd_seek_info; // bitfield of enum mp_osd_seek_info double osd_visible; // for the osd bar only diff --git a/core/mplayer.c b/core/mplayer.c index 52aa34058c..602d1f0616 100644 --- a/core/mplayer.c +++ b/core/mplayer.c @@ -74,6 +74,7 @@ #include "sub/subreader.h" #include "sub/find_subfiles.h" #include "sub/dec_sub.h" +#include "sub/sd.h" #include "core/mp_osd.h" #include "video/out/vo.h" @@ -284,8 +285,6 @@ static void print_stream(struct MPContext *mpctx, struct track *t) const char *codec = s ? s->codec : NULL; if (!codec && t->sh_sub) // external subs hack codec = t->sh_sub->gsh->codec; - if (!codec && t->subdata) - codec = t->subdata->codec; mp_msg(MSGT_CPLAYER, MSGL_INFO, " (%s)", codec ? codec : ""); if (t->is_external) mp_msg(MSGT_CPLAYER, MSGL_INFO, " (external)"); @@ -1052,38 +1051,36 @@ struct track *mp_add_subtitles(struct MPContext *mpctx, char *filename, float fps, int noerr) { struct MPOpts *opts = &mpctx->opts; - sub_data *subd = NULL; struct sh_sub *sh = NULL; + struct ass_track *asst = NULL; + const char *codec = NULL; if (filename == NULL) return NULL; - if (opts->ass_enabled) { + // Note: no text subtitles without libass. This is mainly because sd_ass is + // used for rendering. Even when showing subtitles with term-osd, going + // through sd_ass makes the code much simpler, as sd_ass can handle all + // the weird special-cases. #ifdef CONFIG_ASS - struct ass_track *asst = mp_ass_read_stream(mpctx->ass_library, - filename, sub_cp); - bool is_native_ass = asst; - const char *codec = NULL; - if (!asst) { - subd = sub_read_file(filename, fps, &mpctx->opts); - if (subd) { - codec = subd->codec; - asst = mp_ass_read_subdata(mpctx->ass_library, opts, subd, fps); - talloc_free(subd); - subd = NULL; - } - } - if (asst) { - sh = sd_ass_create_from_track(asst, is_native_ass, opts); - if (codec) - sh->gsh->codec = codec; + if (opts->ass_enabled) { + asst = mp_ass_read_stream(mpctx->ass_library, filename, sub_cp); + codec = "ass"; + } + if (!asst) { + sub_data *subd = sub_read_file(filename, fps, &mpctx->opts); + if (subd) { + codec = subd->codec; + asst = mp_ass_read_subdata(mpctx->ass_library, opts, subd, fps); } + talloc_free(subd); + } + if (asst) + sh = sd_ass_create_from_track(asst, codec, opts); #endif - } else - subd = sub_read_file(filename, fps, &mpctx->opts); - - if (!sh && !subd) { + if (!sh) { + // Used with image subtitles. struct track *ext = open_external_file(mpctx, filename, NULL, 0, STREAM_SUB); if (ext) @@ -1101,7 +1098,6 @@ struct track *mp_add_subtitles(struct MPContext *mpctx, char *filename, .demuxer_id = -1, .is_external = true, .sh_sub = talloc_steal(track, sh), - .subdata = talloc_steal(track, subd), .external_filename = talloc_strdup(track, filename), }; MP_TARRAY_APPEND(mpctx, mpctx->tracks, mpctx->num_tracks, track); @@ -1545,23 +1541,16 @@ void set_osd_function(struct MPContext *mpctx, int osd_function) /** * \brief Display text subtitles on the OSD */ -void set_osd_subtitle(struct MPContext *mpctx, subtitle *subs) -{ - int i; - vo_sub = subs; - vo_osd_changed(OSDTYPE_SUBTITLE); - if (!mpctx->sh_video) { - // reverse order, since newest set_osd_msg is displayed first - for (i = SUB_MAX_TEXT - 1; i >= 0; i--) { - if (!subs || i >= subs->lines || !subs->text[i]) - rm_osd_msg(mpctx, OSD_MSG_SUB_BASE + i); - else { - // HACK: currently display time for each sub line - // except the last is set to 2 seconds. - int display_time = i == subs->lines - 1 ? 180000 : 2000; - set_osd_msg(mpctx, OSD_MSG_SUB_BASE + i, 1, display_time, - "%s", subs->text[i]); - } +static void set_osd_subtitle(struct MPContext *mpctx, const char *text) +{ + if (!text) + text = ""; + if (strcmp(mpctx->osd->sub_text, text) != 0) { + osd_set_sub(mpctx->osd, text); + if (!mpctx->sh_video) { + rm_osd_msg(mpctx, OSD_MSG_SUB_BASE); + if (text && text[0]) + set_osd_msg(mpctx, OSD_MSG_SUB_BASE, 1, INT_MAX, "%s", text); } } } @@ -1877,9 +1866,7 @@ static void reset_subtitles(struct MPContext *mpctx) { if (mpctx->sh_sub) sub_reset(mpctx->sh_sub, mpctx->osd); - sub_clear_text(&mpctx->subs, MP_NOPTS_VALUE); - if (vo_sub) - set_osd_subtitle(mpctx, NULL); + set_osd_subtitle(mpctx, NULL); if (vo_spudec) { spudec_reset(vo_spudec); vo_osd_changed(OSDTYPE_SPU); @@ -1888,33 +1875,22 @@ static void reset_subtitles(struct MPContext *mpctx) static void update_subtitles(struct MPContext *mpctx, double refpts_tl) { - struct MPOpts *opts = &mpctx->opts; - struct sh_video *sh_video = mpctx->sh_video; struct sh_sub *sh_sub = mpctx->sh_sub; struct demux_stream *d_sub = sh_sub ? sh_sub->ds : NULL; unsigned char *packet = NULL; int len; const char *type = sh_sub ? sh_sub->gsh->codec : NULL; - mpctx->osd->sub_offset = mpctx->video_offset; - struct track *track = mpctx->current_track[STREAM_SUB]; if (!track) return; - if (!track->under_timeline) - mpctx->osd->sub_offset = 0; + double video_offset = track->under_timeline ? mpctx->video_offset : 0; - double refpts_s = refpts_tl - mpctx->osd->sub_offset; - double curpts_s = refpts_s + sub_delay; + mpctx->osd->sub_offset = video_offset - sub_delay; - // find sub - if (track->subdata) { - if (sub_fps == 0) - sub_fps = sh_video ? sh_video->fps : 25; - find_sub(mpctx, track->subdata, curpts_s * - (track->subdata->sub_uses_time ? 100. : sub_fps)); - } + double curpts_s = refpts_tl - mpctx->osd->sub_offset; + double refpts_s = refpts_tl - video_offset; // DVD sub: if (is_dvd_sub(type) && !(sh_sub && sh_sub->active)) { @@ -1955,7 +1931,7 @@ static void update_subtitles(struct MPContext *mpctx, double refpts_tl) if (timestamp >= 0) spudec_assemble(vo_spudec, packet, len, timestamp); } - } else if (d_sub && (is_text_sub(type) || (sh_sub && sh_sub->active))) { + } else if (d_sub && sh_sub && sh_sub->active) { bool non_interleaved = is_non_interleaved(mpctx, track); if (non_interleaved) ds_get_next_pts(d_sub); @@ -1967,7 +1943,7 @@ static void update_subtitles(struct MPContext *mpctx, double refpts_tl) "Sub early: c_pts=%5.3f s_pts=%5.3f\n", curpts_s, subpts_s); // Libass handled subs can be fed to it in advance - if (!opts->ass_enabled || !is_text_sub(type)) + if (!sub_accept_packets_in_advance(sh_sub)) break; // Try to avoid demuxing whole file at once if (non_interleaved && subpts_s > curpts_s + 1) @@ -1984,41 +1960,19 @@ static void update_subtitles(struct MPContext *mpctx, double refpts_tl) len = FFMIN(len - 2, AV_RB16(packet)); packet += 2; } - if (sh_sub && sh_sub->active) { - sub_decode(sh_sub, mpctx->osd, packet, len, subpts_s, duration); - } else if (subpts_s != MP_NOPTS_VALUE) { - // text sub - if (duration < 0) - sub_clear_text(&mpctx->subs, MP_NOPTS_VALUE); - if (is_ass_sub(type)) { // 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_s = MP_NOPTS_VALUE; - if (subpts_s != MP_NOPTS_VALUE && duration >= 0) - endpts_s = subpts_s + duration; - sub_add_text(&mpctx->subs, packet, len, endpts_s); - set_osd_subtitle(mpctx, &mpctx->subs); - } + sub_decode(sh_sub, mpctx->osd, packet, len, subpts_s, duration); if (non_interleaved) ds_get_next_pts(d_sub); } - if (!opts->ass_enabled) - if (sub_clear_text(&mpctx->subs, curpts_s)) - set_osd_subtitle(mpctx, &mpctx->subs); } if (vo_spudec) { spudec_heartbeat(vo_spudec, 90000 * curpts_s); if (spudec_changed(vo_spudec)) vo_osd_changed(OSDTYPE_SPU); } + + if (!mpctx->osd->render_bitmap_subs) + set_osd_subtitle(mpctx, sub_get_text(mpctx->osd, curpts_s)); } static int check_framedrop(struct MPContext *mpctx, double frame_time) @@ -2130,12 +2084,8 @@ static void reinit_subs(struct MPContext *mpctx) mpctx->initialized_flags |= INITIALIZED_SUB; - if (track->subdata || track->sh_sub) { -#ifdef CONFIG_ASS - if (opts->ass_enabled && track->sh_sub) - sub_init(track->sh_sub, mpctx->osd); -#endif - vo_osd_changed(OSDTYPE_SUBTITLE); + if (track->sh_sub) { + sub_init(track->sh_sub, mpctx->osd); } else if (track->stream) { struct stream *s = track->demuxer ? track->demuxer->stream : NULL; if (s && s->type == STREAMTYPE_DVD) @@ -2153,6 +2103,12 @@ static void reinit_subs(struct MPContext *mpctx) else sub_init(mpctx->sh_sub, mpctx->osd); } + + // Decides whether to use OSD path or normal subtitle rendering path. + mpctx->osd->render_bitmap_subs = true; + struct sh_sub *sh_sub = mpctx->osd->sh_sub; + if (sh_sub && sh_sub->active && sh_sub->sd_driver->get_text) + mpctx->osd->render_bitmap_subs = opts->ass_enabled; } static char *track_layout_hash(struct MPContext *mpctx) @@ -4551,7 +4507,6 @@ terminate_playback: // don't jump here after ao/vo/getch initialization! talloc_free(mpctx->resolve_result); mpctx->resolve_result = NULL; - vo_sub = NULL; #ifdef CONFIG_ASS if (mpctx->osd->ass_renderer) ass_renderer_done(mpctx->osd->ass_renderer); diff --git a/core/mplayer.h b/core/mplayer.h index b96f814b68..825458b6f5 100644 --- a/core/mplayer.h +++ b/core/mplayer.h @@ -25,9 +25,6 @@ struct MPContext; struct MPOpts; -struct subtitle; - -void set_osd_subtitle(struct MPContext *mpctx, struct subtitle *subs); struct mp_resolve_result { char *url; -- cgit v1.2.3 From 724f576211c1ea07e0423ac8a9c0e4f273c452fb Mon Sep 17 00:00:00 2001 From: wm4 Date: Mon, 29 Apr 2013 01:11:50 +0200 Subject: sub: use DVD PTS fallback code in normal sub decoding path It appears demux_mpg doesn't output timestamps for subtitles. The vobsub code handled this by doing its own PTS calculations. This code is absent from the normal subtitle decoder path. Copy this code into the normal path, so that we can unify the subtitle decoder paths in a later commit. Decoding subtitles with sd_lavc when playing DVD with demux_mpg still doesn't work. --- core/mplayer.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'core') diff --git a/core/mplayer.c b/core/mplayer.c index 602d1f0616..bb6a0872cc 100644 --- a/core/mplayer.c +++ b/core/mplayer.c @@ -1938,6 +1938,20 @@ static void update_subtitles(struct MPContext *mpctx, double refpts_tl) while (d_sub->first) { double subpts_s = ds_get_next_pts(d_sub); + if (subpts_s == MP_NOPTS_VALUE) { + // Try old method of getting PTS. This is only needed in the + // DVD playback case with demux_mpg. + // 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_s; + if (x > -20 && x < 20) // prevent missing subs on pts reset + subpts_s = d_sub->pts; + else + subpts_s = curpts_s; + } if (subpts_s > curpts_s) { mp_dbg(MSGT_CPLAYER, MSGL_DBG2, "Sub early: c_pts=%5.3f s_pts=%5.3f\n", -- cgit v1.2.3 From 26842806431a1d21e3c3c430994cd6901e36a08e Mon Sep 17 00:00:00 2001 From: wm4 Date: Mon, 29 Apr 2013 01:13:22 +0200 Subject: sub: add sd_spu.c to wrap spudec, cleanup mplayer.c This unifies the subtitle rendering path. Now all subtitle rendering goes through sd_ass.c/sd_lavc.c/sd_spu.c. Before that commit, the spudec.h functions were used directly in mplayer.c, which introduced many special cases. Add sd_spu.c, which is just a small wrapper connecting the new subtitle render API with the dusty old vobsub decoder in spudec.c. One detail that changes is that we always pass the palette as extra data, instead of passing the libdvdread palette as pointer to spudec directly. This is a bit roundabout, but actually makes the code simpler and more elegant: the difference between DVD and non-DVD dvdsubs is reduced. Ideally, we would just delete spudec.c and use libavcodec's DVD sub decoder. However, DVD playback with demux_mpg produces packets incompatible to lavc. There are incompatibilities the other way around as well: packets from libavformat's vobsub demuxer are incompatible to spudec.c. So we define a new subtitle codec name for demux_mpg subs, "dvd_subtitle_mpg", which only sd_spu can decode. There is actually code in spudec.c to "assemble" fragments into complete packets, but using the whole spudec.c is easier than trying to move this code into demux_mpg to fix subtitle packets. As additional complication, Libav 9.x can't decode DVD subs correctly, so use sd_spu in that case as well. --- core/command.c | 23 +---------- core/mp_core.h | 2 - core/mplayer.c | 127 ++++++++------------------------------------------------- 3 files changed, 20 insertions(+), 132 deletions(-) (limited to 'core') diff --git a/core/command.c b/core/command.c index 7eb36be5f3..4e82ceccd8 100644 --- a/core/command.c +++ b/core/command.c @@ -50,7 +50,6 @@ #include "audio/filter/af.h" #include "video/decode/dec_video.h" #include "audio/decode/dec_audio.h" -#include "sub/spudec.h" #include "core/path.h" #include "sub/ass_mp.h" #include "stream/tv.h" @@ -1307,8 +1306,7 @@ static int mp_property_sub_visibility(m_option_t *prop, int action, switch (action) { case M_PROPERTY_SET: opts->sub_visibility = *(int *)arg; - if (vo_spudec) - vo_osd_changed(OSDTYPE_SPU); + osd_changed_all(mpctx->osd); return M_PROPERTY_OK; case M_PROPERTY_GET: *(int *)arg = opts->sub_visibility; @@ -1317,23 +1315,6 @@ static int mp_property_sub_visibility(m_option_t *prop, int action, return M_PROPERTY_NOT_IMPLEMENTED; } -/// Show only forced subtitles (RW) -static int mp_property_sub_forced_only(m_option_t *prop, int action, - void *arg, MPContext *mpctx) -{ - struct MPOpts *opts = &mpctx->opts; - - if (!vo_spudec) - return M_PROPERTY_UNAVAILABLE; - - if (action == M_PROPERTY_SET) { - opts->forced_subs_only = *(int *)arg; - spudec_set_forced_subs_only(vo_spudec, opts->forced_subs_only); - return M_PROPERTY_OK; - } - return mp_property_generic_option(prop, action, arg, mpctx); -} - #ifdef CONFIG_TV @@ -1514,7 +1495,7 @@ static const m_option_t mp_properties[] = { M_OPTION_PROPERTY_CUSTOM("sub-pos", mp_property_sub_pos), { "sub-visibility", mp_property_sub_visibility, CONF_TYPE_FLAG, M_OPT_RANGE, 0, 1, NULL }, - M_OPTION_PROPERTY_CUSTOM("sub-forced-only", mp_property_sub_forced_only), + M_OPTION_PROPERTY_CUSTOM("sub-forced-only", property_osd_helper), M_OPTION_PROPERTY_CUSTOM("sub-scale", property_osd_helper), #ifdef CONFIG_ASS M_OPTION_PROPERTY_CUSTOM("ass-use-margins", property_osd_helper), diff --git a/core/mp_core.h b/core/mp_core.h index 665588c5c0..db6bc570e1 100644 --- a/core/mp_core.h +++ b/core/mp_core.h @@ -31,7 +31,6 @@ #define INITIALIZED_AO 2 #define INITIALIZED_VOL 4 #define INITIALIZED_GETCH2 8 -#define INITIALIZED_SPUDEC 32 #define INITIALIZED_STREAM 64 #define INITIALIZED_DEMUXER 512 #define INITIALIZED_ACODEC 1024 @@ -293,7 +292,6 @@ extern int forced_subs_only; void uninit_player(struct MPContext *mpctx, unsigned int mask); void reinit_audio_chain(struct MPContext *mpctx); -void init_vo_spudec(struct MPContext *mpctx); double playing_audio_pts(struct MPContext *mpctx); struct track *mp_add_subtitles(struct MPContext *mpctx, char *filename, float fps, int noerr); diff --git a/core/mplayer.c b/core/mplayer.c index bb6a0872cc..c596aa8504 100644 --- a/core/mplayer.c +++ b/core/mplayer.c @@ -95,8 +95,6 @@ #include "core/codecs.h" -#include "sub/spudec.h" - #include "osdep/getch2.h" #include "osdep/timer.h" @@ -554,12 +552,6 @@ void uninit_player(struct MPContext *mpctx, unsigned int mask) getch2_disable(); } - if (mask & INITIALIZED_SPUDEC) { - mpctx->initialized_flags &= ~INITIALIZED_SPUDEC; - spudec_free(vo_spudec); - vo_spudec = NULL; - } - if (mask & INITIALIZED_VOL) { mpctx->initialized_flags &= ~INITIALIZED_VOL; if (mpctx->mixer.ao) { @@ -1104,38 +1096,6 @@ struct track *mp_add_subtitles(struct MPContext *mpctx, char *filename, return track; } -void init_vo_spudec(struct MPContext *mpctx) -{ - uninit_player(mpctx, INITIALIZED_SPUDEC); - unsigned width, height; - - // we currently can't work without video stream - if (!mpctx->sh_video) - return; - - width = mpctx->sh_video->disp_w; - height = mpctx->sh_video->disp_h; - -#ifdef CONFIG_DVDREAD - if (vo_spudec == NULL && mpctx->stream->type == STREAMTYPE_DVD) { - vo_spudec = spudec_new_scaled(((dvd_priv_t *)(mpctx->stream->priv))-> - cur_pgc->palette, width, height, NULL, 0); - } -#endif - - if (vo_spudec == NULL && mpctx->sh_sub) { - sh_sub_t *sh = mpctx->sh_sub; - vo_spudec = spudec_new_scaled(NULL, width, height, sh->extradata, - sh->extradata_len); - } - - if (vo_spudec != NULL) { - mpctx->initialized_flags |= INITIALIZED_SPUDEC; - mp_property_do("sub-forced-only", M_PROPERTY_SET, - &mpctx->opts.forced_subs_only, mpctx); - } -} - int mp_get_cache_percent(struct MPContext *mpctx) { if (mpctx->stream) { @@ -1867,10 +1827,6 @@ static void reset_subtitles(struct MPContext *mpctx) if (mpctx->sh_sub) sub_reset(mpctx->sh_sub, mpctx->osd); set_osd_subtitle(mpctx, NULL); - if (vo_spudec) { - spudec_reset(vo_spudec); - vo_osd_changed(OSDTYPE_SPU); - } } static void update_subtitles(struct MPContext *mpctx, double refpts_tl) @@ -1892,46 +1848,7 @@ static void update_subtitles(struct MPContext *mpctx, double refpts_tl) double curpts_s = refpts_tl - mpctx->osd->sub_offset; double refpts_s = refpts_tl - video_offset; - // DVD sub: - if (is_dvd_sub(type) && !(sh_sub && sh_sub->active)) { - int timestamp; - // Get a sub packet from the demuxer (or the vobsub.c thing, which - // should be a demuxer, but isn't). - while (1) { - // Vobsub - len = 0; - { - // DVD sub - assert(d_sub->sh == sh_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_s; - if (x > -20 && x < 20) // prevent missing subs on pts reset - timestamp = 90000 * d_sub->pts; - else - timestamp = 90000 * curpts_s; - mp_dbg(MSGT_CPLAYER, MSGL_V, "\rDVD sub: len=%d " - "v_pts=%5.3f s_pts=%5.3f ts=%d \n", len, - refpts_s, 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 (timestamp >= 0) - spudec_assemble(vo_spudec, packet, len, timestamp); - } - } else if (d_sub && sh_sub && sh_sub->active) { + if (d_sub && sh_sub && sh_sub->active) { bool non_interleaved = is_non_interleaved(mpctx, track); if (non_interleaved) ds_get_next_pts(d_sub); @@ -1979,11 +1896,6 @@ static void update_subtitles(struct MPContext *mpctx, double refpts_tl) ds_get_next_pts(d_sub); } } - if (vo_spudec) { - spudec_heartbeat(vo_spudec, 90000 * curpts_s); - if (spudec_changed(vo_spudec)) - vo_osd_changed(OSDTYPE_SPU); - } if (!mpctx->osd->render_bitmap_subs) set_osd_subtitle(mpctx, sub_get_text(mpctx->osd, curpts_s)); @@ -2030,10 +1942,10 @@ static double timing_sleep(struct MPContext *mpctx, double time_frame) } static void set_dvdsub_fake_extradata(struct sh_sub *sh_sub, struct stream *st, - struct sh_video *sh_video) + int width, int height) { #ifdef CONFIG_DVDREAD - if (st->type != STREAMTYPE_DVD || !sh_video) + if (st->type != STREAMTYPE_DVD) return; struct mp_csp_params csp = MP_CSP_PARAMS_DEFAULTS; @@ -2042,10 +1954,13 @@ static void set_dvdsub_fake_extradata(struct sh_sub *sh_sub, struct stream *st, float cmatrix[3][4]; mp_get_yuv2rgb_coeffs(&csp, cmatrix); - int width = sh_video->disp_w; - int height = sh_video->disp_h; int *palette = ((dvd_priv_t *)st->priv)->cur_pgc->palette; + if (width == 0 || height == 0) { + width = 720; + height = 480; + } + char *s = NULL; s = talloc_asprintf_append(s, "size: %dx%d\n", width, height); s = talloc_asprintf_append(s, "palette: "); @@ -2072,6 +1987,7 @@ static void reinit_subs(struct MPContext *mpctx) { struct MPOpts *opts = &mpctx->opts; struct track *track = mpctx->current_track[STREAM_SUB]; + struct osd_state *osd = mpctx->osd; assert(!(mpctx->initialized_flags & INITIALIZED_SUB)); @@ -2098,24 +2014,17 @@ static void reinit_subs(struct MPContext *mpctx) mpctx->initialized_flags |= INITIALIZED_SUB; + osd->sub_video_w = mpctx->sh_video ? mpctx->sh_video->disp_w : 0; + osd->sub_video_h = mpctx->sh_video ? mpctx->sh_video->disp_h : 0; + if (track->sh_sub) { - sub_init(track->sh_sub, mpctx->osd); + sub_init(track->sh_sub, osd); } else if (track->stream) { - struct stream *s = track->demuxer ? track->demuxer->stream : NULL; - if (s && s->type == STREAMTYPE_DVD) - set_dvdsub_fake_extradata(mpctx->sh_sub, s, mpctx->sh_video); - // lavc dvdsubdec doesn't read color/resolution on Libav 9.1 and below - // Don't use it for new ffmpeg; spudec can't handle ffmpeg .idx demuxing - // (ffmpeg added .idx demuxing during lavc 54.79.100) - bool broken_lavc = false; -#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(54, 40, 0) - broken_lavc = true; -#endif - if (is_dvd_sub(mpctx->sh_sub->gsh->codec) && track->demuxer - && (track->demuxer->type == DEMUXER_TYPE_MPEG_PS || broken_lavc)) - init_vo_spudec(mpctx); - else - sub_init(mpctx->sh_sub, mpctx->osd); + if (track->demuxer && track->demuxer->stream) { + set_dvdsub_fake_extradata(mpctx->sh_sub, track->demuxer->stream, + osd->sub_video_w, osd->sub_video_h); + } + sub_init(mpctx->sh_sub, osd); } // Decides whether to use OSD path or normal subtitle rendering path. -- cgit v1.2.3 From fd02f0f4d88371c728aff3b4487974118ba4d014 Mon Sep 17 00:00:00 2001 From: wm4 Date: Mon, 29 Apr 2013 01:39:50 +0200 Subject: options: add --no-sub-visibility for symmetry Not really useful, but for symmetry with the sub-visibility property (mapped to the 'v' key by default). --- core/cfg-mplayer.h | 1 + core/command.c | 25 +------------------------ 2 files changed, 2 insertions(+), 24 deletions(-) (limited to 'core') diff --git a/core/cfg-mplayer.h b/core/cfg-mplayer.h index 5a2c32e0d0..529972766b 100644 --- a/core/cfg-mplayer.h +++ b/core/cfg-mplayer.h @@ -476,6 +476,7 @@ const m_option_t common_opts[] = { {"sub-delay", &sub_delay, CONF_TYPE_FLOAT, 0, 0.0, 10.0, NULL}, {"subfps", &sub_fps, CONF_TYPE_FLOAT, 0, 0.0, 10.0, NULL}, OPT_FLAG("autosub", sub_auto, 0), + OPT_FLAG("sub-visibility", sub_visibility, 0), OPT_FLAG("sub-forced-only", forced_subs_only, 0), // enable Closed Captioning display {"overlapsub", &suboverlap_enabled, CONF_TYPE_FLAG, 0, 0, 2, NULL}, diff --git a/core/command.c b/core/command.c index 4e82ceccd8..5fa914fdf7 100644 --- a/core/command.c +++ b/core/command.c @@ -1294,28 +1294,6 @@ static int mp_property_sub_pos(m_option_t *prop, int action, void *arg, return property_osd_helper(prop, action, arg, mpctx); } -/// Subtitle visibility (RW) -static int mp_property_sub_visibility(m_option_t *prop, int action, - void *arg, MPContext *mpctx) -{ - struct MPOpts *opts = &mpctx->opts; - - if (!mpctx->sh_video) - return M_PROPERTY_UNAVAILABLE; - - switch (action) { - case M_PROPERTY_SET: - opts->sub_visibility = *(int *)arg; - osd_changed_all(mpctx->osd); - return M_PROPERTY_OK; - case M_PROPERTY_GET: - *(int *)arg = opts->sub_visibility; - return M_PROPERTY_OK; - } - return M_PROPERTY_NOT_IMPLEMENTED; -} - - #ifdef CONFIG_TV static tvi_handle_t *get_tvh(struct MPContext *mpctx) @@ -1493,8 +1471,7 @@ static const m_option_t mp_properties[] = { M_OPTION_PROPERTY_CUSTOM("sid", mp_property_sub), M_OPTION_PROPERTY_CUSTOM("sub-delay", mp_property_sub_delay), M_OPTION_PROPERTY_CUSTOM("sub-pos", mp_property_sub_pos), - { "sub-visibility", mp_property_sub_visibility, CONF_TYPE_FLAG, - M_OPT_RANGE, 0, 1, NULL }, + M_OPTION_PROPERTY_CUSTOM("sub-visibility", property_osd_helper), M_OPTION_PROPERTY_CUSTOM("sub-forced-only", property_osd_helper), M_OPTION_PROPERTY_CUSTOM("sub-scale", property_osd_helper), #ifdef CONFIG_ASS -- cgit v1.2.3 From 28116b8a799078b3c6b3b559ed4463669c79cf0e Mon Sep 17 00:00:00 2001 From: wm4 Date: Mon, 29 Apr 2013 01:49:20 +0200 Subject: sub: remove some global variables --- core/cfg-mplayer.h | 16 ++++++++-------- core/command.c | 12 +++++++----- core/defaultopts.c | 2 ++ core/mplayer.c | 11 ++++++----- core/options.h | 10 +++++++++- 5 files changed, 32 insertions(+), 19 deletions(-) (limited to 'core') diff --git a/core/cfg-mplayer.h b/core/cfg-mplayer.h index 529972766b..c29d4c4060 100644 --- a/core/cfg-mplayer.h +++ b/core/cfg-mplayer.h @@ -472,18 +472,18 @@ const m_option_t common_opts[] = { OPT_STRINGLIST("sub", sub_name, 0), OPT_PATHLIST("sub-paths", sub_paths, 0), - {"subcp", &sub_cp, CONF_TYPE_STRING, 0, 0, 0, NULL}, - {"sub-delay", &sub_delay, CONF_TYPE_FLOAT, 0, 0.0, 10.0, NULL}, - {"subfps", &sub_fps, CONF_TYPE_FLOAT, 0, 0.0, 10.0, NULL}, + OPT_STRING("subcp", sub_cp, 0), + OPT_FLOAT("sub-delay", sub_delay, 0), + OPT_FLOAT("subfps", sub_fps, 0), OPT_FLAG("autosub", sub_auto, 0), OPT_FLAG("sub-visibility", sub_visibility, 0), OPT_FLAG("sub-forced-only", forced_subs_only, 0), // enable Closed Captioning display - {"overlapsub", &suboverlap_enabled, CONF_TYPE_FLAG, 0, 0, 2, NULL}, - {"sub-no-text-pp", &sub_no_text_pp, CONF_TYPE_FLAG, 0, 0, 1, NULL}, - {"autosub-match", &sub_match_fuzziness, CONF_TYPE_CHOICE, 0, - M_CHOICES(({"exact", 0}, {"fuzzy", 1}, {"all", 2}))}, - {"sub-pos", &sub_pos, CONF_TYPE_INT, CONF_RANGE, 0, 100, NULL}, + OPT_FLAG_CONSTANTS("overlapsub", suboverlap_enabled, 0, 0, 2), + OPT_FLAG_STORE("sub-no-text-pp", sub_no_text_pp, 0, 1), + OPT_CHOICE("autosub-match", sub_match_fuzziness, 0, + ({"exact", 0}, {"fuzzy", 1}, {"all", 2})), + OPT_INTRANGE("sub-pos", sub_pos, 0, 0, 100), OPT_FLOATRANGE("sub-gauss", sub_gauss, 0, 0.0, 3.0), OPT_FLAG("sub-gray", sub_gray, 0), OPT_FLAG("ass", ass_enabled, 0), diff --git a/core/command.c b/core/command.c index 5fa914fdf7..7971180553 100644 --- a/core/command.c +++ b/core/command.c @@ -1272,11 +1272,12 @@ static int mp_property_sub(m_option_t *prop, int action, void *arg, static int mp_property_sub_delay(m_option_t *prop, int action, void *arg, MPContext *mpctx) { + struct MPOpts *opts = &mpctx->opts; if (!mpctx->sh_video) return M_PROPERTY_UNAVAILABLE; switch (action) { case M_PROPERTY_PRINT: - *(char **)arg = format_delay(sub_delay); + *(char **)arg = format_delay(opts->sub_delay); return M_PROPERTY_OK; } return mp_property_generic_option(prop, action, arg, mpctx); @@ -1285,10 +1286,11 @@ static int mp_property_sub_delay(m_option_t *prop, int action, void *arg, static int mp_property_sub_pos(m_option_t *prop, int action, void *arg, MPContext *mpctx) { + struct MPOpts *opts = &mpctx->opts; if (!mpctx->sh_video) return M_PROPERTY_UNAVAILABLE; if (action == M_PROPERTY_PRINT) { - *(char **)arg = talloc_asprintf(NULL, "%d/100", sub_pos); + *(char **)arg = talloc_asprintf(NULL, "%d/100", opts->sub_pos); return M_PROPERTY_OK; } return property_osd_helper(prop, action, arg, mpctx); @@ -1954,9 +1956,9 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd) struct ass_track *ass_track = sub_get_ass_track(mpctx->osd); if (ass_track) { set_osd_tmsg(mpctx, OSD_MSG_SUB_DELAY, osdl, osd_duration, - "Sub delay: %d ms", ROUND(sub_delay * 1000)); - sub_delay += ass_step_sub(ass_track, - (mpctx->video_pts + sub_delay) * 1000 + .5, movement) / 1000.; + "Sub delay: %d ms", ROUND(opts->sub_delay * 1000)); + double cur = (mpctx->video_pts + opts->sub_delay) * 1000 + .5; + opts->sub_delay += ass_step_sub(ass_track, cur, movement) / 1000.; } } #endif diff --git a/core/defaultopts.c b/core/defaultopts.c index c4e2a0fa98..93dad1e624 100644 --- a/core/defaultopts.c +++ b/core/defaultopts.c @@ -74,6 +74,7 @@ void set_default_mplayer_options(struct MPOpts *opts) .sub_id = -1, .audio_display = 1, .sub_visibility = 1, + .sub_pos = 100, .extension_parsing = 1, .audio_output_channels = MP_CHMAP_INIT_STEREO, .audio_output_format = -1, // AF_FORMAT_UNKNOWN @@ -89,6 +90,7 @@ void set_default_mplayer_options(struct MPOpts *opts) .ass_vsfilter_aspect_compat = 1, .ass_style_override = 1, .use_embedded_fonts = 1, + .suboverlap_enabled = 1, .hwdec_codecs = "all", diff --git a/core/mplayer.c b/core/mplayer.c index c596aa8504..c832aa1fcb 100644 --- a/core/mplayer.c +++ b/core/mplayer.c @@ -1056,7 +1056,7 @@ struct track *mp_add_subtitles(struct MPContext *mpctx, char *filename, // the weird special-cases. #ifdef CONFIG_ASS if (opts->ass_enabled) { - asst = mp_ass_read_stream(mpctx->ass_library, filename, sub_cp); + asst = mp_ass_read_stream(mpctx->ass_library, filename, opts->sub_cp); codec = "ass"; } if (!asst) { @@ -1389,7 +1389,7 @@ static mp_osd_msg_t *get_osd_msg(struct MPContext *mpctx) if (mpctx->osd_visible && now >= mpctx->osd_visible) { mpctx->osd_visible = 0; mpctx->osd->progbar_type = -1; // disable - vo_osd_changed(OSDTYPE_PROGBAR); + osd_changed(mpctx->osd, OSDTYPE_PROGBAR); } if (mpctx->osd_function_visible && now >= mpctx->osd_function_visible) { mpctx->osd_function_visible = 0; @@ -1448,7 +1448,7 @@ void set_osd_bar(struct MPContext *mpctx, int type, const char *name, mpctx->osd->progbar_type = type; mpctx->osd->progbar_value = (val - min) / (max - min); mpctx->osd->progbar_num_stops = 0; - vo_osd_changed(OSDTYPE_PROGBAR); + osd_changed(mpctx->osd, OSDTYPE_PROGBAR); return; } @@ -1465,7 +1465,7 @@ static void update_osd_bar(struct MPContext *mpctx, int type, float new_value = (val - min) / (max - min); if (new_value != mpctx->osd->progbar_value) { mpctx->osd->progbar_value = new_value; - vo_osd_changed(OSDTYPE_PROGBAR); + osd_changed(mpctx->osd, OSDTYPE_PROGBAR); } } } @@ -1831,6 +1831,7 @@ static void reset_subtitles(struct MPContext *mpctx) static void update_subtitles(struct MPContext *mpctx, double refpts_tl) { + struct MPOpts *opts = &mpctx->opts; struct sh_sub *sh_sub = mpctx->sh_sub; struct demux_stream *d_sub = sh_sub ? sh_sub->ds : NULL; unsigned char *packet = NULL; @@ -1843,7 +1844,7 @@ static void update_subtitles(struct MPContext *mpctx, double refpts_tl) double video_offset = track->under_timeline ? mpctx->video_offset : 0; - mpctx->osd->sub_offset = video_offset - sub_delay; + mpctx->osd->sub_offset = video_offset - opts->sub_delay; double curpts_s = refpts_tl - mpctx->osd->sub_offset; double refpts_s = refpts_tl - video_offset; diff --git a/core/options.h b/core/options.h index d870ab9677..31b4bc9136 100644 --- a/core/options.h +++ b/core/options.h @@ -83,7 +83,6 @@ typedef struct MPOpts { int osd_level; int osd_duration; int osd_fractions; - char *vobsub_name; int untimed; char *stream_capture; char *stream_dump; @@ -140,9 +139,17 @@ typedef struct MPOpts { char **sub_lang; int audio_display; int sub_visibility; + int sub_pos; + float sub_delay; + float sub_fps; int forced_subs_only; char *quvi_format; + // subreader.c + int suboverlap_enabled; + char *sub_cp; + int sub_no_text_pp; + char *audio_stream; int audio_stream_cache; char *sub_stream; @@ -170,6 +177,7 @@ typedef struct MPOpts { char **sub_name; char **sub_paths; int sub_auto; + int sub_match_fuzziness; int osd_bar_visible; float osd_bar_align_x; float osd_bar_align_y; -- cgit v1.2.3 From f7b9b92179333e5bf399cbb6289b66ed3439445c Mon Sep 17 00:00:00 2001 From: wm4 Date: Sat, 1 Jun 2013 19:40:09 +0200 Subject: sub: various minor subtitle related changes Just pushing some code around. --- core/mplayer.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) (limited to 'core') diff --git a/core/mplayer.c b/core/mplayer.c index c832aa1fcb..285f19c8ac 100644 --- a/core/mplayer.c +++ b/core/mplayer.c @@ -1833,10 +1833,6 @@ static void update_subtitles(struct MPContext *mpctx, double refpts_tl) { struct MPOpts *opts = &mpctx->opts; struct sh_sub *sh_sub = mpctx->sh_sub; - struct demux_stream *d_sub = sh_sub ? sh_sub->ds : NULL; - unsigned char *packet = NULL; - int len; - const char *type = sh_sub ? sh_sub->gsh->codec : NULL; struct track *track = mpctx->current_track[STREAM_SUB]; if (!track) @@ -1849,12 +1845,16 @@ static void update_subtitles(struct MPContext *mpctx, double refpts_tl) double curpts_s = refpts_tl - mpctx->osd->sub_offset; double refpts_s = refpts_tl - video_offset; - if (d_sub && sh_sub && sh_sub->active) { + if (sh_sub && sh_sub->active) { + struct demux_stream *d_sub = sh_sub->ds; + const char *type = sh_sub->gsh->codec; bool non_interleaved = is_non_interleaved(mpctx, track); - if (non_interleaved) - ds_get_next_pts(d_sub); - while (d_sub->first) { + while (1) { + if (non_interleaved) + ds_get_next_pts(d_sub); + if (!d_sub->first) + break; double subpts_s = ds_get_next_pts(d_sub); if (subpts_s == MP_NOPTS_VALUE) { // Try old method of getting PTS. This is only needed in the @@ -1882,7 +1882,8 @@ static void update_subtitles(struct MPContext *mpctx, double refpts_tl) break; } double duration = d_sub->first->duration; - len = ds_get_packet_sub(d_sub, &packet); + unsigned char *packet = NULL; + int len = ds_get_packet_sub(d_sub, &packet); mp_dbg(MSGT_CPLAYER, MSGL_V, "Sub: c_pts=%5.3f s_pts=%5.3f " "duration=%5.3f len=%d\n", curpts_s, subpts_s, duration, len); @@ -1893,8 +1894,6 @@ static void update_subtitles(struct MPContext *mpctx, double refpts_tl) packet += 2; } sub_decode(sh_sub, mpctx->osd, packet, len, subpts_s, duration); - if (non_interleaved) - ds_get_next_pts(d_sub); } } -- cgit v1.2.3 From 27d383918a3d63559c85ca96b2162a13234f2abc Mon Sep 17 00:00:00 2001 From: wm4 Date: Sat, 1 Jun 2013 19:43:11 +0200 Subject: core: add demux_sub pseudo demuxer Subtitle files are opened in mplayer.c, not using the demuxer infrastructure in general. Pretend that this is not the case (outside of the loading code) by opening a pseudo demuxer that does nothing. One advantage is that the initialization code is now the same, and there's no confusion about what the difference between track->stream, track->sh_sub and mpctx->sh_sub is supposed to be. This is a bit stupid, and it would be much better if there were proper subtitle demuxers (there are many in recent FFmpeg, but not Libav). So for now this is just a transition to a more proper architecture. Look at demux_sub like an artifical limb: it's ugly, but don't hate it - it helps you to get on with your life. --- core/mp_core.h | 9 +++---- core/mplayer.c | 75 ++++++++++++++++++++++++++++++---------------------------- 2 files changed, 42 insertions(+), 42 deletions(-) (limited to 'core') diff --git a/core/mp_core.h b/core/mp_core.h index db6bc570e1..d7aa42e38d 100644 --- a/core/mp_core.h +++ b/core/mp_core.h @@ -103,12 +103,9 @@ struct track { // Invariant: (!demuxer && !stream) || stream->demuxer == demuxer struct sh_stream *stream; - // NOTE: demuxer subtitles, i.e. if stream!=NULL, do not use the following - // fields. The data is stored in stream->sub this case. - - // External text subtitle using libass subtitle renderer. - // The sh_sub is a dummy and doesn't belong to a demuxer. - struct sh_sub *sh_sub; + // For external subtitles, which are read fully on init. Do not attempt + // to read packets from them. + bool preloaded; }; enum { diff --git a/core/mplayer.c b/core/mplayer.c index 285f19c8ac..a19788df0b 100644 --- a/core/mplayer.c +++ b/core/mplayer.c @@ -281,8 +281,6 @@ static void print_stream(struct MPContext *mpctx, struct track *t) if (t->title) mp_msg(MSGT_CPLAYER, MSGL_INFO, " '%s'", t->title); const char *codec = s ? s->codec : NULL; - if (!codec && t->sh_sub) // external subs hack - codec = t->sh_sub->gsh->codec; mp_msg(MSGT_CPLAYER, MSGL_INFO, " (%s)", codec ? codec : ""); if (t->is_external) mp_msg(MSGT_CPLAYER, MSGL_INFO, " (external)"); @@ -482,13 +480,8 @@ void uninit_player(struct MPContext *mpctx, unsigned int mask) if (mask & INITIALIZED_SUB) { mpctx->initialized_flags &= ~INITIALIZED_SUB; - struct track *track = mpctx->current_track[STREAM_SUB]; - // One of these was active; they can't be both active. - assert(!(mpctx->sh_sub && track && track->sh_sub)); if (mpctx->sh_sub) sub_switchoff(mpctx->sh_sub, mpctx->osd); - if (track && track->sh_sub) - sub_switchoff(track->sh_sub, mpctx->osd); cleanup_demux_stream(mpctx, STREAM_SUB); reset_subtitles(mpctx); } @@ -1039,11 +1032,19 @@ static void add_dvd_tracks(struct MPContext *mpctx) #endif } +#ifdef CONFIG_ASS +static int free_ass_track(void *ptr) +{ + struct ass_track *track = *(struct ass_track **)ptr; + ass_free_track(track); + return 1; +} +#endif + struct track *mp_add_subtitles(struct MPContext *mpctx, char *filename, float fps, int noerr) { struct MPOpts *opts = &mpctx->opts; - struct sh_sub *sh = NULL; struct ass_track *asst = NULL; const char *codec = NULL; @@ -1067,33 +1068,37 @@ struct track *mp_add_subtitles(struct MPContext *mpctx, char *filename, } talloc_free(subd); } - if (asst) - sh = sd_ass_create_from_track(asst, codec, opts); -#endif + if (asst) { + struct demuxer *d = new_sub_pseudo_demuxer(opts); + assert(d->num_streams == 1); + struct sh_stream *s = d->streams[0]; + assert(s->type == STREAM_SUB); - if (!sh) { - // Used with image subtitles. - struct track *ext = open_external_file(mpctx, filename, NULL, 0, - STREAM_SUB); - if (ext) - return ext; - mp_tmsg(MSGT_CPLAYER, noerr ? MSGL_WARN : MSGL_ERR, - "Cannot load subtitles: %s\n", filename); - return NULL; + s->sub->track = asst; + s->codec = codec; + + struct ass_track **pptr = talloc(s, struct ass_track*); + *pptr = asst; + talloc_set_destructor(pptr, free_ass_track); + + struct track *t = add_stream_track(mpctx, s, false); + t->is_external = true; + t->preloaded = true; + t->title = talloc_strdup(t, filename); + t->external_filename = talloc_strdup(t, filename); + MP_TARRAY_APPEND(NULL, mpctx->sources, mpctx->num_sources, d); + return t; } +#endif - struct track *track = talloc_ptrtype(NULL, track); - *track = (struct track) { - .type = STREAM_SUB, - .title = talloc_strdup(track, filename), - .user_tid = find_new_tid(mpctx, STREAM_SUB), - .demuxer_id = -1, - .is_external = true, - .sh_sub = talloc_steal(track, sh), - .external_filename = talloc_strdup(track, filename), - }; - MP_TARRAY_APPEND(mpctx, mpctx->tracks, mpctx->num_tracks, track); - return track; + // Used with libavformat subtitles. + struct track *ext = open_external_file(mpctx, filename, NULL, 0, STREAM_SUB); + if (ext) + return ext; + + mp_tmsg(MSGT_CPLAYER, noerr ? MSGL_WARN : MSGL_ERR, + "Cannot load subtitles: %s\n", filename); + return NULL; } int mp_get_cache_percent(struct MPContext *mpctx) @@ -1845,7 +1850,7 @@ static void update_subtitles(struct MPContext *mpctx, double refpts_tl) double curpts_s = refpts_tl - mpctx->osd->sub_offset; double refpts_s = refpts_tl - video_offset; - if (sh_sub && sh_sub->active) { + if (sh_sub && sh_sub->active && !track->preloaded) { struct demux_stream *d_sub = sh_sub->ds; const char *type = sh_sub->gsh->codec; bool non_interleaved = is_non_interleaved(mpctx, track); @@ -2017,9 +2022,7 @@ static void reinit_subs(struct MPContext *mpctx) osd->sub_video_w = mpctx->sh_video ? mpctx->sh_video->disp_w : 0; osd->sub_video_h = mpctx->sh_video ? mpctx->sh_video->disp_h : 0; - if (track->sh_sub) { - sub_init(track->sh_sub, osd); - } else if (track->stream) { + if (track->stream) { if (track->demuxer && track->demuxer->stream) { set_dvdsub_fake_extradata(mpctx->sh_sub, track->demuxer->stream, osd->sub_video_w, osd->sub_video_h); -- cgit v1.2.3 From 02ce316ade9ba932ad405383278d6b01c54e5fc4 Mon Sep 17 00:00:00 2001 From: wm4 Date: Sat, 1 Jun 2013 19:44:12 +0200 Subject: sub: refactor Make the sub decoder stuff independent from sh_sub (except for initialization of course). Sub decoders now access a struct sd only, instead of getting access to sh_sub. The glue code in dec_sub.c is similarily independent from osd. Some simplifications are made. For example, the switch_id stuff is unneeded: the frontend code just has to make sure to call osd_changed() any time subtitles are switched. This is also preparation for introducing subtitle converters. It's much cleaner to completely separate demuxer header/renderer glue/decoders for this purpose, especially since sub converters might completely change how demuxer headers have to be interpreted. Also pass data as demux_packets. Currently, this doesn't help much, but libavcodec converters might need scary stuff like packet side data, so it's perhaps better to go with passing packets. --- core/command.c | 4 +-- core/mplayer.c | 80 +++++++++++++++++++++++++++++++++++----------------------- 2 files changed, 51 insertions(+), 33 deletions(-) (limited to 'core') diff --git a/core/command.c b/core/command.c index 7971180553..416fbcd06a 100644 --- a/core/command.c +++ b/core/command.c @@ -1951,9 +1951,9 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd) case MP_CMD_SUB_STEP: #ifdef CONFIG_ASS - if (sh_video) { + if (mpctx->osd->dec_sub) { int movement = cmd->args[0].v.i; - struct ass_track *ass_track = sub_get_ass_track(mpctx->osd); + struct ass_track *ass_track = sub_get_ass_track(mpctx->osd->dec_sub); if (ass_track) { set_osd_tmsg(mpctx, OSD_MSG_SUB_DELAY, osdl, osd_duration, "Sub delay: %d ms", ROUND(opts->sub_delay * 1000)); diff --git a/core/mplayer.c b/core/mplayer.c index a19788df0b..92c0f717af 100644 --- a/core/mplayer.c +++ b/core/mplayer.c @@ -457,8 +457,10 @@ 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); + if (sh) { + sub_destroy(sh->dec_sub); + sh->dec_sub = NULL; + } } } @@ -481,8 +483,9 @@ void uninit_player(struct MPContext *mpctx, unsigned int mask) if (mask & INITIALIZED_SUB) { mpctx->initialized_flags &= ~INITIALIZED_SUB; if (mpctx->sh_sub) - sub_switchoff(mpctx->sh_sub, mpctx->osd); + sub_reset(mpctx->sh_sub->dec_sub); cleanup_demux_stream(mpctx, STREAM_SUB); + mpctx->osd->dec_sub = NULL; reset_subtitles(mpctx); } @@ -1077,7 +1080,7 @@ struct track *mp_add_subtitles(struct MPContext *mpctx, char *filename, s->sub->track = asst; s->codec = codec; - struct ass_track **pptr = talloc(s, struct ass_track*); + struct ass_track **pptr = talloc(d, struct ass_track*); *pptr = asst; talloc_set_destructor(pptr, free_ass_track); @@ -1830,18 +1833,21 @@ static bool is_non_interleaved(struct MPContext *mpctx, struct track *track) static void reset_subtitles(struct MPContext *mpctx) { if (mpctx->sh_sub) - sub_reset(mpctx->sh_sub, mpctx->osd); + sub_reset(mpctx->sh_sub->dec_sub); set_osd_subtitle(mpctx, NULL); + osd_changed(mpctx->osd, OSDTYPE_SUB); } static void update_subtitles(struct MPContext *mpctx, double refpts_tl) { struct MPOpts *opts = &mpctx->opts; - struct sh_sub *sh_sub = mpctx->sh_sub; + if (!(mpctx->initialized_flags & INITIALIZED_SUB)) + return; struct track *track = mpctx->current_track[STREAM_SUB]; - if (!track) - return; + struct sh_sub *sh_sub = mpctx->sh_sub; + assert(track && sh_sub); + struct dec_sub *dec_sub = sh_sub->dec_sub; double video_offset = track->under_timeline ? mpctx->video_offset : 0; @@ -1850,7 +1856,7 @@ static void update_subtitles(struct MPContext *mpctx, double refpts_tl) double curpts_s = refpts_tl - mpctx->osd->sub_offset; double refpts_s = refpts_tl - video_offset; - if (sh_sub && sh_sub->active && !track->preloaded) { + if (!track->preloaded) { struct demux_stream *d_sub = sh_sub->ds; const char *type = sh_sub->gsh->codec; bool non_interleaved = is_non_interleaved(mpctx, track); @@ -1880,7 +1886,7 @@ static void update_subtitles(struct MPContext *mpctx, double refpts_tl) "Sub early: c_pts=%5.3f s_pts=%5.3f\n", curpts_s, subpts_s); // Libass handled subs can be fed to it in advance - if (!sub_accept_packets_in_advance(sh_sub)) + if (!sub_accept_packets_in_advance(dec_sub)) break; // Try to avoid demuxing whole file at once if (non_interleaved && subpts_s > curpts_s + 1) @@ -1898,12 +1904,18 @@ static void update_subtitles(struct MPContext *mpctx, double refpts_tl) len = FFMIN(len - 2, AV_RB16(packet)); packet += 2; } - sub_decode(sh_sub, mpctx->osd, packet, len, subpts_s, duration); + struct demux_packet pkt = { + .buffer = packet, + .len = len, + .pts = subpts_s, + .duration = duration, + }; + sub_decode(dec_sub, &pkt); } } if (!mpctx->osd->render_bitmap_subs) - set_osd_subtitle(mpctx, sub_get_text(mpctx->osd, curpts_s)); + set_osd_subtitle(mpctx, sub_get_text(dec_sub, curpts_s)); } static int check_framedrop(struct MPContext *mpctx, double frame_time) @@ -1946,7 +1958,7 @@ static double timing_sleep(struct MPContext *mpctx, double time_frame) return time_frame; } -static void set_dvdsub_fake_extradata(struct sh_sub *sh_sub, struct stream *st, +static void set_dvdsub_fake_extradata(struct dec_sub *dec_sub, struct stream *st, int width, int height) { #ifdef CONFIG_DVDREAD @@ -1981,9 +1993,7 @@ static void set_dvdsub_fake_extradata(struct sh_sub *sh_sub, struct stream *st, } s = talloc_asprintf_append(s, "\n"); - free(sh_sub->extradata); - sh_sub->extradata = strdup(s); - sh_sub->extradata_len = strlen(s); + sub_set_extradata(dec_sub, s, strlen(s)); talloc_free(s); #endif } @@ -1992,15 +2002,16 @@ static void reinit_subs(struct MPContext *mpctx) { struct MPOpts *opts = &mpctx->opts; struct track *track = mpctx->current_track[STREAM_SUB]; - struct osd_state *osd = mpctx->osd; assert(!(mpctx->initialized_flags & INITIALIZED_SUB)); init_demux_stream(mpctx, STREAM_SUB); - - if (!track) + if (!mpctx->sh_sub) return; + if (!mpctx->sh_sub->dec_sub) + mpctx->sh_sub->dec_sub = sub_create(opts); + if (track->demuxer && !track->stream) { // Lazily added DVD track - we must not miss the first subtitle packet, // which makes the demuxer create the sh_stream, and contains the first @@ -2016,25 +2027,32 @@ static void reinit_subs(struct MPContext *mpctx) return; } + assert(track->demuxer && track->stream); mpctx->initialized_flags |= INITIALIZED_SUB; - osd->sub_video_w = mpctx->sh_video ? mpctx->sh_video->disp_w : 0; - osd->sub_video_h = mpctx->sh_video ? mpctx->sh_video->disp_h : 0; + struct sh_sub *sh_sub = mpctx->sh_sub; + struct dec_sub *dec_sub = sh_sub->dec_sub; + assert(dec_sub); + + if (!sub_is_initialized(dec_sub)) { + int w = mpctx->sh_video ? mpctx->sh_video->disp_w : 0; + int h = mpctx->sh_video ? mpctx->sh_video->disp_h : 0; - if (track->stream) { - if (track->demuxer && track->demuxer->stream) { - set_dvdsub_fake_extradata(mpctx->sh_sub, track->demuxer->stream, - osd->sub_video_w, osd->sub_video_h); - } - sub_init(mpctx->sh_sub, osd); + set_dvdsub_fake_extradata(dec_sub, track->demuxer->stream, w, h); + sub_set_video_res(dec_sub, w, h); + sub_set_ass_renderer(dec_sub, mpctx->osd->ass_library, + mpctx->osd->ass_renderer); + sub_init_from_sh(dec_sub, sh_sub); } + mpctx->osd->dec_sub = dec_sub; + // Decides whether to use OSD path or normal subtitle rendering path. - mpctx->osd->render_bitmap_subs = true; - struct sh_sub *sh_sub = mpctx->osd->sh_sub; - if (sh_sub && sh_sub->active && sh_sub->sd_driver->get_text) - mpctx->osd->render_bitmap_subs = opts->ass_enabled; + mpctx->osd->render_bitmap_subs = + opts->ass_enabled || !sub_has_get_text(dec_sub); + + reset_subtitles(mpctx); } static char *track_layout_hash(struct MPContext *mpctx) -- cgit v1.2.3 From 3000df35d31f09f13a7c662e2f96bcd7d0f6ac13 Mon Sep 17 00:00:00 2001 From: wm4 Date: Sat, 1 Jun 2013 19:44:55 +0200 Subject: sub: basic subtitle converters Add a basic infrastructure for subtitle converters. These converters work sort-of like decoders, except that they produce packets instead of subtitle bitmaps. They are put in front of actual decoders. Start with sd_movtext. 4 lines of code are blown up to a 55 lines file, but fortunately this is not going to be that bad for the following converters. --- core/mplayer.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'core') diff --git a/core/mplayer.c b/core/mplayer.c index 92c0f717af..1fae2eece8 100644 --- a/core/mplayer.c +++ b/core/mplayer.c @@ -1858,7 +1858,6 @@ static void update_subtitles(struct MPContext *mpctx, double refpts_tl) if (!track->preloaded) { struct demux_stream *d_sub = sh_sub->ds; - const char *type = sh_sub->gsh->codec; bool non_interleaved = is_non_interleaved(mpctx, track); while (1) { @@ -1898,12 +1897,6 @@ static void update_subtitles(struct MPContext *mpctx, double refpts_tl) mp_dbg(MSGT_CPLAYER, MSGL_V, "Sub: c_pts=%5.3f s_pts=%5.3f " "duration=%5.3f len=%d\n", curpts_s, subpts_s, duration, len); - if (type && strcmp(type, "mov_text") == 0) { - if (len < 2) - continue; - len = FFMIN(len - 2, AV_RB16(packet)); - packet += 2; - } struct demux_packet pkt = { .buffer = packet, .len = len, -- cgit v1.2.3 From e19ffa02aa370cbc3b559f85b286ea09b06ab29b Mon Sep 17 00:00:00 2001 From: wm4 Date: Sat, 1 Jun 2013 19:54:18 +0200 Subject: sub: turn subassconvert_ functions into sub converters This means subassconvert.c is split in sd_srt.c and sd_microdvd.c. Now this code is involved in the sub conversion chain like sd_movtext is. The invocation of the converter in sd_ass.c is removed. This requires some other changes to make the new sub converter code work with loading external subtitles. Until now, subtitles loaded via subreader.c was assumed to be in plaintext, or for some formats, in ASS (except in -no-ass mode). Then these were added to an ASS_Track. Change this so that subtitles are always in their original format (as far as decoders/converters for them are available), and turn every sub event read by subreader.c as packet to the dec_sub.c subtitle chain. This removes differences between external/demuxed and -ass/-no-ass code paths further. --- core/mplayer.c | 35 +++++++++++++++-------------------- 1 file changed, 15 insertions(+), 20 deletions(-) (limited to 'core') diff --git a/core/mplayer.c b/core/mplayer.c index 1fae2eece8..de23e97a49 100644 --- a/core/mplayer.c +++ b/core/mplayer.c @@ -1036,10 +1036,12 @@ static void add_dvd_tracks(struct MPContext *mpctx) } #ifdef CONFIG_ASS -static int free_ass_track(void *ptr) +static int free_sub_data(void *ptr) { - struct ass_track *track = *(struct ass_track **)ptr; - ass_free_track(track); + struct sh_sub *sh_sub = *(struct sh_sub **)ptr; + if (sh_sub->track) + ass_free_track(sh_sub->track); + talloc_free(sh_sub->sub_data); return 1; } #endif @@ -1049,7 +1051,7 @@ struct track *mp_add_subtitles(struct MPContext *mpctx, char *filename, { struct MPOpts *opts = &mpctx->opts; struct ass_track *asst = NULL; - const char *codec = NULL; + sub_data *subd = NULL; if (filename == NULL) return NULL; @@ -1059,30 +1061,23 @@ struct track *mp_add_subtitles(struct MPContext *mpctx, char *filename, // through sd_ass makes the code much simpler, as sd_ass can handle all // the weird special-cases. #ifdef CONFIG_ASS - if (opts->ass_enabled) { + if (opts->ass_enabled) asst = mp_ass_read_stream(mpctx->ass_library, filename, opts->sub_cp); - codec = "ass"; - } - if (!asst) { - sub_data *subd = sub_read_file(filename, fps, &mpctx->opts); - if (subd) { - codec = subd->codec; - asst = mp_ass_read_subdata(mpctx->ass_library, opts, subd, fps); - } - talloc_free(subd); - } - if (asst) { + if (!asst) + subd = sub_read_file(filename, fps, &mpctx->opts); + if (asst || subd) { struct demuxer *d = new_sub_pseudo_demuxer(opts); assert(d->num_streams == 1); struct sh_stream *s = d->streams[0]; assert(s->type == STREAM_SUB); + s->codec = asst ? "ass" : subd->codec; s->sub->track = asst; - s->codec = codec; + s->sub->sub_data = subd; - struct ass_track **pptr = talloc(d, struct ass_track*); - *pptr = asst; - talloc_set_destructor(pptr, free_ass_track); + struct sh_sub **pptr = talloc(d, struct sh_sub*); + *pptr = s->sub; + talloc_set_destructor(pptr, free_sub_data); struct track *t = add_stream_track(mpctx, s, false); t->is_external = true; -- cgit v1.2.3 From d5520d20b26e7363882e9f1ebce7a5524a12321b Mon Sep 17 00:00:00 2001 From: wm4 Date: Sun, 2 Jun 2013 19:57:37 +0200 Subject: sub: use libass even if -no-ass is used The -no-ass option used to disable all use of libass completely. This doesn't work this way anymore, and the text subtitle path has an inherent dependency on libass. Currently -no-ass does 3 things: 1. Strip tags and formatting on display, and use a separate renderer for the result. (Which might be the terminal, or libass via O