diff options
-rw-r--r-- | libmpdemux/demux_lavf.c | 25 | ||||
-rw-r--r-- | libmpdemux/demuxer.c | 13 | ||||
-rw-r--r-- | libmpdemux/demuxer.h | 3 | ||||
-rw-r--r-- | mplayer.c | 87 | ||||
-rw-r--r-- | stream/stream.h | 7 | ||||
-rw-r--r-- | stream/stream_bluray.c | 4 | ||||
-rw-r--r-- | stream/stream_dvd.c | 4 |
7 files changed, 112 insertions, 31 deletions
diff --git a/libmpdemux/demux_lavf.c b/libmpdemux/demux_lavf.c index 4dd9938d07..69cb0f02fc 100644 --- a/libmpdemux/demux_lavf.c +++ b/libmpdemux/demux_lavf.c @@ -24,6 +24,7 @@ #include <limits.h> #include <stdbool.h> #include <string.h> +#include <assert.h> #include <libavformat/avformat.h> #include <libavformat/avio.h> @@ -70,6 +71,7 @@ typedef struct lavf_priv { int audio_streams; int video_streams; int sub_streams; + int autoselect_sub; int64_t last_pts; int astreams[MAX_A_STREAMS]; int vstreams[MAX_V_STREAMS]; @@ -164,6 +166,7 @@ static int lavf_check_file(demuxer_t *demuxer) if (!demuxer->priv) demuxer->priv = calloc(sizeof(lavf_priv_t), 1); priv = demuxer->priv; + priv->autoselect_sub = -1; char *format = lavfdopts->format; if (!format) @@ -302,6 +305,8 @@ static void handle_stream(demuxer_t *demuxer, AVFormatContext *avfc, int i) AVCodec *avc = avcodec_find_decoder(codec->codec_id); const char *codec_name = avc ? avc->name : "unknown"; + bool set_demuxer_id = matches_avinputformat_name(priv, "mpeg"); + switch (codec->codec_type) { case AVMEDIA_TYPE_AUDIO: { WAVEFORMATEX *wf; @@ -310,6 +315,8 @@ static void handle_stream(demuxer_t *demuxer, AVFormatContext *avfc, int i) if (!sh_audio) break; sh_audio->demuxer_codecname = codec_name; + if (set_demuxer_id) + sh_audio->gsh->demuxer_id = st->id; stream_type = "audio"; priv->astreams[priv->audio_streams] = i; sh_audio->libav_codec_id = codec->codec_id; @@ -391,6 +398,8 @@ static void handle_stream(demuxer_t *demuxer, AVFormatContext *avfc, int i) if (!sh_video) break; sh_video->demuxer_codecname = codec_name; + if (set_demuxer_id) + sh_video->gsh->demuxer_id = st->id; stream_type = "video"; priv->vstreams[priv->video_streams] = i; sh_video->libav_codec_id = codec->codec_id; @@ -503,6 +512,8 @@ static void handle_stream(demuxer_t *demuxer, AVFormatContext *avfc, int i) if (!sh_sub) break; sh_sub->demuxer_codecname = codec_name; + if (set_demuxer_id) + sh_sub->gsh->demuxer_id = st->id; stream_type = "subtitle"; priv->sstreams[priv->sub_streams] = i; sh_sub->libav_codec_id = codec->codec_id; @@ -774,6 +785,14 @@ static int demux_lavf_fill_buffer(demuxer_t *demux, demux_stream_t *dsds) id = pkt->stream_index; + assert(id >= 0 && id < MAX_S_STREAMS); + if (demux->s_streams[id] && demux->sub->id == -1 && + demux->s_streams[id]->gsh->demuxer_id == priv->autoselect_sub) + { + priv->autoselect_sub = -1; + demux->sub->id = id; + } + if (id == demux->audio->id || priv->internet_radio_hack) { // audio ds = demux->audio; @@ -943,6 +962,12 @@ static int demux_lavf_control(demuxer_t *demuxer, int cmd, void *arg) return DEMUXER_CTRL_OK; } } + case DEMUXER_CTRL_AUTOSELECT_SUBTITLE: + { + demuxer->sub->id = -1; + priv->autoselect_sub = *((int *)arg); + return DEMUXER_CTRL_OK; + } case DEMUXER_CTRL_IDENTIFY_PROGRAM: { demux_program_t *prog = arg; diff --git a/libmpdemux/demuxer.c b/libmpdemux/demuxer.c index 798f701305..ce425751f9 100644 --- a/libmpdemux/demuxer.c +++ b/libmpdemux/demuxer.c @@ -1369,16 +1369,3 @@ int demuxer_set_angle(demuxer_t *demuxer, int angle) return angle; } - -char *demuxer_stream_lang(demuxer_t *d, struct sh_stream *sh) -{ - struct stream_lang_req req = { .id = sh->tid }; // assume 1:1 mapping - switch (sh->type) { - case STREAM_AUDIO: req.type = stream_ctrl_audio; break; - case STREAM_SUB: req.type = stream_ctrl_sub; break; - default: return NULL; - } - if (stream_control(d->stream, STREAM_CTRL_GET_LANG, &req) == STREAM_OK) - return req.name; - return NULL; -} diff --git a/libmpdemux/demuxer.h b/libmpdemux/demuxer.h index f2236c6016..2dd2c5a35a 100644 --- a/libmpdemux/demuxer.h +++ b/libmpdemux/demuxer.h @@ -93,6 +93,7 @@ enum timestamp_type { #define DEMUXER_CTRL_SWITCH_VIDEO 14 #define DEMUXER_CTRL_IDENTIFY_PROGRAM 15 #define DEMUXER_CTRL_CORRECT_PTS 16 +#define DEMUXER_CTRL_AUTOSELECT_SUBTITLE 17 #define SEEK_ABSOLUTE (1 << 0) #define SEEK_FACTOR (1 << 1) @@ -406,6 +407,4 @@ int demuxer_angles_count(struct demuxer *demuxer); struct sh_stream *demuxer_stream_by_demuxer_id(struct demuxer *d, enum stream_type t, int id); -char *demuxer_stream_lang(demuxer_t *d, struct sh_stream *s); - #endif /* MPLAYER_DEMUXER_H */ @@ -252,6 +252,7 @@ int use_filedir_conf; #include "metadata.h" static void reset_subtitles(struct MPContext *mpctx); +static void reinit_subs(struct MPContext *mpctx); static float get_relative_time(struct MPContext *mpctx) { @@ -941,6 +942,20 @@ static int find_new_tid(struct MPContext *mpctx, enum stream_type t) return new_id + 1; } +// Map stream number (as used by libdvdread) to MPEG IDs (as used by demuxer). +static int map_id_from_demuxer(struct demuxer *d, enum stream_type type, int id) +{ + if (d->stream->type == STREAMTYPE_DVD && type == STREAM_SUB) + id = id & 0x1F; + return id; +} +static int map_id_to_demuxer(struct demuxer *d, enum stream_type type, int id) +{ + if (d->stream->type == STREAMTYPE_DVD && type == STREAM_SUB) + id = id | 0x20; + return id; +} + static struct track *add_stream_track(struct MPContext *mpctx, struct sh_stream *stream, bool under_timeline) @@ -949,7 +964,21 @@ static struct track *add_stream_track(struct MPContext *mpctx, struct track *track = mpctx->tracks[i]; if (track->stream == stream) return track; + // DVD subtitle track that was added later + if (stream->type == STREAM_SUB && track->type == STREAM_SUB && + map_id_from_demuxer(stream->demuxer, stream->type, + stream->demuxer_id) == track->demuxer_id + && !track->stream) + { + track->stream = stream; + track->demuxer_id = stream->demuxer_id; + // Initialize lazily selected track + if (track == mpctx->current_track[STREAM_SUB]) + reinit_subs(mpctx); + return track; + } } + struct track *track = talloc_ptrtype(NULL, track); *track = (struct track) { .type = stream->type, @@ -964,12 +993,16 @@ static struct track *add_stream_track(struct MPContext *mpctx, }; MP_TARRAY_APPEND(mpctx, mpctx->tracks, mpctx->num_tracks, track); - // Needed for DVD and Blu-Ray. (Note that at least with DVDs and demux_lavf, - // this code is broken: unlike demux_mpg, the demuxer streams are not - // directly mapped to MPEG stream IDs.) - if (!track->lang) - track->lang = talloc_steal(track, demuxer_stream_lang(track->demuxer, - track->stream)); + // Needed for DVD and Blu-ray. + if (!track->lang) { + struct stream_lang_req req = { + .type = track->type, + .id = map_id_from_demuxer(track->demuxer, track->type, + track->demuxer_id) + }; + stream_control(track->demuxer->stream, STREAM_CTRL_GET_LANG, &req); + track->lang = talloc_steal(track, req.name); + } return track; } @@ -980,6 +1013,31 @@ static void add_demuxer_tracks(struct MPContext *mpctx, struct demuxer *demuxer) add_stream_track(mpctx, demuxer->streams[n], !!mpctx->timeline); } +static void add_dvd_tracks(struct MPContext *mpctx) +{ +#ifdef CONFIG_DVDREAD + struct demuxer *demuxer = mpctx->demuxer; + struct stream *stream = demuxer->stream; + if (stream->type == STREAMTYPE_DVD) { + int n_subs = dvd_number_of_subs(stream); + for (int n = 0; n < n_subs; n++) { + struct track *track = talloc_ptrtype(NULL, track); + *track = (struct track) { + .type = STREAM_SUB, + .user_tid = find_new_tid(mpctx, STREAM_SUB), + .demuxer_id = n, + .demuxer = mpctx->demuxer, + }; + MP_TARRAY_APPEND(mpctx, mpctx->tracks, mpctx->num_tracks, track); + + struct stream_lang_req req = {.type = STREAM_SUB, .id = n}; + stream_control(stream, STREAM_CTRL_GET_LANG, &req); + track->lang = talloc_steal(track, req.name); + } + } +#endif +} + void add_subtitles(struct MPContext *mpctx, char *filename, float fps, int noerr) { @@ -1901,6 +1959,22 @@ static void reinit_subs(struct MPContext *mpctx) if (!track) return; + 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 + // subtitle event. + + // demux_mpg - maps IDs directly to the logical stream number + track->demuxer->sub->id = track->demuxer_id; + + // demux_lavf - IDs are essentially random, have to use MPEG IDs + int id = map_id_to_demuxer(track->demuxer, track->type, + track->demuxer_id); + demux_control(track->demuxer, DEMUXER_CTRL_AUTOSELECT_SUBTITLE, &id); + + return; + } + mpctx->initialized_flags |= INITIALIZED_SUB; if (track->vobsub_id_plus_one) { @@ -3795,6 +3869,7 @@ goto_enable_cache: // On the contrary, the EDL and CUE demuxers are empty wrappers. mpctx->demuxer = mpctx->timeline[0].source; } + add_dvd_tracks(mpctx); add_demuxer_tracks(mpctx, mpctx->demuxer); mpctx->timeline_part = 0; diff --git a/stream/stream.h b/stream/stream.h index 6ce5b7bcac..eeb2f769bd 100644 --- a/stream/stream.h +++ b/stream/stream.h @@ -96,13 +96,8 @@ #define STREAM_CTRL_GET_NUM_TITLES 12 #define STREAM_CTRL_GET_LANG 13 -enum stream_ctrl_type { - stream_ctrl_audio, - stream_ctrl_sub, -}; - struct stream_lang_req { - enum stream_ctrl_type type; + int type; // STREAM_AUDIO, STREAM_SUB int id; char *name; }; diff --git a/stream/stream_bluray.c b/stream/stream_bluray.c index 7c4f970159..68dea3db4c 100644 --- a/stream/stream_bluray.c +++ b/stream/stream_bluray.c @@ -199,11 +199,11 @@ static int bluray_stream_control(stream_t *s, int cmd, void *arg) BLURAY_STREAM_INFO *si = NULL; int count = 0; switch (req->type) { - case stream_ctrl_audio: + case STREAM_AUDIO: count = ti->clips[0].audio_stream_count; si = ti->clips[0].audio_streams; break; - case stream_ctrl_sub: + case STREAM_SUB: count = ti->clips[0].pg_stream_count; si = ti->clips[0].pg_streams; break; diff --git a/stream/stream_dvd.c b/stream/stream_dvd.c index e3e1595619..5332311856 100644 --- a/stream/stream_dvd.c +++ b/stream/stream_dvd.c @@ -693,10 +693,10 @@ static int control(stream_t *stream,int cmd,void* arg) struct stream_lang_req *req = arg; int lang = 0; switch(req->type) { - case stream_ctrl_audio: + case STREAM_AUDIO: lang = dvd_lang_from_aid(stream, req->id); break; - case stream_ctrl_sub: + case STREAM_SUB: lang = dvd_lang_from_sid(stream, req->id); break; } |