1
0
mirror of https://github.com/mpv-player/mpv synced 2024-12-27 01:22:30 +00:00

demux: improve DVD sub auto-selection hack

The code touched by this commit makes sure that DVD subtitle tracks
known by libdvdread but not known by demux_lavf can be selected and
displayed properly. These subtitle tracks have the first packet
some time late in the packet stream, so that libavformat won't
immediately recognize them, and will add the track as soon as the
first packet is seen during normal demuxing.

demux_mpg used to handle this elegantly: you just set the MPEG ID of
the stream you wanted. demux_lavf couldn't do this, so it was emulated
with a DEMUXER_CTRL. This commit changes it so that new streams are
selected by default (if autoselect is enabled), and the playloop
simply can take appropriate action before the lower layer throws away
the first packet.

This also changes the demux_lavf behavior that subtitle packets are
always demuxed, even if not needed. (They were immediately thrown away,
so there was no advantage to this.)

Further, this adds the ability to demux.c to deal with demuxing more
than one stream of a kind at once. (Though currently it's not useful.)
This commit is contained in:
wm4 2013-07-11 19:22:24 +02:00
parent 83eb28fff7
commit e5544e2da3
4 changed files with 37 additions and 42 deletions

View File

@ -913,12 +913,6 @@ static int map_id_from_demuxer(struct demuxer *d, enum stream_type type, int id)
id = id & 0x1F; id = id & 0x1F;
return id; return id;
} }
static int map_id_to_demuxer(struct demuxer *d, enum stream_type type, int id)
{
if (d->stream->uncached_type == STREAMTYPE_DVD && type == STREAM_SUB)
id = id | 0x20;
return id;
}
static struct track *add_stream_track(struct MPContext *mpctx, static struct track *add_stream_track(struct MPContext *mpctx,
struct sh_stream *stream, struct sh_stream *stream,
@ -937,7 +931,9 @@ static struct track *add_stream_track(struct MPContext *mpctx,
track->stream = stream; track->stream = stream;
track->demuxer_id = stream->demuxer_id; track->demuxer_id = stream->demuxer_id;
// Initialize lazily selected track // Initialize lazily selected track
if (track == mpctx->current_track[STREAM_SUB]) bool selected = track == mpctx->current_track[STREAM_SUB];
demuxer_select_track(track->demuxer, stream, selected);
if (selected)
reinit_subs(mpctx); reinit_subs(mpctx);
return track; return track;
} }
@ -973,6 +969,8 @@ static struct track *add_stream_track(struct MPContext *mpctx,
track->lang = talloc_strdup(track, req.name); track->lang = talloc_strdup(track, req.name);
} }
demuxer_select_track(track->demuxer, stream, false);
return track; return track;
} }
@ -1004,6 +1002,7 @@ static void add_dvd_tracks(struct MPContext *mpctx)
track->lang = talloc_strdup(track, req.name); track->lang = talloc_strdup(track, req.name);
} }
} }
demuxer_enable_autoselect(demuxer);
#endif #endif
} }
@ -1885,18 +1884,9 @@ static void reinit_subs(struct MPContext *mpctx)
mpctx->sh_sub->dec_sub = sub_create(opts); mpctx->sh_sub->dec_sub = sub_create(opts);
assert(track->demuxer); assert(track->demuxer);
if (!track->stream) { // Lazily added DVD track - will be created on first sub packet
// Lazily added DVD track - we must not miss the first subtitle packet, if (!track->stream)
// which makes the demuxer create the sh_stream, and contains the first
// subtitle event.
// 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; return;
}
mpctx->initialized_flags |= INITIALIZED_SUB; mpctx->initialized_flags |= INITIALIZED_SUB;

View File

@ -315,6 +315,9 @@ struct sh_stream *new_sh_stream(demuxer_t *demuxer, enum stream_type type)
} }
default: assert(false); default: assert(false);
} }
sh->ds->selected = demuxer->stream_autoselect;
return sh; return sh;
} }
@ -913,18 +916,29 @@ void demuxer_switch_track(struct demuxer *demuxer, enum stream_type type,
{ {
assert(!stream || stream->type == type); assert(!stream || stream->type == type);
// don't flush buffers if stream is already selected / none are selected
for (int n = 0; n < demuxer->num_streams; n++) { for (int n = 0; n < demuxer->num_streams; n++) {
struct sh_stream *cur = demuxer->streams[n]; struct sh_stream *cur = demuxer->streams[n];
bool select = cur == stream; if (cur->type == type)
if (cur->type == type && cur->ds->selected != select) { demuxer_select_track(demuxer, cur, cur == stream);
cur->ds->selected = select;
ds_free_packs(cur->ds);
demux_control(demuxer, DEMUXER_CTRL_SWITCHED_TRACKS, NULL);
}
} }
} }
void demuxer_select_track(struct demuxer *demuxer, struct sh_stream *stream,
bool selected)
{
// don't flush buffers if stream is already selected / unselected
if (stream->ds->selected != selected) {
stream->ds->selected = selected;
ds_free_packs(stream->ds);
demux_control(demuxer, DEMUXER_CTRL_SWITCHED_TRACKS, NULL);
}
}
void demuxer_enable_autoselect(struct demuxer *demuxer)
{
demuxer->stream_autoselect = true;
}
bool demuxer_stream_is_selected(struct demuxer *d, struct sh_stream *stream) bool demuxer_stream_is_selected(struct demuxer *d, struct sh_stream *stream)
{ {
return stream && stream->ds->selected; return stream && stream->ds->selected;

View File

@ -77,7 +77,6 @@ enum timestamp_type {
#define DEMUXER_CTRL_SWITCH_VIDEO 14 #define DEMUXER_CTRL_SWITCH_VIDEO 14
#define DEMUXER_CTRL_IDENTIFY_PROGRAM 15 #define DEMUXER_CTRL_IDENTIFY_PROGRAM 15
#define DEMUXER_CTRL_CORRECT_PTS 16 #define DEMUXER_CTRL_CORRECT_PTS 16
#define DEMUXER_CTRL_AUTOSELECT_SUBTITLE 17
#define SEEK_ABSOLUTE (1 << 0) #define SEEK_ABSOLUTE (1 << 0)
#define SEEK_FACTOR (1 << 1) #define SEEK_FACTOR (1 << 1)
@ -185,6 +184,7 @@ typedef struct demuxer {
struct sh_stream **streams; struct sh_stream **streams;
int num_streams; int num_streams;
bool stream_autoselect;
int num_editions; int num_editions;
int edition; int edition;
@ -255,6 +255,9 @@ int demux_control(struct demuxer *demuxer, int cmd, void *arg);
void demuxer_switch_track(struct demuxer *demuxer, enum stream_type type, void demuxer_switch_track(struct demuxer *demuxer, enum stream_type type,
struct sh_stream *stream); struct sh_stream *stream);
void demuxer_select_track(struct demuxer *demuxer, struct sh_stream *stream,
bool selected);
void demuxer_enable_autoselect(struct demuxer *demuxer);
int demuxer_type_by_filename(char *filename); int demuxer_type_by_filename(char *filename);

View File

@ -73,7 +73,6 @@ typedef struct lavf_priv {
AVFormatContext *avfc; AVFormatContext *avfc;
AVIOContext *pb; AVIOContext *pb;
uint8_t buffer[BIO_BUFFER_SIZE]; uint8_t buffer[BIO_BUFFER_SIZE];
int autoselect_sub;
int64_t last_pts; int64_t last_pts;
struct sh_stream **streams; // NULL for unknown streams struct sh_stream **streams; // NULL for unknown streams
int num_streams; int num_streams;
@ -196,7 +195,6 @@ static int lavf_check_file(demuxer_t *demuxer)
assert(!demuxer->priv); assert(!demuxer->priv);
demuxer->priv = talloc_zero(NULL, lavf_priv_t); demuxer->priv = talloc_zero(NULL, lavf_priv_t);
priv = demuxer->priv; priv = demuxer->priv;
priv->autoselect_sub = -1;
priv->filename = s->url; priv->filename = s->url;
if (!priv->filename) { if (!priv->filename) {
@ -427,7 +425,6 @@ static void handle_stream(demuxer_t *demuxer, int i)
memcpy(sh_sub->extradata, codec->extradata, codec->extradata_size); memcpy(sh_sub->extradata, codec->extradata, codec->extradata_size);
sh_sub->extradata_len = codec->extradata_size; sh_sub->extradata_len = codec->extradata_size;
} }
st->discard = AVDISCARD_DEFAULT;
break; break;
} }
case AVMEDIA_TYPE_ATTACHMENT: { case AVMEDIA_TYPE_ATTACHMENT: {
@ -463,6 +460,9 @@ static void handle_stream(demuxer_t *demuxer, int i)
if (lang && lang->value) if (lang && lang->value)
sh->lang = talloc_strdup(sh, lang->value); sh->lang = talloc_strdup(sh, lang->value);
} }
bool selected = demuxer_stream_is_selected(demuxer, sh);
st->discard = selected ? AVDISCARD_DEFAULT : AVDISCARD_ALL;
} }
// Add any new streams that might have been added // Add any new streams that might have been added
@ -657,13 +657,6 @@ static int demux_lavf_fill_buffer(demuxer_t *demux)
AVStream *st = priv->avfc->streams[pkt->stream_index]; AVStream *st = priv->avfc->streams[pkt->stream_index];
struct sh_stream *stream = priv->streams[pkt->stream_index]; struct sh_stream *stream = priv->streams[pkt->stream_index];
if (stream && stream->type == STREAM_SUB &&
stream->demuxer_id == priv->autoselect_sub)
{
priv->autoselect_sub = -1;
demuxer_switch_track(demux, STREAM_SUB, stream);
}
if (!demuxer_stream_is_selected(demux, stream)) { if (!demuxer_stream_is_selected(demux, stream)) {
talloc_free(pkt); talloc_free(pkt);
return 1; return 1;
@ -799,18 +792,13 @@ static int demux_lavf_control(demuxer_t *demuxer, int cmd, void *arg)
for (int n = 0; n < priv->num_streams; n++) { for (int n = 0; n < priv->num_streams; n++) {
struct sh_stream *stream = priv->streams[n]; struct sh_stream *stream = priv->streams[n];
AVStream *st = priv->avfc->streams[n]; AVStream *st = priv->avfc->streams[n];
if (stream && stream->type != STREAM_SUB) { if (stream) {
bool selected = demuxer_stream_is_selected(demuxer, stream); bool selected = demuxer_stream_is_selected(demuxer, stream);
st->discard = selected ? AVDISCARD_DEFAULT : AVDISCARD_ALL; st->discard = selected ? AVDISCARD_DEFAULT : AVDISCARD_ALL;
} }
} }
return DEMUXER_CTRL_OK; return DEMUXER_CTRL_OK;
} }
case DEMUXER_CTRL_AUTOSELECT_SUBTITLE:
{
priv->autoselect_sub = *((int *)arg);
return DEMUXER_CTRL_OK;
}
case DEMUXER_CTRL_IDENTIFY_PROGRAM: case DEMUXER_CTRL_IDENTIFY_PROGRAM:
{ {
demux_program_t *prog = arg; demux_program_t *prog = arg;