summaryrefslogtreecommitdiffstats
path: root/demux/demux.h
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2015-02-13 21:17:17 +0100
committerwm4 <wm4@nowhere>2015-02-13 21:17:17 +0100
commitf9f2e1cc4e80a66793249651b74d83c1c8f3a8d4 (patch)
treeb7819a91cc528bd8e5d5f24c4e5c5cecf797c073 /demux/demux.h
parent11bd80b31e0d039b1193f8c68d3bb9e5bf6a4a28 (diff)
downloadmpv-f9f2e1cc4e80a66793249651b74d83c1c8f3a8d4.tar.bz2
mpv-f9f2e1cc4e80a66793249651b74d83c1c8f3a8d4.tar.xz
demux: hack for instant stream switching
This removes the delay when switching audio tracks in mkv or mp4 files. Other formats are not enabled, because it's not clear whether the demuxers fulfill the requirements listed in demux.h. (Many formats definitely do not with libavformat.) Background: The demuxer packet cache buffers a certain amount of packets. This includes only packets from selected streams. We discard packets from other streams for various reasons. This introduces a problem: switching to a different audio track introduces a delay. The delay is as big as the demuxer packet cache buffer, because while the file was read ahead to fill the packet buffer, the process of reading packets also discarded all packets from the previously not selected audio stream. Once the remaining packet buffer has been played, new audio packets are available and you hear audio again. We could probably just not discard packets from unselected streams. But this would require additional memory and CPU resources, and also it's hard to tell when packets from unused streams should be discarded (we don't want to keep them forever; it'd be a memory leak). We could also issue a player hr-seek to the current playback position, which would solve the problem in 1 line of code or so. But this can be rather slow. So what we do in this commit instead is: we just seek back to the position where our current packet buffer starts, and start demuxing from this position again. This way we can get the "past" packets for the newly selected stream. For streams which were already selected the packets are simply discarded until the previous position is reached again. That latter part is the hard part. We really want to skip packets exactly until the position where we left off previously, or we will skip packets or feed packets to the decoder twice. If we assume that the demuxer is deterministic (returns exactly the same packets after a seek to a previous position), then we can try to check whether it's the same packet as the one at the end of the packet buffer. If it is, we know that the packet after it is where we left off last time. Unfortunately, this is not very robust, and maybe it can't be made robust. Currently we use the demux_packet.pos field as unique packet ID - which works fine in some scenarios, but will break in arbitrary ways if the basic requirement to the demuxer (as listed in the demux.h additions) are broken. Thus, this is enabled only for the internal mkv demuxer and the libavformat mp4 demuxer. (libavformat mkv does not work, because the packet positions are not unique. Probably could be fixed upstream, but it's not clear whether it's a bug or a feature.)
Diffstat (limited to 'demux/demux.h')
-rw-r--r--demux/demux.h6
1 files changed, 6 insertions, 0 deletions
diff --git a/demux/demux.h b/demux/demux.h
index e18c013a5b..c580a22b18 100644
--- a/demux/demux.h
+++ b/demux/demux.h
@@ -193,6 +193,11 @@ typedef struct demuxer {
// Send relative seek requests, instead of SEEK_ABSOLUTE or SEEK_FACTOR.
// This is only done if the user explicitly uses a relative seek.
bool rel_seeks;
+ // Enable fast track switching hacks. This requires from the demuxer:
+ // - seeking is somewhat reliable; packet contents must not change
+ // - packet position (demux_packet.pos) is set, not negative, and unique
+ // - seeking leaves packet positions invariant
+ bool allow_refresh_seeks;
// Bitmask of DEMUX_EVENT_*
int events;
@@ -262,6 +267,7 @@ void demux_set_wakeup_cb(struct demuxer *demuxer, void (*cb)(void *ctx), void *c
void demux_flush(struct demuxer *demuxer);
int demux_seek(struct demuxer *demuxer, double rel_seek_secs, int flags);
+void demux_set_enable_refresh_seeks(struct demuxer *demuxer, bool enabled);
int demux_control(struct demuxer *demuxer, int cmd, void *arg);