summaryrefslogtreecommitdiffstats
path: root/demux/demux_lavf.c
Commit message (Collapse)AuthorAgeFilesLines
* demux_lavf: log packet read errorsAman Gupta2019-11-221-1/+1
| | | | Signed-off-by: Aman Gupta <aman@tmm1.net>
* demux_lavf: fight ffmpeg API some more and get the timeout setwm42019-11-161-2/+29
| | | | | | | | | | | | | | | | | | | | | | | | It sometimes happens that HLS streams freeze because the HTTP server is not responding for a fragment (or something similar, the exact circumstances are unknown). The --timeout option didn't affect this, because it's never set on HLS recursive connections (these download the fragments, while the main connection likely nothing and just wastes a TCP socket). Apply an elaborate hack on top of an existing elaborate hack to somehow get these options set. Of course this could still break easily, but hey, it's ffmpeg, it can't not try to fuck you over. I'm so fucking sick of ffmpeg's API bullshit, especially wrt. HLS. Of course the change is sort of pointless. For HLS, GET requests should just aggressively retried (because they're not "streamed", they're just actual files on a CDN), while normal HTTP connections should probably not be made this fragile (they could be streamed, i.e. they are backed by some sort of real time encoder, and block if there is no data yet). The 1 minute default timeout is too high to save playback if this happens with HLS. Vaguely related to #5793.
* stream_lavf: set --network-timeout to 60 seconds by defaultwm42019-11-141-1/+2
| | | | | | | | | | | Until now, we've made FFmpeg use the default network timeout - which is apparently infinite. I don't know if this was changed at some point, although it seems likely, as I was sure there was a more useful default. For most use cases, a smaller timeout is more useful (for example recording something in the background), so force a timeout of 1 minute. See: #5793
* stream: turn into a ring buffer, make size configurablewm42019-11-061-4/+3
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | In some corner cases (see #6802), it can be beneficial to use a larger stream buffer size. Use this as argument to rewrite everything for no reason. Turn stream.c itself into a ring buffer, with configurable size. The latter would have been easily achievable with minimal changes, and the ring buffer is the hard part. There is no reason to have a ring buffer at all, except possibly if ffmpeg don't fix their awful mp4 demuxer, and some subtle issues with demux_mkv.c wanting to seek back by small offsets (the latter was handled with small stream_peek() calls, which are unneeded now). In addition, this turns small forward seeks into reads (where data is simply skipped). Before this commit, only stream_skip() did this (which also mean that stream_skip() simply calls stream_seek() now). Replace all stream_peek() calls with something else (usually stream_read_peek()). The function was a problem, because it returned a pointer to the internal buffer, which is now a ring buffer with wrapping. The new function just copies the data into a buffer, and in some cases requires callers to dynamically allocate memory. (The most common case, demux_lavf.c, required a separate buffer allocation anyway due to FFmpeg "idiosyncrasies".) This is the bulk of the demuxer_* changes. I'm not happy with this. There still isn't a good reason why there should be a ring buffer, that is complex, and most of the time just wastes half of the available memory. Maybe another rewrite soon. It also contains bugs; you're an alpha tester now.
* build: add --enable-ffmpeg-strict-abi optionwm42019-10-211-0/+4
| | | | | | | | | This can be used by distros to disable all known FFmpeg ABI violations. Currently only 1 is known, in demux_lavf.c. In addition to if-defing out the access to the private FFmpeg field, this disables the possibly fragile nested open callbacks, which make sense only if the aforementioned field can be accessed.
* video, demux: rip out unused spherical metadata codewm42019-10-171-12/+0
| | | | | | This was preparation into something that never happened. Spherical video is a shit idea anyway.
* demux: restore some of the DVD/BD/CDDA interaction layerswm42019-10-031-15/+0
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This partially reverts commit a9d83eac40c94f44d19fab7b6955331f10efe301 ("Remove optical disc fancification layers"). Mostly due to the timestamp crap, this was never really going to work. The playback layer is sensitive to timestamps, and derives the playback time directly from the low level packet timestamps. DVD/BD works differently, and libdvdnav/libbluray do not make it easy at all to compensate for this. Which is why it never worked well, but not doing it at all is even more awful. demux_disc.c tried this and rewrote packet timestamps from low level TS to playback time. So restore demux_disc.c, which should bring behavior back to the old often non-working but slightly better state. I did not revert anything that affects components above the demuxer layer. For example, the properties for switching DVD angles or listing disc titles are still gone. (Disc titles could be reimplemented as editions. But not by me.) This commit modifies the reverted code a bit; this can't be avoided, because the internal API changed quite a bit. The old seek resync in demux_lavf.c (which was a hack) is replaced with a hack. SEEK_FORCE and demux_params.external_stream are new additions. Some of this could/should be further cleaned up. If you don't want "proper" DVD/BD support to disappear, you should probably volunteer. Now why am I wasting my time for this? Just because some idiot users are too lazy to rip their ever-wearing out shitty physical discs? Then why should I not be lazy and drop support completely? They won't even be thankful for me maintaining this horrible garbage for no compensation.
* demux_lavf: remove recently added author name from license headerwm42019-10-011-1/+0
| | | | | | | | | | | | | | | | | This was added in 585f9ff42f3195c by @bbarenblat (github handle). We don't do this. This file alone probably has multiple dozen of authors (I didn't count, but it has a history of 15 years). If everyone added their names with each small change, this project would have giant lists of contributing authors on every source file. Neither copyright law nor any of the used licenses require listing authors in the license header. Authorship is recorded in the git log. So don't start with this, and remove this recent case to avoid setting a precedent. Some files still have an author in the header. These cases are grandfathered, and usually are the actual authors of the original code.
* demux_lavf: fix seeking in ogg audio streamswm42019-09-221-0/+3
| | | | | | | | | | | | | | | | | This detected the first packet demuxed after a seek as timestamp discontinuity. Obviously this is non-sense. Since the OGG radio streams for which this feature was introduced are normally unseekable, it's simple to fix this: simply disable it (if in auto mode, the default) as soon as a seek is performed. This code is never called if the stream is considered unseekable, unless the user forced it. There's still a chance this linearization is performed before a seek happens. This will be a bit awkward, but no worse than without this feature, since seeking with timestamp resets is inherently broken in both mpv and libavformat. Fixes: #6974 Fixes: 27fcd4d
* demux_lavf: document intentional FFmpeg API violationwm42019-09-191-0/+4
| | | | | | | | | | | | | | | This field is documented as internal, so an API user should not access it. However, this is the only way to get some read statistics without replacing FFmpeg's entire HLS demuxer. (Using custom I/O as workaround doesn't work: the HLS code uses some weird internal APIs that cannot be provided by FFmpeg API users; I even made the author of the relevant patch to provide a public API, but which was shot down by another FFmpeg developer. So I take this as my right to access this field.) Mention this explicitly, as it affects ABI and API compatibility, and I don't want that anyone claims this was a "mistake". Add some explanations.
* demux: make webm dash work by using init fragment on all demuxerswm42019-09-191-32/+3
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Retarded webshit streaming protocols (well, DASH) chop a stream into small fragments, and move unchanging header parts to an "init" fragment to save some bytes (in the case at hand about 300 bytes for each fragment that is 100KB-200KB, sure was worth it, fucking idiots). Since mpv uses an even more retarded hack to inefficiently emulate DASH through EDL, it opens a new demuxer for every fragment. Thus the fragment needs to be virtually concatenated with the init fragment. (To be fair, I'm not sure whether the alternative, reusing the demuxer and letting it see a stream of byte-wise concatenated fragmenmts, would actually be saner.) demux_lavc.c contained a hack for this. Unfortunately, a certain shitty streaming site by an evil company, that will bestow dytopia upon us soon enough, sometimes serves webm based DASH instead of the expected mp4 DASH. And for some reason, libavformat's mkv demuxer can't handle the init fragment or rejects it for some reason. Since I'd rather eat mushrooms grown in Chernobyl than debugging, hacking, or (god no) contributing to FFmpeg, and since Chernobyl is so far away, make it work with our builtin mkv demuxer instead. This is not hard. We just need to copy the hack in demux_lavf.c to demux_mkv.c. Since I'm not _that_ much of a dumbfuck to actually do this, remove the shitty gross demux_lavf.c hack, and replace it by a slightly less bad generic implementation (stream_concat.c from the previous commit), and use it on all demuxers. Although this requires much more code, this frees demux_lavf.c from a hack, and doesn't require adding a duplicated one to demux_mkv.c, so to the naive eye this seems to be a much better outcome. Regarding the code, for some reason stream_memory_open() is never meant to fail, while stream_concat_open() can in extremely obscure situations, and (currently) not in this case, but we handle failure of it anyway. Yep.
* stream: create memory streams in more straightforward waywm42019-09-191-1/+1
| | | | | | | | | | | | | | | Instead of having to rely on the protocol matching, make a function that creates a stream from a stream_info_t directly. Instead of going through a weird indirection with STREAM_CTRL, add a direct argument for non-text arguments to the open callback. Instead of creating a weird dummy mpv_global, just pass an existing one from all callers. (The latter one is just an artifact from the past, where mpv_global wasn't available everywhere.) Actually I just wanted a function that creates a stream without any of that bullshit. This goal was slightly missed, since you still need this heavy "constructor" just to setup a shitty struct with some shitty callbacks.
* demux: redo timed metadatawm42019-09-191-10/+8
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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_lavf: implement bad hack for backward playback of wavwm42019-09-191-4/+64
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This commit generally fixes backward playing in wav, at least in most PCM cases. libavformat's wav demuxer (and actually all other raw PCM based demuxers) have a specific behavior that breaks backward demuxing. The same thing also breaks persistent seek ranges in the demuxer cache, although that's less critical (it just means some cached data gets discarded). The backward demuxing issue is fatal, will log the message "Demuxer not cooperating.", and then typically stop doing anything. Unlike modern media formats, these formats don't organize media data in packets, but just wrap a monolithic byte stream that is described by a header. This is good enough for PCM, which uses fixed frames (a single sample for all audio channels), and for which it would be too expensive to have per frame headers. libavformat (and mpv) is heavily packet based, and using a single packet for each PCM frame causes too much overhead. So they typically "bundle" multiple frames into a single packet. This packet size is obviously arbitrary, and in libavformat's case hardcoded in its source code. The problem is that seeking doesn't respect this arbitrary packet boundary. Seeking is sample accurate. You can essentially seek inside a packet. The resulting packets will not be aligned with previously demuxed packets. This is normally OK. Backward seeking (and some other demuxer layer features) expect that demuxing an earlier demuxed file position eventually results in the same packets, regardless of the seeks that were done to get there. I like to call this "deterministic" demuxing. Backward demuxing in particular requires this to avoid overlaps, which would make it rather hard to get continuous output. Fix this issue by detecting wav and hopefully other raw audio formats with a heuristic (even PCM needs to be detected as heuristic). Then, if a seek is requested, align the seek timestamps on the guessed number of samples in the audio packets returned by the demuxer. The heuristic excludes files with multiple streams. (Except "attachment" video streams, which could be an ID3 tag. Yes, FFmpeg allows ID3 tags on WAV files.) Such files will inherently use the packet concept in some way. We don't know how the demuxer chooses the internal packet size, but we assume that it's fixed and aligned to PCM frame sizes. The frame size is most likely given by block_align (the native wav frame size, according to Microsoft). We possibly need to explicitly read and discard a packet if the seek is done without reading anything before that. We ignore any subsequent packet sizes; we need to avoid the very last packet, which likely has a different size. This hack should be rather benign. In the worst case, it will "round" the seek target a little, but the maximum rounding amount is bounded. Maybe we _could_ round up if SEEK_FORWARD is specified, but I didn't bother. An earlier commit fixed the same issue for mpv's demux_raw. An alternative, and probably much better solution would be clipping decoded data by timestamp. demux.c could allow the type of overlap the wav demuxer introduces, and instruct the decoder to clip the output against the last decoded timestamp. There's already an infrastructure for this (demux_packet.end field) used by EDL/ordered chapters. Although this sounds like a good solution, mpv unfortunately uses floats for timestamps. The rounding errors break sample accuracy. Even if you used integers, you'd need a timebase that is sample accurate (not always easy, since EDL can merge tracks with different sample rates).
* demux_lavf: also fix cache seeking with large codec delaywm42019-09-191-0/+2
| | | | | | | | | Fixes the same thing as the previous commit did with demux_mkv. I'm not sure if this is correct or a good idea (well, it works with my sample file). There are some shady things in this, but describing them would require too many expletives.
* demux: slightly cleanup network speed reportingwm42019-09-191-1/+1
| | | | | | | | | | | | It was an ugly hack, and the next commit will make it even uglier. Slightly reduce the ugliness to prevent death of too many brain cells, though it's still an ugly hack. The cleanup is really minor, but I guess the following commit would be much worse otherwise. In particular, this commit checks accesses (instead of having a public field with evil access rules), which should avoid misunderstandings and incorrect use. Strictly speaking, the added field is redundant, but the next commit complicates it a bit.
* demux_lavf: increase max. probe sizewm42019-09-191-1/+1
| | | | | For those shitty mp3s with extremely large ID3v2/APIC tags, and for which libavformat insists on reading all data until after the ID3v2.
* stream: redo buffer handling and allow arbitrary size for stream_peek()wm42019-09-191-1/+1
| | | | | | | | | | | | | | | | struct stream used to include the stream buffer, including peek buffer, inline in the struct. It could not be resized, which means the maximum peek size was set in stone. This meant demux_lavf.c could peek only so much data. Change it to use a dynamic buffer. Because it's possible, keep the inline buffer for default buffer sizes (which are basically always used outside of file opening). It's unknown whether it really helps with anything. Probably not. This is also the fallback plan in case we need something like the old stream cache in order to deal with mp4 + unseekable http: the code can now be easily changed to use any buffer size.
* demux: get rid of ->control callbackwm42019-09-191-9/+3
| | | | | | | | The only thing left is the notification for track switching. Just get rid of that. There's probably no real reason to get rid of control(), but why not. I think I was actually trying to do some real work but fuck that.
* demux: change hack for closing subtitle files earlywm42019-09-191-8/+8
| | | | | | | | | | | | | | | | | | | | | Subtitles (and a few other file types, like playlists) are not streamed, but fully read on opening. This means keeping the file handle or network socket open is a waste of resources and could cause other weird behavior. This is why there's a hack to close them after opening. Change this hack to make the demuxer itself do this, which is less weird. (Until recently, demuxer->stream ownership was more complex, which is why it was done this way.) There is some evil shit due to a huge ownership/lifetime mess of various objects. Especially EDL (the currently only nested demuxer case) requires being careful about mp_cancel and passing down stream pointers. As one defensive programming measure, stop accessing the "stream" variable in open_given_type(), even where it would still work. This includes removing a redundant line of code, and removing the peak call, which should not be needed anymore, as the remaining demuxers do this mostly correctly.
* demux: return packets directly from demuxer instead of using sh_streamwm42019-09-191-9/+12
| | | | | | | Preparation for other potential changes to separate demuxer cache/thread and actual demuxers. Most things are untested, but it seems to work somewhat.
* command, demux: remove program propertywm42019-09-131-67/+0
| | | | | | | | | The "program" property could switch between TS programs. It was rather complex and rather obscure (even if you deal with TS captures, you usually don't need it). If anyone actually needs it (did anyone ever attempt to even use it?), it should be rewritten. The demuxer should export a program list, and the frontend should handle the "cycling" logic.
* Remove optical disc fancification layerswm42019-09-131-5/+15
| | | | | | | | | | | | | | | | | This removes anything related to DVD/BD/CD that negatively affected the core code. It includes trying to rewrite timestamps (since DVDs and Blurays do not set packet stream timestamps to playback time, and can even have resets mid-stream), export of chapters, stream languages, export of title/track lists, and all that. Only basic seeking is supported. It is very much possible that seeking completely fails on some discs (on some parts of the timeline), because timestamp rewriting was removed. Note that I don't give a shit about optical media. If you want to watch them, rip them. Keeping some bare support for DVD/BD is the most I'm going to do to appease the type of lazy, obnoxious users who will care. There are other players which are better at optical discs.
* Merge branch 'master' into pr6360Jan Ekström2019-03-111-11/+22
|\ | | | | | | | | | | Manual changes done: * Merged the interface-changes under the already master'd changes. * Moved the hwdec-related option changes to video/decode/vd_lavc.c.
| * demux: make ALBUM ReplayGain tags optional when using libavformatBenjamin Barenblat2019-01-161-11/+22
| | | | | | | | | | | | | | Commit e392d6610d1e35cc0190c794c151211b0aae83e6 modified the native demuxer to use track gain as a fallback for album gain if the latter is not present. This commit makes functionally equivalent changes in the libavformat demuxer.
* | demux_lavf: to get effective HLS bitratewm42018-12-061-1/+80
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | In theory, this could be easily done with custom I/O. In practice, all the halfassed garbage in FFmpeg shits itself and fucks up like there's no tomorrow. There are several problems: 1. FFmpeg pretends you can do custom I/O, but in reality there's a lot that custom I/O can do. hls.c even contains explicit checks to disable important things if custom I/O is used! In particular, you can't use the HTTP keepalive functionality (needed for somewhat decent HLS performance), because some cranky asshole in the cursed FFmpeg dev. community blocked it. 2. The implementation of nested I/O callbacks (io_open/io_close) is bogus and halfassed (like everything in FFmpeg, really). It will call io_open on some URLs without ever calling io_close. Instead, it'll call avio_close() on the context directly. From what I can tell, avio_close() is incompable to custom I/O anyway (overwhelmed by their own garbage, the fFmpeg devs created the io_close callback for this reason, because they couldn't fix their own fucking garbage). This commit adds some shitty workaround for this (technically triggers UB, but with that garbage heap of a library we depend on it's not like it matters). 3. Even then, you can't proxy I/O contexts (see 1.), but we can just keep track of the opened nested I/O contexts. The bytes_read is documented as not public, but reading it is literally the only way to get what we want. A more reasonable approach would probably be using curl. It could transparently handle the keep-alive thing, as well as propagating cookies etc. (which doesn't work with the FFmpeg approach if you use custom I/O). Of course even better if there were an independent HLS implementation anywhere. FFmpeg's HLS support is so embarrassing pathetic and just goes to show that they belong into the past (multimedia from 2000-2010) and should either modernize or fuck off. With FFmpeg's shit-crusted structures, todic communities, and retarded assholes denying progress, probably the latter. Did I already mention that FFmpeg is a shit fucked steaming pile of garbage shit? And all just to get some basic I/O stats, that any proper HLS consumer requires in order to implement adaptive streaming correctly (i.e. browser based players, and nothing FFmshit based).
* | Merg