@ -110,6 +110,7 @@ typedef struct DVDVideoPlaybackState {
int in_pgc ; /* if our navigator is in the PGC */
int in_ps ; /* if our navigator is in the program stream */
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 */
uint64_t pgc_duration_est ; /* estimated duration as reported by IFO */
uint64_t pgc_elapsed ; /* the elapsed time of the PGC, cell-relative */
@ -167,6 +168,7 @@ typedef struct DVDVideoDemuxContext {
int play_end ; /* signal EOF to the parent demuxer */
DVDVideoPlaybackState play_state ; /* the active playback state */
int play_started ; /* signal that playback has started */
int seek_warned ; /* signal that we warned about seeking limits */
int segment_started ; /* signal that subdemuxer is on a segment */
} DVDVideoDemuxContext ;
@ -715,7 +717,8 @@ static int dvdvideo_play_next_ps_block(AVFormatContext *s, DVDVideoPlaybackState
state - > in_pgc = 1 ;
}
} else if ( state - > celln > = e_cell - > cellN | | state - > pgn > cur_pgn ) {
} else if ( ! state - > is_seeking & &
( state - > celln > = e_cell - > cellN | | state - > pgn > cur_pgn ) ) {
return AVERROR_EOF ;
}
@ -728,7 +731,7 @@ static int dvdvideo_play_next_ps_block(AVFormatContext *s, DVDVideoPlaybackState
if ( ! state - > in_pgc )
continue ;
if ( ( state - > ptt > 0 & & state - > ptt > cur_ptt ) | |
if ( ( ! state - > is_seeking & & state - > ptt > 0 & & state - > ptt > cur_ptt ) | |
( c - > opt_chapter_end > 0 & & cur_ptt > c - > opt_chapter_end ) ) {
return AVERROR_EOF ;
}
@ -811,6 +814,8 @@ static int dvdvideo_play_next_ps_block(AVFormatContext *s, DVDVideoPlaybackState
( * p_nav_event ) = nav_event ;
state - > is_seeking = 0 ;
return nav_len ;
case DVDNAV_WAIT :
if ( dvdnav_wait_skip ( state - > dvdnav ) ! = DVDNAV_STATUS_OK ) {
@ -1688,6 +1693,67 @@ static int dvdvideo_close(AVFormatContext *s)
return 0 ;
}
static int dvdvideo_read_seek ( AVFormatContext * s , int stream_index , int64_t timestamp , int flags )
{
DVDVideoDemuxContext * c = s - > priv_data ;
int64_t new_nav_pts ;
pci_t * new_nav_pci ;
dsi_t * new_nav_dsi ;
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 " ) ;
return AVERROR_PATCHWELCOME ;
}
if ( ( flags & AVSEEK_FLAG_BYTE ) )
return AVERROR ( ENOSYS ) ;
if ( timestamp < 0 )
return AVERROR ( EINVAL ) ;
if ( ! c - > seek_warned ) {
av_log ( s , AV_LOG_WARNING , " Seeking is inherently unreliable and will result "
" in imprecise timecodes from this point \n " ) ;
c - > seek_warned = 1 ;
}
/* 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 ) {
av_log ( s , AV_LOG_ERROR , " libdvdnav: seeking to % " PRId64 " failed \n " , timestamp ) ;
return AVERROR_EXTERNAL ;
}
new_nav_pts = dvdnav_get_current_time ( c - > play_state . dvdnav ) ;
new_nav_pci = dvdnav_get_current_nav_pci ( c - > play_state . dvdnav ) ;
new_nav_dsi = dvdnav_get_current_nav_dsi ( c - > play_state . dvdnav ) ;
if ( new_nav_pci = = NULL | | new_nav_dsi = = NULL ) {
av_log ( s , AV_LOG_ERROR , " Invalid NAV packet after seeking \n " ) ;
return AVERROR_INVALIDDATA ;
}
c - > play_state . in_pgc = 1 ;
c - > play_state . in_ps = 0 ;
c - > play_state . is_seeking = 1 ;
c - > play_state . nav_pts = timestamp ;
c - > play_state . ts_offset = timestamp ;
c - > play_state . vobu_e_ptm = new_nav_pci - > pci_gi . vobu_s_ptm ;
c - > first_pts = 0 ;
c - > play_started = 0 ;
dvdvideo_subdemux_flush ( s ) ;
av_log ( s , AV_LOG_DEBUG , " seeking: requested_nav_pts=% " PRId64 " new_nav_pts=% " PRId64 " \n " ,
timestamp , new_nav_pts ) ;
return 0 ;
}
# define OFFSET(x) offsetof(DVDVideoDemuxContext, x)
static const AVOption dvdvideo_options [ ] = {
{ " angle " , " playback angle number " , OFFSET ( opt_angle ) , AV_OPT_TYPE_INT , { . i64 = 1 } , 1 , 9 , AV_OPT_FLAG_DECODING_PARAM } ,
@ -1716,11 +1782,12 @@ const FFInputFormat ff_dvdvideo_demuxer = {
. p . name = " dvdvideo " ,
. p . long_name = NULL_IF_CONFIG_SMALL ( " DVD-Video " ) ,
. p . priv_class = & dvdvideo_class ,
. p . flags = AVFMT_NOFILE | AVFMT_ SHOW_IDS | AVFMT_TS_DISCONT |
AVFMT_NO_BYTE_SEEK | AVFMT_NOGENSEARCH | AVFMT_NOBINSEARCH ,
. p . flags = AVFMT_SHOW_IDS | AVFMT_TS_DISCONT | AVFMT_SEEK_TO_PTS |
AVFMT_NOFILE | AVFMT_NO _BYTE_SEEK | AVFMT_NOGENSEARCH | AVFMT_NOBINSEARCH ,
. priv_data_size = sizeof ( DVDVideoDemuxContext ) ,
. flags_internal = FF_INFMT_FLAG_INIT_CLEANUP ,
. read_close = dvdvideo_close ,
. read_header = dvdvideo_read_header ,
. read_packet = dvdvideo_read_packet
. read_packet = dvdvideo_read_packet ,
. read_seek = dvdvideo_read_seek
} ;