summaryrefslogtreecommitdiffstats
path: root/demux
Commit message (Collapse)AuthorAgeFilesLines
* demux: fix excessive backwards seeking with backwards playbackwm42019-09-191-1/+2
| | | | | | | | | | | | | | | | Backwards demuxing usually seeks back back by a "random" amount (set by a user option) when it needs new preceding packets. It turns out a past change made these backwards seek amounts add up when it didn't need to (i.e. subtracting the amount from the seek pos without properly resetting it), which could possibly slow down playback as it went on. The reason for this was that back_seek_pos was set for every stream on every seek. This made the reset not affect other streams (in particular streams which weren't used and never were reset, or which didn't reset that often). But as the commit adding it showed, this is needed only to set the initial position. So do that. Fixes: "demux: fix initial backward demuxing state in some cases"
* demux: fix minor seek_preroll consistency issuewm42019-09-191-0/+2
| | | | | | | | | When packet appending sets the start of the range, it adjusts the range by seek_preroll. Do this when packets are pruned from the start of the range too. (Yeah, seek_preroll handling is probably broken in some other cases. It was halfhearted to begin with.)
* demux: mess with seek range updates and pruningwm42019-09-193-118/+156
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The main thing this commit does is removing demux_packet.kf_seek_pts. It gets rid of 8 bytes per packet. Which doesn't matter, but whatever. This field was involved with much of seek range updating and pruning, because it tracked the canonical seek PTS (i.e. start PTS) of a packet range. We have to deal with timestamp reordering, and assume the start PTS is the lowest PTS across all packets (not necessarily just the first packet). So knowing this PTS requires looping over all packets of a range (no, the demuxer isn't going to tell us, that would be too sane). Having this as packet field was perfectly fine. I'm just removing it because I started hating extra packet fields recently. Before this commit, this value was cached in the kf_seek_pts field (and computed "incrementally" when adding packets). This commit computes the value on demand (compute_keyframe_times()) by iterating over the placket list. There is some similarity with the state before 10d0963d851fa, where I introduced the kf_seek_pts field - maybe I'm just moving in circles. The commit message claims something about quadratic complexity, but if the code before that had this problem, this new commit doesn't reintroduce it, at least. (See below.) The pruning logic is simplified (I think?) - there is no "incremental" cached pruning decision anymore (next_prune_target is removed), and instead it simply prunes until the next keyframe like it's supposed to. I think this incremental stuff was only there because of very old code that got refactored away before. I don't even know what I was thinking there, it just seems complex. Now the seek range is updated when a keyframe packet is removed. Instead of using the kf_seek_pts field, queue->seek_start is used to determine the stream with the lowest timestamp, which should be pruned first. This is different, but should work well. Doing the same as the previous code would require compute_keyframe_times(), which would introduce quadratic complexity. On the other hand, it's fine to call compute_keyframe_times() when the seek range is recomputed on pruning, because this is called only once per removed keyframe packet. Effectively, this will iterate over the packet list twice instead of once, and with some locality. The same happens when packets are appended - it loops over the recently added packets once again. (And not more often, which would go above linear complexity.) This introduces some "cleverness" with avoiding calling update_seek_ranges() even when keyframe packets added/removed, which is not really tightly coupled to the new code, and could have been in a separate commit. Removing next_prune_target achieves the same as commit b275232141f56, which is hereby reverted (stale is_bof flags prevent seeking before the current range, even if the beginning of the file was pruned). The seek range is now strictly computed after at least one packet was removed, and stale state should not be possible anymore. Range joining may over-allocate the index a little. It tried hard to avoid this before by explicitly freeing the old index before creating a new one. Now it iterates over the old index while adding the entries to the new one, which is simpler, but may allocate twice the memory in the worst case. It's not going to matter for anything, though. Seeking will be slightly slower. It needs to compute the seek PTS values across all packets in the vicinity of the seek target. The previous code also iterated over these packets, but now it iterates one packet range more. Another minor detail is that the special seeking code for SEEK_FORWARD goes away. The seeking code will now iterate over the very last packet range too, even if it's incomplete (i.e. packets are still being appended to it). It's fine that it touches the incomplete range, because the seek_end fields prevent that anything particularly incorrect can happen. On the other hand, SEEK_FORWARD can now consider this as seek target, which the deleted code had to do explicitly, as kf_seek_pts was unset for incomplete packet ranges.
* demux: fix a commentwm42019-09-191-1/+1
| | | | | | | | | Obviously doesn't sense with this order. The git history shows that this comment was touched multiple times, without ever fixing it. It was originally added in 2016, where the "for" was missing. Later, the "for" was added, but to the wrong position. What the fuck?
* demux: cache a valuewm42019-09-191-10/+9
| | | | | Just for readability purposes. Although the field is mutable, it never changes within the function.
* demux: redo timed metadatawm42019-09-195-194/+200
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The old implementation didn't work for the OGG case. Discard the old shit code (instead of fixing it), and write new shit code. The old code was already over a year old, so it's about time to rewrite it for no reason anyway. While it's true that the old code appears to be broken, the main reason to rewrite this is to make it simpler. While the amount of code seems to be about the same, both the concept and the actual tag handling are simpler. The result is probably a bit more correct. The packet struct shrinks by 8 byte. That fact that it wasted 8 bytes per packet for a rather obscure use case was the reason I started this at all (and when I found that OGG updates didn't work). While these 8 bytes aren't going to hurt, the packet struct was getting too bloated. If you buffer a lot of data, these extra fields will add up. Still quite some effort for 8 bytes. Fortunately, it's not like there are any managers that need to be convinced whether it's worth doing. The freedom to waste time on dumb shit. The old implementation attached the current metadata to each packet. When the decoder read the packet, the packet's metadata was made current. The new implementation stores metadata as separate list, and requires that the player frontend tells it the current playback time, which will be used to find the currently valid metadata. In both cases, the objective was to correctly update metadata even if a lot of data is buffered ahead (and to update them correctly when seeking within the demuxer cache). The new implementation is actually slightly more correct, because it uses the playback time for the metadata lookup. Consider if you have an audio filter which buffers 15 seconds (unfortunately such a filter exists), then the old code would update the current title 15 seconds too early, while the new one does it correctly. The new code also simplifies mixing the 3 metadata sources (global, per stream, ICY). We assume these aren't mixed in a meaningful way. The old code tried to be a bit more "exact". I didn't bother to look how the old code did this, but the new code simply always "merges" with the previous metadata, so if a newer tag removes a field, it's going to stick around anyway. I tried to keep it simple. Other approaches include making metadata a special sh_stream with metadata packets. This would have been conceptually clean, but the implementation would probably have been unnatural (and doesn't match well with libavformat's API anyway). It would have been nice to make the metadata updates chapter points (makes a lot of sense for the intended use case, web radio current song information), but I don't think it would have been a good idea to make chapters suddenly so dynamic. (Still an idea to keep in mind; the new code actually makes it easier to work towards this.) You could mention how subtitles are timed metadata, and actually are implemented as sparse packet streams in some formats. mp4 implements chapters as special subtitle stream, AFAIK. (Ironically, this is very not-ideal for files. It would be useful for streaming like web radio, but mp4 is extremely bad for streaming by design for other reasons.) bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla
* demux_lavf: compensate timestamp resets for OGG web radio streamswm42019-09-191-5/+58
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | Some OGG web radio streams use timestamp resets when a new song starts (you can find those Xiph's directory - other streams there don't show this behavior). Basically, the OGG stream behaves like concatenated OGG files, and "of course" the timestamps will start at 0 again when the song changes. This is very inconvenient, and breaks the seekable demuxer cache. In fact, any kind of seeking will break This is more time wasted in Xiph's bullshit. No, having timestamp resets by design is not reasonable, and fuck you. I much prefer the awful ICY/mp3 streaming mess, even if that's lower quality and awful. Maybe it wouldn't be so bad if libavformat could tell us WHERE THE FUCK THE RESET HAPPENS. But it doesn't, and the randomly changing timestamps is the only thing we get from its API. At this point, demux_lavf.c is like 90% hacks. But well, if libavformat applies this strange mixture of being clever for us vs. giving us unfiltered garbage (while pretending it abstracts everything, and hiding _useful_ implementation/low level details), not much we can do. This timestamp linearizing would, in general, probably be better done after the decoder, because then we wouldn't need to deal with timestamp resets. But the main purpose of this change is to fix seeking within the demuxer cache, so we have to do it on the lowest level. This can probably be applied to other containers and video streams too. But that is untested. Some further caveats are explained in the manpage.
* demux_lavf: add per-stream statewm42019-09-191-8/+17
| | | | Seems like this will be useful later.
* demux_lavf: use common mpv/ffmpeg timestamp conversion functionwm42019-09-191-4/+2
| | | | | | | Probably doesn't change anything, other than looking slightly better. In theory, the common function has some stuff that makes it more likely that timestamps round-trip through conversions properly, but I didn't confirm that.
* demux: refactor cache range init/deinitwm42019-09-193-59/+51
| | | | | | | | | | | | | | | | | | | | Remove the duplicated creation of the first range. Explicitly destroy ranges, including the last one on final deinit. It looks like this also fixes a leak of removed range structs, which was never noticed because they're so small, and were freed on final deinit due to having the demuxer as talloc parent. This improves upon the previous commit too (that change should have been part of it I guess). Sub-demuxers (demux_timeline only) now automatically don't use the cache (like it was intended by the previous commit). The cache is "initialized" (or disabled) last in the recursive call chain, which is messy, but this sub demuxer stuff FUCKING SUCKS, as mentioned in the previous commit message. This would be no problem if the caching layer and actual demuxer implementations were separate. Most of this change has no purpose. Might make (de-)initialization of further cache exerpiments simpler.
* demux: really disable cache for sub-demuxerswm42019-09-192-5/+11
| | | | | | | | | | | | | | | | | | It seems the so called demuxer cache wasn't really disabled for sub-demuxers (timeline stuff). This was relatively harmless, since the actual packet data was shared anyway via refcounting. But with the addition of a mmap cache backend, this may change a lot. So strictly disable any caching for sub-demuxers. This assumes that users of sub-demuxers (only demux_timeline.c by now?) strictly use demux_read_any_packet(), since demux_read_packet_async() will require some minor read-ahead if a low level packet read returned a packet for a different stream. This requires some awkward messing with this fucking heap of trash. The thing that is really wrong here is that the demuxer API mixes different concepts, and sub-demuxers get the same API as decoders, and use the cache code.
* demux: handle accounting for index size differentlywm42019-09-191-16/+25
| | | | | | | | | | | | | | | | | | | | | | | | The demuxer cache tries to track the number of bytes allocated for the cache. In addition to the packet queue, the seek index is another data structure that roughly depends on the amount of packets cached. So the index size should somehow be part of the total number of bytes tracking. Until now, this was handled with KF_SEEK_ENTRY_WORST_CASE, basically a shitty heuristic. It was a guess (and probably rather an upper bound than a lower bound). The implementation details made it annoying, and it was conceptually inaccurate too. Change this, and instead simply add the index size to the total cache size. This essentially makes it part of the backbuffer. It's nice that this cleanly decouples it from the packet size tracking itself. Since it's part of the backbuffer number of bytes now, packet pruning can't necessarily free enough space in the backbuffer anymore. Before this commit, the backbuffer consisted of packets only, so it was possible to reduce its size to 0 by pruning all packets until the decoder reader position, at which point a packet was accounted as forward buffered. Now the index is added to this, and it can't be pruned. Replace the assert() because of this changed invariant.
* packet: change len field from int to size_twm42019-09-192-2/+2
| | | | | Why not. struct demux_packet doesn't change on 64 bit size due to alignment padding.
* demux: fix assertion when switching tracks during backward playbackwm42019-09-191-20/+20
| | | | | | | | | | | | | | Someone who rams a knife into his own hand just to see what happens is normally put in a psychiatric ward. But in software, this is acceptable behavior. Programs are not supposed to crash just because a user did something unreasonably dumb. Switching tracks during backward playback is such a thing. It triggered an assertion because the newly enabled stream was not properly initialized for backward playback. Fix this, and make it actually work (mostly; it still takes a "while" until playback recovers fully). This actually makes some aspects of initialization slightly cleaner.
* demux: use binary search for cache seek indexwm42019-09-191-7/+28
| | | | | | | | | | | | | Not sure if this is bug-free. You _always_ make bugs when writing a binary search from scratch (and such is the curse of C, though if I did this in C++ it would probably end in blood). It seems to work though, checking against the normal linear search. It's slightly faster. Not much. I wonder if the termination condition can be written in a nicer/elegant way. I guess the fact that it's not a == predicate makes this slightly messier?
* demux: create full seek index for cached packetswm42019-09-191-26/+72
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The purpose of the seek index is to avoid having to iterate over the full linked list of cached packets, which should speed up seeking. Until now, there was an excuse of a seek index, that didn't really work. The idea of the old index was nice: have a fixed number of entries (no need to worry about exceeding memory requirements), which are "stretched" out as the cache gets bigger. The size of it was 16 entries, which in theory should speed up seeking by the factor 16, given evenly spaced out entries. To achieve this even spacing, it attempted to "thin out" the index by half once the index was full (see e.g. index_distance field). In my observations this didn't really work, and the distribution of the index entries was very uneven. Effectively, this did nothing. It probably worked once and I can't be assed to debug my own shit code. Writing new shit code is more fun. Write new shit code for fun. This time it's a complete index. It's kept in a ringbuffer (for easier LIFO style appending/removing), which is resized with realloc if it becomes too small. Actually, the index is not completely completely; it's still "thinned out" by a hardcoded time value (INDEX_STEP_SIZE). This should help with things like audio or crazy subtitle tracks (do they still create those?), where we can just iterate over a small part of the linked packet list to get the exact seek position. For example, for AAC audio tracks with typical samplerates/framesizes we'd iterate about 50 packets in the linked list. The results are good. Seeking in large caches is much faster now, apparently at least 1 or 2 orders of magnitude. Part of this is because we don't need to touch every damn packet in a huge linked list (bad cache behavior - the index is a linear memory region instead), but "thinning" out the search space also helps. Both aspects can be easily tested (setting INDEX_STEP_SIZE to 0, and replacing e->pts with e->pkt->kf_seek_pts in find_seek_target()). This does use more memory of course. In theory, we could tolerate memory allocation failures (the index is optional and only for performance), but I didn't bother and inserted an apologetic comment instead, have fun with the shit code). the memory usage doesn't seem to be that bad, though. Due to INDEX_STEP_SIZE it's bounded by the file duration too. Try to account for the additional memory usage with an approximation (see KF_SEEK_ENTRY_WORST_CASE). It's still a bit different, because the index needs a single, potentially large allocation.
* demux: simplify cache search and exit earlywm42019-09-191-15/+10
| | | | | | | | | | | | | | The search was slightly more complicated and slow than it had to be. It didn't assume that the packet list was sorted, which is responsible for much of this. (I think the search code was borrowed from demux_mkv.c, which does not sort index entries.) There was a half-hearted attempt to make it exit early, but it was mostly ineffective. Simplify the code based on the assumption that the list is sorted. This will exit the search loop once the worst case candidate entry was checked.
* demux: update some commentswm42019-09-191-15/+28
| | | | | | | Mostly about the packet queue and the subtitle handling of it. (This mess sure sounds like a good argument to give up the separate stream queues, and using a single packet queue per cached range.)
* demux: shorten some redundant outputwm42019-09-191-3/+1
| | | | This message would always show "correct_dts=0 correct_pos=0".
* demux: demux multiple audio frames in backward playbackwm42019-09-191-38/+65
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Until now, this usually passed a single audio frame to the decoder, and then did a backstep operation (cache seek + frame search) again. This is probably not very efficient, especially considering it has to search the packet queue from the "start" every time again. Also, with most audio codecs, an additional "preroll" frame was passed first. In these cases, the preroll frame would make up 50% of audio decoding time. Also not very efficient. Attempt to fix this by returning multiple frames at once. This reduces the number of backstep operations and the ratio the preoll frames. In theory, this should help efficiency. I didn't test it though, why would I do this? It's just a pain. Set it to unscientific 10 frames. (Actually, these are 10 keyframes, so it's much more for codecs like TrueHD. But I don't care about TrueHD.) This commit changes some other implementation details. Since we can return more than 1 non-preroll keyframe to the decoder, some new state is needed to remember how much. The resume packet search is adjusted to find N ("total") keyframe packets in general, not just preroll frames. I'm removing the special case for 1 preroll packet; audio used this, but doesn't anymore, and it's premature optimization anyway. Expose the new mechanism with 2 new options. They're almost completely pointless, since nobody will try them, and if they do, they won't understand what these options truly do. And if they actually do, they most likely would be capable of editing the source code, and we could just hardcode the parameters. Just so you know that I know that the added options are pointless. The following two things are truly unrelated to this commit, and more like general refactoring, but fortunately nobody can stop me. Don't set back_seek_pos in dequeue_packet() anymore. This was sort of pointless, since it was set in find_backward_restart_pos() anyway (using some of the same packets). The latter function tries to restrict this to the first keyframe range though, which is an optimization that in theory might break with broken files (duh), but in these cases a lot of other things would be broken anyway. Don't set back_restart_* in dequeue_packet(). I think this is an artifact of the old restart code (cf. ad9e473c555). It can be done directly in find_backward_restart_pos() now. Although this adds another shitty packet search loop, I prefer this, because clearer what's actually happening.
* demux: remove further calls to packet size estimation functionwm42019-09-191-2/+5
| | | | May as well be part of the previous commit.
* demux: don't loop over all packets to find forward buffered size on seekwm42019-09-192-46/+50
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The size of all forward buffered packets is used to control maximum buffering. Until now, this size was incrementally adjusted, but had to be recomputed on seeks within the cache. Doing this was actually pretty expensive. It iterates over a linked list of separate memory allocations (which are probably spread all over the heap due to the allocation behavior), and the demux_packet_estimate_total_size() call touches a lot of further memory locations. I guess this affects the cache rather negatively. In an unscientific test, the recompute_buffers() function (which contained this loop) was responsible for roughly half of the time seeking took. Replace this with a way that computes the buffered size between 2 packets in constant times. The demux_packet.cum_pos field contains the summed sizes of all previous packets, so subtracting cum_pos between two packets yields the size of all packets in between. We can do this because we never remove packets from the middle of the queue. We only add packets to the end, or remove packets at the beginning. The tail_cum_pos field is needed because we don't store the end position of a packet, so the last packet's position would be unknown. We could recompute the "estimated" packet size, or store the estimated size in the packet struct, but I just didn't like this. This also removes the cached fw_bytes fields. It's slightly nicer to just recompute them when needed. Maintaining them incrementally was annoying. total_size stays though, since recomputing it isn't that cheap (would need to loop over all ranges every time). I'm always using uint64_t for sizes. This is certainly needed (a stream could easily burn through more than 4GB of data, even if much less of that is cached). The actual cached amount should always fit into size_t, so it's casted to size_t for printfs (yes, I hate the way you specify stdint.h types in printfs, the less I have to use that crap, the better).
* demux: remove tracking of number of forward buffered packetswm42019-09-191-14/+10
| | | | | | | | | | | | | | In ancient times, the number of packets was used to limit excessive read-ahead. This was completely replaced by tracking the size in bytes. The number of packets was used in debugging output only. In one case (packet got demuxed and is added to a queue), only log whether there were packets on this stream before. (Unknown whether it's useful.) In another case (queue overflow), actually count the number of packets. It's vaguely useful, and the message with the number of packets is shown only once after a seek reset, so it doesn't matter whether it's slow.
* demux: fix backward demuxing freeze if first packet is not a keyframewm42019-09-191-1/+8
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Some files don't start with keyframe packets. Normally, this is not sane, but the sample file which triggered this was a cut TV capture transport stream. And this shouldn't happen anyway. Introduce a further heuristic: if the last seek target was before the start of the cached data, and the start of the cache is marked as BOF (beginning of file), then we won't find anything better. This is possibly a bit shaky, because both seek_start and back_seek_pos weren't made for this purpose. But I can't come up with situations where this would actually break. (Leave this to shitty broken files I hit later.) I also considered finding the first packet in the cache that is marked as keyframe, i.e. the first actual seek target, and comparing it to "first", but I didn't like it much. Well whatever. It's a bit silly that this caused a hard freeze (and similar issues still will). The problem is that the demuxer holds the lock and has no reason to release it. And in general, there's a single lock for the entire demuxer cache. Finer grained locking would probably not make much sense. In theory status of available data and maybe certain commands to the demuxer could be moved to separate locks, but it would raise complexity, and you'd probably still need to get the central lock in some cases, which would deadlock you anyway. It would still be nice if some minor corner case in the wonderfully terrible and complex backward demuxer state machine couldn't lock up the player. As a hack, unlock and then immediately lock again. Depending on the OS mutex implementation, this may give other waiters a chance to grab the lock. This is not a guarantee (some OSes may for example not wake up other waiters until the next time slice or something), but works well on Linux.
* demux: simplify and improve performance of backward playback steppingwm42019-09-191-33/+6
| | | | | | | | | | | | | | | | | The step_backwards function set reader_head to the start of the current cache range. This was completely unnecessary and made it _much_ slower. Remove the code that adjusts reader_head. Merge the rest of the code into the only caller and remove the function. The comment on the removed code was quite right. It was "inefficient". Removing it delegates going to an early position to the normal seek code, triggered by find_backward_restart_pos() incremental back seek logic. I suppose especially audio benefits from this, because this happens for every single audio packet (except maybe freaky bullshit like TrueHD, which has "keyframes"). The blabla about performance in the removed comments is still true, but now applies to the seek code itself only.
* demux: fix backward playback at EOF with full demuxer cachewm42019-09-191-3/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | Fixes "mpv file.mkv --cache --demuxer-cache-wait --play-dir=backward", and other situations where the demuxer cache contains the entire file, and playback is to start from the end. It also can be triggered when starting playback normally with --cache, and once everything is in the cache, enabling backward playback and seeking past EOF. In all cases, the cache seek will set reader_head=NULL (because you seeked to/past EOF). Then the code (the one modified by this commit) sees that ds->queue->is_bof==true, and thinks we've reached BOF (beginning of file) while searching for a useful packet, i.e. we found nothing and playback really can only end. Obviously this is nonsense, we've found only nothing if we actually searched from the beginning, not some "random" reader_head (== first) value that does not include the entire cache. That means the condition should trigger only if the start of the search (first variable) points to the beginning of the cache (ds->queue->head). Not taking this if means we'll seek to an earlier position and retry. Also, a seek before the beginning of the cache will always end up with reader_head==ds->queue->head, i.e. we'll terminate properly. That comment was quite right.
* demux: more backwards playback preroll packets for vorbis and mp3wm42019-09-191-1/+3
| | | | | | | | | | | | | | | | | | | | Together with the previous commit, this seems to make backward playback work in files with vorbis and mp3 audio codecs. For Vorbis (with libavcodec's decoder, didn't test libvorbis), the first packet was just always completely discarded. This happened even though we tell libavcodec that we do discar