mirror of
https://github.com/mpv-player/mpv
synced 2025-03-19 18:05:21 +00:00
demux_lavf: add simple seek-by-bytes mode for MPEG
Seeking in MPEG files with pts resets could fail completely, as it was always done by timestamps and those of course don't unambiguously specify a file position in such files. Add basic functionality for byte-based seeking and playback position reporting, and decide whether to use that functionality based on a simple heuristic (could be improved).
This commit is contained in:
parent
3c2cfee488
commit
8fb91511b1
@ -77,6 +77,8 @@ typedef struct lavf_priv {
|
|||||||
int nb_streams_last;
|
int nb_streams_last;
|
||||||
bool internet_radio_hack;
|
bool internet_radio_hack;
|
||||||
bool use_dts;
|
bool use_dts;
|
||||||
|
bool seek_by_bytes;
|
||||||
|
int bitrate;
|
||||||
}lavf_priv_t;
|
}lavf_priv_t;
|
||||||
|
|
||||||
static int mp_read(void *opaque, uint8_t *buf, int size) {
|
static int mp_read(void *opaque, uint8_t *buf, int size) {
|
||||||
@ -612,7 +614,22 @@ static demuxer_t* demux_open_lavf(demuxer_t *demuxer){
|
|||||||
demuxer->video->id=-2; // audio-only
|
demuxer->video->id=-2; // audio-only
|
||||||
} //else if (best_video > 0 && demuxer->video->id == -1) demuxer->video->id = best_video;
|
} //else if (best_video > 0 && demuxer->video->id == -1) demuxer->video->id = best_video;
|
||||||
|
|
||||||
demuxer->accurate_seek = true;
|
/* libavformat sets bitrate for mpeg based on pts at start and end
|
||||||
|
* of file, which fails for files with pts resets. So calculate our
|
||||||
|
* own bitrate estimate. */
|
||||||
|
if (priv->avif->flags & AVFMT_TS_DISCONT) {
|
||||||
|
for (int i = 0; i < avfc->nb_streams; i++)
|
||||||
|
priv->bitrate += avfc->streams[i]->codec->bit_rate;
|
||||||
|
/* pts-based is more accurate if there are no resets; try to make
|
||||||
|
* a somewhat reasonable guess */
|
||||||
|
if (!avfc->duration || avfc->duration == AV_NOPTS_VALUE
|
||||||
|
|| priv->bitrate && (avfc->bit_rate < priv->bitrate / 2
|
||||||
|
|| avfc->bit_rate > priv->bitrate * 2))
|
||||||
|
priv->seek_by_bytes = true;
|
||||||
|
if (!priv->bitrate)
|
||||||
|
priv->bitrate = 1440000;
|
||||||
|
}
|
||||||
|
demuxer->accurate_seek = !priv->seek_by_bytes;
|
||||||
|
|
||||||
return demuxer;
|
return demuxer;
|
||||||
}
|
}
|
||||||
@ -751,6 +768,14 @@ static void demux_seek_lavf(demuxer_t *demuxer, float rel_seek_secs, float audio
|
|||||||
int avsflags = 0;
|
int avsflags = 0;
|
||||||
mp_msg(MSGT_DEMUX,MSGL_DBG2,"demux_seek_lavf(%p, %f, %f, %d)\n", demuxer, rel_seek_secs, audio_delay, flags);
|
mp_msg(MSGT_DEMUX,MSGL_DBG2,"demux_seek_lavf(%p, %f, %f, %d)\n", demuxer, rel_seek_secs, audio_delay, flags);
|
||||||
|
|
||||||
|
if (priv->seek_by_bytes) {
|
||||||
|
int64_t pos = demuxer->filepos;
|
||||||
|
rel_seek_secs *= priv->bitrate / 8;
|
||||||
|
pos += rel_seek_secs;
|
||||||
|
av_seek_frame(priv->avfc, -1, pos, AVSEEK_FLAG_BYTE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (flags & SEEK_ABSOLUTE) {
|
if (flags & SEEK_ABSOLUTE) {
|
||||||
priv->last_pts = 0;
|
priv->last_pts = 0;
|
||||||
} else {
|
} else {
|
||||||
@ -780,14 +805,25 @@ static int demux_lavf_control(demuxer_t *demuxer, int cmd, void *arg)
|
|||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case DEMUXER_CTRL_CORRECT_PTS:
|
case DEMUXER_CTRL_CORRECT_PTS:
|
||||||
return DEMUXER_CTRL_OK;
|
return DEMUXER_CTRL_OK;
|
||||||
case DEMUXER_CTRL_GET_TIME_LENGTH:
|
case DEMUXER_CTRL_GET_TIME_LENGTH:
|
||||||
|
if (priv->seek_by_bytes) {
|
||||||
|
/* Our bitrate estimate may be better than would be used in
|
||||||
|
* otherwise similar fallback code at higher level */
|
||||||
|
if (demuxer->movi_end <= 0)
|
||||||
|
return DEMUXER_CTRL_DONTKNOW;
|
||||||
|
*(double *)arg = (demuxer->movi_end - demuxer->movi_start) * 8 /
|
||||||
|
priv->bitrate;
|
||||||
|
return DEMUXER_CTRL_GUESS;
|
||||||
|
}
|
||||||
if (priv->avfc->duration == 0 || priv->avfc->duration == AV_NOPTS_VALUE)
|
if (priv->avfc->duration == 0 || priv->avfc->duration == AV_NOPTS_VALUE)
|
||||||
return DEMUXER_CTRL_DONTKNOW;
|
return DEMUXER_CTRL_DONTKNOW;
|
||||||
|
|
||||||
*((double *)arg) = (double)priv->avfc->duration / AV_TIME_BASE;
|
*((double *)arg) = (double)priv->avfc->duration / AV_TIME_BASE;
|
||||||
return DEMUXER_CTRL_OK;
|
return DEMUXER_CTRL_OK;
|
||||||
|
|
||||||
case DEMUXER_CTRL_GET_PERCENT_POS:
|
case DEMUXER_CTRL_GET_PERCENT_POS:
|
||||||
|
if (priv->seek_by_bytes)
|
||||||
|
return DEMUXER_CTRL_DONTKNOW; // let it use the fallback code
|
||||||
if (priv->avfc->duration == 0 || priv->avfc->duration == AV_NOPTS_VALUE)
|
if (priv->avfc->duration == 0 || priv->avfc->duration == AV_NOPTS_VALUE)
|
||||||
return DEMUXER_CTRL_DONTKNOW;
|
return DEMUXER_CTRL_DONTKNOW;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user