summaryrefslogtreecommitdiffstats
path: root/player
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 /player
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 'player')
-rw-r--r--player/loadfile.c5
1 files changed, 5 insertions, 0 deletions
diff --git a/player/loadfile.c b/player/loadfile.c
index d9d6a0036c..472304d5f0 100644
--- a/player/loadfile.c
+++ b/player/loadfile.c
@@ -548,6 +548,9 @@ void mp_switch_track_n(struct MPContext *mpctx, int order, enum stream_type type
if (current)
current->selected = false;
+ if (track && track->demuxer == mpctx->demuxer)
+ demux_set_enable_refresh_seeks(mpctx->demuxer, true);
+
reselect_demux_streams(mpctx);
mpctx->current_track[order][type] = track;
@@ -557,6 +560,8 @@ void mp_switch_track_n(struct MPContext *mpctx, int order, enum stream_type type
reselect_demux_streams(mpctx);
+ demux_set_enable_refresh_seeks(mpctx->demuxer, false);
+
if (type == STREAM_VIDEO && order == 0) {
reinit_video_chain(mpctx);
} else if (type == STREAM_AUDIO && order == 0) {