demux_raw: fix operation with demuxer cache and backward playback

Raw audio formats can be accessed sample-wise, and logically audio
packets demuxed from it would contain only 1 sample. This is
inefficient, so raw audio demuxers typically "bundle" multiple samples
in one packet.

The problem for the demuxer cache and backward playback is that they
need properly aligned packets to make seeking "deterministic". The
requirement is that if you read some packets, and then seek back, you
eventually see the same packets again. demux_raw basically allowed to
seek into the middle of a previously returned packet, which makes it
impossible to make the transition seamless. (Unless you'd be aware of
the packet data format and cut them to make it seamless, which is too
complex for such a use case.)

Solve this by always aligning seeks to packet boundaries. This reduces
the seek accuracy to the arbitrarily chosen packet size. But you can use
hr-seek to fix this. The gain from not making raw audio an awful special
case pays in exchange for this "stupid" suggestion to use hr-seek.

It appears this also fixes that it could and did seek into the middle of
the frame (not sure if this code was ever tested - it goes back to
removing the code duplication between the former demux_rawaudio.c and
demux_rawvideo.c).

If you really cared, you could introduce a seek flag that controls
whether the seek is aligned or not. Then code which requires
"deterministic" demuxing could set it. But this isn't really useful for
us, and we'd always set the flag anyway, unless maybe the caching were
forced disabled.

libavformat's wav demuxer exhibits the same issue. We can't fix it (it
would require the unpleasant experience of contributing to FFmpeg), so
document this in otions.rst. In theory, this also affects seek range
joining, but the only bad effect should be that cached data is
discarded.
This commit is contained in:
wm4 2019-05-20 02:18:59 +02:00
parent 5d69dcfb89
commit 5b4ae42328
2 changed files with 13 additions and 1 deletions

View File

@ -479,6 +479,16 @@ Playback Control
framestep commands are transposed. Backstepping will perform very framestep commands are transposed. Backstepping will perform very
expensive work to step forward by 1 frame. expensive work to step forward by 1 frame.
- Backward playback in wav files does not work properly (and possibly
similar formats, typically raw audio formats used through libavformat).
This is because libavformat does not align seeks on the packet sizes it
uses. (The packet sizes are arbitrary and chosen by libavformat
internally. Seeks on the other hand are sample-exact, which leads to
overlapping packets if the backward playback state machine seeks back.
This is very complex to work around, so it doesn't attempt to.)
A workaround is to remux to a format like mkv, which enforces packet
boundaries. Making mpv cache the entire file in memory also works.
Tuning: Tuning:
- Remove all ``--vf``/``--af`` filters you have set. Disable deinterlacing. - Remove all ``--vf``/``--af`` filters you have set. Disable deinterlacing.

View File

@ -301,7 +301,9 @@ static void raw_seek(demuxer_t *demuxer, double seek_pts, int flags)
stream_t *s = demuxer->stream; stream_t *s = demuxer->stream;
int64_t end = 0; int64_t end = 0;
stream_control(s, STREAM_CTRL_GET_SIZE, &end); stream_control(s, STREAM_CTRL_GET_SIZE, &end);
int64_t pos = seek_pts * p->frame_rate * p->frame_size; int64_t frame_nr = seek_pts * p->frame_rate;
frame_nr = frame_nr - (frame_nr % p->read_frames);
int64_t pos = frame_nr * p->frame_size;
if (flags & SEEK_FACTOR) if (flags & SEEK_FACTOR)
pos = end * seek_pts; pos = end * seek_pts;
if (pos < 0) if (pos < 0)