summaryrefslogtreecommitdiffstats
path: root/demux
diff options
context:
space:
mode:
Diffstat (limited to 'demux')
-rw-r--r--demux/demux_edl.c51
-rw-r--r--demux/demux_timeline.c87
-rw-r--r--demux/timeline.h8
3 files changed, 114 insertions, 32 deletions
diff --git a/demux/demux_edl.c b/demux/demux_edl.c
index 9d276732fe..afa14cc084 100644
--- a/demux/demux_edl.c
+++ b/demux/demux_edl.c
@@ -49,6 +49,9 @@ struct tl_parts {
bool disable_chapters;
bool dash, no_clip;
char *init_fragment_url;
+ char *title, *lang;
+ bool delay_open;
+ enum stream_type delay_open_st;
struct tl_part *parts;
int num_parts;
struct tl_parts *next;
@@ -102,6 +105,9 @@ static struct tl_root *parse_edl(bstr str)
bool is_header = bstr_eatstart0(&str, "!");
bstr f_type = {0};
bstr f_init = {0};
+ bstr f_lang = {0};
+ bstr f_title = {0};
+ bstr f_mt = {0};
struct tl_part p = { .length = -1 };
int nparam = 0;
while (1) {
@@ -135,6 +141,12 @@ static struct tl_root *parse_edl(bstr str)
f_type = val;
} else if (bstr_equals0(name, "init")) {
f_init = val;
+ } else if (bstr_equals0(name, "lang")) {
+ f_lang = val;
+ } else if (bstr_equals0(name, "title")) {
+ f_title = val;
+ } else if (bstr_equals0(name, "media_type")) {
+ f_mt = val;
}
} else {
if (bstr_equals0(name, "file")) {
@@ -168,9 +180,28 @@ static struct tl_root *parse_edl(bstr str)
} else if (bstr_equals0(f_type, "no_clip")) {
tl->no_clip = true;
} else if (bstr_equals0(f_type, "new_stream")) {
- tl = add_part(root);
+ // (Special case: ignore "redundant" headers at the start for
+ // general symmetry.)
+ if (root->num_pars > 1 || tl->num_parts)
+ tl = add_part(root);
} else if (bstr_equals0(f_type, "no_chapters")) {
tl->disable_chapters = true;
+ } else if (bstr_equals0(f_type, "track_meta")) {
+ if (f_lang.start)
+ tl->lang = bstrto0(tl, f_lang);
+ if (f_title.start)
+ tl->title = bstrto0(tl, f_title);
+ } else if (bstr_equals0(f_type, "delay_open")) {
+ if (bstr_equals0(f_mt, "video")) {
+ tl->delay_open_st = STREAM_VIDEO;
+ } else if (bstr_equals0(f_mt, "audio")) {
+ tl->delay_open_st = STREAM_AUDIO;
+ } else if (bstr_equals0(f_mt, "sub")) {
+ tl->delay_open_st = STREAM_SUB;
+ } else {
+ goto error;
+ }
+ tl->delay_open = true;
} else {
goto error;
}
@@ -265,6 +296,10 @@ static struct timeline_par *build_timeline(struct timeline *root,
tl->track_layout = NULL;
tl->dash = parts->dash;
tl->no_clip = parts->no_clip;
+ tl->title = talloc_strdup(tl, parts->title);
+ tl->lang = talloc_strdup(tl, parts->lang);
+ tl->delay_open = parts->delay_open;
+ tl->delay_open_st = parts->delay_open_st;
if (parts->init_fragment_url && parts->init_fragment_url[0]) {
MP_VERBOSE(root, "Opening init fragment...\n");
@@ -309,6 +344,15 @@ static struct timeline_par *build_timeline(struct timeline *root,
if (!tl->track_layout)
tl->track_layout = open_source(root, tl, part->filename);
+ } else if (tl->delay_open) {
+ if (n == 0 && !part->offset_set) {
+ part->offset = starttime;
+ part->offset_set = true;
+ }
+ if (part->chapter_ts || (part->length < 0 && !tl->no_clip)) {
+ MP_ERR(root, "Incomplete specification for delay_open stream.\n");
+ goto error;
+ }
} else {
MP_VERBOSE(root, "Opening segment %d...\n", n);
@@ -372,6 +416,9 @@ static struct timeline_par *build_timeline(struct timeline *root,
tl->num_parts++;
}
+ if (tl->no_clip && tl->num_parts > 1)
+ MP_WARN(root, "Multiple parts with no_clip. Undefined behavior ahead.\n");
+
if (!tl->track_layout) {
// Use a heuristic to select the "broadest" part as layout.
for (int n = 0; n < parts->num_parts; n++) {
@@ -384,7 +431,7 @@ static struct timeline_par *build_timeline(struct timeline *root,
}
}
- if (!tl->track_layout)
+ if (!tl->track_layout && !tl->delay_open)
goto error;
if (!root->meta)
root->meta = tl->track_layout;
diff --git a/demux/demux_timeline.c b/demux/demux_timeline.c
index ecce06bcb2..362e113402 100644
--- a/demux/demux_timeline.c
+++ b/demux/demux_timeline.c
@@ -56,7 +56,7 @@ struct virtual_stream {
struct virtual_source {
struct timeline_par *tl;
- bool dash, no_clip;
+ bool dash, no_clip, delay_open;
struct segment **segments;
int num_segments;
@@ -207,11 +207,15 @@ static void reopen_lazy_segments(struct demuxer *demuxer,
if (src->current->d)
return;
- close_lazy_segments(demuxer, src);
+ // Note: in delay_open mode, we must _not_ close segments during demuxing,
+ // because demuxed packets have demux_packet.codec set to objects owned
+ // by the segments. Closing them would create dangling pointers.
+ if (!src->delay_open)
+ close_lazy_segments(demuxer, src);
struct demuxer_params params = {
.init_fragment = src->tl->init_fragment,
- .skip_lavf_probing = true,
+ .skip_lavf_probing = src->tl->dash,
.stream_flags = demuxer->stream_origin,
};
src->current->d = demux_open_url(src->current->url, &params,
@@ -418,10 +422,12 @@ static bool do_read_next_packet(struct demuxer *demuxer,
if (pkt->stream < 0 || pkt->stream >= seg->num_stream_map)
goto drop;
- if (!src->no_clip) {
+ if (!src->no_clip || src->delay_open) {
pkt->segmented = true;
if (!pkt->codec)
pkt->codec = demux_get_stream(seg->d, pkt->stream)->codec;
+ }
+ if (!src->no_clip) {
if (pkt->start == MP_NOPTS_VALUE || pkt->start < seg->start)
pkt->start = seg->start;
if (pkt->end == MP_NOPTS_VALUE || pkt->end > seg->end)
@@ -509,14 +515,14 @@ static int d_open(struct demuxer *demuxer, enum demux_check check)
demuxer->num_chapters = p->tl->num_chapters;
struct demuxer *meta = p->tl->meta;
- if (!meta)
- return -1;
- demuxer->metadata = meta->metadata;
- demuxer->attachments = meta->attachments;
- demuxer->num_attachments = meta->num_attachments;
- demuxer->editions = meta->editions;
- demuxer->num_editions = meta->num_editions;
- demuxer->edition = meta->edition;
+ if (meta) {
+ demuxer->metadata = meta->metadata;
+ demuxer->attachments = meta->attachments;
+ demuxer->num_attachments = meta->num_attachments;
+ demuxer->editions = meta->editions;
+ demuxer->num_editions = meta->num_editions;
+ demuxer->edition = meta->edition;
+ }
for (int n = 0; n < p->tl->num_pars; n++) {
if (!add_tl(demuxer, p->tl->pars[n]))
@@ -536,9 +542,11 @@ static int d_open(struct demuxer *demuxer, enum demux_check check)
demuxer->seekable = true;
demuxer->partially_seekable = false;
- demuxer->filetype = talloc_asprintf(p, "%s/%s",
- p->tl->format,
- meta->filetype ? meta->filetype : meta->desc->name);
+ const char *format_name = "unknown";
+ if (meta)
+ format_name = meta->filetype ? meta->filetype : meta->desc->name;
+
+ demuxer->filetype = talloc_asprintf(p, "%s/%s", p->tl->format, format_name);
reselect_streams(demuxer);
@@ -553,11 +561,12 @@ static bool add_tl(struct demuxer *demuxer, struct timeline_par *tl)
*src = (struct virtual_source){
.tl = tl,
.dash = tl->dash,
+ .delay_open = tl->delay_open,
.no_clip = tl->no_clip || tl->dash,
.dts = MP_NOPTS_VALUE,
};
- if (!tl->num_parts || !tl->track_layout)
+ if (!tl->num_parts)
return false;
MP_TARRAY_APPEND(p, p->sources, p->num_sources, src);
@@ -566,19 +575,32 @@ static bool add_tl(struct demuxer *demuxer, struct timeline_par *tl)
struct demuxer *meta = tl->track_layout;
- int num_streams = demux_get_num_stream(meta);
+ // delay_open streams normally have meta==0, and 1 virtual stream
+ int num_streams = meta ? demux_get_num_stream(meta) : tl->delay_open;
for (int n = 0; n < num_streams; n++) {
- struct sh_stream *sh = demux_get_stream(meta, n);
- struct sh_stream *new = demux_alloc_sh_stream(sh->type);
- new->demuxer_id = sh->demuxer_id;
- new->codec = sh->codec;
- new->title = sh->title;
- new->lang = sh->lang;
- new->default_track = sh->default_track;
- new->forced_track = sh->forced_track;
- new->hls_bitrate = sh->hls_bitrate;
- new->missing_timestamps = sh->missing_timestamps;
- new->attached_picture = sh->attached_picture;
+ struct sh_stream *sh = meta ? demux_get_stream(meta, n) : NULL;
+ struct sh_stream *new = NULL;
+
+ if (sh) {
+ new = demux_alloc_sh_stream(sh->type);
+ new->demuxer_id = sh->demuxer_id;
+ new->codec = sh->codec;
+ new->title = tl->title ? tl->title : sh->title;
+ new->lang = tl->lang ? tl->lang : sh->lang;
+ new->default_track = sh->default_track;
+ new->forced_track = sh->forced_track;
+ new->hls_bitrate = sh->hls_bitrate;
+ new->missing_timestamps = sh->missing_timestamps;
+ new->attached_picture = sh->attached_picture;
+ } else {
+ assert(tl->delay_open);
+ new = demux_alloc_sh_stream(tl->delay_open_st);
+ new->codec->type = new->type;
+ new->codec->codec = "null";
+ new->title = tl->title ? tl->title : NULL;
+ new->lang = tl->lang ? tl->lang : NULL;
+ }
+
demux_add_sh_stream(demuxer, new);
struct virtual_stream *vs = talloc_ptrtype(p, vs);
*vs = (struct virtual_stream){
@@ -600,6 +622,9 @@ static bool add_tl(struct demuxer *demuxer, struct timeline_par *tl)
demuxer->is_streaming |= part->source->is_streaming;
}
+ if (!part->source)
+ assert(tl->dash || tl->delay_open);
+
struct segment *seg = talloc_ptrtype(src, seg);
*seg = (struct segment){
.d = part->source,
@@ -616,8 +641,10 @@ static bool add_tl(struct demuxer *demuxer, struct timeline_par *tl)
MP_TARRAY_APPEND(src, src->segments, src->num_segments, seg);
}
- demuxer->is_network |= tl->track_layout->is_network;
- demuxer->is_streaming |= tl->track_layout->is_streaming;
+ if (tl->track_layout) {
+ demuxer->is_network |= tl->track_layout->is_network;
+ demuxer->is_streaming |= tl->track_layout->is_streaming;
+ }
return true;
}
diff --git a/demux/timeline.h b/demux/timeline.h
index c8151a0606..04ded0ad64 100644
--- a/demux/timeline.h
+++ b/demux/timeline.h
@@ -1,6 +1,8 @@
#ifndef MP_TIMELINE_H_
#define MP_TIMELINE_H_
+#include "common/common.h"
+
// Single segment in a timeline.
struct timeline_part {
// (end time must match with start time of the next part)
@@ -22,6 +24,12 @@ struct timeline_par {
bstr init_fragment;
bool dash, no_clip;
+ bool delay_open;
+ enum stream_type delay_open_st; // valid if delay_open=true, promised type
+
+ char *lang;
+ char *title;
+
// Segments to play, ordered by time.
struct timeline_part *parts;
int num_parts;