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. --- Makefile | 1 + core/mp_core.h | 9 +++---- core/mplayer.c | 75 +++++++++++++++++++++++++++++-------------------------- demux/demux.c | 19 ++++++++++++-- demux/demux.h | 7 +++--- demux/demux_sub.c | 38 ++++++++++++++++++++++++++++ demux/stheader.h | 1 + sub/dec_sub.h | 3 --- sub/sd_ass.c | 32 ++++-------------------- 9 files changed, 108 insertions(+), 77 deletions(-) create mode 100644 demux/demux_sub.c diff --git a/Makefile b/Makefile index e91564703e..6e52253543 100644 --- a/Makefile +++ b/Makefile @@ -205,6 +205,7 @@ SOURCES = talloc.c \ demux/demux_mf.c \ demux/demux_mkv.c \ demux/demux_mpg.c \ + demux/demux_sub.c \ demux/demux_ts.c \ demux/mp3_hdr.c \ demux/parse_es.c \ 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); diff --git a/demux/demux.c b/demux/demux.c index 3e27b43f93..12e0d9083a 100644 --- a/demux/demux.c +++ b/demux/demux.c @@ -66,6 +66,7 @@ extern const demuxer_desc_t demuxer_desc_mpeg_es; extern const demuxer_desc_t demuxer_desc_mpeg4_es; extern const demuxer_desc_t demuxer_desc_h264_es; extern const demuxer_desc_t demuxer_desc_mpeg_ts; +extern const demuxer_desc_t demuxer_desc_sub; /* Please do not add any new demuxers here. If you want to implement a new * demuxer, add it to libavformat, except for wrappers around external @@ -95,6 +96,8 @@ const demuxer_desc_t *const demuxer_list[] = { &demuxer_desc_mpeg_ts, // auto-probe last, because it checks file-extensions only &demuxer_desc_mf, + // no auto-probe + &demuxer_desc_sub, /* Please do not add any new demuxers here. If you want to implement a new * demuxer, add it to libavformat, except for wrappers around external * libraries and demuxers requiring binary support. */ @@ -217,8 +220,8 @@ static const demuxer_desc_t *get_demuxer_desc_from_type(int file_format) } -demuxer_t *new_demuxer(struct MPOpts *opts, stream_t *stream, int type, - int a_id, int v_id, int s_id, char *filename) +static demuxer_t *new_demuxer(struct MPOpts *opts, stream_t *stream, int type, + int a_id, int v_id, int s_id, char *filename) { struct demuxer *d = talloc_zero(NULL, struct demuxer); d->stream = stream; @@ -248,6 +251,18 @@ demuxer_t *new_demuxer(struct MPOpts *opts, stream_t *stream, int type, return d; } +// for demux_sub.c +demuxer_t *new_sub_pseudo_demuxer(struct MPOpts *opts) +{ + struct stream *s = open_stream("null://", NULL, NULL); + assert(s); + struct demuxer *d = new_demuxer(opts, s, DEMUXER_TYPE_SUB, + -1, -1, -1, NULL); + new_sh_stream(d, STREAM_SUB); + talloc_steal(d, s); + return d; +} + static struct sh_stream *new_sh_stream_id(demuxer_t *demuxer, enum stream_type type, int stream_index, diff --git a/demux/demux.h b/demux/demux.h index 886252fa85..e58c56141f 100644 --- a/demux/demux.h +++ b/demux/demux.h @@ -77,6 +77,7 @@ enum demuxer_type { DEMUXER_TYPE_END, DEMUXER_TYPE_PLAYLIST, + DEMUXER_TYPE_SUB, }; enum timestamp_type { @@ -304,9 +305,9 @@ static inline void *realloc_struct(void *ptr, size_t nmemb, size_t size) return realloc(ptr, nmemb * size); } -struct demuxer *new_demuxer(struct MPOpts *opts, struct stream *stream, - int type, int a_id, int v_id, int s_id, - char *filename); +demuxer_t *new_sub_pseudo_demuxer(struct MPOpts *opts); + + void free_demuxer(struct demuxer *demuxer); void demuxer_add_packet(demuxer_t *demuxer, struct sh_stream *stream, diff --git a/demux/demux_sub.c b/demux/demux_sub.c new file mode 100644 index 0000000000..ab99091215 --- /dev/null +++ b/demux/demux_sub.c @@ -0,0 +1,38 @@ +/* + * This file is part of mpv. + * + * mpv is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * mpv is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with mpv. If not, see . + */ + +// Note: not a real demuxer. The frontend has its own code to open subtitle +// code, and then creates a new dummy demuxer with new_sub_demuxer(). +// But eventually, all subtitles should be opened this way, and this +// file can be removed. + +#include "demux.h" + +static int dummy_fill_buffer(struct demuxer *demuxer, struct demux_stream *ds) +{ + return 0; +} + +const struct demuxer_desc demuxer_desc_sub = { + .info = "External subtitles pseudo demuxer", + .name = "sub", + .shortdesc = "sub", + .author = "", + .comment = "", + .type = DEMUXER_TYPE_SUB, + .fill_buffer = dummy_fill_buffer, +}; diff --git a/demux/stheader.h b/demux/stheader.h index 433dc7ef71..09e9d8682b 100644 --- a/demux/stheader.h +++ b/demux/stheader.h @@ -164,6 +164,7 @@ typedef struct sh_sub { bool active; // after track switch decoder may stay initialized, not active unsigned char *extradata; // extra header data passed from demuxer int extradata_len; + struct ass_track *track; // loaded by libass const struct sd_functions *sd_driver; } sh_sub_t; diff --git a/sub/dec_sub.h b/sub/dec_sub.h index 263df19bc0..4eb833c52b 100644 --- a/sub/dec_sub.h +++ b/sub/dec_sub.h @@ -21,9 +21,6 @@ void sub_reset(struct sh_sub *sh, struct osd_state *osd); void sub_switchoff(struct sh_sub *sh, struct osd_state *osd); void sub_uninit(struct sh_sub *sh); -struct sh_sub *sd_ass_create_from_track(struct ass_track *track, - const char *codec, struct MPOpts *opts); - #ifdef CONFIG_ASS struct ass_track *sub_get_ass_track(struct osd_state *osd); #endif diff --git a/sub/sd_ass.c b/sub/sd_ass.c index 02d0ed15bf..b107e0438f 100644 --- a/sub/sd_ass.c +++ b/sub/sd_ass.c @@ -79,7 +79,9 @@ static int init(struct sh_sub *sh, struct osd_state *osd) } else { ctx = talloc_zero(NULL, struct sd_ass_priv); sh->context = ctx; - if (ass) { + if (sh->track) { + ctx->ass_track = sh->track; + } else if (ass) { ctx->ass_track = ass_new_track(osd->ass_library); if (sh->extradata) ass_process_codec_private(ctx->ass_track, sh->extradata, @@ -277,7 +279,8 @@ static void uninit(struct sh_sub *sh) { struct sd_ass_priv *ctx = sh->context; - ass_free_track(ctx->ass_track); + if (sh->track != ctx->ass_track) + ass_free_track(ctx->ass_track); talloc_free(ctx); } @@ -293,31 +296,6 @@ const struct sd_functions sd_ass = { .uninit = uninit, }; -static int sd_ass_track_destructor(void *ptr) -{ - uninit(ptr); - return 1; -} - -struct sh_sub *sd_ass_create_from_track(struct ass_track *track, - const char *codec, struct MPOpts *opts) -{ - struct sh_sub *sh = talloc(NULL, struct sh_sub); - talloc_set_destructor(sh, sd_ass_track_destructor); - *sh = (struct sh_sub) { - .opts = opts, - .gsh = talloc_struct(sh, struct sh_stream, { - .codec = codec, - }), - .context = talloc_struct(sh, struct sd_ass_priv, { - .ass_track = track, - .vsfilter_aspect = is_ass_sub(codec), - }), - .initialized = true, - }; - return sh; -} - struct ass_track *sub_get_ass_track(struct osd_state *osd) { struct sh_sub *sh = osd ? osd->sh_sub : NULL; -- cgit v1.2.3