2009-05-08 21:51:13 +00:00
|
|
|
/*
|
2015-04-13 07:36:54 +00:00
|
|
|
* This file is part of mpv.
|
2009-05-08 21:51:13 +00:00
|
|
|
*
|
demux: change license to LGPL
As usual, the history of these files is a bit murky. It starts with the
initial commit. (At which some development had already been done,
according to the AUTHORS and ChangeLog files at the time, we should be
but covered with relicensing agreements, though.) then it goes on with
complete lack of modularization, which was cleaned up later (cd68e161).
As usual, we don't consider the copyright of the stuff that has been
moved out cleanly.
There were also contributions to generic code by people who could not be
reached or who did not agree to the relicensing, but this was all
removed.
The only patches that we could not relicense and which were still in the
current code in some form are from Dénes Balatoni: 422b0d2a, 32937181.
We could not reach him, so commits f34e1a0d and 18905298 remove his
additions. It still leaves the demux_control() declaration itself, but
we don't consider it copyrightable. It's basically an idiom that existed
in MPlayer before that change, applied to the demuxer struct. (We even
went as far as making sure to remove all DEMUXER_CTRLs the original
author added.)
Commit be54f481 might be a bit of a corner case, but this was rewritten,
and we consider the old copyright removed long ago.
2017-06-20 12:09:46 +00:00
|
|
|
* mpv is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
2009-05-08 21:51:13 +00:00
|
|
|
*
|
2015-04-13 07:36:54 +00:00
|
|
|
* mpv is distributed in the hope that it will be useful,
|
2009-05-08 21:51:13 +00:00
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
demux: change license to LGPL
As usual, the history of these files is a bit murky. It starts with the
initial commit. (At which some development had already been done,
according to the AUTHORS and ChangeLog files at the time, we should be
but covered with relicensing agreements, though.) then it goes on with
complete lack of modularization, which was cleaned up later (cd68e161).
As usual, we don't consider the copyright of the stuff that has been
moved out cleanly.
There were also contributions to generic code by people who could not be
reached or who did not agree to the relicensing, but this was all
removed.
The only patches that we could not relicense and which were still in the
current code in some form are from Dénes Balatoni: 422b0d2a, 32937181.
We could not reach him, so commits f34e1a0d and 18905298 remove his
additions. It still leaves the demux_control() declaration itself, but
we don't consider it copyrightable. It's basically an idiom that existed
in MPlayer before that change, applied to the demuxer struct. (We even
went as far as making sure to remove all DEMUXER_CTRLs the original
author added.)
Commit be54f481 might be a bit of a corner case, but this was rewritten,
and we consider the old copyright removed long ago.
2017-06-20 12:09:46 +00:00
|
|
|
* GNU Lesser General Public License for more details.
|
2009-05-08 21:51:13 +00:00
|
|
|
*
|
demux: change license to LGPL
As usual, the history of these files is a bit murky. It starts with the
initial commit. (At which some development had already been done,
according to the AUTHORS and ChangeLog files at the time, we should be
but covered with relicensing agreements, though.) then it goes on with
complete lack of modularization, which was cleaned up later (cd68e161).
As usual, we don't consider the copyright of the stuff that has been
moved out cleanly.
There were also contributions to generic code by people who could not be
reached or who did not agree to the relicensing, but this was all
removed.
The only patches that we could not relicense and which were still in the
current code in some form are from Dénes Balatoni: 422b0d2a, 32937181.
We could not reach him, so commits f34e1a0d and 18905298 remove his
additions. It still leaves the demux_control() declaration itself, but
we don't consider it copyrightable. It's basically an idiom that existed
in MPlayer before that change, applied to the demuxer struct. (We even
went as far as making sure to remove all DEMUXER_CTRLs the original
author added.)
Commit be54f481 might be a bit of a corner case, but this was rewritten,
and we consider the old copyright removed long ago.
2017-06-20 12:09:46 +00:00
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with mpv. If not, see <http://www.gnu.org/licenses/>.
|
2009-05-08 21:51:13 +00:00
|
|
|
*/
|
|
|
|
|
2008-02-22 09:09:46 +00:00
|
|
|
#ifndef MPLAYER_DEMUXER_H
|
|
|
|
#define MPLAYER_DEMUXER_H
|
2001-04-23 16:12:21 +00:00
|
|
|
|
2008-06-17 09:09:36 +00:00
|
|
|
#include <sys/types.h>
|
2008-03-05 23:32:01 +00:00
|
|
|
#include <stdint.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2009-03-16 21:30:48 +00:00
|
|
|
#include <stdbool.h>
|
2008-03-05 23:32:01 +00:00
|
|
|
|
2014-08-29 10:09:04 +00:00
|
|
|
#include "misc/bstr.h"
|
2013-12-17 01:39:45 +00:00
|
|
|
#include "common/common.h"
|
2014-04-13 12:01:55 +00:00
|
|
|
#include "common/tags.h"
|
2013-11-18 17:46:44 +00:00
|
|
|
#include "packet.h"
|
2012-08-19 16:01:30 +00:00
|
|
|
#include "stheader.h"
|
2006-07-07 18:26:51 +00:00
|
|
|
|
demux: support multiple seekable cached ranges
Until now, the demuxer cache was limited to a single range. Extend this
to multiple range. Should be useful for slow network streams.
This commit changes a lot in the internal demuxer cache logic, so
there's a lot of room for bugs and regressions. The logic without
demuxer cache is mostly untouched, but also involved with the code
changes. Or in other words, this commit probably fucks up shit.
There are two things which makes multiple cached ranges rather hard:
1. the need to resume the demuxer at the end of a cached range when
seeking to it
2. joining two adjacent ranges when the lowe range "grows" into it (and
resuming the demuxer at the end of the new joined range)
"Resuming" the demuxer means that we perform a low level seek to the end
of a cached range, and properly append new packets to it, without adding
packets multiple times or creating holes due to missing packets.
Since audio and video never line up exactly, there is no clean "cut"
possible, at which you could resume the demuxer cleanly (for 1.) or
which you could use to detect that two ranges are perfectly adjacent
(for 2.). The way how the demuxer interleaves multiple streams is also
unpredictable. Typically you will have to expect that it randomly allows
one of the streams to be ahead by a bit, and so on.
To deal with this, we have heuristics in place to detect when one packet
equals or is "behind" a packet that was demuxed earlier. We reuse the
refresh seek logic (used to "reread" packets into the demuxer cache when
enabling a track), which checks for certain packet invariants.
Currently, it observes whether either the raw packet position, or the
packet DTS is strictly monotonically increasing. If none of them are
true, we discard old ranges when creating a new one.
This heavily depends on the file format and the demuxer behavior. For
example, not all file formats have DTS, and the packet position can be
unset due to libavformat not always setting it (e.g. when parsers are
used).
At the same time, we must deal with all the complicated state used to
track prefetching and seek ranges. In some complicated corner cases, we
just give up and discard other seek ranges, even if the previously
mentioned packet invariants are fulfilled.
To handle joining, we're being particularly dumb, and require a small
overlap to be confident that two ranges join perfectly. (This could be
done incrementally with as little overlap as 1 packet, but corner cases
would eat us: each stream needs to be joined separately, and the cache
pruning logic could remove overlapping packets for other streams again.)
Another restriction is that switching the cached range will always
trigger an asynchronous low level seek to resume demuxing at the new
range. Some users might find this annoying.
Dealing with interleaved subtitles is not fully handled yet. It will
clamp the seekable range to where subtitle packets are.
2017-11-09 08:53:46 +00:00
|
|
|
#define MAX_SEEK_RANGES 10
|
2017-10-30 13:26:54 +00:00
|
|
|
|
|
|
|
struct demux_seek_range {
|
|
|
|
double start, end;
|
|
|
|
};
|
|
|
|
|
2021-10-20 01:16:22 +00:00
|
|
|
struct demux_ctrl_ts_info {
|
|
|
|
double duration;
|
|
|
|
double reader; // approx. timestamp of decoder position
|
|
|
|
double end; // approx. timestamp of end of buffered range
|
|
|
|
};
|
|
|
|
|
2018-09-07 20:26:48 +00:00
|
|
|
struct demux_reader_state {
|
2017-10-30 13:26:54 +00:00
|
|
|
bool eof, underrun, idle;
|
2019-05-17 20:28:12 +00:00
|
|
|
bool bof_cached, eof_cached;
|
2021-10-20 01:16:22 +00:00
|
|
|
struct demux_ctrl_ts_info ts_info;
|
|
|
|
struct demux_ctrl_ts_info ts_per_stream[STREAM_TYPE_COUNT];
|
2017-11-10 15:43:09 +00:00
|
|
|
int64_t total_bytes;
|
|
|
|
int64_t fw_bytes;
|
demux: add a on-disk cache
Somewhat similar to the old --cache-file, except for the demuxer cache.
Instead of keeping packet data in memory, it's written to disk and read
back when needed.
The idea is to reduce main memory usage, while allowing fast seeking in
large cached network streams (especially live streams). Keeping the
packet metadata on disk would be rather hard (would use mmap or so, or
rewrite the entire demux.c packet queue handling), and since it's
relatively small, just keep it in memory.
Also for simplicity, the disk cache is append-only. If you're watching
really long livestreams, and need pruning, you're probably out of luck.
This still could be improved by trying to free unused blocks with
fallocate(), but since we're writing multiple streams in an interleaved
manner, this is slightly hard.
Some rather gross ugliness in packet.h: we want to store the file
position of the cached data somewhere, but on 32 bit architectures, we
don't have any usable 64 bit members for this, just the buf/len fields,
which add up to 64 bit - so the shitty union aliases this memory.
Error paths untested. Side data (the complicated part of trying to
serialize ffmpeg packets) untested.
Stream recording had to be adjusted. Some minor details change due to
this, but probably nothing important.
The change in attempt_range_joining() is because packets in cache
have no valid len field. It was a useful check (heuristically
finding broken cases), but not a necessary one.
Various other approaches were tried. It would be interesting to list
them and to mention the pros and cons, but I don't feel like it.
2019-06-13 17:10:32 +00:00
|
|
|
int64_t file_cache_bytes;
|
2018-01-05 15:41:16 +00:00
|
|
|
double seeking; // current low level seek target, or NOPTS
|
|
|
|
int low_level_seeks; // number of started low level seeks
|
2019-11-07 15:05:27 +00:00
|
|
|
uint64_t byte_level_seeks; // number of byte stream level seeks
|
2018-01-05 15:41:16 +00:00
|
|
|
double ts_last; // approx. timestamp of demuxer position
|
2018-09-01 11:04:45 +00:00
|
|
|
uint64_t bytes_per_second; // low level statistics
|
2017-10-30 13:26:54 +00:00
|
|
|
// Positions that can be seeked to without incurring the latency of a low
|
|
|
|
// level seek.
|
|
|
|
int num_seek_ranges;
|
|
|
|
struct demux_seek_range seek_ranges[MAX_SEEK_RANGES];
|
command: redo ancient TV/DVB/PVR commands
Convert all these commands to properties. (Except tv_last_channel, not
sure what to do with this.) Also, internally, don't access stream
details directly, but dispatch commands with stream ctrls.
Many of the new properties are a bit strange, because they're write-
only. Also remove some OSD output these commands produced, because I
couldn't be bothered to port these.
In general, this makes everything much cleaner, and will also make it
easier to e.g. move the demuxer to its own thread.
Don't bother updating input.conf, but changes.rst documents how old
commands map to the new ones.
Mostly untested, due to lack of hardware.
2014-06-09 21:38:28 +00:00
|
|
|
};
|
|
|
|
|
2023-09-19 20:26:10 +00:00
|
|
|
extern const struct m_sub_options demux_conf;
|
|
|
|
|
|
|
|
struct demux_opts {
|
|
|
|
int enable_cache;
|
|
|
|
bool disk_cache;
|
|
|
|
int64_t max_bytes;
|
|
|
|
int64_t max_bytes_bw;
|
|
|
|
bool donate_fw;
|
|
|
|
double min_secs;
|
|
|
|
double hyst_secs;
|
|
|
|
bool force_seekable;
|
|
|
|
double min_secs_cache;
|
|
|
|
bool access_references;
|
|
|
|
int seekable_cache;
|
|
|
|
int index_mode;
|
|
|
|
double mf_fps;
|
|
|
|
char *mf_type;
|
|
|
|
bool create_ccs;
|
|
|
|
char *record_file;
|
|
|
|
int video_back_preroll;
|
|
|
|
int audio_back_preroll;
|
|
|
|
int back_batch[STREAM_TYPE_COUNT];
|
|
|
|
double back_seek_size;
|
|
|
|
char *meta_cp;
|
|
|
|
bool force_retry_eof;
|
2024-07-16 15:02:52 +00:00
|
|
|
int autocreate_playlist;
|
2023-09-19 20:26:10 +00:00
|
|
|
};
|
|
|
|
|
2015-01-19 19:45:31 +00:00
|
|
|
#define SEEK_FACTOR (1 << 1) // argument is in range [0,1]
|
|
|
|
#define SEEK_FORWARD (1 << 2) // prefer later time if not exact
|
2017-10-23 17:05:39 +00:00
|
|
|
// (if unset, prefer earlier time)
|
player: allow seeking in cached parts of unseekable streams
Before this change and before the seekable stream cache became a thing,
we could possibly seek using the stream cache. But we couldn't know
whether the seek would succeed. We knew the available byte range, but
could in general not tell whether a demuxer would stay within the range
when trying to seek to a specific time position. We preferred to have
safe defaults, so seeking in streams that were detected as unseekable
were not honored. We allowed overriding this via --force-seekable=yes,
in which case it depended on your luck whether the seek would work, or
the player crapped its pants.
With the demuxer packet cache, we can tell exactly whether a seek will
work (at least if there's only 1 seek range). We can just let seeks go
through. Everything to allow this is already in place, and this commit
just moves around some minor things.
Note that the demux_seek() return value was not used before, because low
level (i.e. network level) seeks are usually asynchronous, and if they
fail, the state is pretty much undefined. We simply repurpose the return
value to signal whether cache seeking worked. If it didn't, we can just
resume playback normally, because demuxing continues unaffected, and no
decoder are reset.
This should be particularly helpful to people who for some reason stream
data into stdin via streamlink and such.
2017-12-23 21:28:08 +00:00
|
|
|
#define SEEK_CACHED (1 << 3) // allow packet cache seeks only
|
Implement backwards playback
See manpage additions. This is a huge hack. You can bet there are shit
tons of bugs. It's literally forcing square pegs into round holes.
Hopefully, the manpage wall of text makes it clear enough that the whole
shit can easily crash and burn. (Although it shouldn't literally crash.
That would be a bug. It possibly _could_ start a fire by entering some
sort of endless loop, not a literal one, just something where it tries
to do work without making progress.)
(Some obvious bugs I simply ignored for this initial version, but
there's a number of potential bugs I can't even imagine. Normal playback
should remain completely unaffected, though.)
How this works is also described in the manpage. Basically, we demux in
reverse, then we decode in reverse, then we render in reverse.
The decoding part is the simplest: just reorder the decoder output. This
weirdly integrates with the timeline/ordered chapter code, which also
has special requirements on feeding the packets to the decoder in a
non-straightforward way (it doesn't conflict, although a bugmessmass
breaks correct slicing of segments, so EDL/ordered chapter playback is
broken in backward direction).
Backward demuxing is pretty involved. In theory, it could be much
easier: simply iterating the usual demuxer output backward. But this
just doesn't fit into our code, so there's a cthulhu nightmare of shit.
To be specific, each stream (audio, video) is reversed separately. At
least this means we can do backward playback within cached content (for
example, you could play backwards in a live stream; on that note, it
disables prefetching, which would lead to losing new live video, but
this could be avoided).
The fuckmess also meant that I didn't bother trying to support
subtitles. Subtitles are a problem because they're "sparse" streams.
They need to be "passively" demuxed: you don't try to read a subtitle
packet, you demux audio and video, and then look whether there was a
subtitle packet. This means to get subtitles for a time range, you need
to know that you demuxed video and audio over this range, which becomes
pretty messy when you demux audio and video backwards separately.
Backward display is the most weird (and potentially buggy) part. To
avoid that we need to touch a LOT of timing code, we negate all
timestamps. The basic idea is that due to the navigation, all
comparisons and subtractions of timestamps keep working, and you don't
need to touch every single of them to "reverse" them.
E.g.:
bool before = pts_a < pts_b;
would need to be:
bool before = forward
? pts_a < pts_b
: pts_a > pts_b;
or:
bool before = pts_a * dir < pts_b * dir;
or if you, as it's implemented now, just do this after decoding:
pts_a *= dir;
pts_b *= dir;
and then in the normal timing/renderer code:
bool before = pts_a < pts_b;
Consequently, we don't need many changes in the latter code. But some
assumptions inhererently true for forward playback may have been broken
anyway. What is mainly needed is fixing places where values are passed
between positive and negative "domains". For example, seeking and
timestamp user display always uses positive timestamps. The main mess is
that it's not obvious which domain a given variable should or does use.
Well, in my tests with a single file, it suddenly started to work when I
did this. I'm honestly surprised that it did, and that I didn't have to
change a single line in the timing code past decoder (just something
minor to make external/cached text subtitles display). I committed it
immediately while avoiding thinking about it. But there really likely
are subtle problems of all sorts.
As far as I'm aware, gstreamer also supports backward playback. When I
looked at this years ago, I couldn't find a way to actually try this,
and I didn't revisit it now. Back then I also read talk slides from the
person who implemented it, and I'm not sure if and which ideas I might
have taken from it. It's possible that the timestamp reversal is
inspired by it, but I didn't check. (I think it claimed that it could
avoid large changes by changing a sign?)
VapourSynth has some sort of reverse function, which provides a backward
view on a video. The function itself is trivial to implement, as
VapourSynth aims to provide random access to video by frame numbers (so
you just request decreasing frame numbers). From what I remember, it
wasn't exactly fluid, but it worked. It's implemented by creating an
index, and seeking to the target on demand, and a bunch of caching. mpv
could use it, but it would either require using VapourSynth as demuxer
and decoder for everything, or replacing the current file every time
something is supposed to be played backwards.
FFmpeg's libavfilter has reversal filters for audio and video. These
require buffering the entire media data of the file, and don't really
fit into mpv's architecture. It could be used by playing a libavfilter
graph that also demuxes, but that's like VapourSynth but worse.
2019-05-18 00:10:51 +00:00
|
|
|
#define SEEK_SATAN (1 << 4) // enable backward demuxing
|
2015-01-19 19:45:31 +00:00
|
|
|
#define SEEK_HR (1 << 5) // hr-seek (this is a weak hint only)
|
2019-10-02 22:22:18 +00:00
|
|
|
#define SEEK_FORCE (1 << 6) // ignore unseekable flag
|
2020-02-29 19:06:40 +00:00
|
|
|
#define SEEK_BLOCK (1 << 7) // upon successfully queued seek, block readers
|
|
|
|
// (simplifies syncing multiple reader threads)
|
2008-01-29 15:11:38 +00:00
|
|
|
|
2013-07-12 19:58:11 +00:00
|
|
|
// Strictness of the demuxer open format check.
|
|
|
|
// demux.c will try by default: NORMAL, UNSAFE (in this order)
|
|
|
|
// Using "-demuxer format" will try REQUEST
|
|
|
|
// Using "-demuxer +format" will try FORCE
|
|
|
|
// REQUEST can be used as special value for raw demuxers which have no file
|
|
|
|
// header check; then they should fail if check!=FORCE && check!=REQUEST.
|
|
|
|
//
|
|
|
|
// In general, the list is sorted from weakest check to normal check.
|
|
|
|
// You can use relation operators to compare the check level.
|
|
|
|
enum demux_check {
|
|
|
|
DEMUX_CHECK_FORCE, // force format if possible
|
|
|
|
DEMUX_CHECK_UNSAFE, // risky/fuzzy detection
|
|
|
|
DEMUX_CHECK_REQUEST,// requested by user or stream implementation
|
|
|
|
DEMUX_CHECK_NORMAL, // normal, safe detection
|
|
|
|
};
|
|
|
|
|
2014-07-05 14:45:56 +00:00
|
|
|
enum demux_event {
|
2014-07-16 20:40:21 +00:00
|
|
|
DEMUX_EVENT_INIT = 1 << 0, // complete (re-)initialization
|
|
|
|
DEMUX_EVENT_STREAMS = 1 << 1, // a stream was added
|
|
|
|
DEMUX_EVENT_METADATA = 1 << 2, // metadata or stream_metadata changed
|
2017-12-24 00:56:09 +00:00
|
|
|
DEMUX_EVENT_DURATION = 1 << 3, // duration updated
|
2014-07-16 20:40:21 +00:00
|
|
|
DEMUX_EVENT_ALL = 0xFFFF,
|
2014-07-05 14:45:56 +00:00
|
|
|
};
|
|
|
|
|
2008-04-24 02:49:44 +00:00
|
|
|
struct demuxer;
|
2015-02-17 22:46:12 +00:00
|
|
|
struct timeline;
|
2005-08-05 19:57:47 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Demuxer description structure
|
|
|
|
*/
|
2008-04-24 02:49:44 +00:00
|
|
|
typedef struct demuxer_desc {
|
2011-02-10 10:05:26 +00:00
|
|
|
const char *name; // Demuxer name, used with -demuxer switch
|
2013-07-12 20:12:02 +00:00
|
|
|
const char *desc; // Displayed to user
|
2011-02-10 10:05:26 +00:00
|
|
|
|
2020-01-04 18:47:36 +00:00
|
|
|
// If non-NULL, these are added to the global option list.
|
|
|
|
const struct m_sub_options *options;
|
|
|
|
|
2013-07-11 18:08:12 +00:00
|
|
|
// Return 0 on success, otherwise -1
|
2013-07-12 19:58:11 +00:00
|
|
|
int (*open)(struct demuxer *demuxer, enum demux_check check);
|
2013-07-11 18:08:12 +00:00
|
|
|
// The following functions are all optional
|
2018-09-07 13:12:24 +00:00
|
|
|
// Try to read a packet. Return false on EOF. If true is returned, the
|
|
|
|
// demuxer may set *pkt to a new packet (the reference goes to the caller).
|
|
|
|
// If *pkt is NULL (the value when this function is called), the call
|
|
|
|
// will be repeated.
|
|
|
|
bool (*read_packet)(struct demuxer *demuxer, struct demux_packet **pkt);
|
2013-07-11 18:08:12 +00:00
|
|
|
void (*close)(struct demuxer *demuxer);
|
2014-07-21 17:28:18 +00:00
|
|
|
void (*seek)(struct demuxer *demuxer, double rel_seek_secs, int flags);
|
2018-09-07 21:10:14 +00:00
|
|
|
void (*switched_tracks)(struct demuxer *demuxer);
|
2015-02-17 22:46:12 +00:00
|
|
|
// See timeline.c
|
|
|
|
void (*load_timeline)(struct timeline *tl);
|
2005-08-05 19:57:47 +00:00
|
|
|
} demuxer_desc_t;
|
|
|
|
|
2008-04-24 02:49:44 +00:00
|
|
|
typedef struct demux_chapter
|
2006-08-06 18:55:34 +00:00
|
|
|
{
|
2013-04-12 11:20:37 +00:00
|
|
|
int original_index;
|
2014-11-02 16:20:04 +00:00
|
|
|
double pts;
|
2013-09-08 05:42:05 +00:00
|
|
|
struct mp_tags *metadata;
|
|
|
|
uint64_t demuxer_id; // for mapping to internal demuxer data structures
|
2006-08-06 18:55:34 +00:00
|
|
|
} demux_chapter_t;
|
|
|
|
|
2014-01-22 23:54:08 +00:00
|
|
|
struct demux_edition {
|
|
|
|
uint64_t demuxer_id;
|
|
|
|
bool default_edition;
|
|
|
|
struct mp_tags *metadata;
|
|
|
|
};
|
|
|
|
|
2013-10-07 00:49:12 +00:00
|
|
|
struct matroska_segment_uid {
|
|
|
|
unsigned char segment[16];
|
|
|
|
uint64_t edition;
|
|
|
|
};
|
|
|
|
|
2009-03-16 21:30:48 +00:00
|
|
|
struct matroska_data {
|
2013-10-07 00:49:12 +00:00
|
|
|
struct matroska_segment_uid uid;
|
2009-03-16 21:30:48 +00:00
|
|
|
// Ordered chapter information if any
|
|
|
|
struct matroska_chapter {
|
|
|
|
uint64_t start;
|
|
|
|
uint64_t end;
|
|
|
|
bool has_segment_uid;
|
2013-10-07 00:49:12 +00:00
|
|
|
struct matroska_segment_uid uid;
|
2009-04-02 02:00:22 +00:00
|
|
|
char *name;
|
2009-03-16 21:30:48 +00:00
|
|
|
} *ordered_chapters;
|
|
|
|
int num_ordered_chapters;
|
|
|
|
};
|
|
|
|
|
2014-03-25 10:46:10 +00:00
|
|
|
struct replaygain_data {
|
|
|
|
float track_gain;
|
|
|
|
float track_peak;
|
|
|
|
float album_gain;
|
|
|
|
float album_peak;
|
|
|
|
};
|
|
|
|
|
2008-04-24 02:49:44 +00:00
|
|
|
typedef struct demux_attachment
|
2008-01-12 01:12:36 +00:00
|
|
|
{
|
2011-02-10 10:05:26 +00:00
|
|
|
char *name;
|
|
|
|
char *type;
|
|
|
|
void *data;
|
|
|
|
unsigned int data_size;
|
2008-01-12 01:12:36 +00:00
|
|
|
} demux_attachment_t;
|
|
|
|
|
2011-08-04 05:38:39 +00:00
|
|
|
struct demuxer_params {
|
2019-06-07 15:09:22 +00:00
|
|
|
bool is_top_level; // if true, it's not a sub-demuxer (enables cache etc.)
|
2015-02-20 20:21:14 +00:00
|
|
|
char *force_format;
|
2013-09-26 06:22:06 +00:00
|
|
|
int matroska_num_wanted_uids;
|
2013-10-07 00:49:12 +00:00
|
|
|
struct matroska_segment_uid *matroska_wanted_uids;
|
2013-04-14 00:49:07 +00:00
|
|
|
int matroska_wanted_segment;
|
|
|
|
bool *matroska_was_valid;
|
Rewrite ordered chapters and timeline stuff
This uses a different method to piece segments together. The old
approach basically changes to a new file (with a new start offset) any
time a segment ends. This meant waiting for audio/video end on segment
end, and then changing to the new segment all at once. It had a very
weird impact on the playback core, and some things (like truly gapless
segment transitions, or frame backstepping) just didn't work.
The new approach adds the demux_timeline pseudo-demuxer, which presents
an uniform packet stream from the many segments. This is pretty similar
to how ordered chapters are implemented everywhere else. It also reminds
of the FFmpeg concat pseudo-demuxer.
The "pure" version of this approach doesn't work though. Segments can
actually have different codec configurations (different extradata), and
subtitles are most likely broken too. (Subtitles have multiple corner
cases which break the pure stream-concatenation approach completely.)
To counter this, we do two things:
- Reinit the decoder with each segment. We go as far as allowing
concatenating files with completely different codecs for the sake
of EDL (which also uses the timeline infrastructure). A "lighter"
approach would try to make use of decoder mechanism to update e.g.
the extradata, but that seems fragile.
- Clip decoded data to segment boundaries. This is equivalent to
normal playback core mechanisms like hr-seek, but now the playback
core doesn't need to care about these things.
These two mechanisms are equivalent to what happened in the old
implementation, except they don't happen in the playback core anymore.
In other words, the playback core is completely relieved from timeline
implementation details. (Which honestly is exactly what I'm trying to
do here. I don't think ordered chapter behavior deserves improvement,
even if it's bad - but I want to get it out from the playback core.)
There is code duplication between audio and video decoder common code.
This is awful and could be shareable - but this will happen later.
Note that the audio path has some code to clip audio frames for the
purpose of codec preroll/gapless handling, but it's not shared as
sharing it would cause more pain than it would help.
2016-02-15 20:04:07 +00:00
|
|
|
struct timeline *timeline;
|
2016-10-22 15:17:04 +00:00
|
|
|
bool disable_timeline;
|
2017-01-30 18:38:43 +00:00
|
|
|
bstr init_fragment;
|
|
|
|
bool skip_lavf_probing;
|
2018-09-01 14:06:41 +00:00
|
|
|
bool stream_record; // if true, enable stream recording if option is set
|
2015-08-03 23:01:09 +00:00
|
|
|
int stream_flags;
|
2019-10-02 22:22:18 +00:00
|
|
|
struct stream *external_stream; // if set, use this, don't open or close streams
|
2024-07-16 15:02:52 +00:00
|
|
|
bool allow_playlist_create;
|
2015-08-03 23:01:09 +00:00
|
|
|
// result
|
|
|
|
bool demuxer_failed;
|
2011-08-04 05:38:39 +00:00
|
|
|
};
|
|
|
|
|
2008-04-24 02:49:44 +00:00
|
|
|
typedef struct demuxer {
|
2011-02-10 10:05:26 +00:00
|
|
|
const demuxer_desc_t *desc; ///< Demuxer description structure
|
2011-05-04 20:12:55 +00:00
|
|
|
const char *filetype; // format name when not identified by demuxer (libavformat)
|
2012-11-18 19:46:12 +00:00
|
|
|
int64_t filepos; // input stream current pos.
|
2018-09-07 19:58:46 +00:00
|
|
|
int64_t filesize;
|
2013-07-12 19:58:11 +00:00
|
|
|
char *filename; // same as stream->url
|
2015-01-26 12:46:33 +00:00
|
|
|
bool seekable;
|
2016-03-03 14:30:55 +00:00
|
|
|
bool partially_seekable; // true if _maybe_ seekable; implies seekable=true
|
2014-07-05 14:54:49 +00:00
|
|
|
double start_time;
|
2017-06-20 11:57:58 +00:00
|
|
|
double duration; // -1 if unknown
|
2013-03-01 12:20:33 +00:00
|
|
|
// File format allows PTS resets (even if the current file is without)
|
|
|
|
bool ts_resets_possible;
|
2015-02-18 20:10:43 +00:00
|
|
|
// The file data was fully read, and there is no need to keep the stream
|
|
|
|
// open, keep the cache active, or to run the demuxer thread. Generating
|
|
|
|
// packets is not slow either (unlike e.g. libavdevice pseudo-demuxers).
|
|
|
|
// Typical examples: text subtitles, playlists
|
|
|
|
bool fully_read;
|
2016-08-26 10:31:09 +00:00
|
|
|
bool is_network; // opened directly from a network stream
|
2019-09-20 15:01:35 +00:00
|
|
|
bool is_streaming; // implies a "slow" input, such as network or FUSE
|
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 08:41:42 +00:00
|
|
|
int stream_origin; // any STREAM_ORIGIN_* (set from source stream)
|
2016-12-04 22:15:31 +00:00
|
|
|
bool access_references; // allow opening other files/URLs
|
2001-04-23 16:12:21 +00:00
|
|
|
|
2023-09-19 20:26:10 +00:00
|
|
|
struct demux_opts *opts;
|
|
|
|
struct m_config_cache *opts_cache;
|
|
|
|
|
2014-07-05 14:45:56 +00:00
|
|
|
// Bitmask of DEMUX_EVENT_*
|
|
|
|
int events;
|
|
|
|
|
2014-01-22 23:54:08 +00:00
|
|
|
struct demux_edition *editions;
|
2012-08-25 23:19:42 +00:00
|
|
|
int num_editions;
|
|
|
|
int edition;
|
2011-12-31 12:20:08 +00:00
|
|
|
|
2011-02-10 10:05:26 +00:00
|
|
|
struct demux_chapter *chapters;
|
|
|
|
int num_chapters;
|
|
|
|
|
|
|
|
struct demux_attachment *attachments;
|
|
|
|
int num_attachments;
|
2008-01-12 01:12:36 +00:00
|
|
|
|
2009-03-16 21:30:48 +00:00
|
|
|
struct matroska_data matroska_data;
|
|
|
|
|
2013-08-25 18:40:21 +00:00
|
|
|
// If the file is a playlist file
|
|
|
|
struct playlist *playlist;
|
|
|
|
|
2013-09-08 04:32:48 +00:00
|
|
|
struct mp_tags *metadata;
|
2014-07-05 14:45:56 +00:00
|
|
|
|
2011-02-10 10:05:26 +00:00
|
|
|
void *priv; // demuxer-specific internal data
|
2013-12-21 19:24:20 +00:00
|
|
|
struct mpv_global *global;
|
2013-12-21 20:55:41 +00:00
|
|
|
struct mp_log *log, *glog;
|
2011-08-04 05:38:39 +00:00
|
|
|
struct demuxer_params *params;
|
2014-07-16 20:40:21 +00:00
|
|
|
|
2016-08-12 19:39:32 +00:00
|
|
|
// internal to demux.c
|
|
|
|
struct demux_internal *in;
|
2014-07-16 20:40:21 +00:00
|
|
|
|
2018-05-18 13:48:14 +00:00
|
|
|
// Triggered when ending demuxing forcefully. Usually bound to the stream too.
|
|
|
|
struct mp_cancel *cancel;
|
|
|
|
|
2014-07-16 20:40:21 +00:00
|
|
|
// Since the demuxer can run in its own thread, and the stream is not
|
|
|
|
// thread-safe, only the demuxer is allowed to access the stream directly.
|
2016-08-26 11:05:14 +00:00
|
|
|
// Also note that the stream can get replaced if fully_read is set.
|
2014-07-16 20:40:21 +00:00
|
|
|
struct stream *stream;
|
2001-04-23 16:12:21 +00:00
|
|
|
} demuxer_t;
|
|
|
|
|
2018-05-19 12:41:06 +00:00
|
|
|
void demux_free(struct demuxer *demuxer);
|
2018-05-19 15:06:00 +00:00
|
|
|
void demux_cancel_and_free(struct demuxer *demuxer);
|
2001-04-23 16:12:21 +00:00
|
|
|
|
2018-05-19 16:19:07 +00:00
|
|
|
struct demux_free_async_state;
|
|
|
|
struct demux_free_async_state *demux_free_async(struct demuxer *demuxer);
|
|
|
|
void demux_free_async_force(struct demux_free_async_state *state);
|
|
|
|
bool demux_free_async_finish(struct demux_free_async_state *state);
|
|
|
|
|
2015-12-22 01:35:15 +00:00
|
|
|
void demuxer_feed_caption(struct sh_stream *stream, demux_packet_t *dp);
|
2013-07-11 17:10:33 +00:00
|
|
|
|
2014-07-18 13:08:05 +00:00
|
|
|
int demux_read_packet_async(struct sh_stream *sh, struct demux_packet **out_pkt);
|
2020-02-27 01:23:58 +00:00
|
|
|
int demux_read_packet_async_until(struct sh_stream *sh, double min_pts,
|
2023-09-28 02:51:49 +00:00
|
|
|
struct demux_packet **out_pkt);
|
2014-07-06 17:02:21 +00:00
|
|
|
bool demux_stream_is_selected(struct sh_stream *stream);
|
2018-01-29 12:51:47 +00:00
|
|
|
void demux_set_stream_wakeup_cb(struct sh_stream *sh,
|
|
|
|
void (*cb)(void *ctx), void *ctx);
|
2014-07-05 14:57:56 +00:00
|
|
|
struct demux_packet *demux_read_any_packet(struct demuxer *demuxer);
|
2001-04-23 16:12:21 +00:00
|
|
|
|
demux: remove weird tripple-buffering for the sh_stream list
The demuxer infrastructure was originally single-threaded. To make it
suitable for multithreading (specifically, demuxing and decoding on
separate threads), some sort of tripple-buffering was introduced. There
are separate "struct demuxer" allocations. The demuxer thread sets the
state on d_thread. If anything changes, the state is copied to d_buffer
(the copy is protected by a lock), and the decoder thread is notified.
Then the decoder thread copies the state from d_buffer to d_user (again
while holding a lock). This avoids the need for locking in the
demuxer/decoder code itself (only demux.c needs an internal, "invisible"
lock.)
Remove the streams/num_streams fields from this tripple-buffering
schema. Move them to the internal struct, and protect them with the
internal lock. Use accessors for read access outside of demux.c.
Other than replacing all field accesses with accessors, this separates
allocating and adding sh_streams. This is needed to avoid race
conditions. Before this change, this was awkwardly handled by first
initializing the sh_stream, and then sending a stream change event. Now
the stream is allocated, then initialized, and then declared as
immutable and added (at which point it becomes visible to the decoder
thread immediately).
This change is useful for PR #2626. And eventually, we should probably
get entirely of the tripple buffering, and this makes a nice first step.
2015-12-23 20:44:53 +00:00
|
|
|
struct sh_stream *demux_get_stream(struct demuxer *demuxer, int index);
|
|
|
|
int demux_get_num_stream(struct demuxer *demuxer);
|
|
|
|
|
|
|
|
struct sh_stream *demux_alloc_sh_stream(enum stream_type type);
|
|
|
|
void demux_add_sh_stream(struct demuxer *demuxer, struct sh_stream *sh);
|
2013-07-11 17:35:09 +00:00
|
|
|
|
2015-02-20 20:56:55 +00:00
|
|
|
struct mp_cancel;
|
|
|
|
struct demuxer *demux_open_url(const char *url,
|
|
|
|
struct demuxer_params *params,
|
|
|
|
struct mp_cancel *cancel,
|
|
|
|
struct mpv_global *global);
|
|
|
|
|
2014-07-16 20:40:21 +00:00
|
|
|
void demux_start_thread(struct demuxer *demuxer);
|
|
|
|
void demux_stop_thread(struct demuxer *demuxer);
|
|
|
|
void demux_set_wakeup_cb(struct demuxer *demuxer, void (*cb)(void *ctx), void *ctx);
|
2019-05-16 14:29:45 +00:00
|
|
|
void demux_start_prefetch(struct demuxer *demuxer);
|
2014-07-16 20:40:21 +00:00
|
|
|
|
2015-03-09 21:32:04 +00:00
|
|
|
bool demux_cancel_test(struct demuxer *demuxer);
|
|
|
|
|
2011-02-10 10:05:26 +00:00
|
|
|
void demux_flush(struct demuxer *demuxer);
|
2014-10-29 21:47:25 +00:00
|
|
|
int demux_seek(struct demuxer *demuxer, double rel_seek_secs, int flags);
|
2015-11-16 21:47:17 +00:00
|
|
|
void demux_set_ts_offset(struct demuxer *demuxer, double offset);
|
2001-04-23 16:12:21 +00:00
|
|
|
|
2018-09-07 20:26:48 +00:00
|
|
|
void demux_get_bitrate_stats(struct demuxer *demuxer, double *rates);
|
|
|
|
void demux_get_reader_state(struct demuxer *demuxer, struct demux_reader_state *r);
|
2002-03-03 18:47:29 +00:00
|
|
|
|
2018-01-17 06:07:15 +00:00
|
|
|
void demux_block_reading(struct demuxer *demuxer, bool block);
|
|
|
|
|
2013-07-11 17:22:24 +00:00
|
|
|
void demuxer_select_track(struct demuxer *demuxer, struct sh_stream *stream,
|
2023-09-30 13:58:56 +00:00
|
|
|
double ref_pts, bool selected);
|
2020-11-19 14:07:53 +00:00
|
|
|
void demuxer_refresh_track(struct demuxer *demuxer, struct sh_stream *stream,
|
2023-09-30 13:58:56 +00:00
|
|
|
double ref_pts);
|
2003-01-19 00:21:54 +00:00
|
|
|
|
2021-03-07 00:08:17 +00:00
|
|
|
int demuxer_help(struct mp_log *log, const m_option_t *opt, struct bstr name);
|
2006-08-06 18:55:34 +00:00
|
|
|
|
2015-06-24 12:18:51 +00:00
|
|
|
int demuxer_add_attachment(struct demuxer *demuxer, char *name,
|
|
|
|
char *type, void *data, size_t data_size);
|
|
|
|
int demuxer_add_chapter(demuxer_t *demuxer, char *name,
|
2014-11-02 16:20:04 +00:00
|
|
|
double pts, uint64_t demuxer_id);
|
demux: redo timed metadata
The old implementation didn't work for the OGG case. Discard the old
shit code (instead of fixing it), and write new shit code. The old code
was already over a year old, so it's about time to rewrite it for no
reason anyway.
While it's true that the old code appears to be broken, the main reason
to rewrite this is to make it simpler. While the amount of code seems to
be about the same, both the concept and the actual tag handling are
simpler. The result is probably a bit more correct.
The packet struct shrinks by 8 byte. That fact that it wasted 8 bytes
per packet for a rather obscure use case was the reason I started this
at all (and when I found that OGG updates didn't work). While these 8
bytes aren't going to hurt, the packet struct was getting too bloated.
If you buffer a lot of data, these extra fields will add up. Still quite
some effort for 8 bytes. Fortunately, it's not like there are any
managers that need to be convinced whether it's worth doing. The freedom
to waste time on dumb shit.
The old implementation attached the current metadata to each packet.
When the decoder read the packet, the packet's metadata was made
current. The new implementation stores metadata as separate list, and
requires that the player frontend tells it the current playback time,
which will be used to find the currently valid metadata. In both cases,
the objective was to correctly update metadata even if a lot of data is
buffered ahead (and to update them correctly when seeking within the
demuxer cache).
The new implementation is actually slightly more correct, because it
uses the playback time for the metadata lookup. Consider if you have an
audio filter which buffers 15 seconds (unfortunately such a filter
exists), then the old code would update the current title 15 seconds too
early, while the new one does it correctly.
The new code also simplifies mixing the 3 metadata sources (global, per
stream, ICY). We assume these aren't mixed in a meaningful way. The old
code tried to be a bit more "exact". I didn't bother to look how the old
code did this, but the new code simply always "merges" with the previous
metadata, so if a newer tag removes a field, it's going to stick around
anyway.
I tried to keep it simple. Other approaches include making metadata a
special sh_stream with metadata packets. This would have been
conceptually clean, but the implementation would probably have been
unnatural (and doesn't match well with libavformat's API anyway). It
would have been nice to make the metadata updates chapter points (makes
a lot of sense for the intended use case, web radio current song
information), but I don't think it would have been a good idea to make
chapters suddenly so dynamic. (Still an idea to keep in mind; the new
code actually makes it easier to work towards this.)
You could mention how subtitles are timed metadata, and actually are
implemented as sparse packet streams in some formats. mp4 implements
chapters as special subtitle stream, AFAIK. (Ironically, this is very
not-ideal for files. It would be useful for streaming like web radio,
but mp4 is extremely bad for streaming by design for other reasons.)
bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla
bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla
bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla
bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla
bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla
bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla
bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla
bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla
bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla
bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla
bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla
bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla
bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla
bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla
2019-06-10 00:18:20 +00:00
|
|
|
void demux_stream_tags_changed(struct demuxer *demuxer, struct sh_stream *sh,
|
|
|
|
struct mp_tags *tags, double pts);
|
demux: change hack for closing subtitle files early
Subtitles (and a few other file types, like playlists) are not streamed,
but fully read on opening. This means keeping the file handle or network
socket open is a waste of resources and could cause other weird
behavior. This is why there's a hack to close them after opening.
Change this hack to make the demuxer itself do this, which is less
weird. (Until recently, demuxer->stream ownership was more complex,
which is why it was done this way.)
There is some evil shit due to a huge ownership/lifetime mess of various
objects. Especially EDL (the currently only nested demuxer case)
requires being careful about mp_cancel and passing down stream pointers.
As one defensive programming measure, stop accessing the "stream"
variable in open_given_type(), even where it would still work. This
includes removing a redundant line of code, and removing the peak call,
which should not be needed anymore, as the remaining demuxers do this
mostly correctly.
2018-09-07 21:02:36 +00:00
|
|
|
void demux_close_stream(struct demuxer *demuxer);
|
2006-08-06 18:55:34 +00:00
|
|
|
|
demux: support for some kinds of timed metadata
This makes ICY title changes show up at approximately the correct time,
even if the demuxer buffer is huge. (It'll still be wrong if the stream
byte cache contains a meaningful amount of data.)
It should have the same effect for mid-stream metadata changes in e.g.
OGG (untested).
This is still somewhat fishy, but in parts due to ICY being fishy, and
FFmpeg's metadata change API being somewhat fishy. For example, what
happens if you seek? With FFmpeg AVFMT_EVENT_FLAG_METADATA_UPDATED and
AVSTREAM_EVENT_FLAG_METADATA_UPDATED we hope that FFmpeg will correctly
restore the correct metadata when the first packet is returned.
If you seke with ICY, we're out of luck, and some audio will be
associated with the wrong tag until we get a new title through ICY
metadata update at an essentially random point (it's mostly inherent to
ICY). Then the tags will switch back and forth, and this behavior will
stick with the data stored in the demuxer cache. Fortunately, this can
happen only if the HTTP stream is actually seekable, which it usually is
not for ICY things. Seeking doesn't even make sense with ICY, since you
can't know the exact metadata location. Basically ICY metsdata sucks.
Some complexity is due to a microoptimization: I didn't want additional
atomic accesses for each packet if no timed metadata is used. (It
probably doesn't matter at all.)
2018-04-16 20:23:08 +00:00
|
|
|
void demux_metadata_changed(demuxer_t *demuxer);
|
demux: redo timed metadata
The old implementation didn't work for the OGG case. Discard the old
shit code (instead of fixing it), and write new shit code. The old code
was already over a year old, so it's about time to rewrite it for no
reason anyway.
While it's true that the old code appears to be broken, the main reason
to rewrite this is to make it simpler. While the amount of code seems to
be about the same, both the concept and the actual tag handling are
simpler. The result is probably a bit more correct.
The packet struct shrinks by 8 byte. That fact that it wasted 8 bytes
per packet for a rather obscure use case was the reason I started this
at all (and when I found that OGG updates didn't work). While these 8
bytes aren't going to hurt, the packet struct was getting too bloated.
If you buffer a lot of data, these extra fields will add up. Still quite
some effort for 8 bytes. Fortunately, it's not like there are any
managers that need to be convinced whether it's worth doing. The freedom
to waste time on dumb shit.
The old implementation attached the current metadata to each packet.
When the decoder read the packet, the packet's metadata was made
current. The new implementation stores metadata as separate list, and
requires that the player frontend tells it the current playback time,
which will be used to find the currently valid metadata. In both cases,
the objective was to correctly update metadata even if a lot of data is
buffered ahead (and to update them correctly when seeking within the
demuxer cache).
The new implementation is actually slightly more correct, because it
uses the playback time for the metadata lookup. Consider if you have an
audio filter which buffers 15 seconds (unfortunately such a filter
exists), then the old code would update the current title 15 seconds too
early, while the new one does it correctly.
The new code also simplifies mixing the 3 metadata sources (global, per
stream, ICY). We assume these aren't mixed in a meaningful way. The old
code tried to be a bit more "exact". I didn't bother to look how the old
code did this, but the new code simply always "merges" with the previous
metadata, so if a newer tag removes a field, it's going to stick around
anyway.
I tried to keep it simple. Other approaches include making metadata a
special sh_stream with metadata packets. This would have been
conceptually clean, but the implementation would probably have been
unnatural (and doesn't match well with libavformat's API anyway). It
would have been nice to make the metadata updates chapter points (makes
a lot of sense for the intended use case, web radio current song
information), but I don't think it would have been a good idea to make
chapters suddenly so dynamic. (Still an idea to keep in mind; the new
code actually makes it easier to work towards this.)
You could mention how subtitles are timed metadata, and actually are
implemented as sparse packet streams in some formats. mp4 implements
chapters as special subtitle stream, AFAIK. (Ironically, this is very
not-ideal for files. It would be useful for streaming like web radio,
but mp4 is extremely bad for streaming by design for other reasons.)
bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla
bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla
bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla
bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla
bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla
bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla
bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla
bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla
bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla
bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla
bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla
bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla
bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla
bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla
2019-06-10 00:18:20 +00:00
|
|
|
void demux_update(demuxer_t *demuxer, double playback_pts);
|
2014-07-16 20:40:21 +00:00
|
|
|
|
demux, command: add a third stream recording mechanism
That's right, and it's probably not the end of it. I'll just claim that
I have no idea how to create a proper user interface for this, so I'm
creating multiple partially-orthogonal, of which some may work better in
each of its special use cases.
Until now, there was --record-file. You get relatively good control
about what is muxed, and it can use the cache. But it sucks that it's
bound to playback. If you pause while it's set, muxing stops. If you
seek while it's set, the output will be sort-of trashed, and that's by
design.
Then --stream-record was added. This is a bit better (especially for
live streams), but you can't really control well when muxing stops or
ends. In particular, it can't use the cache (it just dumps whatever the
underlying demuxer returns).
Today, the idea is that the user should just be able to select a time
range to dump to a file, and it should not affected by the user seeking
around in the cache. In addition, the stream may still be running, so
there's some need to continue dumping, even if it's redundant to
--stream-record.
One notable thing is that it uses the async command shit. Not sure
whether this is a good idea. Maybe not, but whatever. Also, a user can
always use the "async" prefix to pretend it doesn't.
Much of this was barely tested (especially the reinterleaving crap),
let's just hope it mostly works. I'm sure you can tolerate the one or
other crash?
2019-07-07 18:38:22 +00:00
|
|
|
bool demux_cache_dump_set(struct demuxer *demuxer, double start, double end,
|
|
|
|
char *file);
|
|
|
|
int demux_cache_dump_get_status(struct demuxer *demuxer);
|
|
|
|
|
2019-07-10 19:38:37 +00:00
|
|
|
double demux_probe_cache_dump_target(struct demuxer *demuxer, double pts,
|
|
|
|
bool for_end);
|
|
|
|
|
2018-08-31 10:48:36 +00:00
|
|
|
bool demux_is_network_cached(demuxer_t *demuxer);
|
2017-12-10 04:07:36 +00:00
|
|
|
|
2019-01-05 07:49:31 +00:00
|
|
|
void demux_report_unbuffered_read_bytes(struct demuxer *demuxer, int64_t new);
|
demux_timeline: report network speed of slave connections
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).
2019-01-05 07:52:41 +00:00
|
|
|
int64_t demux_get_bytes_read_hack(struct demuxer *demuxer);
|
2019-01-05 07:49:31 +00:00
|
|
|
|
2012-08-19 16:01:30 +00:00
|
|
|
struct sh_stream *demuxer_stream_by_demuxer_id(struct demuxer *d,
|
|
|
|
enum stream_type t, int id);
|
2008-03-30 16:55:46 +00:00
|
|
|
|
2014-11-02 16:20:04 +00:00
|
|
|
struct demux_chapter *demux_copy_chapter_data(struct demux_chapter *c, int num);
|
|
|
|
|
2013-10-07 00:49:12 +00:00
|
|
|
bool demux_matroska_uid_cmp(struct matroska_segment_uid *a,
|
|
|
|
struct matroska_segment_uid *b);
|
|
|
|
|
2014-02-15 15:48:56 +00:00
|
|
|
const char *stream_type_name(enum stream_type type);
|
|
|
|
|
2008-02-22 09:09:46 +00:00
|
|
|
#endif /* MPLAYER_DEMUXER_H */
|