0
0
mirror of https://github.com/mpv-player/mpv.git synced 2024-09-20 12:02:23 +02:00
Commit Graph

1406 Commits

Author SHA1 Message Date
datasone
ee62a1a56e demux: add support for r128 replaygain tags 2022-04-28 20:13:36 +00:00
Cœur
bb5b4b1ba6 various: fix typos 2022-04-25 09:07:18 -04:00
Dudemanguy
8087e3371f build: remove aviocontext bytes_read check
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.
2022-01-25 00:17:01 +02:00
sfan5
b1bf4393a8 demux/packet: replace deprecated av_init_packet() 2022-01-10 22:56:52 +01:00
Niklas Haas
88047f7654 demux_lavf: properly forward dovi config record
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)
2022-01-09 13:06:27 +01:00
Dudemanguy
f610fe16c0 demux_edl: rename ebml_defs.c to ebml_defs.inc
The extension is completely arbitrary since ebml_defs.c isn't a real c
file that actually is compiled at any point in time. It's just used as
an include. The reason for changing the extension is because meson needs
to add this to its list of sources for dependency/ordering purposes.
Understandably, meson will try to compile any .c file added to a c
project executable object. Obviously, this compilation will never
succeed, and this shouldn't be compiled anyways. Just make it .inc
instead.
2021-11-14 19:13:10 +00:00
Niklas Haas
8bd0dee531 osdep: rename MP_UNREACHABLE
It was pointed out on IRC that the name is misleading, since the actual
semantics of the macro is to assert first.
2021-11-03 15:15:20 +01:00
Niklas Haas
c704824b45 osdep: add MP_UNREACHABLE
This seems to work on gcc, clang and mingw as-is, but I made it
conditional on __GNUC__ just in case, even though I can't figure out
which compilers we care about that don't export this define.

Also replace all instances of assert(0) in the code by MP_UNREACHABLE(),
which is a strict improvement.
2021-11-03 14:09:27 +01:00
Jan Ekström
78cfeee2b9 {wscript,demux_lavf}: clean up last bits of !FFMPEG_STRICT_ABI
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.
2021-10-26 01:21:56 +03:00
Guido Cella
9954fe01a9 player: add track-list/N/image sub-property
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".
2021-10-14 15:39:07 +00:00
Guido Cella
00669dabd3 demux_lavf: improve image detection
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.
2021-10-14 15:39:07 +00:00
Jan Ekström
5304e9fe31 Revert "player: add track-list/N/image sub-property"
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.
2021-10-02 16:55:13 +00:00
Guido Cella
0862664ac9 player: add track-list/N/image sub-property
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".
2021-10-02 14:44:18 +00:00
Dan Oscarsson
fa767b6268 demux_mkv: enable AVCodec parser timestamp usage for parsed audio
Without this, cases where the parser cannot return data right away
will end up utilizing the following fed packet's timestamps. This
will in turn cause an unnecessary offset in the audio stream
timestamps.

An example of such buffered parser in libavcodec is the EAC3 one.
2021-09-21 01:28:26 +03:00
Avi Halachmi (:avih)
3405f814fb demux_playlist: extend maximum line size (again) to 2M
Last time it was extended was de3ecc60 from 8K to 512K two years ago.

The issue currently is that youtube EDL files can get very big.
Size of about 520K (one line), was observed, at the time of writing:
  mpv https://youtube.com/watch?v=DBzFQgSMHdQ --ytdl-format=299

ytdl_hook.lua is unaffected by this because EDL lists don't go through
the file reader at demux_playlist.c (where each line was limited to
512K before this commit), however, EDL files on disk which are
loaded with --playlist=file.edl do.

Increase the limit to 2M so that such EDL files can also be loaded
from disk.

Fixes #9186
2021-09-06 10:16:25 +03:00
Shreesh Adiga
8ace8e8790 demux: acquire lock before calling update_bytes_read
in->byte_level_seeks field is written and modified inside
update_bytes_read at the same time when demux_get_reader_state
is executing, which locks the demux thread mutex.  This results
in a data race, reported by Thread Sanitizer when playing mp3 file
of sufficient long length.
2021-07-13 15:16:59 +00:00
TheAMM
4d3df1c842 recorder: add support for attachments (fonts)
Though, only when the output format is matroska, to avoid muxing errors.
This is quite useful when the input has ASS subtitles, as they tend to
rely on embedded fonts.
2021-07-08 12:44:06 +03:00
TheAMM
dd9ed47c99 demux, dump-cache: fix demux cache range sorting
dump_cache() calls qsort() to order an array of pointers, while the
comparator forgets it's receiving pointers to pointers.
Since cache-dumping over multiple cache ranges is fairly rare, this
seems to have gone unnoticed.
2021-07-08 12:44:06 +03:00
Your Name
adcf51dccd edl: add a way to add tags
Add new header which shows up as tags/metadata (associated with
--display-tags). The way this is added means it doesn't always work,
because root->meta (see code) can be NULL for some absurd reason. But it
works for the one case I intended to use it (ytdl_hook, see next
commit), though only in default configurations.
2021-05-11 22:18:40 +02:00
sfan5
39630dc8b6 build: address AVCodec, AVInputFormat, AVOutputFormat const warnings
FFmpeg recently changed these to be const on their side.
2021-05-01 22:07:31 +02:00
rland jon
f665149fc8 demux_lavf: fix minor memory leaks 2021-04-20 13:28:48 +03:00
sfan5
f1d0365a6f demux: undeprecate --cache-secs
It serves a purpose and a rework of the cache won't be coming anytime soon.
This partially reverts commit 8427292eb7.
2021-04-08 23:47:35 +03:00
Avi Halachmi (:avih)
d0c530919d demux_mf: improve format string processing
Before this commit, the user could specify a printf format string
which wasn't verified, and could result in:
- Undefined behavior due to missing or non-matching arguments.
- Buffer overflow due to untested result length.

The offending code was added at commit 103a9609 (2002, mplayer svn):
git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@4566 b3059339-0415-0410-9bf9-f77b7e298cf2

It moved around but was not modified meaningfully until now.

Now we reject all conversion specifiers at the format except %%
and a simple subset of the valid specifiers. Also, we now use
snprintf to avoid buffer overflow.

The format string is provided by the user as part of mf:// URI.

Report and initial patch by Stefan Schiller.
Patch reviewed by @jeeb, @sfan5, Stefan Schiller.
2021-04-05 18:24:55 +03:00
Philip Langdale
c8f474e3e5 demux: Move demuxer help to new standard mechanism
Previously, demux help was handled as a special case in main.c and this
is no longer necessary.
2021-03-28 19:46:32 +03:00
Paul B Mahol
0075b76eeb demuxer/demux_mf: add support for more image codecs 2021-02-06 12:30:53 +01:00
sfan5
10fbd305c8 demux: add function to refresh a track without (de-)selecting it 2020-11-27 17:28:59 +01:00
Mia Herkt
49d6a1e77d
demux_lavf: initialize ReplayGain data
This was causing undefined behavior when playing streams without RG tags
but with RG enabled. Broken in 585f9ff42f.

Thanks to uau for bisecting.
2020-10-23 14:22:57 +02:00
wm4
16b44d93f7 Revert "demux: add a POS"
This reverts commit 4f18e7927b.

It was a mistake, and barely anyone needs this.
2020-10-08 11:17:10 +02:00
wm4
4f18e7927b demux: add a POS
I regret doing this so much, it's fucking garbage.

Fixes: #5100
2020-10-08 00:35:37 +02:00
wm4
9806e9f82b command, demux: make drop-buffers reset state even harder
Leave nothing left when it's executed.
2020-09-17 15:34:40 +02:00
wm4
74e62ed2d1 Revert "demux_lavf: always give libavformat the filename when probing"
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.
2020-08-23 12:44:54 +02:00
wm4
85f38a9765 demux_mf: actually report errors
Well, whatever. Only results in an error message being printed, because
there is no other error reporting mechanism, and the general policy is
to keep trying with the rest of the data (i.e. not report EOF).
2020-08-22 20:46:45 +02:00
wm4
d6bf3880d7 demux_mkv: warn against some other aspects of mismatching codec data
Such files violate the specification. Unfortunately, I could not test
whether it really works correctly, since I don't have a sample at hand
that is not broken in this regard.
2020-08-16 01:00:29 +02:00
wm4
06033df715 demux_lavf: workaround reading gif from unseekable streams
FFmpeg, being the pile of trash as usual, recently broke this. Add our
own trash hack to trashily workaround this shit.

Fixes: #7893
2020-07-09 12:29:22 +02:00
wm4
07b0c18bad build: change filenames of generated files
Force them into a more consistent naming schema.
2020-06-04 16:59:05 +02:00
Kevin Mitchell
2aa5964b43
stream_libarchive: remember archive headers from initial open
The header probing hacks were previously all broken. They only worked
the first time the archive file was open. Since subsequent opens (on
seek) occured in the middle of the source stream rather than at the
beginning, the stream_read_peek calls meant to retrieve the headers were
instead returning random bytes in the middle of the file.

Perhaps the worst manifestation of this was when seeking within a
multi-volume .rar archive with the "legacy" file naming pattern. If the
seek required a reopen, the fact that the archive was multi-volume would
be forgotten and the file would appear truncated terminating playback.

To solve this, only perform the header probling the first time the
archive is opened. Save the results and reuse them on subsequent
reopens. Put this in a wrapper so this is transparent to
demux_libarchive.
2020-04-28 22:13:03 -07:00
wm4
ace169ad0f demux_mkv: add png intra support
Evil, non-standard shit.

Sample file and script:
https://github.com/mpv-player/random-stuff/tree/master/matroska/png
2020-04-16 00:03:26 +02:00
wm4
30855638df demux_mkv: concatenate multiple tags
Instead of just picking the last tag that was encountered. The order of
the tags still depends on the file order.

This is probably wrong, and we should respect TargetTypeValue. But
despite staring at the spec, I have no idea what the hell this should
do, so fuck that.

Fixes: #7604
2020-04-13 16:28:15 +02:00
wm4
dc9135b164 demux: don't let --sub-create-cc-track add a track for attached pictures
Unfortunately, attached pictures (from tags etc.) are treated as video
tracks. That meant --sub-create-cc-track added a CC track for them as
well. Stop doing that.

See: #7608
2020-04-13 15:56:52 +02:00
wm4
bc1a18ee24 options: cleanup .min use for OPT_CHANNELS
Replace use of .min==1 with a proper flag. This is a good idea, because
it has nothing to do with numeric limits (also see commit 9d32d62b61
for how this can go wrong).

With this, m_option.min/max are strictly used for numeric limits.
2020-04-09 11:27:38 +02:00
wm4
fd3caa264e stats: some more performance graphs
Add an infrastructure for collecting performance-related data, use it in
some places. Add rendering of them to stats.lua.

There were two main goals: minimal impact on the normal code and normal
playback. So all these stats_* function calls either happen only during
initialization, or return immediately if no stats collection is going
on. That's why it does this lazily adding of stats entries etc. (a first
iteration made each stats entry an API thing, instead of just a single
stats_ctx, but I thought that was getting too intrusive in the "normal"
code, even if everything gets worse inside of stats.c).

You could get most of this information from various profilers (including
the extremely primitive --dump-stats thing in mpv), but this makes it
easier to see the most important information at once (at least in
theory), partially because we know best about the context of various
things.

Not very happy with this. It's all pretty primitive and dumb. At this
point I just wanted to get over with it, without necessarily having to
revisit it later, but with having my stupid statistics.

Somehow the code feels terrible. There are a lot of meh decisions in
there that could be better or worse (but mostly could be better), and it
just sucks but it's also trivial and uninteresting and does the job. I
guess I hate programming. It's so tedious and the result is always shit.
Anyway, enjoy.
2020-04-09 00:33:38 +02:00
wm4
2de783125b demux: average reported download speed some more
Currently, this reported the number of received bytes per second.
Improve this slightly by averaging over 2 seconds (but still updating
every second).
2020-03-21 19:32:50 +01:00
wm4
41e96d8b6b options: fix OPT_BYTE_SIZE upper limits
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.
2020-03-18 20:51:38 +01:00
wm4
a550bf4927 demux_mkv: fix another integer/float conversion warning
This code could assign INT64_MAX+1 (as double) to int64_t.
2020-03-18 20:44:54 +01:00
wm4
26f4f18c06 options: change option macros and all option declarations
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.
2020-03-18 19:52:01 +01:00
wm4
8d965a1bfb options: change how option range min/max is handled
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.
2020-03-13 17:34:46 +01:00
wm4
d6f282e162 demux: bump --cache-secs default value
Change to it 1000 hours, which is "infinite" enough. (Hesitant to use
INFINITY, as that is not in the option's range. The option parser
rejects it because it causes only problems in API users and so on.)
2020-03-07 12:47:46 +01:00
wm4
f20dfef880 demux: mark recently added debug option as deprecated
It was the intention to remove it again after a release or two; mark it
was deprecated so nobody thinks it gets to stay.
2020-03-07 12:47:46 +01:00
wm4
8427292eb7 demux: deprecate --cache-secs
Because it's confusing and useless. If nobody complains, we'll have one
weird cache configuration option less.
2020-03-05 22:00:50 +01:00
mg
24acddbdc4 demuxer-lavf: udp_multicast rtsp-transport option 2020-03-03 18:31:20 +01:00
wm4
b31a5e3a58 demux: another hack to deal with track switching refresh
The demuxer cache employs a strange method to make track switching
instant with caching enabled. Normally this would mean you have to wait
until the cache has played out (and you get new packets, including
packets from the newly selected track), or you have to perform a slow
high level seek (decoding video again etc.). The strange method is that
it performs a demuxer-level seek without a high level seek so it looks
like a continuous stream to the decoder, and the newly select stream
gets packets at the current playback position. This is called a refresh
seek.

This works only if some weird heuristics work. It needs a packet "unique
ID", for which it uses either dts or pts. The value must be strictly
monotonic increasing. If this doesn't work, the referesh seek can't be
executed, and the user has to wait until the end of the cache. Sometimes
there are files that simply do not work.

In the present case, there's actually a hack that we can extend. Packets
with unset position are likely generated by the parser, and the hack
which this commit touches simply attempts to make up a new (hopefully
unique) position value, even if the value itself makes no sense. It only
ha to be deterministic.

It turns out libavcodec sometimes output packets with repeating position
values. This commit tries to handle this case too with the same hack.

Fixes: #7498
2020-02-29 23:03:39 +01:00
wm4
c79619f110 demux: add a way to block reading after seeks
Preparation for a future commit. The demuxer queues might be read from
other threads than the one to issue the seek, and passing SEEK_BLOCK
with such a seek will provide a convenient way to synchronize this.
2020-02-29 21:49:00 +01:00
wm4
d32ce14d2c demux_lavf: don't interpret errors as EOF
It seems sporadic errors are possible, such as connection timeouts.
Before the recent demuxer change, the demuxer thread retried many times
even on EOF, so an error was only interpreted as EOF once the decoder
queues ran out.

Change it to use EOF only. Since this may actually lead to the demuxer
thread being "stuck" and retrying forever (depending on libavformat API
behavior), I'm also adding a heuristic to prevent this, using a random
retry counter. This should not be necessary, but libavformat cannot be
trusted. (This retrying forever could be stopped by the user, but
obviously it would still heat the CPU for a longer time if the user is
not present.)
2020-02-28 17:25:07 +01:00
wm4
3ae4094ec0 demux: make seek ranges work for static images + audio
In this case the video track has seek_start == seek_end, and due to the
"seek_start >= seek_end" condition, this was considered broken, and no
seek range was created, breaking cached seeking.

Fix this by allowing the case if they're equal, and a valid timestamp.

(NB: seeking backward in this will still jump to position 0, because it
is the video timestamp. This is unfortunately how it's supposed to work.
HR-seeks will also do this, but decode and skip the entire audio until
the seek target, so it will mostly appear to work.)
2020-02-28 00:59:11 +01:00
wm4
2b628d4352 demux_timeline: fix bad EOF reporting
Exposed by commit b56e2efd5f. 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.
2020-02-28 00:08:36 +01:00
wm4
05564af1ac demux_mkv: document probe-start-time option and enable it by default
This is useful with live streams, and it's not much worse than the h264
first packet hack, which reads some data anyway.

For some reason, the option wasn't even documented, so do that.

In addition, print the start time even if it's negative. That should not
be possible, but for some reason, the field is an int64_t copied from an
uint64_t so... whatever. Keeping the logging slightly more straight
forward is better anyway.
2020-02-27 22:30:46 +01:00
wm4
b56e2efd5f demux: simplify some internals, stop trying to read packets after EOF
Remove some redundant fields that controlled or indicated whether the
demuxer was/could/should prefetch. Redefine how the eof/reading fields
work.

The in->eof field is now always valid, instead of weirdly being reset to
false in random situations. The in->reading field now corresponds to
whether the demuxer thread is working at all, and is reset if it stops
doing anything.

Also, I always found it stupid that dequeue_packet() forced the demuxer
thread to retry reading if it was EOF. This makes little sense, but was
probably added for files that are being appended to (running downloads).
It makes no sense, because if the cache really tried to read until file
EOF, it would encounter partial packets and throw errors, so all is lost
anyway. Plus stream_file now handles this better. So stop this behavior,
but add a temporary option that enables the old behavior.

I think checking for ds->eager when enabling prefetching never really
made sense (could be debated, but no, not really). On the other hand,
the change above exposed a missing wakeup in the backward demuxing code.

Some chances of regressions that could make it stuck in certain states
or so, or incorrect demuxer cache state reporting to the player
frontend.
2020-02-27 22:30:46 +01:00
wm4
cf2b7a4997 sub, demux: improve behavior with negative subtitle delay/muxed subs
A negative subtitle delay means that subtitles from the future should be
shown earlier. With muxed subtitles, subtitle packets are demuxed along
with audio and video packets. But since they are demuxed "lazily",
nothing guarantees that subtitle packets from the future are available
in time.

Typically, the user-observed effect is that subtitles do not appear at
all (or too late) with large negative --sub-delay values, but that using
--cache might fix this.

Make this behave better. Automatically extend read-ahead to as much as
needed by the subtitles. It seems it's the easiest to pass the subtitle
render timestamp to the demuxer in order to guarantee that everything is
read. This timestamp based approach might be fragile, so disable it if
no negative sub-delay is used.

As far as the player frontend part is concerned, this makes use of the
code path for external subtitles, which are not lazily demuxed, and may
already trigger waiting.

Fixes: #7484
2020-02-27 02:23:58 +01:00
wm4
b873f1f8e5 demux: avoid some queue management corner cases with subtitles
Subtitle tracks are usually "lazy" (ds->eager=false), There are a number
of weird special cases associated with it. One of them is that they have
some sort of "temporary" EOF (to signal that there isn't a packet right
now, and the decoder should not block playback by waiting for more
packets). In a the next commit, I want to call mark_stream_eof() in case
of (some) of these temporary EOFs.

The problem is that mark_stream_eof() also calls the functions touched
by this commit. Basically they shouldn't do any complex work due to
these temporary EOFs (because they might happen very often). It turns
out that lazy tracks barely matter here: they do not extend the seek
range of a packet/EOF happens on them, they do not trigger seek range
joining, and they do not support backward demuxing.

This change should enable the following commit, while not causing any
behavior changes (i.e. bugs) with the current state.
2020-02-27 02:15:21 +01:00
wm4
605e1fb766 ytdl_hook, edl: add fps, samplerate codec parameters
Well, didn't help much in the case I was interested it.
2020-02-21 14:48:23 +01:00
wm4
a77780e6be edl: make it possible to set the track "default" flag
Also, the forced flag (and in the future, potentially a number of other
flags not implemented yet). See next commit for purpose.
2020-02-21 14:16:26 +01:00
wm4
9f5b9011d6 demux_edl: correct warning on duplicate parameters
A parameter that is actually used is removed from the param_names[]
array, so we can report unused parameters. This also happened on
duplicate parameters, so adjust the warning to make it less confusing.

(In any case, you're not supposed to provide duplicate parameters.)
2020-02-21 12:05:29 +01:00
wm4
6f0297dff4 edl: make it possible to delay-load files with multiple tracks
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.
2020-02-21 00:19:17 +01:00
wm4
6726b7a1ba demux_lavf: signal no seeking for RTSP streams without duration
RTSP supports seeking, but at least the libavformat implementation makes
this dependent on runtime behavior. So you have to perform a seek, and
check if it fails. But even if you do this, the stream is interrupted
and restarted, and there seem to be other issues.

Assume that RTSP with unknown duration means it's a live stream, and
disable seeking in this case, as suggested by the issue reporter.

Fixes: #7472
2020-02-20 15:28:49 +01:00
wm4
bd6d8d320f demux_timeline: don't open every delayed-open track on seeking
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.
2020-02-20 15:21:27 +01:00
wm4
0020b47ffd demux: fix seek range caching with delay_open hack
These have ->segmented set (so the codec can be initialized properly),
but have no segment start or end times. This code was (probably) the
only thing which didn't handle this case.
2020-02-20 15:11:46 +01:00
wm4
e64645540a demux_timeline: warn if streams are invisible
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.
2020-02-20 12:16:32 +01:00
wm4
b8f80b3854 player: print manifest per-stream bitrate information to terminal
Aka hls-bitrate. In turn, remove the demux_lavf.c hack, which made the
track title use this.
2020-02-19 16:26:22 +01:00
wm4
fbc226af51 demux: cosmetic change
This was sort of asymmetric and annoying.
2020-02-17 00:04:56 +01:00
wm4
26ec5862b3 demux: update file-size property even when paused
While paused, the decoders typically stop reading data from the demuxer.
But for some reason, the file size is returned as a public field in
struct demuxer (wat...), and updated only when the packet reading
function is called. This caused the file size property to always return
the same value when paused, even though the demuxer thread was reading
new data, and the internal file size was updated.

Fix with a simple hack.
2020-02-16 23:59:21 +01:00
wm4
1a54339705 demux: only query stream size at most once per second
Instead of every packet. Doing it every packet led to the performance
regression mentioned in the fstat() commit. This should now be over, but
out of being careful, don't query the file size that often. This is only
used for user interface things, so this should not cause any problems.

For the sake of leaving the code compact, abuse another thing that is
updated only every second (speed statistics).
2020-02-16 23:49:42 +01:00
wm4
27bf978e75 demux: invert update_cache() locking
Equivalent, just slightly more convenient for the following change.
2020-02-16 23:43:13 +01:00
wm4
7d11eda72e Remove remains of Libav compatibility
Libav seems rather dead: no release for 2 years, no new git commits in
master for almost a year (with one exception ~6 months ago). From what I
can tell, some developers resigned themselves to the horrifying idea to
post patches to ffmpeg-devel instead, while the rest of the developers
went on to greener pastures.

Libav was a better project than FFmpeg. Unfortunately, FFmpeg won,
because it managed to keep the name and website. Libav was pushed more
and more into obscurity: while there was initially a big push for Libav,
FFmpeg just remained "in place" and visible for most people. FFmpeg was
slowly draining all manpower and energy from Libav. A big part of this
was that FFmpeg stole code from Libav (regular merges of the entire
Libav git tree), making it some sort of Frankenstein mirror of Libav,
think decaying zombie with additional legs ("features") nailed to it.
"Stealing" surely is the wrong word; I'm just aping the language that
some of the FFmpeg members used to use. All that is in the past now, I'm
probably the only person left who is annoyed by this, and with this
commit I'm putting this decade long problem finally to an end. I just
thought I'd express my annoyance about this fucking shitshow one last
time.

The most intrusive change in this commit is the resample filter, which
originally used libavresample. Since the FFmpeg developer refused to
enable libavresample by default for drama reasons, and the API was
slightly different, so the filter used some big preprocessor mess to
make it compatible to libswresample. All that falls away now. The
simplification to the build system is also significant.
2020-02-16 15:14:55 +01:00
wm4
c92c08edc6 edl: add mechanism for delay loading streams
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.
2020-02-15 18:29:44 +01:00
wm4
1d53a8f2e7 demux_edl: warn if no_clip is used with multiple parts
Well whatever.
2020-02-15 15:25:12 +01:00
wm4
921f316281 demux_edl: allow a redundant new_stream at the beginning
Normally, the first sub-stream is implicitly created. This change lets
the user use more orthogonal syntax, and use a new_stream header for
every sub-stream, instead of having to skip the header for the first
one.
2020-02-15 15:22:05 +01:00
wm4
64c4c59770 demux_edl: accept protocol entries in EDL entries again
Accidentally broken by commit 99700bc52c. mp_path_join() does not
check for this, because it's supposed to work on filesystem strings (and
e.g. "http://fubar" is a valid relative path in UNIX).
2020-02-15 15:11:05 +01:00
wm4
96ef62161a demux_edl: improve parsing slightly
Add a mp_log context to the parse_edl() function, and report some
errors. Previously, this just told you that something was wrong. Add
some error reporting to make it slightly less evil.

Put all parameters in a list before processing them. This makes adding
parameters for special headers easier, and we can report parameters that
were not understood. (For "compatibility", which probably doesn't matter
at all, still don't count them as errors; as before.)
2020-02-15 15:07:52 +01:00
wm4
121bc6ad62 demux_timeline: fix another cursed memory management issue
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.
2020-02-15 14:07:46 +01:00
wm4
64a03b03ea demux_timeline: fix a comment 2020-02-15 13:55:54 +01:00
wm4
d5de8ddb65 demux_timeline: reorder some functions
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.
2020-02-15 13:55:37 +01:00
wm4
27d5d32020 demux: add option to disable "sharing" between back and forward buffers
As requested. I guess option name and manpage text could be better and
clearer.

Closes: #7442
2020-02-07 15:58:13 +01:00
wm4
cbee577d0a cue: tolerate NBSP as whitespace
Apparently such .cue files exist. They fail both probing and parsing. To
make it worse, the sample at hand was encoded as Latin1.

One part of this is replacing bstr_lstrip() with a version that supports
NBSP. One could argue that bstr_lstrip() should always do this, but I
don't want to overdo it. There are many more unicode abomination which
it could be said it's supposed to handle, so it will stay ASCII instead
of going down this rabbit hole. I'm just assuming this cue sheet was
generated by some stupid software that inexplicably liked NBSPs (which
is how we justify a one-off fix). The new lstrip_whitespace() doesn't
look particularly efficient, but it doesn't have to be.

The second part is dealing with the fact that the charset is not
necessarily UTF-8. We don't want to do conversion before probing thinks
it knows it's a cue sheet (would probably make it more fragile all
around), so just make it work with Latin1 by assuming invalid code
points are Latin1. This fallback is part of why lstrip_whitespace() is
sort of roundabout.

(You could still rewrite it as much more efficient state machine,
instead of using a slow and validating UTF-8 parser that is called per
codepoint. Starting to overthink this.)

Multimedia is terrible. Legacy charsets are terrible. Everything is
terrible.

Fixes: #7429
2020-02-03 19:13:44 +01:00
wm4
1b283f6b60 libarchive: some shitty hack to make opening slightly faster
See manpage additions. The libarchive behavior mentioned in the last
paragraph there is technically unrelated, but makes this new option
mostly pointless.

See: #7182
2020-01-04 19:56:09 +01:00
wm4
5016a1e4a6 demux: add per-demuxer sub-options
Until now, they were all just added to options.c (e.g. demux_mkv_conf).
This adds a mechanism which can be used to add future options in a
(very) slightly more elegant way.
2020-01-04 19:47:36 +01:00
wm4
04bde06095 stream_libarchive: some more hacks to improve multi-volume archives
Instead of opening every volume on start just to see if it's there, all
all volumes that could possibly exist, and "handle" it on opening. This
requires working around some of libarchive's amazing stupidity and using
some empirically determined behavior. Will possibly break if libarchive
changes some of this behavior.

See: #7182
2020-01-04 18:59:23 +01:00
wm4
99700bc52c demux_edl: restore relative path resolution
Playing e.g. "dir/f.edl" should make all non-absolute paths in f.edl
relative to "dir".

Commit 0e98b2ad8e accidentally broke this.
2020-01-02 23:31:02 +01:00
wm4
3b6c4e7be1 demux: make track switching instant with certain mpegts files
When switching tracks, the data for the new track is missing by the
amount of data prefetched. This is because all demuxers return
interleaved data, and you can't just seek the switched track alone.
Normally, this would mean that the new track simply gets no data for a
while (e.g. silence if it's an audio track). To avoid this, mpv performs
a special "refresh seek" in the demuxer, which tries to resume demuxing
from an earlier position, in a way that does not disrupt decoding for
the non-changed tracks. (Could write a lot about the reasons for doing
something so relatively complex, and the alternatives and their
weaknesses, but let's not.)

This requires that the demuxer can tell whether a packet after a seek
was before or after a previously demuxed packet, sort of like an unique
ID. The code can use the byte position (pos) and the DTS for this. The
DTS is normally strictly monotonically increasing, the position in most
sane file formats too (notably not mp4, in theory).

The file at hand had DTS==NOPTS packets (which is fine, usually this
happens when PTS can be used instead, but the demux.c code structure
doesn't make it easy to use this), and pos==-1 at the same time. The
latter is what libavformat likes to return when the packet was produced
by a "parser" (or in other words, packets were split or reassembled),
and the packet has no real file position. That means the refresh seek
mechanism has no packet position and can't work.

Fix this by making up a pseudo-position if it's missing. This needs to
set the same value every time, which is why it does not work for
keyframe packets (which, by definition, could be a seek target).

Fixes: #7306 (sort of)
2019-12-31 00:17:46 +01:00
wm4
f0d0822595 demux: fix --stream-record runtime change handling
Well, if that wasn't particularly dumb.
2019-12-29 20:18:35 +01:00
wm4
582f3f7cc0 playlist: change from linked list to an array
Although a linked list was ideal at first, there are cases where it
sucks, and became increasingly awkward (with the mpv command API
preferring integer indexes to access the list). In future, we probably
want to add more playlist-related functionality, so better change it to
an array now.

An array isn't always ideal either. Since playlist entries are still
separate objects (because in some cases you need a stable "iterator" to
it), but you still need to efficiently get the next/previous playlist
entry, there's a pl_index field, that needs to be maintained. E.g.
adding an entry at the start of the playlist => update the pl_index
field for all other entries. Well, it's not really worth to do something
more complicated to avoid these things.

This commit is probably buggy as shit. It's not like I bothered to test
everything. That's _your_ role.
2019-12-28 21:32:15 +01:00
wm4
36da3325a3 demux: stop setting dummy stream on demux_close_stream()
Demuxers can call demux_close_stream() to close the underlying stream if
it's not needed anymore. (Useful to release "heavy" resources like FDs
and sockets. Plus merely keeping a file open can have visible side
effects such as inability to unmount a filesystem or, on Windows, to do
anything with the file.)

Until now, this set demuxer->stream to a dummy stream, because most code
used to assume that the stream field is non-NULL. But this requirement
disappeared (in some cases, the stream field is already NULL), so stop
doing that. demux_lavf.c, one of the demuxers which calls this function,
still had some of this, though.
2019-12-23 11:09:42 +01:00
wm4
cd09ea92be demux_mf: use stream API to open list files
mf:// has an obscure feature that lets you pass a list of filenames
separated by newlines. Who knows whether anyone is using that. It opened
these listfiles with fopen(), so the recent stream origin bullshit
doesn't operate on it. Fix this by using the mpv internal stream API
instead. Unfortunately there is no fgets(), so write an ad-hoc one. (An
implementation of line reading via "stream" is still in demux_playlist,
but it's better to keep it quarantined there.)
2019-12-23 11:01:29 +01:00
wm4
9e15e3ad8f demux: remove debug abort()
WHAT THE FUCK

Fixes: #7279
2019-12-22 04:57:18 +01:00
wm4
8448fe0b62 demux: add an option to control tag charset
Fucking gross that you need this in almost-2020.

Fixes: #7255
2019-12-20 13:00:39 +01:00
wm4
0e98b2ad8e edl: accept arbitrary paths
Until now, .edl files accepted only "simple" filenames, i.e. no relative
or absolute paths, no URLs. Now that the origin bullshit is a bit
cleaned up and enforced in the EDL code, there's absolutely no reason to
keep this.

The new code behaves somewhat similar to playlists. (Although playlists
are special because they're not truly recursively opened.)
2019-12-20 13:00:39 +01:00
wm4
1cb9e7efb8 stream, demux: redo origin policy thing
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
2019-12-20 13:00:39 +01:00
wm4
572c32abbe libarchive: prefix entry names in archive URLs with '/'
This has the advantage that playlists within the archive will work as
expected, because demux_playlist will correctly join the archive base
URL and entry name. Before this change, it could skip before the "|",
resulting in a broken URL.
2019-12-20 08:35:08 +01:00
wm4
0bf0efd6d3 demux_edl: fix reusing segment source files
EDL files can have multiple segments taken from the same source file. In
this case, the source file is supposed to be opened only once. This
stopped working, and it created a new demuxer instance for every single
segment entry. This made it slow and made it use much more memory than
needed.

This was because it tried to iterate over the array of source files, but
the array count (num_parts) was only set to a non-0 value later. Fix
this by maintaining the count correctly.

In addition, the actual code for checking whether a source can be reused
(in open_source()) regressed and stopped working correctly. d->stream
could be NULL. Use demuxer.filename instead; I'm not entirely sure
whether this is always correct, but fortunately we have a distributed
almost-AI driven test suite (called "users") which will probably find
and report such cases.

Probably broke with commit a09396ee60 or something close, but didn't
check closer.

Fixes: #7267
2019-12-17 01:57:42 +01:00
wm4
d60bbd86e3 demux_lavf: export demuxer_id for more formats which have it
See previous commit. libavformat exports this information as AVStream.id
field.

The big problem is that the libavformat field is simply 0 if it's
unknown (i.e. the demuxer never sets it). So it needs to remain a
whitelist. Just add more formats which are known to have a meaningful
ID.

I considered exporting IDs for all formats, and then either leaving the
values as they are, or filtering duplicate values (and choosing
arbitrary but unique different IDs). But then again, I think it's sort
of mpv's job to filter FFmpeg's absurd bullshit API, and it should make
an effort to hide it rather than to reflect it.

See: #7211
2019-12-03 21:15:40 +01:00
wm4
370ed5777c demux: do not make up demuxer_id
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.
2019-12-03 21:04:53 +01:00