summaryrefslogtreecommitdiffstats
path: root/demux
diff options
context:
space:
mode:
Diffstat (limited to 'demux')
-rw-r--r--demux/cue.c2
-rw-r--r--demux/demux.c137
-rw-r--r--demux/demux.h6
-rw-r--r--demux/demux_disc.c28
-rw-r--r--demux/demux_edl.c152
-rw-r--r--demux/demux_lavf.c54
-rw-r--r--demux/demux_mf.c5
-rw-r--r--demux/demux_mkv.c30
-rw-r--r--demux/demux_mkv_timeline.c2
-rw-r--r--demux/demux_playlist.c2
-rw-r--r--demux/demux_timeline.c180
-rw-r--r--demux/demux_tv.c7
-rw-r--r--demux/ebml.c2
-rw-r--r--demux/packet.c24
-rw-r--r--demux/packet.h2
-rw-r--r--demux/timeline.c4
-rw-r--r--demux/timeline.h4
17 files changed, 441 insertions, 200 deletions
diff --git a/demux/cue.c b/demux/cue.c
index 69f30f4871..9dbde71062 100644
--- a/demux/cue.c
+++ b/demux/cue.c
@@ -70,7 +70,7 @@ static enum cue_command read_cmd(struct bstr *data, struct bstr *out_params)
return CUE_EMPTY;
for (int n = 0; cue_command_strings[n].command != -1; n++) {
struct bstr name = bstr0(cue_command_strings[n].text);
- if (bstr_startswith(line, name)) {
+ if (bstr_case_startswith(line, name)) {
struct bstr rest = bstr_cut(line, name.len);
if (rest.len && !strchr(WHITESPACE, rest.start[0]))
continue;
diff --git a/demux/demux.c b/demux/demux.c
index 18c9b3b5c1..0c45083e2d 100644
--- a/demux/demux.c
+++ b/demux/demux.c
@@ -205,6 +205,9 @@ struct demux_stream {
struct demux_packet *head;
struct demux_packet *tail;
+ struct demux_packet *attached_picture;
+ bool attached_picture_added;
+
// for closed captions (demuxer_feed_caption)
struct sh_stream *cc;
};
@@ -243,6 +246,7 @@ static void ds_flush(struct demux_stream *ds)
ds->last_pos = -1;
ds->last_dts = MP_NOPTS_VALUE;
ds->correct_dts = ds->correct_pos = true;
+ ds->attached_picture_added = false;
}
void demux_set_ts_offset(struct demuxer *demuxer, double offset)
@@ -291,6 +295,8 @@ void demux_add_sh_stream(struct demuxer *demuxer, struct sh_stream *sh)
if (!sh->codec->codec)
sh->codec->codec = "";
+ sh->ds->attached_picture = sh->attached_picture;
+
sh->index = in->num_streams;
if (sh->ff_index < 0)
sh->ff_index = sh->index;
@@ -655,7 +661,9 @@ static bool read_packet(struct demux_internal *in)
demux->desc->seek(demux, seek_pts, SEEK_BACKWARD | SEEK_HR);
}
- bool eof = !demux->desc->fill_buffer || demux->desc->fill_buffer(demux) <= 0;
+ bool eof = true;
+ if (demux->desc->fill_buffer && !demux_cancel_test(demux))
+ eof = demux->desc->fill_buffer(demux) <= 0;
update_cache(in);
pthread_mutex_lock(&in->lock);
@@ -677,28 +685,6 @@ static bool read_packet(struct demux_internal *in)
return true;
}
-// must be called locked; may temporarily unlock
-static void ds_get_packets(struct demux_stream *ds)
-{
- const char *t = stream_type_name(ds->type);
- struct demux_internal *in = ds->in;
- MP_DBG(in, "reading packet for %s\n", t);
- in->eof = false; // force retry
- while (ds->selected && !ds->head) {
- ds->active = true;
- // Note: the following code marks EOF if it can't continue
- if (in->threading) {
- MP_VERBOSE(in, "waiting for demux thread (%s)\n", t);
- pthread_cond_signal(&in->wakeup);
- pthread_cond_wait(&in->wakeup, &in->lock);
- } else {
- read_packet(in);
- }
- if (ds->eof)
- break;
- }
-}
-
static void execute_trackswitch(struct demux_internal *in)
{
in->tracks_switched = false;
@@ -777,6 +763,13 @@ static void *demux_thread(void *pctx)
static struct demux_packet *dequeue_packet(struct demux_stream *ds)
{
+ if (ds->attached_picture) {
+ ds->eof = true;
+ if (ds->attached_picture_added)
+ return NULL;
+ ds->attached_picture_added = true;
+ return demux_copy_packet(ds->attached_picture);
+ }
if (!ds->head)
return NULL;
struct demux_packet *pkt = ds->head;
@@ -820,16 +813,23 @@ static struct demux_packet *dequeue_packet(struct demux_stream *ds)
return pkt;
}
+// Whether to avoid actively demuxing new packets to find a new packet on the
+// given stream.
+// Attached pictures (cover art) should never actively read.
// Sparse packets (Subtitles) interleaved with other non-sparse packets (video,
// audio) should never be read actively, meaning the demuxer thread does not
// try to exceed default readahead in order to find a new packet.
-static bool use_lazy_subtitle_reading(struct demux_stream *ds)
+static bool use_lazy_packet_reading(struct demux_stream *ds)
{
+ if (ds->attached_picture)
+ return true;
if (ds->type != STREAM_SUB)
return false;
+ // Subtitles are only lazily read if there's at least 1 other actively read
+ // stream.
for (int n = 0; n < ds->in->num_streams; n++) {
struct demux_stream *s = ds->in->streams[n]->ds;
- if (s->type != STREAM_SUB && s->selected && !s->eof)
+ if (s->type != STREAM_SUB && s->selected && !s->eof && !s->attached_picture)
return true;
}
return false;
@@ -843,12 +843,29 @@ struct demux_packet *demux_read_packet(struct sh_stream *sh)
struct demux_stream *ds = sh ? sh->ds : NULL;
struct demux_packet *pkt = NULL;
if (ds) {
- pthread_mutex_lock(&ds->in->lock);
- if (!use_lazy_subtitle_reading(ds))
- ds_get_packets(ds);
+ struct demux_internal *in = ds->in;
+ pthread_mutex_lock(&in->lock);
+ if (!use_lazy_packet_reading(ds)) {
+ const char *t = stream_type_name(ds->type);
+ MP_DBG(in, "reading packet for %s\n", t);
+ in->eof = false; // force retry
+ while (ds->selected && !ds->head) {
+ ds->active = true;
+ // Note: the following code marks EOF if it can't continue
+ if (in->threading) {
+ MP_VERBOSE(in, "waiting for demux thread (%s)\n", t);
+ pthread_cond_signal(&in->wakeup);
+ pthread_cond_wait(&in->wakeup, &in->lock);
+ } else {
+ read_packet(in);
+ }
+ if (ds->eof)
+ break;
+ }
+ }
pkt = dequeue_packet(ds);
- pthread_cond_signal(&ds->in->wakeup); // possibly read more
- pthread_mutex_unlock(&ds->in->lock);
+ pthread_cond_signal(&in->wakeup); // possibly read more
+ pthread_mutex_unlock(&in->lock);
}
return pkt;
}
@@ -874,7 +891,7 @@ int demux_read_packet_async(struct sh_stream *sh, struct demux_packet **out_pkt)
if (ds->in->threading) {
pthread_mutex_lock(&ds->in->lock);
*out_pkt = dequeue_packet(ds);
- if (use_lazy_subtitle_reading(ds)) {
+ if (use_lazy_packet_reading(ds)) {
r = *out_pkt ? 1 : -1;
} else {
r = *out_pkt ? 1 : ((ds->eof || !ds->selected) ? -1 : 0);
@@ -1231,8 +1248,7 @@ static struct demuxer *open_given_type(struct mpv_global *global,
.events = DEMUX_EVENT_ALL,
};
demuxer->seekable = stream->seekable;
- if (demuxer->stream->uncached_stream &&
- !demuxer->stream->uncached_stream->seekable)
+ if (demuxer->stream->underlying && !demuxer->stream->underlying->seekable)
demuxer->seekable = false;
struct demux_internal *in = demuxer->in = talloc_ptrtype(demuxer, in);
@@ -1249,9 +1265,6 @@ static struct demuxer *open_given_type(struct mpv_global *global,
pthread_mutex_init(&in->lock, NULL);
pthread_cond_init(&in->wakeup, NULL);
- if (stream->uncached_stream)
- in->min_secs = MPMAX(in->min_secs, opts->min_secs_cache);
-
*in->d_thread = *demuxer;
*in->d_buffer = *demuxer;
@@ -1290,7 +1303,8 @@ static struct demuxer *open_given_type(struct mpv_global *global,
demux_init_cache(demuxer);
demux_changed(in->d_thread, DEMUX_EVENT_ALL);
demux_update(demuxer);
- stream_control(demuxer->stream, STREAM_CTRL_SET_READAHEAD, &(int){false});
+ stream_control(demuxer->stream, STREAM_CTRL_SET_READAHEAD,
+ &(int){params ? params->initial_readahead : false});
if (!(params && params->disable_timeline)) {
struct timeline *tl = timeline_load(global, log, demuxer);
if (tl) {
@@ -1299,11 +1313,15 @@ static struct demuxer *open_given_type(struct mpv_global *global,
struct demuxer *sub =
open_given_type(global, log, &demuxer_desc_timeline, stream,
&params2, DEMUX_CHECK_FORCE);
- if (sub)
- return sub;
- timeline_destroy(tl);
+ if (sub) {
+ demuxer = sub;
+ } else {
+ timeline_destroy(tl);
+ }
}
}
+ if (demuxer->is_network || stream->caching)
+ in->min_secs = MPMAX(in->min_secs, opts->min_secs_cache);
return demuxer;
}
@@ -1382,12 +1400,6 @@ struct demuxer *demux_open_url(const char *url,
cancel, global);
if (!s)
return NULL;
- if (params->allow_capture) {
- char *f;
- mp_read_option_raw(global, "stream-capture", &m_option_type_string, &f);
- stream_set_capture_file(s, f);
- talloc_free(f);
- }
if (!params->disable_cache)
stream_enable_cache_defaults(&s);
struct demuxer *d = demux_open(s, params, global);
@@ -1724,6 +1736,7 @@ static void thread_demux_control(void *p)
int demux_control(demuxer_t *demuxer, int cmd, void *arg)
{
struct demux_internal *in = demuxer->in;
+ assert(demuxer == in->d_user);
if (in->threading) {
pthread_mutex_lock(&in->lock);
@@ -1735,37 +1748,29 @@ int demux_control(demuxer_t *demuxer, int cmd, void *arg)
int r = 0;
struct demux_control_args args = {demuxer, cmd, arg, &r};
- demux_run_on_thread(demuxer, thread_demux_control, &args);
-
- return r;
-}
-
-int demux_stream_control(demuxer_t *demuxer, int ctrl, void *arg)
-{
- struct demux_ctrl_stream_ctrl c = {ctrl, arg, STREAM_UNSUPPORTED};
- demux_control(demuxer, DEMUXER_CTRL_STREAM_CTRL, &c);
- return c.res;
-}
-
-void demux_run_on_thread(struct demuxer *demuxer, void (*fn)(void *), void *ctx)
-{
- struct demux_internal *in = demuxer->in;
- assert(demuxer == in->d_user);
-
if (in->threading) {
MP_VERBOSE(in, "blocking on demuxer thread\n");
pthread_mutex_lock(&in->lock);
while (in->run_fn)
pthread_cond_wait(&in->wakeup, &in->lock);
- in->run_fn = fn;
- in->run_fn_arg = ctx;
+ in->run_fn = thread_demux_control;
+ in->run_fn_arg = &args;
pthread_cond_signal(&in->wakeup);
while (in->run_fn)
pthread_cond_wait(&in->wakeup, &in->lock);
pthread_mutex_unlock(&in->lock);
} else {
- fn(ctx);
+ thread_demux_control(&args);
}
+
+ return r;
+}
+
+int demux_stream_control(demuxer_t *demuxer, int ctrl, void *arg)
+{
+ struct demux_ctrl_stream_ctrl c = {ctrl, arg, STREAM_UNSUPPORTED};
+ demux_control(demuxer, DEMUXER_CTRL_STREAM_CTRL, &c);
+ return c.res;
}
bool demux_cancel_test(struct demuxer *demuxer)
diff --git a/demux/demux.h b/demux/demux.h
index 0e5a5e15c6..8a1da4e400 100644
--- a/demux/demux.h
+++ b/demux/demux.h
@@ -162,9 +162,11 @@ struct demuxer_params {
bool *matroska_was_valid;
struct timeline *timeline;
bool disable_timeline;
+ bool initial_readahead;
+ bstr init_fragment;
+ bool skip_lavf_probing;
// -- demux_open_url() only
int stream_flags;
- bool allow_capture;
bool disable_cache;
// result
bool demuxer_failed;
@@ -287,8 +289,6 @@ double demuxer_get_time_length(struct demuxer *demuxer);
int demux_stream_control(demuxer_t *demuxer, int ctrl, void *arg);
-void demux_run_on_thread(struct demuxer *demuxer, void (*fn)(void *), void *ctx);
-
void demux_changed(demuxer_t *demuxer, int events);
void demux_update(demuxer_t *demuxer);
diff --git a/demux/demux_disc.c b/demux/demux_disc.c
index 805ba4ccff..ad54db8c19 100644
--- a/demux/demux_disc.c
+++ b/demux/demux_disc.c
@@ -43,6 +43,8 @@ struct priv {
double base_dts; // packet DTS that maps to base_time
double last_dts; // DTS of previously demuxed packet
bool seek_reinit; // needs reinit after seek
+
+ bool is_dvd, is_cdda;
};
// If the timestamp difference between subsequent packets is this big, assume
@@ -65,7 +67,7 @@ static void reselect_streams(demuxer_t *demuxer)
static void get_disc_lang(struct stream *stream, struct sh_stream *sh)
{
struct stream_lang_req req = {.type = sh->type, .id = sh->demuxer_id};
- if (stream->uncached_type == STREAMTYPE_DVD && sh->type == STREAM_SUB)
+ if (sh->type == STREAM_SUB)
req.id = req.id & 0x1F; // mpeg ID to index
stream_control(stream, STREAM_CTRL_GET_LANG, &req);
if (req.name[0])
@@ -76,7 +78,7 @@ static void add_dvd_streams(demuxer_t *demuxer)
{
struct priv *p = demuxer->priv;
struct stream *stream = demuxer->stream;
- if (stream->uncached_type != STREAMTYPE_DVD)
+ if (!p->is_dvd)
return;
struct stream_dvd_info_req info;
if (stream_control(stream, STREAM_CTRL_GET_DVD_INFO, &info) > 0) {
@@ -162,7 +164,7 @@ static void d_seek(demuxer_t *demuxer, double seek_pts, int flags)
{
struct priv *p = demuxer->priv;
- if (demuxer->stream->uncached_type == STREAMTYPE_CDDA) {
+ if (p->is_cdda) {
demux_seek(p->slave, seek_pts, flags);
return;
}
@@ -222,7 +224,7 @@ static int d_fill_buffer(demuxer_t *demuxer)
return 1;
}
- if (demuxer->stream->uncached_type == STREAMTYPE_CDDA) {
+ if (p->is_cdda) {
demux_add_packet(sh, pkt);
return 1;
}
@@ -285,7 +287,21 @@ static int d_open(demuxer_t *demuxer, enum demux_check check)
struct demuxer_params params = {.force_format = "+lavf"};
- if (demuxer->stream->uncached_type == STREAMTYPE_CDDA)
+ struct stream *cur = demuxer->stream;
+ const char *sname = "";
+ while (cur) {
+ if (cur->info)
+ sname = cur->info->name;
+ cur = cur->underlying; // down the caching chain
+ }
+
+ p->is_cdda = strcmp(sname, "cdda") == 0;
+ p->is_dvd = strcmp(sname, "dvd") == 0 ||
+ strcmp(sname, "ifo") == 0 ||
+ strcmp(sname, "dvdnav") == 0 ||
+ strcmp(sname, "ifo_dvdnav") == 0;
+
+ if (p->is_cdda)
params.force_format = "+rawaudio";
char *t = NULL;
@@ -311,7 +327,7 @@ static int d_open(demuxer_t *demuxer, enum demux_check check)
// (actually libavformat/mpegts.c) to seek sometimes when reading a packet.
// It does this to seek back a bit in case the current file position points
// into the middle of a packet.
- if (demuxer->stream->uncached_type != STREAMTYPE_CDDA) {
+ if (!p->is_cdda) {
demuxer->stream->seekable = false;
// Can be seekable even if the stream isn't.
diff --git a/demux/demux_edl.c b/demux/demux_edl.c
index 623cae35b3..8b6f402b27 100644
--- a/demux/demux_edl.c
+++ b/demux/demux_edl.c
@@ -44,12 +44,15 @@ struct tl_part {
};
struct tl_parts {
+ bool dash;
+ char *init_fragment_url;
struct tl_part *parts;
int num_parts;
};
struct priv {
bstr data;
+ bool allow_any;
};
// Parse a time (absolute file time or duration). Currently equivalent to a
@@ -64,6 +67,8 @@ static bool parse_time(bstr str, double *out_time)
return true;
}
+#define MAX_PARAMS 10
+
/* Returns a list of parts, or NULL on parse error.
* Syntax (without file header or URI prefix):
* url ::= <entry> ( (';' | '\n') <entry> )*
@@ -78,7 +83,10 @@ static struct tl_parts *parse_edl(bstr str)
bstr_split_tok(str, "\n", &(bstr){0}, &str);
if (bstr_eatstart0(&str, "\n") || bstr_eatstart0(&str, ";"))
continue;
+ bool is_header = bstr_eatstart0(&str, "!");
struct tl_part p = { .length = -1 };
+ bstr param_names[MAX_PARAMS];
+ bstr param_vals[MAX_PARAMS];
int nparam = 0;
while (1) {
bstr name, val;
@@ -116,10 +124,25 @@ static struct tl_parts *parse_edl(bstr str)
if (bstr_equals0(val, "chapters"))
p.chapter_ts = true;
}
+ if (nparam >= MAX_PARAMS)
+ goto error;
+ param_names[nparam] = name;
+ param_vals[nparam] = val;
nparam++;
if (!bstr_eatstart0(&str, ","))
break;
}
+ if (is_header) {
+ if (tl->num_parts)
+ goto error; // can't have header once an entry was defined
+ bstr type = param_vals[0]; // value, because no "="
+ if (bstr_equals0(type, "mp4_dash")) {
+ tl->dash = true;
+ if (bstr_equals0(param_names[1], "init"))
+ tl->init_fragment_url = bstrto0(tl, param_vals[1]);
+ }
+ continue;
+ }
if (!p.filename)
goto error;
MP_TARRAY_APPEND(tl, tl->parts, tl->num_parts, p);
@@ -139,7 +162,10 @@ static struct demuxer *open_source(struct timeline *tl, char *filename)
if (strcmp(d->stream->url, filename) == 0)
return d;
}
- struct demuxer *d = demux_open_url(filename, NULL, tl->cancel, tl->global);
+ struct demuxer_params params = {
+ .init_fragment = tl->init_fragment,
+ };
+ struct demuxer *d = demux_open_url(filename, &params, tl->cancel, tl->global);
if (d) {
MP_TARRAY_APPEND(tl, tl->sources, tl->num_sources, d);
} else {
@@ -202,61 +228,110 @@ static void resolve_timestamps(struct tl_part *part, struct demuxer *demuxer)
static void build_timeline(struct timeline *tl, struct tl_parts *parts)
{
+ tl->track_layout = NULL;
+ tl->dash = parts->dash;
+
+ if (parts->init_fragment_url && parts->init_fragment_url[0]) {
+ MP_VERBOSE(tl, "Opening init fragment...\n");
+ stream_t *s = stream_create(parts->init_fragment_url, STREAM_READ,
+ tl->cancel, tl->global);
+ if (s)
+ tl->init_fragment = stream_read_complete(s, tl, 1000000);
+ free_stream(s);
+ if (!tl->init_fragment.len) {
+ MP_ERR(tl, "Could not read init fragment.\n");
+ goto error;
+ }
+ s = open_memory_stream(tl->init_fragment.start, tl->init_fragment.len);
+ tl->track_layout = demux_open(s, NULL, tl->global);
+ if (!tl->track_layout) {
+ free_stream(s);
+ MP_ERR(tl, "Could not demux init fragment.\n");
+ goto error;
+ }
+ }
+
tl->parts = talloc_array_ptrtype(tl, tl->parts, parts->num_parts + 1);
double starttime = 0;
for (int n = 0; n < parts->num_parts; n++) {
struct tl_part *part = &parts->parts[n];
- struct demuxer *source = open_source(tl, part->filename);
- if (!source)
- goto error;
-
- resolve_timestamps(part, source);
+ struct demuxer *source = NULL;
- double end_time = source_get_length(source);
- if (end_time >= 0)
- end_time += source->start_time;
+ if (tl->dash) {
+ part->offset = starttime;
+ if (part->length <= 0)
+ MP_WARN(tl, "Segment %d has unknown duration.\n", n);
+ if (part->offset_set)
+ MP_WARN(tl, "Offsets are ignored.\n");
+ tl->demuxer->is_network = true;
- // Unknown length => use rest of the file. If duration is unknown, make
- // something up.
- if (part->length < 0) {
- if (end_time < 0) {
- MP_WARN(tl, "EDL: source file '%s' has unknown duration.\n",
- part->filename);
- end_time = 1;
+ if (!tl->track_layout) {
+ source = open_source(tl, part->filename);
+ if (!source)
+ goto error;
}
- part->length = end_time - part->offset;
- } else if (end_time >= 0) {
- double end_part = part->offset + part->length;
- if (end_part > end_time) {
- MP_WARN(tl, "EDL: entry %d uses %f "
- "seconds, but file has only %f seconds.\n",
- n, end_part, end_time);
+ } else {
+ MP_VERBOSE(tl, "Opening segment %d...\n", n);
+
+ source = open_source(tl, part->filename);
+ if (!source)
+ goto error;
+
+ resolve_timestamps(part, source);
+
+ double end_time = source_get_length(source);
+ if (end_time >= 0)
+ end_time += source->start_time;
+
+ // Unknown length => use rest of the file. If duration is unknown, make
+ // something up.
+ if (part->length < 0) {
+ if (end_time < 0) {
+ MP_WARN(tl, "EDL: source file '%s' has unknown duration.\n",
+ part->filename);
+ end_time = 1;
+ }
+ part->length = end_time - part->offset;
+ } else if (end_time >= 0) {
+ double end_part = part->offset + part->length;
+ if (end_part > end_time) {
+ MP_WARN(tl, "EDL: entry %d uses %f "
+ "seconds, but file has only %f seconds.\n",
+ n, end_part, end_time);
+ }
}
- }
- // Add a chapter between each file.
- struct demux_chapter ch = {
- .pts = starttime,
- .metadata = talloc_zero(tl, struct mp_tags),
- };
- mp_tags_set_str(ch.metadata, "title", part->filename);
- MP_TARRAY_APPEND(tl, tl->chapters, tl->num_chapters, ch);
+ // Add a chapter between each file.
+ struct demux_chapter ch = {
+ .pts = starttime,
+ .metadata = talloc_zero(tl, struct mp_tags),
+ };
+ mp_tags_set_str(ch.metadata, "title", part->filename);
+ MP_TARRAY_APPEND(tl, tl->chapters, tl->num_chapters, ch);
- // Also copy the source file's chapters for the relevant parts
- copy_chapters(&tl->chapters, &tl->num_chapters, source, part->offset,
- part->length, starttime);
+ // Also copy the source file's chapters for the relevant parts
+ copy_chapters(&tl->chapters, &tl->num_chapters, source, part->offset,
+ part->length, starttime);
+ }
tl->parts[n] = (struct timeline_part) {
.start = starttime,
.source_start = part->offset,
.source = source,
+ .url = talloc_strdup(tl, part->filename),
};
starttime += part->length;
+
+ if (source) {
+ tl->demuxer->is_network |= source->is_network;
+
+ if (!tl->track_layout)
+ tl->track_layout = source;
+ }
}
tl->parts[parts->num_parts] = (struct timeline_part) {.start = starttime};
tl->num_parts = parts->num_parts;
- tl->track_layout = tl->parts[0].source;
return;
error:
@@ -286,8 +361,7 @@ static void build_mpv_edl_timeline(struct timeline *tl)
return;
}
MP_TARRAY_APPEND(tl, tl->sources, tl->num_sources, tl->demuxer);
- // Source is .edl and not edl:// => don't allow arbitrary paths
- if (tl->demuxer->stream->uncached_type != STREAMTYPE_EDL)
+ if (!p->allow_any)
fix_filenames(parts, tl->demuxer->filename);
build_timeline(tl, parts);
talloc_free(parts);
@@ -303,8 +377,10 @@ static int try_open_file(struct demuxer *demuxer, enum demux_check check)
demuxer->fully_read = true;
struct stream *s = demuxer->stream;
- if (s->uncached_type == STREAMTYPE_EDL) {
+ if (s->info && strcmp(s->info->name, "edl") == 0) {
p->data = bstr0(s->path);
+ // Source is edl:// and not .edl => allow arbitrary paths
+ p->allow_any = true;
return 0;
}
if (check >= DEMUX_CHECK_UNSAFE) {
diff --git a/demux/demux_lavf.c b/demux/demux_lavf.c
index 124956378c..46a2f558af 100644
--- a/demux/demux_lavf.c
+++ b/demux/demux_lavf.c
@@ -183,6 +183,8 @@ typedef struct lavf_priv {
AVInputFormat *avif;
int avif_flags;
AVFormatContext *avfc;
+ bstr init_fragment;
+ int64_t stream_pos;
AVIOContext *pb;
struct sh_stream **streams; // NULL for unknown streams
int num_streams;
@@ -218,7 +220,14 @@ static int mp_read(void *opaque, uint8_t *buf, int size)
struct stream *stream = priv->stream;
int ret;
- ret = stream_read(stream, buf, size);
+ if (priv->stream_pos < priv->init_fragment.len) {
+ ret = MPMIN(size, priv->init_fragment.len - priv->stream_pos);
+ memcpy(buf, priv->init_fragment.start + priv->stream_pos, ret);
+ priv->stream_pos += ret;
+ } else {
+ ret = stream_read(stream, buf, size);
+ priv->stream_pos = priv->init_fragment.len + stream_tell(stream);
+ }
MP_TRACE(demuxer, "%d=mp_read(%p, %p, %d), pos: %"PRId64", eof:%d\n",
ret, stream, buf, size, stream_tell(stream), stream->eof);
@@ -230,32 +239,44 @@ static int64_t mp_seek(void *opaque, int64_t pos, int whence)
struct demuxer *demuxer = opaque;
lavf_priv_t *priv = demuxer->priv;
struct stream *stream = priv->stream;
- int64_t current_pos;
+
MP_TRACE(demuxer, "mp_seek(%p, %"PRId64", %s)\n", stream, pos,
whence == SEEK_END ? "end" :
whence == SEEK_CUR ? "cur" :
whence == SEEK_SET ? "set" : "size");
if (whence == SEEK_END || whence == AVSEEK_SIZE) {
- int64_t end = stream_get_size(stream);
+ int64_t end = stream_get_size(stream) + priv->init_fragment.len;
if (end < 0)
return -1;
if (whence == AVSEEK_SIZE)
return end;
pos += end;
} else if (whence == SEEK_CUR) {
- pos += stream_tell(stream);
+ pos += priv->stream_pos;
} else if (whence != SEEK_SET) {
return -1;
}
if (pos < 0)
return -1;
- current_pos = stream_tell(stream);
- if (stream_seek(stream, pos) == 0) {
+
+ int64_t stream_target = pos - priv->init_fragment.len;
+ bool seek_before = stream_target < 0;
+ if (seek_before)
+ stream_target = 0; // within init segment - seek real stream to 0
+
+ int64_t current_pos = stream_tell(stream);
+ if (stream_seek(stream, stream_target) == 0) {
stream_seek(stream, current_pos);
return -1;
}
+ if (seek_before) {
+ priv->stream_pos = pos;
+ } else {
+ priv->stream_pos = priv->init_fragment.len + stream_tell(stream);
+ }
+
return pos;
}
@@ -338,7 +359,7 @@ static int lavf_check_file(demuxer_t *demuxer, enum demux_check check)
priv->filename = remove_prefix(s->url, prefixes);
char *avdevice_format = NULL;
- if (s->uncached_type == STREAMTYPE_AVDEVICE) {
+ if (s->info && strcmp(s->info->name, "avdevice") == 0) {
// always require filename in the form "format:filename"
char *sep = strchr(priv->filename, ':');
if (!sep) {
@@ -376,7 +397,7 @@ static int lavf_check_file(demuxer_t *demuxer, enum demux_check check)
// Disable file-extension matching with normal checks
.filename = check <= DEMUX_CHECK_REQUEST ? priv->filename : "",
.buf_size = 0,
- .buf = av_mallocz(PROBE_BUF_SIZE + FF_INPUT_BUFFER_PADDING_SIZE),
+ .buf = av_mallocz(PROBE_BUF_SIZE + AV_INPUT_BUFFER_PADDING_SIZE),
};
if (!avpd.buf)
return -1;
@@ -771,6 +792,9 @@ static int demux_open_lavf(demuxer_t *demuxer, enum demux_check check)
if (lavf_check_file(demuxer, check) < 0)
return -1;
+ if (demuxer->params)
+ priv->init_fragment = bstrdup(priv, demuxer->params->init_fragment);
+
avfc = avformat_alloc_context();
if (!avfc)
return -1;
@@ -808,10 +832,7 @@ static int demux_open_lavf(demuxer_t *demuxer, enum demux_check check)
AVDictionary *dopts = NULL;
- if ((priv->avif_flags & AVFMT_NOFILE) ||
- priv->stream->type == STREAMTYPE_AVDEVICE ||
- priv->format_hack.no_stream)
- {
+ if ((priv->avif_flags & AVFMT_NOFILE) || priv->format_hack.no_stream) {
mp_setup_av_network_options(&dopts, demuxer->global, demuxer->log);
// This might be incorrect.
demuxer->seekable = true;
@@ -867,9 +888,12 @@ static int demux_open_lavf(demuxer_t *demuxer, enum demux_check check)
av_dict_free(&dopts);
priv->avfc = avfc;
- if (avformat_find_stream_info(avfc, NULL) < 0) {
- MP_ERR(demuxer, "av_find_stream_info() failed\n");
- return -1;
+
+ if (!demuxer->params || !demuxer->params->skip_lavf_probing) {
+ if (avformat_find_stream_info(avfc, NULL) < 0) {
+ MP_ERR(demuxer, "av_find_stream_info() failed\n");
+ return -1;
+ }
}
MP_VERBOSE(demuxer, "avformat_find_stream_info() finished after %"PRId64
diff --git a/demux/demux_mf.c b/demux/demux_mf.c
index 4abd394317..50afd355b7 100644
--- a/demux/demux_mf.c
+++ b/demux/demux_mf.c
@@ -294,9 +294,10 @@ static int demux_open_mf(demuxer_t *demuxer, enum demux_check check)
mf_t *mf;
if (strncmp(demuxer->stream->url, "mf://", 5) == 0 &&
- demuxer->stream->type == STREAMTYPE_MF)
+ demuxer->stream->info && strcmp(demuxer->stream->info->name, "mf") == 0)
+ {
mf = open_mf_pattern(demuxer, demuxer->log, demuxer->stream->url + 5);
- else {
+ } else {
mf = open_mf_single(demuxer, demuxer->log, demuxer->stream->url);
int bog = 0;
MP_TARRAY_APPEND(mf, mf->streams, bog, demuxer->stream);
diff --git a/demux/demux_mkv.c b/demux/demux_mkv.c
index ddda2ecb61..d564999fc6 100644
--- a/demux/demux_mkv.c
+++ b/demux/demux_mkv.c
@@ -162,6 +162,7 @@ struct block_info {
bstr data;
void *alloc;
int64_t filepos;
+ struct ebml_block_additions *additions;
};
typedef struct mkv_demuxer {
@@ -2392,6 +2393,8 @@ static void free_block(struct block_info *block)
free(block->alloc);
block->alloc = NULL;
block->data = (bstr){0};
+ talloc_free(block->additions);
+ block->additions = NULL;
}
static void index_block(demuxer_t *demuxer, struct block_info *block)
@@ -2552,6 +2555,15 @@ static int handle_block(demuxer_t *demuxer, struct block_info *block_info)
block_info->discardpadding / 1e9 * srate);
mkv_d->a_skip_preroll = 0;
}
+ if (block_info->additions) {
+ for (int n = 0; n < block_info->additions->n_block_more; n++) {
+ struct ebml_block_more *add =
+ &block_info->additions->block_more[n];
+ int64_t id = add->n_block_add_id ? add->block_add_id : 1;
+ demux_packet_add_blockadditional(dp, id,
+ add->block_additional.start, add->block_additional.len);
+ }
+ }
mkv_parse_and_add_packet(demuxer, track, dp);
talloc_free_children(track->parser_tmp);
@@ -2604,8 +2616,22 @@ static int read_block_group(demuxer_t *demuxer, int64_t end,
int64_t num = eb