summaryrefslogtreecommitdiffstats
path: root/filters/f_decoder_wrapper.c
Commit message (Collapse)AuthorAgeFilesLines
* player: let frontend decide whether to use cover-art modewm42020-09-281-6/+16
| | | | | | | | | | | | | Essentially, this lets video.c decide whether to consider a video track cover art, instead of having the decoder wrapper use the lower level sh_stream flag. Some pain because of the dumb threading shit. Moving the code further down to make some of it part of the lock should not change behavior, although it could (framedrop nonsense). This commit should not change actual behavior, and is only preparation for the following commit.
* f_decoder_wrapper: make log prefix less verbosewm42020-09-201-2/+2
|
* f_decoder_wrapper: pass through EOF after EOFwm42020-08-271-0/+7
| | | | | | | | | It's relevant in some obscure corner cases (EDL file that has a segment without audio). Didn't test what's actually going on (is ad_lavc.c behaving wrong? is libavcodec behaving wrong or in an unexpected way? is lavc_process wrong?) and just patched it over with some bullshit, so the fix might be too complicated, and could be reworked at some later point. This sure is a real data flow fuckmess.
* f_decoder_wrapper: fix use of destroyed mutexwm42020-03-181-0/+2
| | | | | | | | | After calling the main filter's destroy callback, all child filters are destroyed. But one of them still tried to access the cache_lock mutex (which is destroyed in said destroy callback). This actually caused a crash on Android with _FORTIFY_SOURCE. Fix this by destroying the child filters first.
* options: fix OPT_BYTE_SIZE upper limitswm42020-03-181-3/+3
| | | | | | | | | | | | | | | | | | | | | | | | As an unfortunate disaster, min/max values use the type double, which causes tons of issues with int64_t types. Anyway, OPT_BYTE_SIZE is often used as maximum for size_t quantities, which can have a size different from (u)int64_t. OPT_BYTE_SIZE still uses in64_t, because in theory, you could use it for file sizes. (demux.c would for example be capable of caching more than 2GB on 32 bit platforms if a file cache is used. Though for some reason the accounting code still uses size_t, so that use case is broken. But still insist that it _could_ be used this way.) There were various inconsistent attempts to set m_option.max to a value such that the size_t/int64_t upper limit is not exceeded. Due to the double max field, this didn't really work correctly. Try to fix this with the M_MAX_MEM_BYTES constant. It's a good approximation, because on 32 bit it should allow 2GB (untested, also would probably exhaust address space in practice but whatever), and something "high enough" in 64 bit. For some reason, clang 11 still warns. But I think this might be a clang bug, or I'm crazy. The result is correct anyway.
* options: change option macros and all option declarationswm42020-03-181-19/+22
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Change all OPT_* macros such that they don't define the entire m_option initializer, and instead expand only to a part of it, which sets certain fields. This requires changing almost every option declaration, because they all use these macros. A declaration now always starts with {"name", ... followed by designated initializers only (possibly wrapped in macros). The OPT_* macros now initialize the .offset and .type fields only, sometimes also .priv and others. I think this change makes the option macros less tricky. The old code had to stuff everything into macro arguments (and attempted to allow setting arbitrary fields by letting the user pass designated initializers in the vararg parts). Some of this was made messy due to C99 and C11 not allowing 0-sized varargs with ',' removal. It's also possible that this change is pointless, other than cosmetic preferences. Not too happy about some things. For example, the OPT_CHOICE() indentation I applied looks a bit ugly. Much of this change was done with regex search&replace, but some places required manual editing. In particular, code in "obscure" areas (which I didn't include in compilation) might be broken now. In wayland_common.c the author of some option declarations confused the flags parameter with the default value (though the default value was also properly set below). I fixed this with this change.
* options: change how option range min/max is handledwm42020-03-131-4/+5
| | | | | | | | | | | | | | | | | Before this commit, option declarations used M_OPT_MIN/M_OPT_MAX (and some other identifiers based on these) to signal whether an option had min/max values. Remove these flags, and make it use a range implicitly on the condition if min<max is true. This requires care in all cases when only M_OPT_MIN or M_OPT_MAX were set (instead of both). Generally, the commit replaces all these instances with using DBL_MAX/DBL_MIN for the "unset" part of the range. This also happens to fix some cases where you could pass over-large values to integer options, which were silently truncated, but now cause an error. This commit has some higher potential for regressions.
* filter: minor cosmetic naming issuewm42020-03-081-2/+2
| | | | | Just putting some more lipstick on the pig, maybe it looks a bit nicer now.
* f_decoder_wrapper: make decoder thread responsive while filling queuewm42020-03-051-0/+8
| | | | | | | | | | | | | | | | | | | | | | | | | | The mp_filter_run() invocation blocks as long as the demuxer provides packets and the queue can be filled. That means it may block quite a long time of the decoder queue size is large (since we use libavcodec in a blocking manner; it regrettably does not have an async. API). This made the main thread freeze in certain situations, because it has to wait on the decoder thread. Other than I suspected (I wrote that code, but that doesn't mean I know how the hell it works), this did not freeze during seeking: seek resets flushed the queue, which also prevented the decoder thread from adding more frames to it, thus stopping decoding and responding to the main thread in time. But it does fix the issue that exiting the player waited for the decoder to finish filling the queue when stopping playback. (This happened because it called mp_decoder_wrapper_set_play_dir() before any resets. Related to the somewhat messy way play_dir is generally set. But it affects all "synchronous" decoder wrapper API calls.) This uses pretty weird mechanisms in filter.h and dispatch.h. The resulting durr hurr interactions are probably hard to follow, and this whole thing is a sin. On the other hand, this is a _very_ user visible issue, and I'm happy that it can be fixed in such an unintrusive way.
* f_decoder_wrapper: use proper log prefix for all involved filterswm42020-03-051-1/+1
| | | | | | p->log has a prefix set that gives some context and distinguishes audio and video decoders. The "public" wrapper filter didn't use it, which is a regression since commit a3823ce0e03.
* f_decoder_wrapper: enable DR and hwdec with --vd-queue-enablewm42020-03-051-0/+10
| | | | | | | | | | | | | | This was forgotten. Hardware decoding typically breaks immediately, because many hw decoding APIs require allocating all surfaces in advance (and/or libavcodec was not made flexible enough to add new surfaces later). If the queue is large enough, it will run out of surfaces, fail decoding, and fall back to software decoding. We consider this the user's fault. --hwdec-extra-frames can be used to avoid this, if you have enough GPU memory, and the needed number of frames is lower than the arbitrary mpv-set maximum limit of that option.
* f_decoder_wrapper: make most queue options runtime changeablewm42020-03-011-13/+21
| | | | Why not.
* options: make decoder options local to decoder wrapperwm42020-03-011-19/+90
| | | | | | | | | | | | | | | Instead of having f_decoder_wrapper create its own copy of the entire mpv option tree, create a struct local to that file and move all used options to there. movie_aspect is used by the "video-aspect" deprecated property code. I think it's probably better not to remove the property yet, but fortunately it's easy to work around without needing special handling for this option or so. correct_pts is used to prevent use of hr-seek in playloop.c. Ignore that, if you use --no-correct-pts you're asking for trouble anyway. This is the only behavior change.
* player: add optional separate video decoding threadwm42020-02-291-54/+325
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | See manpage additions. This has been a topic in MPlayer/mplayer2/mpv since forever. But since libavcodec multi-threaded decoding was added, I've always considered this pointless. libavcodec requires you to "preload" it with packets, and then you can pretty much avoid blocking on it, if decoding is fast enough. But in some cases, a decoupled decoder thread _might_ help. Users have for example come up with cases where decoding video in a separate process and piping it as raw video to mpv helped. (Or my memory is false, and it was about vapoursynth filtering, who knows.) So let's just see whether this helps with anything. Note that this would have been _much_ easier if libavcodec had an asynchronous (or rather, non-blocking) API. It could probably have easily gained that with a small change to its multi-threading code and a small extension to its API, but I guess not. Unfortunately, this uglifies f_decoder_wrapper quite a lot. Part of this is due to annoying corner cases like legacy frame dropping and hardware decoder state. These could probably be prettified later on. There is also a change in playloop.c: this is because there is a need to coordinate playback resets between demuxer thread, decoder thread, and playback logic. I think this SEEK_BLOCK idea worked out reasonably well. There are still a number of problems. For example, if the demuxer cache is full, the decoder thread will simply block hard until the output queue is full, which interferes with seeking. Could also be improved later. Hardware decoding will probably die in a fire, because it will run out of surfaces quickly. We could reduce the queue to size 1... maybe later. We could update the queue options at runtime easily, but currently I'm not going to bother. I could only have put the lavc wrapper itself on a separate thread. But there is some annoying interaction with EDL and backward playback shit, and also you would have had to loop demuxer packets through the playloop, so this sounded less annoying. The food my mother made for us today was delicious. Because audio uses the same code, also for audio (even if completely pointless). Fixes: #6926
* f_decoder_wrapper: replace most public fields with setters/getterswm42020-02-291-28/+81
| | | | | | | | | | | | | | | | | | | I may (optionally) move decoding to a separate thread in a future change. It's a bit attractive to move the entire decoder wrapper to there, so if the demuxer has a new packet, it doesn't have to wake up the main thread, and can directly wake up the decoder. (Although that's bullshit, since there's a queue in between, and libavcodec's multi-threaded decoding plays cross-threads ping pong with packets anyway. On the other hand, the main thread would still have to shuffle the packets around, so whatever, just seems like better design.) As preparation, there shouldn't be any mutable state exposed by the wrapper. But there's still a large number of corner-caseish crap, so just use setters/getters for them. This recorder thing will inherently not work, so it'll have to be disabled if threads are used. This is a bit painful, but probably still the right thing. Like speculatively pulling teeth.
* f_decoder_wrapper, sd_add: accept "null" codecwm42020-02-151-1/+7
| | | | | | | | | | | | | This is for easier use with the "delay_open" feature added in the previous commit. The "null" codec is reported if the codec is unknown (because the stream was not opened yet at time the tracks were added). The rest of the timeline mechanism will set the correct codec at runtime. But this means every time a delay-loaded track is selected, it wants to initialize a decoder for the "null" codec. Accept a "null" decoder. But since FFmpeg has no such codec, and out of my own laziness, just let it fall back to "common" codecs that need no other initialization data.
* options: get rid of GLOBAL_CONFIG hackwm42019-11-291-1/+1
| | | | | | | Just an implementation detail that can be cleaned up now. Internally, m_config maintains a tree of m_sub_options structs, except for the root it was not defined explicitly. GLOBAL_CONFIG was a hack to get access to it anyway. Define it explicitly instead.
* f_decoder_wrapper: put coverart through image output logicwm42019-11-171-2/+4
| | | | | | This wasn't done, probably regression from one of the last dozen of times this special code path was touched. This meant coverart images ignored the user-set aspect ratio completely, and some other things.
* vd_lavc: simplify fallback handling for full stream hw decoderwm42019-11-021-1/+1
| | | | | | | | | | | | Shovel the code around to make the data flow slightly simpler (?). At least there's only one send_packet function now. The old code had the problem that send_packet() could be called even if there were queued packets; due to sending the queued packets in the receive_frame function, this should not happen anymore (the code checking for this case in send_packet should normally never be called). Untested with actual full stream hw decoders (none available here); I created a test case by making hwaccel decoding fail.
* f_decoder_wrapper: reduce uninit message log levelwm42019-11-011-1/+1
| | | | For vd/ad.
* f_decoder_wapper: trust frame return over error codewm42019-10-251-5/+5
| | | | | | | | | | | | | | | | | lavc_process() calls the receive/send callbacks, which mirror libavcodec's send/receive API. The receive API in particular can return both a status code and a frame. Normally, libavcodec is pretty explicit that it can't return both a frame and an error. But the receive callback does more stuff in addition (vd_lavc does hardware decoding fallbacks etc.). The previous commit shows an instance where this happened, and where it leaked a frame in this case. For robustness, check whether the frame is set first, i.e. trust it over the status code. Before this, it checked for an EOF status first. Hopefully is of no consequence otherwise. I made this change after testing everything (can someone implement a test suite which tests this exhaustively).
* ad_lavc, vd_lavc: return full error codes to shared decoder loopwm42019-10-241-9/+15
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | ad_lavc and vd_lavc use the lavc_process() helper to translate the FFmpeg push/pull API to the internal filter API (which completely mismatch, even though I'm responsible for both, just fucking kill me). This interface was "slightly" too tight. It returned only a bool indicating "progress", which was not enough to handle some cases (see following commit). While we're at it, move all state into a struct. This is only a single bool, but we get the chance to add more if needed. This fixes mpv falling asleep if decoding returns an error during draining. If decoding fails when we already sent EOF, the state machine stopped making progress. This left mpv just sitting around and doing nothing. A test case can be created with: echo $RANDOM >> image.png This makes libavformat read a proper packet plus a packet of garbage. libavcodec will decode a frame, and then return an error code. The lavc_process() wrapper could not deal with this, because there was no way to differentiate between "retry" and "send new packet". Normally, it would send a new packet, so decoding would make progress anyway. If there was "progress", we couldn't just retry, because it'd retry forever. This is made worse by the fact that it tries to decode at least two frames before starting display, meaning it will "sit around and do nothing" before the picture is displayed. Change it so that on error return, "receiving" a frame is retried. This will make it return the EOF, so everything works properly. This is a high-risk change, because all these funny bullshit exceptions for hardware decoding are in the way, and I didn't retest them. For example, if hardware decoding is enabled, it keeps a list of packets, that are fed into the decoder again if hardware decoding fails, and a software fallback is performed. Another case of horrifying accidental complexity. Fixes: #6618
* video, demux: rip out unused spherical metadata codewm42019-10-171-4/+0
| | | | | | This was preparation into something that never happened. Spherical video is a shit idea anyway.
* f_decoder_wrapper: fix initialization statewm42019-09-191-0/+2
| | | | | | | | | | | Some state wasn't reset when decoding was started without a seek reset before it. The code used to rely on reset_decoder() resetting this state, but since the commit referenced below, reset_decoder() does less than reset(). Fix this by explicitly calling reset() on initialization. Fixes: "f_decoder_wrapper: avoid full reset on timeline switch etc."
* f_decoder_wrapper: reorganize, fix EDL/ordered chapters backward playbackwm42019-09-191-115/+136
| | | | | | | | | | | | | | | | | | | | | | | Before this commit, there was a single process_decoded_frame() function. It handled various aspects of dealing with a newly decoded frame. Move some of these to a separate process_output_frame() function. This new function is called in the order the frames are returned to the playback core. Some correct_audio_pts() (was process_audio_frame()) becomes slightly less awkward due to this, and the timestamp smoothing can actually work in backward playback mode now (thus moving p->pts out of reset_decoder()). Behavior for normal playback also changes subtly. This shouldn't matter in sane cases, but if you mix broken files, --no-correct-pts, and timeline stuff, differences in behavior might be visible. Timeline clipping (EDL/ordered chapters) works now, because it's done before "transforming" the timestamps. Audio timestamp smoothing happens after it, which is a behavior change, but should be more correct. This still runs crazy_video_pts_stuff() before everything else. On the pther hand, --no-correct-pts or missing timestamp processing is done last. But these things didn't really work with timeline before.
* f_decoder_wrapper: avoid full reset on timeline switch etc.wm42019-09-191-20/+19
| | | | | | | | Slightly cleaner. We don't need to awkwardly backup "some" state on backwards playback. Due to not resetting last_format, normal timeline switches don't unconditionally trigger recomputing of certain image parameters. Also probably doesn't reset framedrop parameters, although I don't care about that part.
* f_decoder_wrapper: fully reset timestamp fixup logic on seekswm42019-09-191-0/+4
| | | | | | | | | | | | | This could lead to nonsense when backward playback is involved. Better reduce the possible interactions. Besides, it's better to fully reset things on seeks in general. The only exception is has_broken_packet_pts, which enables hr-seek if everything looks good. It's intended to trigger at the second hr-seek or so if the file is normal, and to disable it if the file is broken. It tries to avoid enabling the hr-seek logic before it can know about whether things are "good", so resetting it on seeks would obviously never enable it. Document it as explicit exception.
* f_decoder_wrapper: move option update to a common entrypointwm42019-09-191-3/+1
| | | | | process() calls these functions. It's a much better place to potentially copy changed option values into the cache struct.
* f_decoder_wrapper: hack for discarding preroll in backward playback modewm42019-09-191-11/+15
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Some audio codecs will discard or cut the first frames when starting decoding. While some of that works through well-defined mechanisms (like initial padding), it's in general very codec/decoder specific, and not really predictable. In addition, libavcodec isn't very good with reporting "dropped" frames (and our internal interface reflects this). It seems our only chance to handle this is through timestamps. In theory, it would be best to discard frames that have timestamps before the "resume" position. But since video has reordered timestamps, we'd need to put some effort into finding this position. The first video packet doesn't necessarily contain this timestamp. (In theory, we could just do this in the demuxer with some trivial additional work, and set it on the packet's kf_seek_pts field. Although this field is supposed to contain just this value, the field is considered demuxer-internal, and I didn't want to make matters worse by reusing it for the interface to the decoder. With some more effort and buffering, we could calculate this value within the decoder, but fuck that.) The approach chosen in this commit is setting the timestamp to NOPTS. This will break in some obscure situations, but backward playback is a pretty obscure feature to begin with, so I considered this a reasonable implementation choice. Before passing a preroll packet to the decoder, its timestamps are set to NOPTS. Frames that are returned from the decoder and have the NOPTS timestamp are considered preroll and are discarded. This happens only during "preroll" mode (preroll_discard==true), so it doesn't affect normal forward playback. It's disabled on the first packet with a timestamp, so it can tolerate some crap even in backward playback mode. We don't check the dts fields out of laziness (decoded audio frames don't even have this field). I considered using an approach using the EDL clipping infrastructure (as mentioned in the last two paragraphs in the commit message of commit " demux_lavf: implement bad hack for backward playback of wav"). This didn't work, and I blamed timestamp rounding within mpv for it. But the problem was actually due to Matroska-rounded timestamps. Since the audio frame size isn't exactly aligned to 1ms, there will be an overlap (or gap) in the timestamps. This overlap is much smaller than 1ms, since it's just the sub-millisecond remainder part of the audio frame size. This makes the timestamps discontinuous and unreliable for the purpose we wanted to use it. We can't just smooth the timestamps in the demuxer either.
* f_decoder_wrapper: remove stale/duplicated commentwm42019-09-191-2/+0
|
* demux, f_decoder_wrapper: fix coverart in backward modewm42019-09-191-2/+6
| | | | | | | | | | | | Shitty ancient hack that wastes my time all the time. demux.c: always return the coverart packet as soon as possible, and don't let the backward demux state machine possibly stop it. f_decoder_wrapper.c: mess with some shit until it somehow starts to work. I think the old code tried to let it cleverly fall through so the packet was processed "normally"; just make it run the "usual" code instead.
* Implement backwards playbackwm42019-09-191-13/+115
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | See manpage additions. This is a huge hack. You can bet there are shit tons of bugs. It's literally forcing square pegs into round holes. Hopefully, the manpage wall of text makes it clear enough that the whole shit can easily crash and burn. (Although it shouldn't literally crash. That would be a bug. It possibly _could_ start a fire by entering some sort of endless loop, not a literal one, just something where it tries to do work without making progress.) (Some obvious bugs I simply ignored for this initial version, but there's a number of potential bugs I can't even imagine. Normal playback should remain completely unaffected, though.) How this works is also described in the manpage. Basically, we demux in reverse, then we decode in reverse, then we render in reverse. The decoding part is the simplest: just reorder the decoder output. This weirdly integrates with the timeline/ordered chapter code, which also has special requirements on feeding the packets to the decoder in a non-straightforward way (it doesn't conflict, although a bugmessmass breaks correct slicing of segments, so EDL/ordered chapter playback is broken in backward direction). Backward demuxing is pretty involved. In theory, it could be much easier: simply iterating the usual demuxer output backward. But this just doesn't fit into our code, so there's a cthulhu nightmare of shit. To be specific, each stream (audio, video) is reversed separately. At least this means we can do backward playback within cached content (for example, you could play backwards in a live stream; on that note, it disables prefetching, which would lead to losing new live video, but this could be avoided). The fuckmess also meant that I didn't bother trying to support subtitles. Subtitles are a problem because they're "sparse" streams. They need to be "passively" demuxed: you don't try to read a subtitle packet, you demux audio and video, and then look whether there was a subtitle packet. This means to get subtitles for a time range, you need to know that you demuxed video and audio over this range, which becomes pretty messy when you demux audio and video backwards separately. Backward display is the most weird (and potentially buggy) part. To avoid that we need to touch a LOT of timing code, we negate all timestamps. The basic idea is that due to the navigation, all comparisons and subtractions of timestamps keep working, and you don't need to touch every single of them to "reverse" them. E.g.: bool before = pts_a < pts_b; would need to be: bool before = forward ? pts_a < pts_b : pts_a > pts_b; or: bool before = pts_a * dir < pts_b * dir; or if you, as it's implemented now, just do this after decoding: pts_a *= dir; pts_b *= dir; and then in the normal timing/renderer code: bool before = pts_a < pts_b; Consequently, we don't need many changes in the latter code. But some assumptions inhererently true for forward playback may have been broken anyway. What is mainly needed is fixing places where values are passed between positive and negative "domains". For example, seeking and timestamp user display always uses positive timestamps. The main mess is that it's not obvious which domain a given variable should or does use. Well, in my tests with a single file, it suddenly started to work when I did this. I'm honestly surprised that it did, and that I didn't have to change a single line in the timing code past decoder (just something minor to make external/cached text subtitles display). I committed it immediately while avoiding thinking about it. But there really likely are subtle problems of all sorts. As far as I'm aware, gstreamer also supports backward playback. When I looked at this years ago, I couldn't find a way to actually try this, and I didn't revisit it now. Back then I also read talk slides from the person who implemented it, and I'm not sure if and which ideas I might have taken from it. It's possible that the timestamp reversal is inspired by it, but I didn't check. (I think it claimed that it could avoid large changes by changing a sign?) VapourSynth has some sort of reverse function, which provides a backward view on a video. The function itself is trivial to implement, as VapourSynth aims to provide random access to video by frame numbers (so you just request decreasing frame numbers). From what I remember, it wasn't exactly fluid, but it worked. It's implemented by creating an index, and seeking to the target on demand, and a bunch of caching. mpv could use it, but it would either require using VapourSynth as demuxer and decoder for everything, or replacing the current file every time something is supposed to be played backwards. FFmpeg's libavfilter has reversal filters for audio and video. These require buffering the entire media data of the file, and don't really fit into mpv's architecture. It could be used by playing a libavfilter graph that also demuxes, but that's like VapourSynth but worse.
* f_decoder_wrapper: move cover art retrievalwm42019-09-191-5/+5
| | | | | This is basically a refactor in preparation for future changes and shouldn't have much influence on actual behavior