summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2013-06-04 00:29:29 +0200
committerwm4 <wm4@nowhere>2013-06-04 00:29:44 +0200
commit92ae48db0f91fbfcfbb1722fa81c922808f62d5a (patch)
treee32fe21b5f8c11ada7788768a76e2d9f7d061c66 /core
parentdaf8ed831b4ae63cf0931cc3d6727956137f865f (diff)
parentc1ac97b99b3e80bbf84ed540178dd6689ead0b87 (diff)
downloadmpv-92ae48db0f91fbfcfbb1722fa81c922808f62d5a.tar.bz2
mpv-92ae48db0f91fbfcfbb1722fa81c922808f62d5a.tar.xz
Merge branch 'sub_mess'
This branch heavily refactors the subtitle code (both loading and rendering), and adds support for a few new formats through FFmpeg. We don't remove any of the old code yet. There are still some subtleties related to subreader.c to be resolved: code page detection & conversion, timing post-processing, UTF-16 subtitle support, support for the -subfps option. Also, SRT reading and loading ASS via libass should be turned into proper demuxers. (SRT is needed because Libav's is gravely broken, and we want ASS loading via libass to cover full libass format support. Both should be demuxers which are probed _before_ libavformat, so that all subtitles can be loaded through the demuxer infrastructure, and libavformat subtitles don't need to be treated in a special way.)
Diffstat (limited to 'core')
-rw-r--r--core/av_common.c20
-rw-r--r--core/av_common.h2
-rw-r--r--core/cfg-mplayer.h17
-rw-r--r--core/command.c80
-rw-r--r--core/defaultopts.c2
-rw-r--r--core/mp_core.h17
-rw-r--r--core/mplayer.c415
-rw-r--r--core/mplayer.h3
-rw-r--r--core/options.h10
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 re