diff --git a/demux/demux_disc.c b/demux/demux_disc.c index d0b10e267c..aa163d66e3 100644 --- a/demux/demux_disc.c +++ b/demux/demux_disc.c @@ -353,6 +353,22 @@ static void sync_initial_edition(struct demuxer *demuxer) } } +static void refresh_disc_metadata(struct demuxer *demuxer) +{ + double len; + if (stream_control(demuxer->stream, STREAM_CTRL_GET_TIME_LENGTH, &len) >= 1) + demux_set_duration(demuxer, len); + else + demux_set_duration(demuxer, -1); + + // Old chapter metadata is not freed here, they are parented to demuxer. + demuxer->chapters = NULL; + demuxer->num_chapters = 0; + add_stream_chapters(demuxer); + sync_initial_edition(demuxer); + demux_lists_changed(demuxer); +} + static bool reopen_slave(struct demuxer *demuxer) { struct priv *p = demuxer->priv; @@ -386,23 +402,27 @@ static bool reopen_slave(struct demuxer *demuxer) p->slave_to_outer[n] = NULL; sync_streams(demuxer); + refresh_disc_metadata(demuxer); - // Refresh duration / chapters / edition for the new playlist. - double len; - if (stream_control(demuxer->stream, STREAM_CTRL_GET_TIME_LENGTH, &len) >= 1) - demux_set_duration(demuxer, len); - else - demux_set_duration(demuxer, -1); + return true; +} - for (int n = 0; n < demuxer->num_chapters; n++) - talloc_free(demuxer->chapters[n].metadata); - demuxer->num_chapters = 0; - add_stream_chapters(demuxer); - - sync_initial_edition(demuxer); - - demux_lists_changed(demuxer); +// Handle a disc-nav discontinuity (title/menu/cell jump) +static bool process_discontinuity(struct demuxer *demuxer, uint32_t new_id) +{ + struct priv *p = demuxer->priv; + if (!p->is_dvd) { + // BD needs a full reopen (codecs can change across titles). + if (!reopen_slave(demuxer)) + return false; + } else { + if (p->slave->desc->drop_buffers) + p->slave->desc->drop_buffers(p->slave); + refresh_disc_metadata(demuxer); + } + p->last_discontinuity_id = new_id; + p->seek_reinit = true; return true; } @@ -416,14 +436,11 @@ static bool d_read_packet(struct demuxer *demuxer, struct demux_packet **out_pkt p->nav_active = nav.nav_active; demux_set_nav_active(demuxer, nav.nav_active); } - if (nav.discontinuity_id != p->last_discontinuity_id) { - MP_VERBOSE(demuxer, "discontinuity %u->%u, reopening slave\n", + if (!p->is_dvd && nav.discontinuity_id != p->last_discontinuity_id) { + MP_VERBOSE(demuxer, "discontinuity %u->%u, handling\n", p->last_discontinuity_id, nav.discontinuity_id); - if (!reopen_slave(demuxer)) + if (!process_discontinuity(demuxer, nav.discontinuity_id)) return false; - if (stream_control(demuxer->stream, STREAM_CTRL_GET_NAV_STATE, &nav) >= 1) - p->last_discontinuity_id = nav.discontinuity_id; - p->seek_reinit = true; } } @@ -434,18 +451,16 @@ static bool d_read_packet(struct demuxer *demuxer, struct demux_packet **out_pkt struct demux_packet *pkt = demux_read_any_packet(p->slave); if (!pkt) { - // The slave can hit EOF mid-playback when the stream layer breaks - // its read at a disc-driven discontinuity. + // EOF is either a real still (hold the frame) or the one-shot drain + // EOF at a jump boundary; in the latter case resync and continue. struct stream_nav_state nav2 = {0}; if (stream_control(demuxer->stream, STREAM_CTRL_GET_NAV_STATE, &nav2) >= 1 && nav2.discontinuity_id != p->last_discontinuity_id) { - MP_VERBOSE(demuxer, "discontinuity %u->%u at EOF, reopening slave\n", + MP_VERBOSE(demuxer, "discontinuity %u->%u at EOF, handling\n", p->last_discontinuity_id, nav2.discontinuity_id); - if (!reopen_slave(demuxer)) + if (!process_discontinuity(demuxer, nav2.discontinuity_id)) return false; - p->last_discontinuity_id = nav2.discontinuity_id; - p->seek_reinit = true; pkt = demux_read_any_packet(p->slave); } if (!pkt) { @@ -457,8 +472,10 @@ static bool d_read_packet(struct demuxer *demuxer, struct demux_packet **out_pkt demux_update(p->slave, MP_NOPTS_VALUE); - if (p->seek_reinit) + if (p->seek_reinit) { reset_pts(demuxer); + refresh_disc_metadata(demuxer); + } int slave_index = pkt->stream; if (demux_get_num_stream(p->slave) > p->slave_to_outer_count ||