diff options
Diffstat (limited to 'core')
-rw-r--r-- | core/av_common.c | 20 | ||||
-rw-r--r-- | core/av_common.h | 2 | ||||
-rw-r--r-- | core/cfg-mplayer.h | 17 | ||||
-rw-r--r-- | core/command.c | 80 | ||||
-rw-r--r-- | core/defaultopts.c | 2 | ||||
-rw-r--r-- | core/mp_core.h | 17 | ||||
-rw-r--r-- | core/mplayer.c | 415 | ||||
-rw-r--r-- | core/mplayer.h | 3 | ||||
-rw-r--r-- | core/options.h | 10 |
9 files changed, 209 insertions, 357 deletions
diff --git a/core/av_common.c b/core/av_common.c index 5e6c8a4352..a4dc525aa9 100644 --- a/core/av_common.c +++ b/core/av_common.c @@ -18,8 +18,10 @@ #include <assert.h> #include <libavutil/common.h> +#include <libavcodec/avcodec.h> #include "core/mp_talloc.h" +#include "demux/demux_packet.h" #include "av_common.h" #include "codecs.h" @@ -58,6 +60,24 @@ void mp_copy_lav_codec_headers(AVCodecContext *avctx, AVCodecContext *st) avctx->bits_per_coded_sample = st->bits_per_coded_sample; } +// Set dst from mpkt. Note that dst is not refcountable. +// mpkt can be NULL to generate empty packets (used to flush delayed data). +// Does not set pts or duration fields. +void mp_set_av_packet(AVPacket *dst, struct demux_packet *mpkt) +{ + av_init_packet(dst); + dst->data = mpkt ? mpkt->buffer : NULL; + dst->size = mpkt ? mpkt->len : 0; + /* Some codecs (ZeroCodec, some cases of PNG) may want keyframe info + * from demuxer. */ + if (mpkt && mpkt->keyframe) + dst->flags |= AV_PKT_FLAG_KEY; + if (mpkt && mpkt->avpacket) { + dst->side_data = mpkt->avpacket->side_data; + dst->side_data_elems = mpkt->avpacket->side_data_elems; + } +} + void mp_add_lavc_decoders(struct mp_decoder_list *list, enum AVMediaType type) { AVCodec *cur = NULL; diff --git a/core/av_common.h b/core/av_common.h index 25593ed3d0..2fa8f127b0 100644 --- a/core/av_common.h +++ b/core/av_common.h @@ -22,8 +22,10 @@ #include <libavcodec/avcodec.h> struct mp_decoder_list; +struct demux_packet; void mp_copy_lav_codec_headers(AVCodecContext *avctx, AVCodecContext *st); +void mp_set_av_packet(AVPacket *dst, struct demux_packet *mpkt); void mp_add_lavc_decoders(struct mp_decoder_list *list, enum AVMediaType type); int mp_codec_to_av_codec_id(const char *codec); const char *mp_codec_from_av_codec_id(int codec_id); diff --git a/core/cfg-mplayer.h b/core/cfg-mplayer.h index 5a2c32e0d0..c29d4c4060 100644 --- a/core/cfg-mplayer.h +++ b/core/cfg-mplayer.h @@ -472,17 +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 3ee8f39c3d..416fbcd06a 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" @@ -1273,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); @@ -1286,56 +1286,16 @@ 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); } -/// 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; - vo_osd_changed(OSDTYPE_SUBTITLE); - if (vo_spudec) - vo_osd_changed(OSDTYPE_SPU); - return M_PROPERTY_OK; - case M_PROPERTY_GET: - *(int *)arg = opts->sub_visibility; - return M_PROPERTY_OK; - } - 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 static tvi_handle_t *get_tvh(struct MPContext *mpctx) @@ -1513,9 +1473,8 @@ 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-forced-only", mp_property_sub_forced_only), + 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 M_OPTION_PROPERTY_CUSTOM("ass-use-margins", property_osd_helper), @@ -1991,26 +1950,18 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd) } case MP_CMD_SUB_STEP: - 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 (mpctx->osd->dec_sub) { + int movement = cmd->args[0].v.i; + struct ass_track *ass_track = sub_get_ass_track(mpctx->osd->dec_sub); if (ass_track) { - available = true; - 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)); + "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 break; case MP_CMD_OSD: { @@ -2194,7 +2145,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 +2182,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 +2214,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/defaultopts.c b/core/defaultopts.c index 5f6521ebfb..a8a6b26930 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/mp_core.h b/core/mp_core.h index 9e61c8ffa3..d7aa42e38d 100644 --- a/core/mp_core.h +++ b/core/mp_core.h @@ -22,8 +22,6 @@ #include <stdbool.h> #include "core/options.h" -#include "sub/subreader.h" -#include "sub/find_subfiles.h" #include "audio/mixer.h" #include "demux/demux.h" @@ -33,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 @@ -106,15 +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; - - // External text subtitle using non-libass subtitle renderer. - struct sub_data *subdata; + // For external subtitles, which are read fully on init. Do not attempt + // to read packets from them. + bool preloaded; }; enum { @@ -129,7 +120,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 @@ -299,7 +289,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 b5123a3d41..baae55b581 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" @@ -94,8 +95,6 @@ #include "core/codecs.h" -#include "sub/spudec.h" - #include "osdep/getch2.h" #include "osdep/timer.h" @@ -282,10 +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; - if (!codec && t->subdata) - codec = t->subdata->codec; mp_msg(MSGT_CPLAYER, MSGL_INFO, " (%s)", codec ? codec : "<unknown>"); if (t->is_external) mp_msg(MSGT_CPLAYER, MSGL_INFO, " (external)"); @@ -462,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; + } } } @@ -485,14 +482,10 @@ 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); + sub_reset(mpctx->sh_sub->dec_sub); cleanup_demux_stream(mpctx, STREAM_SUB); + mpctx->osd->dec_sub = NULL; reset_subtitles(mpctx); } @@ -555,12 +548,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) { @@ -1048,96 +1035,67 @@ static void add_dvd_tracks(struct MPContext *mpctx) #endif } +#ifdef CONFIG_ASS +static int free_sub_data(void *ptr) +{ + 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 + struct track *mp_add_subtitles(struct MPContext *mpctx, char *filename, float fps, int noerr) { struct MPOpts *opts = &mpctx->opts; + struct ass_track *asst = NULL; sub_data *subd = NULL; - struct sh_sub *sh = 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; - } -#endif - } else + asst = mp_ass_read_stream(mpctx->ass_library, filename, opts->sub_cp); + if (!asst) subd = sub_read_file(filename, fps, &mpctx->opts); - - - if (!sh && !subd) { - struct track *ext = open_external_file(mpctx, filename, NULL, 0, - STREAM_SUB); - if (ext) - return ext; - mp_tmsg(MSGT_CPLAYER, noerr ? MSGL_WARN : MSGL_ERR, - "Cannot load subtitles: %s\n", filename); - return NULL; - } - - 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), - .subdata = talloc_steal(track, subd), - .external_filename = talloc_strdup(track, filename), - }; - MP_TARRAY_APPEND(mpctx, mpctx->tracks, mpctx->num_tracks, track); - 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); + 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->sub->sub_data = subd; + + 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; + 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 - 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); - } + // Used with libavformat subtitles. + struct track *ext = open_external_file(mpctx, filename, NULL, 0, STREAM_SUB); + if (ext) + return ext; - if (vo_spudec != NULL) { - mpctx->initialized_flags |= INITIALIZED_SPUDEC; - mp_property_do("sub-forced-only", M_PROPERTY_SET, - &mpctx->opts.forced_subs_only, mpctx); - } + 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) @@ -1433,7 +1391,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; @@ -1492,7 +1450,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; } @@ -1509,7 +1467,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); } } } @@ -1545,25 +1503,20 @@ 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); } } + if (!text[0]) + rm_osd_msg(mpctx, OSD_MSG_SUB_BASE); } // sym == mpctx->osd_function @@ -1876,149 +1829,79 @@ 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_clear_text(&mpctx->subs, MP_NOPTS_VALUE); - if (vo_sub) - set_osd_subtitle(mpctx, NULL); - if (vo_spudec) { - spudec_reset(vo_spudec); - vo_osd_changed(OSDTYPE_SPU); - } + 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_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; + 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; - 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 - opts->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)) { - 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 && (is_text_sub(type) || (sh_sub && sh_sub->active))) { + if (!track->preloaded) { + struct demux_stream *d_sub = sh_sub->ds; 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 + // 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", 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(dec_sub)) break; // Try to avoid demuxing whole file at once if (non_interleaved && subpts_s > curpts_s + 1) break; } - double duration = d_sub->first->duration; - len = ds_get_packet_sub(d_sub, &packet); + struct demux_packet pkt; + struct demux_packet *orig = ds_get_packet_sub(d_sub); + if (!orig) + break; + pkt = *orig; + pkt.pts = subpts_s; 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; - } - 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); - } - if (non_interleaved) - ds_get_next_pts(d_sub); + "duration=%5.3f len=%d\n", curpts_s, pkt.pts, pkt.duration, + pkt.len); + sub_decode(dec_sub, &pkt); } - 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 || !mpctx->sh_video) + set_osd_subtitle(mpctx, sub_get_text(dec_sub, curpts_s)); } static int check_framedrop(struct MPContext *mpctx, double frame_time) @@ -2061,11 +1944,11 @@ 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, - struct sh_video *sh_video) +static void set_dvdsub_fake_extradata(struct dec_sub *dec_sub, struct stream *st, + 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; @@ -2074,10 +1957,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: "); @@ -2093,9 +1979,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 } @@ -2108,10 +1992,12 @@ static void reinit_subs(struct MPContext *mpctx) 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 @@ -2127,32 +2013,32 @@ static void reinit_subs(struct MPContext *mpctx) return; } + assert(track->demuxer && track->stream); 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); - } 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 |