The options parameter here can be NULL. It's NULL checked a few lines down,
but not for the propagate_opts loop. This results in null derefence with
--demuxer-lavf-format=image2.
Fixes: b6413f82b2
There are jpg files out there that have extra embedded metadata
(pictures from smartphones commonly have an embedded gain map). ffmpeg
doesn't currently support this, so mpv currently sees the extra metadata
as essentially another frame. This results in weird video-like behavior.
Until ffmpeg support this more properly, we can work around this by
simply discarding extra packets and not sending the new frame to the
internal playloop. If demux_lavf detects that the stream is a
single-frame jpg, then we only accepts the packet at pos 0. Anything
else is discarded. Ref #13192.
Passing jpg filenames to ffmpeg is actually quite bad. This causes all
jpg images (at least in my testing) to be probed as image2 which is
blacklisted in demux_lavf since it's completely broken (see commit
74e62ed2d1 for some details). What happens
in practice is that the lavf demxuer fails and the it opens in the mf
demuxer instead. This is OK for simple viewing, but because that demuxer
is limited, many specific file properities and other things are
completely unavailable which breaks any script that may depend on them
(e.g. width, height, etc.) For the small subset of files that this
commit appeared to "fix" (in reality, it just fell back to the mf
demuxer) is not worth breaking property usage in the vast majority of
normal proper files. Ideally ffmpeg should fix this but some other
workaround on our end can be used instead.
This reverts commit d0aeca5918.
avif files will commonly be probed as "mov,mp4,m4a,3gp,3g2,mj2" by
ffmpeg, but demux_lavf currently has some logic to skip
avformat_find_stream_info for these kinds of files. It was introduced in
6f8c953042. Presumably, the optimization
of mentioned in that commit is still valid however for avif we
specifically need to do the avformat_find_stream_info call. Without it,
several codec proprieties like width, height, etc. are unavailable. So
just check the extension type and disable the skipinfo optimization.
Remove this "hack" from 2017 which disabled `advanced_editlist` while
demuxing mov/mp4. See: b7b12c36af as well
as b86a2316df
At present, advanced edit list support seems to be mature enough that it
doesn't need to be disabled by us and disabling it seems to break more
files based on testing with `elist` files in FFmpeg's FATE suite.
This better reflects what it actually does. As a bonus, script writers
won't be misled into thinking that fps displays the actual video or
display fps.
Use mp_tags_move_from_av_dictionary() in place of
mp_tags_copy_from_av_dictionary().
This ensures that when lavf appends metadata
that occurs later in the stream,
it starts from empty each time.
Fixes: <https://github.com/mpv-player/mpv/issues/12559>
With the previous commit, we can just access option values directly now
and avoid a lot of complication. Note that the mp_read_option_raw call
for edition requires calling mp_get_config_group since that option needs
to live in MPOpts.
`demux->duration` is set to -1 on initialization, and some checks rely
on it being -1 when unknown. Before this commit, we set
`demux->duration` to 0 when unknown. This is incorrect and breaks rtsp
logic for disabling seeking outside of cached regions.
To fix these issues, initialize `total_duration` and `av_duration` at
-1. They're only changed if a real duration is detected, so in cases
where the duration is unknown, demux->duration is set to -1 correctly.
Fixes: e6afc53e7c ("demux_lavf: get total duration from track durations")
Before this change, mpv used to get the total duration from
`avformat_find_stream_info` and used the per-track duration as a
fallback. This change reverses this order of preference.
The timestamps returned by `avformat_find_stream_info` are truncated or
rounded or floored (depending on the decoder) at the 6th decimal place.
For e.g. `avformat_find_stream_info` may return us a duration like
44.138667, whereas the duration we get from the per-track struct has a
higher degree of precision like 44.13866666666... and so on.
This caused various problems such as the playback_pts being a bigger
value than the duration, which would cause time-remaining to be a
negative value in some cases. Or cause you to reach a negative starting
timestamp when looping on an audio file with `gapless-audio`.
Moreover, we already skipped calling `avformat_find_stream_info` for
mp4, so we had already been utilizing this per-track fallback method for
finding the duration for mp4 files. It should be noted that while this
change is only required for audio-only formats, there is no harm in
doing this for videos as well.
If demux_open_lavf fails between calling avformat_alloc_context() and
assigning the context to priv->avfc, it will never be properly freed.
Fixes#11793.
Pass "dummy.m3u8" filename to work around FFmpeg commit
6b1f68ccb04d791f0250e05687c346a99ff47ea1 which broke their HLS demuxer
and its ability to probe.
Since the above commit, libavformat will check the filename of the file
to be probed and reject it if it doesn't end with a valid HLS extension
i.e. m3u8,hls,m3u (never mind that .hls is not a valid HLS extension).
In addition to a bug with query strings, this also breaks mpv
functionality as mpv explicitly doesn't tell libavformat the filename
when probing, in order to properly detect the file based only on their
contents.
The [HLS specification](https://www.rfc-editor.org/rfc/rfc8216.txt) aka
RFC 8216, specifies in section 4 that "Each Playlist file MUST be
identifiable either by the path component of its URI or by HTTP
Content-Type." Notably, it does not require both, so this FFmpeg commit
is noncompliant. We work around this noncompliance by checking the MIME
type ourselves. If the mimetype matches one of the valid HLS mimetypes
(and also application/x-mpegurl, a legacy pre-standardization type),
then we pass "dummy.m3u8" to libavformat in order to work around its
overly strict checking of filenames.
Without this patch, we are unable to play many HLS streams, including a
few from the ytdl hook. This patch restores those ability to play those
streams when built against FFmpeg master. Do note that if the server
sends an invalid content-type header then we cannot implement this
workaround so those streams will still fail to play.
`io_close2` was introduced as a superior replacement for `io_close` in
ffmpeg 5.0, and then deprecated in 6.0. The difference is that
`io_close2` can return errors. In our case, we're just calling through
to the original function anyway, so we don't need to do more than pass
the return value back.
c784820454 introduced a bool option type
as a replacement for the flag type, but didn't actually transition and
remove the flag type because it would have been too much mundane work.
In the previous change, I replaced the callsites that used
`av_init_packet`, but there are a handful of places that use stack
allocated packets with no initialisation.
In one case, I just switched to heap allocation as it's only done once
per stream at most.
In the other case, I removed our usage of the AVPackets as a
convenience mechanism to transfer data into a heap allocated packet.
Instead, I inlined the data copying.
Now that 0.35 has been released, we can consider increasing our minimum
required ffmpeg version. Currently, we think 4.4 is the most recent
version we can move to (from the current requirement of 4.0).
This allows us to remove a few conditionals. There are more that we
won't be able to remove unless we move further up to 5.1.
This define was always just a stopgap for that two month period (August
2021 - October 2021) where the bytes_read field in ffmpeg was completely
missing. Before that time, it was a private member in a struct (which
mpv used). Afterwards, it officially became public. Fortunately, the
lack of this field never actually made it into a release, so it could
have only possibly affected people building from the master branch.
Since ffmpeg 5.0 came out recently, and it's been plenty of months since
that two month window, we can go ahead and drop this check. This
finishes up the work done in 78cfeee2b9.
Sidenote: the cached ffmpeg version in the mingw ci were from that time
period when the bytes_read field was missing. The N in the workflow is
bumped to force a full rebuild and fresh clone of ffmpeg.
This needs to be forwarded from the AVStream to the AVPacket itself, so
that it reaches the decoder. There exists an FFmpeg function for this,
we just need to call it. (Also add some logging)
The bytes_read struct member in AVIOContext is now officially public,
so its usage no longer has to be specified as non-compliance with
FFmpeg's ABI/API rules.
That said, unfortunately there was a short period of time between
August 2021 and October 2021 where the struct member did not exist
in FFmpeg's git master, so keep a feature check for it alive for
now to enable building with those versions. Thankfully, no release
version of FFmpeg will be without this field, so it should be
possible to drop this check with time.
Finally, simplify the function in case the struct member is not
found. After all, there is zero reason to iterate through the AVIO
contexts if we cannot get the information we require.
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".
This moves the image check to where the number of frames is available of
comparison, which allows not detecting jpg and png videos as images, and
detecting 1-frame gifs as images. This works with the mjpeg and png
videos in the FATE suite, though unfortunately the bmp video is still
detected as an image since it has nb_frames = 0.
aliaspix streams are also now considered images.
Attached pictures are now treated like standalone images, so audio with
attached pictures now has mf-fps as container-fps instead of
unavailable, which makes it consistent with external cover art, which
was already being assigned mf-fps.
Unfortunately images in a codec commonly used for videos are never
detected, and detection was inaccurate even using the now private
codec_info_nb_frames field in AVStream, and mediainfo gets them wrong
too, so I guess it's just a lost cause.
Unfortunately, this functionality in large part based on a struct
member that was made private in FFmpeg/FFmpeg@7489f63281
in May. Unfortunately, this was not noticed during review.
This reverts commit 0862664ac9.
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 d0fee0ac33.
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".
This reverts commit 41243e7c4f.
This fixes image format detection. FFmpeg has an utter called "image2",
which is designed to read patterns in filenames (so you can play
something like "%*.jpg" for all jpg files in the current directory).
"image2" is not what we want; it's just broken with custom I/O like
mpv uses it, and we don't want to "accidentally" interpret filenames
as pattern. That's why mpv blacklists it.
Unfortunately, "image2" is sometimes the format that FFmpeg's probe API
returns as best match. Thus demux_lavf fails to detect the file type,
and after some more futile attempts, we end up at demux_mf, which uses
detection by file extension. (Not sure why. I guess MPlayer did that,
and foudn that sufficient.) If the file extension is wrong (which
happens a lot because apparently the world is full of idiots who don't
manage to get the most simple things right), the image "loads", but
decoding obviously fails.
There's no easy way around this. The FFmpeg API has no mechanism to
exclude a specific format from probing (like image2, which breaks stuff
for us). Out of the 5 probe functions the API provides, none can probe
a specific format or include or exclude specific formats. The main
problem is that AVInputFormat.read_probe is a private symbol.
FFmpeg itself has no problem opening such files. It turns out that it
works, because even though image2 by itself uses detection by file
extension, it uses private API to further probe the exact format. It
explicitly excludes itself to prevent recursion.
But fortunately, that also means that it's impossible to get the image2
format if no filename is passed to the prober. (No filename, no file
extension.) Apparently we pass it in because it helps in corner cases.
Until almost 3 years ago, we passed the filename only when normal
probing already failed. Restore this by this revert. It makes
incorrectly named files work. The revert also makes the (apparently
forgotten) comment above the touched line of code true again.
Yes, quite possible that this breaks some mp3s again. You can't win
with FFmpeg. Thanks FFmpeg for making us fail at opening simple image
files and/or the most widely used file format for audio.
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.