* [FFmpeg-devel] [PATCH] avformat/dvdvideodec: fix seeking on multi-angle discs
@ 2025-02-04 16:55 Marth64
0 siblings, 0 replies; only message in thread
From: Marth64 @ 2025-02-04 16:55 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Marth64, Kacper Michajlow
When seeking on multi-angle titles, libdvdnav does not lock on
to the correct sectors initially as it seeks to find the right NAV packet.
This manifests itself as two bugs:
(1) When seeking on the first angle in a multi-angle segment,
frames from another angle will appear (for example in intro
or credits scenes). This issue is present in VLC also.
(2) When seeking during a segment on angle n+1, the demuxer
cannot deduce the right position from dvdnav and does not allow
seeking within the segment (due to it maintaining a strict state).
Correct the issue by switching to angle 1 before doing the seek
operation, and skipping 3 VOBUs (NAV packet led segments) ahead
where dvdnav will have positioned itself correctly.
Reported-by: Kacper Michajlow <kasper93@gmail.com>
Signed-off-by: Marth64 <marth64@proxyid.net>
---
libavformat/dvdvideodec.c | 36 ++++++++++++++++++++++++++++++++++++
1 file changed, 36 insertions(+)
diff --git a/libavformat/dvdvideodec.c b/libavformat/dvdvideodec.c
index 5b9abebbf2..9596468ce2 100644
--- a/libavformat/dvdvideodec.c
+++ b/libavformat/dvdvideodec.c
@@ -111,6 +111,7 @@ typedef struct DVDVideoPlaybackState {
int in_vts; /* if our navigator is in the VTS */
int is_seeking; /* relax navigation path while seeking */
int64_t nav_pts; /* PTS according to IFO, not frame-accurate */
+ int nb_vobu_skip; /* number of VOBUs we should skip */
uint64_t pgc_duration_est; /* estimated duration as reported by IFO */
uint64_t pgc_elapsed; /* the elapsed time of the PGC, cell-relative */
int pgc_nb_pg_est; /* number of PGs as reported by IFOs */
@@ -165,6 +166,7 @@ typedef struct DVDVideoDemuxContext {
/* playback control */
int64_t first_pts; /* the PTS of the first video keyframe */
+ int nb_angles; /* number of angles in the current title */
int play_started; /* signal that playback has started */
DVDVideoPlaybackState play_state; /* the active playback state */
int64_t *prev_pts; /* track the previous PTS emitted per stream */
@@ -298,6 +300,8 @@ static int dvdvideo_ifo_open(AVFormatContext *s)
return AVERROR_INVALIDDATA;
}
+ c->nb_angles = title_info.nr_of_angles;
+
return 0;
}
@@ -759,6 +763,13 @@ static int dvdvideo_play_next_ps_block(AVFormatContext *s, DVDVideoPlaybackState
return AVERROR_INVALIDDATA;
}
+ if (state->nb_vobu_skip > 0) {
+ av_log(s, AV_LOG_VERBOSE, "Skipping VOBU at SCR %d\n",
+ e_dsi->dsi_gi.nv_pck_scr);
+ state->nb_vobu_skip -= 1;
+ continue;
+ }
+
state->vobu_duration = e_pci->pci_gi.vobu_e_ptm - e_pci->pci_gi.vobu_s_ptm;
state->pgc_elapsed += state->vobu_duration;
state->nav_pts = dvdnav_get_current_time(state->dvdnav);
@@ -1736,6 +1747,7 @@ static int dvdvideo_read_seek(AVFormatContext *s, int stream_index, int64_t time
int64_t new_nav_pts;
pci_t* new_nav_pci;
dsi_t* new_nav_dsi;
+ int seek_failed = 0;
if (c->opt_menu || c->opt_chapter_start > 1) {
av_log(s, AV_LOG_ERROR, "Seeking is not compatible with menus or chapter extraction\n");
@@ -1755,9 +1767,30 @@ static int dvdvideo_read_seek(AVFormatContext *s, int stream_index, int64_t time
c->seek_warned = 1;
}
+ /* dvdnav loses NAV packets when seeking on multi-angle discs, so enforce angle 1 then revert */
+ if (c->nb_angles > 1) {
+ if (dvdnav_angle_change(c->play_state.dvdnav, 1) != DVDNAV_STATUS_OK) {
+ av_log(s, AV_LOG_ERROR, "Unable to open angle 1 for seeking\n");
+
+ return AVERROR_EXTERNAL;
+ }
+ }
+
/* XXX(PATCHWELCOME): use dvdnav_jump_to_sector_by_time(c->play_state.dvdnav, timestamp, 0)
* when it is available in a released version of libdvdnav; it is more accurate */
if (dvdnav_time_search(c->play_state.dvdnav, timestamp) != DVDNAV_STATUS_OK) {
+ seek_failed = 1;
+ }
+
+ if (c->nb_angles > 1) {
+ if (dvdnav_angle_change(c->play_state.dvdnav, c->opt_angle) != DVDNAV_STATUS_OK) {
+ av_log(s, AV_LOG_ERROR, "Unable to revert to angle %d after seeking\n", c->opt_angle);
+
+ return AVERROR_EXTERNAL;
+ }
+ }
+
+ if (seek_failed) {
av_log(s, AV_LOG_ERROR, "libdvdnav: seeking to %" PRId64 " failed\n", timestamp);
return AVERROR_EXTERNAL;
@@ -1781,6 +1814,9 @@ static int dvdvideo_read_seek(AVFormatContext *s, int stream_index, int64_t time
c->play_state.ptm_discont = 0;
c->play_state.vobu_e_ptm = new_nav_pci->pci_gi.vobu_s_ptm;
+ /* if there are multiple angles, skip the next 3 VOBUs as dvdnav will be at the wrong angle */
+ c->play_state.nb_vobu_skip = c->nb_angles > 1 ? 3 : 0;
+
c->first_pts = 0;
c->play_started = 0;
c->pts_offset = timestamp;
--
2.34.1
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2025-02-04 17:00 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-02-04 16:55 [FFmpeg-devel] [PATCH] avformat/dvdvideodec: fix seeking on multi-angle discs Marth64
Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
This inbox may be cloned and mirrored by anyone:
git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git
# If you have public-inbox 1.1+ installed, you may
# initialize and index your mirror using the following commands:
public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
ffmpegdev@gitmailbox.com
public-inbox-index ffmpegdev
Example config snippet for mirrors.
AGPL code for this site: git clone https://public-inbox.org/public-inbox.git