summaryrefslogtreecommitdiffstats
path: root/demux/demux_timeline.c
Commit message (Collapse)AuthorAgeFilesLines
* Revert "demux: improve stream selection state"Dudemanguy2023-09-301-1/+1
| | | | | | | | The stream selection state wasn't improved. I didn't realize this messed with caches. All in all, just not a good idea. Back to drawing board I guess. This reverts commit f40bbfec4fcd2d9a787a4d98ec7698a646e5607e.
* demux: improve stream selection stateDudemanguy2023-09-271-1/+1
| | | | | | | | | | | | | | | | | | | | | | | This replaces the previous commit and makes more sense. The internal demux marked tracks as eager depending on their type and for subtitles it would always lazily read them unless there happened to be no available av stream. However, we want the sub stream to be eager if the player is paused. The existing subtitle is still preserved on the screen, but if the user changes tracks that's when the problem occurs. So to handle this case, propagate the mpctx->paused down to the stream selection logic. This modifies both demuxer_refresh_track and demuxer_select_track to take that boolean value. A few other parts of the player use this, but we can just assume false there (no change in behavior from before) since they should never be related to subtitles. The core player code is aware of its own state naturally, and can always pass the appropriate value so go ahead and do so. When we change the pause state, a refresh seek is done on all existing subtitle tracks to make sure their eager state is the appropriate value (i.e. so it's not still set to eager after a pause and a track switch). Slightly invasive change, but it works with the existing logic instead of going around it so ultimately it should be a better approach. We can additionally remove the old force boolean from sub_read_packets since it is no longer needed.
* player: add track-list/N/image sub-propertyGuido Cella2021-10-141-0/+1
| | | | | | | | | | | | | | | | | | | | | | This exposes whether a video track is detected as an image, which is useful for profile conditions, property expansion and lavfi-complex. The lavf demuxer sets image to true when the existing check detects an image. When the lavf demuxer fails, the mf one guesses if the file is an image by its extension, so sh->image is set to true when the mf demuxer succeds and there's only one file. The mkv demuxer just sets image to true for any attached picture. The timeline demuxer just copies the value of image from source to destination. This sets image to true for attached pictures, standalone images and images added with !new_stream in EDL playlists, but it is imperfect since you could concatenate multiple images in an EDL playlist (which should be done with the mf demuxer anyway). This is good enough anyway since the comment of the modified function already says it is "Imperfect and arbitrary".
* Revert "player: add track-list/N/image sub-property"Jan Ekström2021-10-021-1/+0
| | | | | | | | Unfortunately, this functionality in large part based on a struct member that was made private in FFmpeg/FFmpeg@7489f632815c98ad58c3db71d1a5239b5dae266c in May. Unfortunately, this was not noticed during review. This reverts commit 0862664ac952d21fef531a8923a58ae575268fc5.
* player: add track-list/N/image sub-propertyGuido Cella2021-10-021-0/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This exposes whether a video track is detected as an image. This is useful for profile conditions, property expansion and lavfi-complex, and is more accurate than any detection even Lua scripts can perform, since they can't differentiate between images and videos without container-fps and audio and with duration 1 (which is the duration set by the mf demuxer with the default --mf-fps=1). The lavf demuxer image check is moved to where the number of frames is available for comparison, and is modified to check the number of frames and duration instead of the video codec. This doesn't misdetect videos in a codec commonly used for images (e.g. mjpeg) as images, and can detect images in a codec commonly used for videos (e.g. 1-frame gifs). pix files are also now detected as images, while before they weren't since the condition was checking if the AVInputFormat name ends with _pipe, and alias_pix doesn't. Both nb_frames and codec_info_nb_frames are checked because nb_frames is 0 for some video codecs (hevc, av1, vc1, mpeg1video, vp9 if forcing --demuxer=lavf), and codec_info_nb_frames is 1 for others (mpeg, mpeg4, wmv3). The duration is checked as well because for some uncommon codecs and containers found in FFMpeg's FATE suite, libavformat returns nb_frames = 0 and codec_info_nb_frames = 1. For some of them it even returns duration = 0, so they are blacklisted in order to never be considered images. The extra codecs that would have to be blacklisted without checking the duration are AV_CODEC_ID_4XM, AV_CODEC_ID_BINKVIDEO, AV_CODEC_ID_DSICINVIDEO, AV_CODEC_ID_ESCAPE130, AV_CODEC_ID_MMVIDEO, AV_CODEC_ID_NUV, AV_CODEC_ID_RL2, AV_CODEC_ID_SMACKVIDEO and AV_CODEC_ID_XAN_WC3, while the containers are film-cpk, ivf and ogg. The lower limit for duration is 10 because that's the duration of 1-frame gifs. Streams with codec_info_nb_frames 0 are not considered images because vp9 and av1 have nb_frames = 0 and codec_info_nb_frames = 0, and we can't rely on just the duration to detect them because they could be livestreams without an initial duration, and actually even if we could for these codecs libavformat returns huge negative durations like -9223372036854775808. Some more images in the FATE suite that are really frames cut from a video in an uncommon codec and container, like cine/bayer_gbrg8.cine, could be detected by allowing codec_info_nb_frames = 0, but then any present and future video codec with nb_frames = 0 and codec_info_nb_frames = 0 would need to be added to the blacklist. Some even have duration > 10, so to detect these images the duration check would have to be removed, and all the previously mentioned extra codecs and containers would have to be added added to the blacklists, which means that images that use them (if they exist anywhere) will never be detected. These FATE images aren't detected as such by mediainfo either anyway, nor can a Lua script reliably detect them as images since they have container-fps and duration > 0 and != 1, and you probably will never see files like them anywhere else. For attached pictures the lavf demuxer always set image to true, which is necessary because they have duration > 10. There is a minor change in behavior for which audio with attached pictures now has mf-fps as container-fps instead of unavailable, but this makes it consistent with external cover art, which was already being assigned mf-fps. When the lavf demuxer fails, the mf one guesses if the file is an image by its extension, so sh->image is set to true when the mf demuxer succeds and there's only one file. Even if you add a video's file type to --mf-type and open it with the mf protocol, only the first frame is used, so setting image to true is still accurate. When converting an image to the extensions listed in demux/demux_mf.c, tga and pam files are currently the only ones detected by the mf demuxer rather than lavf. Actually they are detected with the image2 format, but it is blacklisted; see d0fee0ac33a. The mkv demuxer just sets image to true for any attached picture. The timeline demuxer just copies the value of image from source to destination. This sets image to true for attached pictures, standalone images and images added with !new_stream in EDL playlists, but it is imperfect since you could concatenate multiple images in an EDL playlist (which should be done with the mf demuxer anyway). This is good enough anyway since the comment of the modified function already says it is "Imperfect and arbitrary".
* demux_timeline: fix bad EOF reportingwm42020-02-281-11/+10
| | | | | | | | | | | | | | | | Exposed by commit b56e2efd5f3d. demux_timeline reported a bogus EOF if "parallel" streams were used. If a virtual source reported EOF, it was propagated as global EOF, without serving packets of other virtual sources that have not ended yet. Fix this by not reporting global EOF just because a source has not returned a packet. Instead make the reader retry by returning no packet and no EOF state, which will call d_read_packet() again with a different source. Rely on the eof_reached flags to signal global EOF. Since eof_reached is now more important, set it in a certain other case when it apparently should have been set. do_read_next_packet()'s return value is now ignored, so get rid of it.
* edl: make it possible to delay-load files with multiple trackswm42020-02-211-7/+19
| | | | | | | | | | | | | | Until now, delay-loading was for files with single tracks only (basically what DASH and HLS like to expose, so adaptive streaming and codec selection becomes easier - for sites, not for us). But they also provide some interleaved versions, probably for compatibility. Until now, we were forced to eagerly load it (making startup slightly slower). But there is not much missing. We just need a way to provide multiple metadata entries, and use them to represent each track. A side effect is now that the "track_meta" header can be used for normal EDL files too.
* demux_timeline: don't open every delayed-open track on seekingwm42020-02-201-1/+1
| | | | | | | Now this was stupid. To seek a source, it obviously has to be opened... so just don't try to seek any unused source. If the track is actually selected during playback, a seek to the correct position is performed anyway.
* demux_timeline: warn if streams are invisiblewm42020-02-201-0/+6
| | | | | | | | ytdl_hook.lua can do this with all_formats and when delay_open is used, and if the source stream actually contains both audio and video. In this case, it might accidentally hide a media type completely, or waste bandwidth (if the stream has true interleaved audio/video). So it's important to warn.
* edl: add mechanism for delay loading streamswm42020-02-151-30/+77
| | | | | | | | | | | | | Add something that will access an URL embedded in EDL only when the track it corresponds to is actually selected. This is meant to help with ytdl_hook.lua and to improve loading speeds. In theory, all this stuff is available to any mpv user, but discourage using it, as it's so specialized towards ytdl_hook.lua, that there's danger we'll just break this once ytdl_hook.lua stops using it, or similar. Mostly untested.
* demux_timeline: fix another cursed memory management issuewm42020-02-151-3/+7
| | | | | | | | | | | | | The timeline stuff has messed up memory management because there are no clear ownership rules between a some demuxer instances (master or demux_timeline) and the timeline object itself. This is another subtle problem that happened: apparently, demux_timeline.open is supposed to take over ownership of timeline, but only on success. If it fails, it's not supposed to free it. It didn't follow this, which lead to a double-free if demux_timeline.open failed. The failure path in demux.c calls both timeline_destroy() and demux_timeline.close on failure.
* demux_timeline: fix a commentwm42020-02-151-2/+2
|
* demux_timeline: reorder some functionswm42020-02-151-157/+153
| | | | | | Move them around in the source code to get rid of the forward declarations. Other than rearranging the lines and removing the 2 forward declarations, there are no other changes at all.
* stream, demux: redo origin policy thingwm42019-12-201-0/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | mpv has a very weak and very annoying policy that determines whether a playlist should be used or not. For example, if you play a remote playlist, you usually don't want it to be able to read local filesystem entries. (Although for a media player the impact is small I guess.) It's weak and annoying as in that it does not prevent certain cases which could be interpreted as bad in some cases, such as allowing playlists on the local filesystem to reference remote URLs. It probably barely makes sense, but we just want to exclude some other "definitely not a good idea" things, all while playlists generally just work, so whatever. The policy is: - from the command line anything is played - local playlists can reference anything except "unsafe" streams ("unsafe" means special stream inputs like libavfilter graphs) - remote playlists can reference only remote URLs - things like "memory://" and archives are "transparent" to this This commit does... something. It replaces the weird stream flags with a slightly clearer "origin" value, which is now consequently passed down and used everywhere. It fixes some deviations from the described policy. I wanted to force archives to reference only content within them, but this would probably have been more complicated (or required different abstractions), and I'm too lazy to figure it out, so archives are now "transparent" (playlists within archives behave the same outside). There may be a lot of bugs in this. This is unfortunately a very noisy commit because: - every stream open call now needs to pass the origin - so does every demuxer open call (=> params param. gets mandatory) - most stream were changed to provide the "origin" value - the origin value needed to be passed along in a lot of places - I was too lazy to split the commit Fixes: #7274
* demux: do not make up demuxer_idwm42019-12-031-1/+1
| | | | | | | | | | | | | | | | | | The demuxer_id (exported in as "src-id" property) is supposed to be the native stream ID, as it exists in the file, or -1 if that does not exist (actually any negative value), or if it is unknown. Until now, an ID was made up if it was missing. That seems like strange non-sense, and I can't find the reason why it was done. But it was probably for convenience by the EDL stuff or so. Stop doing this. Fortunately, the src-id property was documented as being unavailable if the ID is not known. Even the code for this was present, it was just inactive until now. Extend input.rst with some explanations. Also fixing 3 other places where negative demuxer_id was ignored or avoided.
* demux_timeline, demux_edl: correctly enable cache in pseudo-DASH modewm42019-10-081-0/+3
| | | | | | | | | | | | | | | | | | In pseudo-DASH mode, we may have no real streams opened until the demuxer layer is fully loaded and playback actually starts. The only hint that the stream is from network is, at that point, the init segment, which is only opened as stream, and then separately as demuxer (which is dumb but happened to fit the internal architecture better). So just propagate the flags from the init segment stream. Seems like an annoyance, but doesn't hurt that much I guess. (Until someone gets the idea to pass the init segment data inline or so, but nothing does that.) The sample link in the linked issue will probably soon switch to another format, because that service always does this after recent uploads or so. Fixes: #7038
* demux: propagate streaming flag through demux_timelinewm42019-09-201-1/+4
| | | | | | | | | | | | | | Before this commit, EDL or CUE files did not properly enable the cache if they were on "slow" media (stream->streaming==true). This happened because the stream is unset for demux_timeline, so the streaming flag could not be queried anymore. Fix this by adding this flag to struct demuxer, and propagate it exactly like the is_network flag. is_network is not used for checking the cache options anymore, and its main function seems to be something else. Normal http streams set the streaming flag already. This should fix #6958.
* demux: refactor cache range init/deinitwm42019-09-191-6/+2
| | | | | | | | | | | | | | | | | | | | 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_timeline: add heuristic to fix shifted seeks with separate audiowm42019-09-191-11/+80
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | If you have a EDL stream with separate sources for audio and video stream (like ytdl_hook now creates), you can get the problem that the video stream seeks to a different position than audio due to different key frame granularity. In particular, if you seek backward, the video might undershoot the seek target by a lot. Then video will resume from an earlier position than audio, and the player plays silence. This is annoying. Fix this by explicitly implementing a heuristic to detect separate audio/video streams, determining where a video seek ends up, and then seeking the audio stream to the video destination. This also makes sure to not seek audio with SEEK_FORWARD, so it will always seek before the video position. Non-precise seeks still skip audio to the video target, so this helps with ensuring that audio is present at the final seek target. The implementation is very annoying, because the only way to determine the seek target is to actually read a packet. Thus a 1-packet queue needs to be added. In theory, we could get the seek target from the index of the video file (especially if it's mp4), but libavformat does not have public API that exports this index, so we're stuck with this roundabout generic method. Note that this is only for non-precise seeks. If precise seeks are done, the problem is handled by the frontend by skipping unwanted video frames. But non-precise seeking should still work. (Personally I prefer non-precise seek mode by default because they're still significantly faster.) It also needs to be said that this is the 4th implementation of this seek adjustment thing in mpv. The 1st implementation is in the frontend (look for MPContext.seek_slave). This works only if the external audio stream is known as such on the frontend level. The 2nd implementation is in the demuxer level packet cache (top of execute_cache_seek()). This is similar to code that any demuxer needs to handle non-precise seeks sufficiently nicely. The 3rd is in demux_mkv.c. Since mkv is an interleaved format, this implementation mostly consists on trying to pick index entries for video packets if a video stream is selected. Maybe these "redundant" implementations could be avoided by exposing separate streams through the demuxer API (and making them individually seekable) or something like this, but this is messy and not without problems for multiple reasons. So for now this commit is the best way to fix the observed behavior.
* demux_edl, cue, mkv: slightly nicer file format indicationwm42019-09-191-2/+2
| | | | | | | | | | | | | Instead of just using "edl/" for the file format, report mkv_oc if it's generated from ordered chapters, "cue/" if from .cue, "multi/" if it's from EDL but only for adding separate streams, "dash/" if it's from EDL but only using the DASH hack, and "edl/" for everything else. The EDL variants are mostly special-cased to the variants the ytdl wrapper usually generates. This has no effect other than what the command.c file-format property returns.
* demux_edl, cue, mkv: clean up timeline stuff slightlywm42019-09-191-13/+24
| | | | | | | | | | | | | | | | | | | | | Remove the singly linked list hack, replace it with a slightly more proper data structure. This probably gets rid of a few minor bugs along the way, caused by the awkward nonsensical sharing/duplication of some fields. Another change (because I'm touching everything related to timeline anyway) is that I'm removing the special semantics for parts[num_parts]. This is now strictly out of bounds, and instead of using the start time of the next/beyond-last part, there is an end time field now. Unfortunately, this also requires touching the code for cue and mkv ordered chapters. From some superficial testing, they still seem to mostly work. One observable change is that the "no_chapters" header is per-stream now, which is arguably more correct, and getting the old behavior would require adding code to handle it as special-case, so just adjust ytdl_hook.lua to the new behavior.
* demux_edl: add no_clipwm42019-09-191-6/+7
| | | | | | Used by the next commit. It mostly exposes part of mp4_dash functionality. It actually makes little sense other than for ytdl special-use. See next commit.
* demux_timeline: include "dash" hint in reported file formatwm42019-09-191-1/+2
|
* demux_timeline: disable end-of-segment handling in DASH modewm42019-09-191-2/+2
| | | | | | | | Normal EDL needs to clip packets coming from the underlying demuxer to the segment range (including complicated stuff due to frame reordering). This is unwanted In pseudo-DASH mode. A broken or subtly incorrect manifest would lead to "bad stuff" happening. The intention of the pseudo-DASH mode is to literally concatenate fragments.
* demux_timeline: report network speed of slave connectionswm42019-09-191-1/+15
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | demux_timeline doesn't do any transport accesses itself. The slave demuxers do this (these will actually access the stream layer and perform e.g. network accesses). As a consequence, demux_timeline always reported 0 bytes read, and network speed display didn't work. Fix this by awkwardly reporting the amount of read bytes upwards. This is not very nice, and requires explicit calls whenever the slave "might" have read data. Due to the way the reporting is done, it only works if the slaves do not run demuxer threads, which makes things even less nice. (Fortunately they don't anyway, because it would be a waste of resources.) Some identifiers contain the word "hack" as a warning. Some of the stupidity comes from the fact that demux.c itself resets the stats randomly in order to calculate the bytes_per_second value, which is useless for a slave, but of course is still done, because demux.c itself is not aware of whether it's on the slave or top-level layer. Unfortunately, this must do. In theory, the demuxer thread/cache layer should be separated from demuxer implementations. This would get rid of all the awkwardness and nonsense. For example, the only threading involved would be the caching layer, completely separate from demuxers themselves. It'd be the only thing calculates speed rates for the player frontend, too (instead of doing it for each demuxer, even if unused).
* demux, demux_edl: add extension for tracks sourced from separate streamswm42019-09-191-137/+241
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This commit adds an extension to mpv EDL, which basically allows you to do the same as --audio-file, --external-file, etc. in a single EDL file. This is a relatively quick & dirty implementation. The dirty part lies in the fact that several shortcuts are taken. For example, struct timeline now forms a singly linked list, which is really weird, but also means the other timeline using demuxers (cue, mkv) don't need to be touched. Also, memory management becomes even worse (weird object ownership rules that are just fragile WTFs). There are some other dubious small changes, mostly related to the weird representation of separate streams. demux_timeline.c contains the actual implementation of the separate stream handling. For the most part, most things that used to be on the top level are now in struct virtual_source, of which one for each separate stream exists. This is basically like running multiple demux_edl.c in parallel. Some changes could strictly speaking be split into a separate commit, such as the stream_map type change. Mostly untested. Seems to work for the intended purpose. Potential for regressions for other timeline uses (like ordered chapters) is probably low. One thing which could definitely break and which I didn't test is the pseudo-DASH fragmented EDL code, of which ytdl can trigger various forms in obscure situations. (Uh why don't we have a test suite.) Background: The intention is to use this for the ytdl wrapper. A certain streaming site from a particularly brain damaged and plain evil Silicon Valley company usually provides streams as separate audio and video streams. The ytdl wrapper simply does use audio-add (i.e. adding it as external track, like with --audio-file), which works mostly fine. Unfortunately, mpv manages caching completely separately for external files. This has the following potential problems: 1. Seek ranges are rendered incorrectly. They always use the "main" stream, in this case the video stream. E.g. clicking into a cached range on the OSC could trigger a low level seek if the audio stream is actually not cached at the target position. 2. The stream cache bloats unnecessarily. Each stream may allocate the full configured maximum cache size, which is not what the user intends to do. Cached ranges are not pruned the same way, which creates disjoint cache ranges, which only use memory and won't help with fast seeking or playback. 3. mpv will try to aggressively read from both streams. This is done from different threads, with no regard which stream is more important. So it might happen that one stream starves the other one, especially if they have different bitrates. 4. Every stream will use a separate thread, which is an unnecessary waste of system resources. In theory, the following solutions are available (this commit works towards D): A. Centrally manage reading and caching of all streams. A single thread would do all I/O, and decide from which stream it should read next. As long as the total TCP/socket buffering is not too high, this should be effective to avoid starvation issues. This can also manage the cached ranges better. It would also get rid of the quite useless additional demuxer threads. This solution is conceptually simple, but requires refactoring the entire demuxer middle layer. B. Attempt to coordinate the demuxer threads. This would maintain a shared cache and readahead state to solve the mentioned problems explicitly. While this sounds simple and like an incremental change, it's probably hard to implement, creates more messy special cases, solution A. seems just a better and simpler variant of this. (On the other hand, A. requires refactoring more code.) C. Render an intersection of the seek ranges across all streams. This fixes only problem 1. D. Merge all streams in a dedicated wrapper demuxer. The general demuxer layer remains unchanged, and reading from separate streams is handled as special case. This effectively achieves the same as A. In particular, caching is simply handled by the usual demuxer cache layer, which sees the wrapper demuxer as a single stream of interleaved packets. One implementation variant of this is to reuse the EDL infrastructure, which this commit does. All in all, solution A would be preferable, because it's cleaner and works for all external streams in general. Some previous commit tried to prepare for implementing solution A. This could still happen. But it could take years until this is finally seriously started and finished. In any case, this commit doesn't block or complicate such attempts, which is also why it's the way to go. It's worth mentioning that original mplayer handles external files by creating a wrapper demuxer. This is like a less ideal mixture of A. and D. (The similarity with A. is that extending the mplayer approach to be fully dynamic and without certain disadvantages caused by the wrapper would end up with A. anyway. The similarity with D. is that due to the wrapper, no higher level code needs to be changed.)
* demux: get rid of ->control callbackwm42019-09-191-8/+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_timeline: fix off by one error, rearrange weird codewm42019-09-191-4/+4
| | | | | | | | | | This code set pkt->stream to a value which I'm not sure whether it's correct. A recent commit overwrote it with a value that is definitely correct. There appears to be an off by one error. No fucking clue whether this was somehow correct, but applying an apparent fix does not seem to break anything, so whatever.
* demux: return packets directly from demuxer instead of using sh_streamwm42019-09-191-8/+9
| | | | | | | Preparation for other potential changes to separate demuxer cache/thread and actual demuxers. Most things are untested, but it seems to work somewhat.
* demux: get rid of free_demuxer[_and_stream]()wm42018-05-241-2/+2
| | | | | | | Them being separate is just dumb. Replace them with a single demux_free() function, and free its stream by default. Not freeing the stream is only needed in 1 special case (demux_disc.c), use a special flag to not free the stream in this case.
* demux: add a "cancel" fieldwm4