diff options
Diffstat (limited to 'demux')
-rw-r--r-- | demux/cue.c | 2 | ||||
-rw-r--r-- | demux/demux.c | 137 | ||||
-rw-r--r-- | demux/demux.h | 6 | ||||
-rw-r--r-- | demux/demux_disc.c | 28 | ||||
-rw-r--r-- | demux/demux_edl.c | 152 | ||||
-rw-r--r-- | demux/demux_lavf.c | 54 | ||||
-rw-r--r-- | demux/demux_mf.c | 5 | ||||
-rw-r--r-- | demux/demux_mkv.c | 30 | ||||
-rw-r--r-- | demux/demux_mkv_timeline.c | 2 | ||||
-rw-r--r-- | demux/demux_playlist.c | 2 | ||||
-rw-r--r-- | demux/demux_timeline.c | 180 | ||||
-rw-r--r-- | demux/demux_tv.c | 7 | ||||
-rw-r--r-- | demux/ebml.c | 2 | ||||
-rw-r--r-- | demux/packet.c | 24 | ||||
-rw-r--r-- | demux/packet.h | 2 | ||||
-rw-r--r-- | demux/timeline.c | 4 | ||||
-rw-r--r-- | demux/timeline.h | 4 |
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, ¶ms2, 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, ¶ms, 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 |