summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libmpdemux/demux_lavf.c25
-rw-r--r--libmpdemux/demuxer.c13
-rw-r--r--libmpdemux/demuxer.h3
-rw-r--r--mplayer.c87
-rw-r--r--stream/stream.h7
-rw-r--r--stream/stream_bluray.c4
-rw-r--r--stream/stream_dvd.c4
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 */
diff --git a/mplayer.c b/mplayer.c
index 0bf52dc9ab..b17b13c9c3 100644
--- a/mplayer.c
+++ b/mplayer.c
@@ -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;
}