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. --- demux/demux_mpg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'demux') diff --git a/demux/demux_mpg.c b/demux/demux_mpg.c index b30fb8e6e1..d47b3afd86 100644 --- a/demux/demux_mpg.c +++ b/demux/demux_mpg.c @@ -523,7 +523,7 @@ static int demux_mpg_read_packet(demuxer_t *demux,int id){ if(!demux->s_streams[aid]){ sh_sub_t *sh = new_sh_sub(demux, aid); - if (sh) sh->gsh->codec = "dvd_subtitle"; + if (sh) sh->gsh->codec = "dvd_subtitle_mpg"; mp_msg(MSGT_DEMUX,MSGL_V,"==> Found subtitle: %d\n",aid); } -- 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. --- demux/demux.c | 19 +++++++++++++++++-- demux/demux.h | 7 ++++--- demux/demux_sub.c | 38 ++++++++++++++++++++++++++++++++++++++ demux/stheader.h | 1 + 4 files changed, 60 insertions(+), 5 deletions(-) create mode 100644 demux/demux_sub.c (limited to 'demux') 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; -- 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. --- demux/stheader.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'demux') diff --git a/demux/stheader.h b/demux/stheader.h index 09e9d8682b..8220d65a61 100644 --- a/demux/stheader.h +++ b/demux/stheader.h @@ -161,11 +161,10 @@ typedef struct sh_video { typedef struct sh_sub { SH_COMMON - 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; + struct dec_sub *dec_sub; // decoder context } sh_sub_t; // demuxer.c: -- 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. --- demux/stheader.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'demux') diff --git a/demux/stheader.h b/demux/stheader.h index 8220d65a61..421dfaf857 100644 --- a/demux/stheader.h +++ b/demux/stheader.h @@ -163,8 +163,9 @@ typedef struct sh_sub { SH_COMMON unsigned char *extradata; // extra header data passed from demuxer int extradata_len; - struct ass_track *track; // loaded by libass - struct dec_sub *dec_sub; // decoder context + struct ass_track *track; // loaded by libass + struct sub_data *sub_data; // loaded by subreader.c + struct dec_sub *dec_sub; // decoder context } sh_sub_t; // demuxer.c: -- cgit v1.2.3 From 6dbedd27d53b61744d512e27bb0c3853cf6d7bba Mon Sep 17 00:00:00 2001 From: wm4 Date: Sat, 1 Jun 2013 19:54:34 +0200 Subject: demux_lavf: always set packet duration Makes WebVTT actually work. Also simplify the logic for setting duration. Only the subtitle path uses the packet duration, so the checks for STREAM_SUB as well as the keyframe flag are redundant. Apparently duration and convergence_duration are the same thing, but convergence_duration was added as Matroska-specific hack to get a higher value range (int vs. int64_t) with high resolution Matroska timebases. For us it doesn't matter, because double floats are used for timestamps and durations. --- demux/demux_lavf.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'demux') diff --git a/demux/demux_lavf.c b/demux/demux_lavf.c index a978bc9cee..a482f736c6 100644 --- a/demux/demux_lavf.c +++ b/demux/demux_lavf.c @@ -671,11 +671,8 @@ static int demux_lavf_fill_buffer(demuxer_t *demux, demux_stream_t *dsds) if (ts != AV_NOPTS_VALUE) { dp->pts = ts * av_q2d(st->time_base); priv->last_pts = dp->pts * AV_TIME_BASE; - // always set duration for subtitles, even if AV_PKT_FLAG_KEY isn't set, - // otherwise they will stay on screen to long if e.g. ASS is demuxed - // from mkv - if ((stream->type == STREAM_SUB || (pkt->flags & AV_PKT_FLAG_KEY)) && - pkt->convergence_duration > 0) + dp->duration = pkt->duration * av_q2d(st->time_base); + if (pkt->convergence_duration > 0) dp->duration = pkt->convergence_duration * av_q2d(st->time_base); } dp->pos = demux->filepos; -- cgit v1.2.3 From 13a1ce16f9581871cf7ac0d06ece407534a98f89 Mon Sep 17 00:00:00 2001 From: wm4 Date: Mon, 3 Jun 2013 01:28:14 +0200 Subject: sub: pass subtitle packets directly Before this, subtitle packets were returned as data ptr/len pairs, and mplayer.c got the rest (pts and duration) directly from the demuxer data structures. Then mplayer.c reassembled the packet data structure again. Pass packets directly instead. The mplayer.c side stays a bit awkward, because the (now by default unused) DVD path keeps getting in the way. In demux.c there's lots of weird stuff (3 functions that read packets, really?), but we want to keep the code equivalent for now to avoid hitting weird issues and corner cases. --- demux/demux.c | 18 +++++++++--------- demux/demux.h | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) (limited to 'demux') diff --git a/demux/demux.c b/demux/demux.c index 12e0d9083a..25f31a3f60 100644 --- a/demux/demux.c +++ b/demux/demux.c @@ -801,20 +801,20 @@ int ds_get_packet_pts(demux_stream_t *ds, unsigned char **start, double *pts) return len; } -int ds_get_packet_sub(demux_stream_t *ds, unsigned char **start) +struct demux_packet *ds_get_packet_sub(demux_stream_t *ds) { - int len; if (ds->buffer_pos >= ds->buffer_size) { - *start = NULL; if (!ds->packs) - return -1; // no sub + return NULL; // no sub if (!ds_fill_buffer(ds)) - return -1; // EOF + return NULL; // EOF } - len = ds->buffer_size - ds->buffer_pos; - *start = &ds->buffer[ds->buffer_pos]; - ds->buffer_pos += len; - return len; + if (ds->buffer_pos < ds->buffer_size) { + ds->current->buffer += ds->buffer_pos; + ds->buffer_size -= ds->buffer_pos; + } + ds->buffer_pos = ds->buffer_size; + return ds->current; } struct demux_packet *ds_get_packet2(struct demux_stream *ds, bool repeat_last) diff --git a/demux/demux.h b/demux/demux.h index e58c56141f..9ec6d0c6f0 100644 --- a/demux/demux.h +++ b/demux/demux.h @@ -344,7 +344,7 @@ void ds_free_packs(struct demux_stream *ds); int ds_get_packet(struct demux_stream *ds, unsigned char **start); int ds_get_packet_pts(struct demux_stream *ds, unsigned char **start, double *pts); -int ds_get_packet_sub(struct demux_stream *ds, unsigned char **start); +struct demux_packet *ds_get_packet_sub(demux_stream_t *ds); struct demux_packet *ds_get_packet2(struct demux_stream *ds, bool repeat_last); double ds_get_next_pts(struct demux_stream *ds); int ds_parse(struct demux_stream *sh, uint8_t **buffer, int *len, double pts, -- cgit v1.2.3