mirror of https://github.com/mpv-player/mpv
some shit
This commit is contained in:
parent
641d102101
commit
a9acfa82c3
|
@ -182,6 +182,71 @@ this will use a unified cache for all streams.
|
||||||
The ``new_stream`` header is not part of the core EDL format. It may be changed
|
The ``new_stream`` header is not part of the core EDL format. It may be changed
|
||||||
or removed at any time, depending on mpv's internal requirements.
|
or removed at any time, depending on mpv's internal requirements.
|
||||||
|
|
||||||
|
Ff the first ``!new_stream`` is redundant, it is ignored. This is the same
|
||||||
|
example as above::
|
||||||
|
|
||||||
|
# mpv EDL v0
|
||||||
|
!new_stream
|
||||||
|
video.mkv
|
||||||
|
!new_stream
|
||||||
|
audio.mkv
|
||||||
|
|
||||||
|
Note that ``!new_stream`` must be the first header. Whether the parser accepts
|
||||||
|
(i.e. ignores) or rejects other headers before that is implementation specific.
|
||||||
|
|
||||||
|
Track metadata
|
||||||
|
==============
|
||||||
|
|
||||||
|
The special ``track_meta`` header can set some specific metadata fields of the
|
||||||
|
current ``!new_stream`` partition. The tags are applied to all tracks within
|
||||||
|
the partition. It is not possible to set the metadata for individual tracks (the
|
||||||
|
feature was needed only for single-track media).
|
||||||
|
|
||||||
|
It provides following parameters change track metadata:
|
||||||
|
|
||||||
|
``lang``
|
||||||
|
Set the language tag.
|
||||||
|
|
||||||
|
``title``
|
||||||
|
Set the title tag.
|
||||||
|
|
||||||
|
Example::
|
||||||
|
|
||||||
|
# mpv EDL v0
|
||||||
|
!track_meta,lang=bla,title=blabla
|
||||||
|
file.mkv
|
||||||
|
!new_stream
|
||||||
|
!track_meta,title=ducks
|
||||||
|
sub.srt
|
||||||
|
|
||||||
|
If ``file.mkv`` has an audio and a video stream, both will use ``blabla`` as
|
||||||
|
title. The subtitle stream will use ``ducks`` as title.
|
||||||
|
|
||||||
|
The ``track_meta`` header is not part of the core EDL format. It may be changed
|
||||||
|
or removed at any time, depending on mpv's internal requirements.
|
||||||
|
|
||||||
|
Delayed media opening
|
||||||
|
=====================
|
||||||
|
|
||||||
|
The special ``delay_open`` header can be used to open the media URL of the
|
||||||
|
stream only when the track is selected for the first time. This is supposed to
|
||||||
|
be an optimization to speed up opening of a remote stream if there are many
|
||||||
|
tracks for whatever reasons.
|
||||||
|
|
||||||
|
This has various tricky restrictions, and also will defer failure to open a
|
||||||
|
stream to "later". By design, it's supposed to be used for single-track streams.
|
||||||
|
|
||||||
|
Using multiple segments requires you to specify all offsets and durations (also
|
||||||
|
it was never tested whether it works at all). Interaction with ``mp4_dash`` may
|
||||||
|
be strange.
|
||||||
|
|
||||||
|
This requires specifying the ``media_type`` parameter, which has to be set to
|
||||||
|
``video``, ``audio``, or ``sub``. Other tracks in the opened URL are ignored.
|
||||||
|
This is the minimum metadata that must be provided.
|
||||||
|
|
||||||
|
The ``delay_open`` header is not part of the core EDL format. It may be changed
|
||||||
|
or removed at any time, depending on mpv's internal requirements.
|
||||||
|
|
||||||
Timestamp format
|
Timestamp format
|
||||||
================
|
================
|
||||||
|
|
||||||
|
|
|
@ -49,6 +49,9 @@ struct tl_parts {
|
||||||
bool disable_chapters;
|
bool disable_chapters;
|
||||||
bool dash, no_clip;
|
bool dash, no_clip;
|
||||||
char *init_fragment_url;
|
char *init_fragment_url;
|
||||||
|
char *title, *lang;
|
||||||
|
bool delay_open;
|
||||||
|
enum stream_type delay_open_st;
|
||||||
struct tl_part *parts;
|
struct tl_part *parts;
|
||||||
int num_parts;
|
int num_parts;
|
||||||
struct tl_parts *next;
|
struct tl_parts *next;
|
||||||
|
@ -102,6 +105,9 @@ static struct tl_root *parse_edl(bstr str)
|
||||||
bool is_header = bstr_eatstart0(&str, "!");
|
bool is_header = bstr_eatstart0(&str, "!");
|
||||||
bstr f_type = {0};
|
bstr f_type = {0};
|
||||||
bstr f_init = {0};
|
bstr f_init = {0};
|
||||||
|
bstr f_lang = {0};
|
||||||
|
bstr f_title = {0};
|
||||||
|
bstr f_mt = {0};
|
||||||
struct tl_part p = { .length = -1 };
|
struct tl_part p = { .length = -1 };
|
||||||
int nparam = 0;
|
int nparam = 0;
|
||||||
while (1) {
|
while (1) {
|
||||||
|
@ -135,6 +141,12 @@ static struct tl_root *parse_edl(bstr str)
|
||||||
f_type = val;
|
f_type = val;
|
||||||
} else if (bstr_equals0(name, "init")) {
|
} else if (bstr_equals0(name, "init")) {
|
||||||
f_init = val;
|
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 {
|
} else {
|
||||||
if (bstr_equals0(name, "file")) {
|
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")) {
|
} else if (bstr_equals0(f_type, "no_clip")) {
|
||||||
tl->no_clip = true;
|
tl->no_clip = true;
|
||||||
} else if (bstr_equals0(f_type, "new_stream")) {
|
} 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")) {
|
} else if (bstr_equals0(f_type, "no_chapters")) {
|
||||||
tl->disable_chapters = true;
|
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 {
|
} else {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
@ -265,6 +296,10 @@ static struct timeline_par *build_timeline(struct timeline *root,
|
||||||
tl->track_layout = NULL;
|
tl->track_layout = NULL;
|
||||||
tl->dash = parts->dash;
|
tl->dash = parts->dash;
|
||||||
tl->no_clip = parts->no_clip;
|
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]) {
|
if (parts->init_fragment_url && parts->init_fragment_url[0]) {
|
||||||
MP_VERBOSE(root, "Opening init fragment...\n");
|
MP_VERBOSE(root, "Opening init fragment...\n");
|
||||||
|
@ -309,6 +344,15 @@ static struct timeline_par *build_timeline(struct timeline *root,
|
||||||
|
|
||||||
if (!tl->track_layout)
|
if (!tl->track_layout)
|
||||||
tl->track_layout = open_source(root, tl, part->filename);
|
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 {
|
} else {
|
||||||
MP_VERBOSE(root, "Opening segment %d...\n", n);
|
MP_VERBOSE(root, "Opening segment %d...\n", n);
|
||||||
|
|
||||||
|
@ -372,6 +416,9 @@ static struct timeline_par *build_timeline(struct timeline *root,
|
||||||
tl->num_parts++;
|
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) {
|
if (!tl->track_layout) {
|
||||||
// Use a heuristic to select the "broadest" part as layout.
|
// Use a heuristic to select the "broadest" part as layout.
|
||||||
for (int n = 0; n < parts->num_parts; n++) {
|
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;
|
goto error;
|
||||||
if (!root->meta)
|
if (!root->meta)
|
||||||
root->meta = tl->track_layout;
|
root->meta = tl->track_layout;
|
||||||
|
|
|
@ -56,7 +56,7 @@ struct virtual_stream {
|
||||||
struct virtual_source {
|
struct virtual_source {
|
||||||
struct timeline_par *tl;
|
struct timeline_par *tl;
|
||||||
|
|
||||||
bool dash, no_clip;
|
bool dash, no_clip, delay_open;
|
||||||
|
|
||||||
struct segment **segments;
|
struct segment **segments;
|
||||||
int num_segments;
|
int num_segments;
|
||||||
|
@ -207,11 +207,15 @@ static void reopen_lazy_segments(struct demuxer *demuxer,
|
||||||
if (src->current->d)
|
if (src->current->d)
|
||||||
return;
|
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 = {
|
struct demuxer_params params = {
|
||||||
.init_fragment = src->tl->init_fragment,
|
.init_fragment = src->tl->init_fragment,
|
||||||
.skip_lavf_probing = true,
|
.skip_lavf_probing = src->tl->dash,
|
||||||
.stream_flags = demuxer->stream_origin,
|
.stream_flags = demuxer->stream_origin,
|
||||||
};
|
};
|
||||||
src->current->d = demux_open_url(src->current->url, ¶ms,
|
src->current->d = demux_open_url(src->current->url, ¶ms,
|
||||||
|
@ -418,10 +422,12 @@ static bool do_read_next_packet(struct demuxer *demuxer,
|
||||||
if (pkt->stream < 0 || pkt->stream >= seg->num_stream_map)
|
if (pkt->stream < 0 || pkt->stream >= seg->num_stream_map)
|
||||||
goto drop;
|
goto drop;
|
||||||
|
|
||||||
if (!src->no_clip) {
|
if (!src->no_clip || src->delay_open) {
|
||||||
pkt->segmented = true;
|
pkt->segmented = true;
|
||||||
if (!pkt->codec)
|
if (!pkt->codec)
|
||||||
pkt->codec = demux_get_stream(seg->d, pkt->stream)->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)
|
if (pkt->start == MP_NOPTS_VALUE || pkt->start < seg->start)
|
||||||
pkt->start = seg->start;
|
pkt->start = seg->start;
|
||||||
if (pkt->end == MP_NOPTS_VALUE || pkt->end > seg->end)
|
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;
|
demuxer->num_chapters = p->tl->num_chapters;
|
||||||
|
|
||||||
struct demuxer *meta = p->tl->meta;
|
struct demuxer *meta = p->tl->meta;
|
||||||
if (!meta)
|
if (meta) {
|
||||||
return -1;
|
demuxer->metadata = meta->metadata;
|
||||||
demuxer->metadata = meta->metadata;
|
demuxer->attachments = meta->attachments;
|
||||||
demuxer->attachments = meta->attachments;
|
demuxer->num_attachments = meta->num_attachments;
|
||||||
demuxer->num_attachments = meta->num_attachments;
|
demuxer->editions = meta->editions;
|
||||||
demuxer->editions = meta->editions;
|
demuxer->num_editions = meta->num_editions;
|
||||||
demuxer->num_editions = meta->num_editions;
|
demuxer->edition = meta->edition;
|
||||||
demuxer->edition = meta->edition;
|
}
|
||||||
|
|
||||||
for (int n = 0; n < p->tl->num_pars; n++) {
|
for (int n = 0; n < p->tl->num_pars; n++) {
|
||||||
if (!add_tl(demuxer, p->tl->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->seekable = true;
|
||||||
demuxer->partially_seekable = false;
|
demuxer->partially_seekable = false;
|
||||||
|
|
||||||
demuxer->filetype = talloc_asprintf(p, "%s/%s",
|
const char *format_name = "unknown";
|
||||||
p->tl->format,
|
if (meta)
|
||||||
meta->filetype ? meta->filetype : meta->desc->name);
|
format_name = meta->filetype ? meta->filetype : meta->desc->name;
|
||||||
|
|
||||||
|
demuxer->filetype = talloc_asprintf(p, "%s/%s", p->tl->format, format_name);
|
||||||
|
|
||||||
reselect_streams(demuxer);
|
reselect_streams(demuxer);
|
||||||
|
|
||||||
|
@ -553,11 +561,12 @@ static bool add_tl(struct demuxer *demuxer, struct timeline_par *tl)
|
||||||
*src = (struct virtual_source){
|
*src = (struct virtual_source){
|
||||||
.tl = tl,
|
.tl = tl,
|
||||||
.dash = tl->dash,
|
.dash = tl->dash,
|
||||||
|
.delay_open = tl->delay_open,
|
||||||
.no_clip = tl->no_clip || tl->dash,
|
.no_clip = tl->no_clip || tl->dash,
|
||||||
.dts = MP_NOPTS_VALUE,
|
.dts = MP_NOPTS_VALUE,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!tl->num_parts || !tl->track_layout)
|
if (!tl->num_parts)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
MP_TARRAY_APPEND(p, p->sources, p->num_sources, src);
|
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;
|
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++) {
|
for (int n = 0; n < num_streams; n++) {
|
||||||
struct sh_stream *sh = demux_get_stream(meta, n);
|
struct sh_stream *sh = meta ? demux_get_stream(meta, n) : NULL;
|
||||||
struct sh_stream *new = demux_alloc_sh_stream(sh->type);
|
struct sh_stream *new = NULL;
|
||||||
new->demuxer_id = sh->demuxer_id;
|
|
||||||
new->codec = sh->codec;
|
if (sh) {
|
||||||
new->title = sh->title;
|
new = demux_alloc_sh_stream(sh->type);
|
||||||
new->lang = sh->lang;
|
new->demuxer_id = sh->demuxer_id;
|
||||||
new->default_track = sh->default_track;
|
new->codec = sh->codec;
|
||||||
new->forced_track = sh->forced_track;
|
new->title = tl->title ? tl->title : sh->title;
|
||||||
new->hls_bitrate = sh->hls_bitrate;
|
new->lang = tl->lang ? tl->lang : sh->lang;
|
||||||
new->missing_timestamps = sh->missing_timestamps;
|
new->default_track = sh->default_track;
|
||||||
new->attached_picture = sh->attached_picture;
|
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);
|
demux_add_sh_stream(demuxer, new);
|
||||||
struct virtual_stream *vs = talloc_ptrtype(p, vs);
|
struct virtual_stream *vs = talloc_ptrtype(p, vs);
|
||||||
*vs = (struct virtual_stream){
|
*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;
|
demuxer->is_streaming |= part->source->is_streaming;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!part->source)
|
||||||
|
assert(tl->dash || tl->delay_open);
|
||||||
|
|
||||||
struct segment *seg = talloc_ptrtype(src, seg);
|
struct segment *seg = talloc_ptrtype(src, seg);
|
||||||
*seg = (struct segment){
|
*seg = (struct segment){
|
||||||
.d = part->source,
|
.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);
|
MP_TARRAY_APPEND(src, src->segments, src->num_segments, seg);
|
||||||
}
|
}
|
||||||
|
|
||||||
demuxer->is_network |= tl->track_layout->is_network;
|
if (tl->track_layout) {
|
||||||
demuxer->is_streaming |= tl->track_layout->is_streaming;
|
demuxer->is_network |= tl->track_layout->is_network;
|
||||||
|
demuxer->is_streaming |= tl->track_layout->is_streaming;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
#ifndef MP_TIMELINE_H_
|
#ifndef MP_TIMELINE_H_
|
||||||
#define MP_TIMELINE_H_
|
#define MP_TIMELINE_H_
|
||||||
|
|
||||||
|
#include "common/common.h"
|
||||||
|
|
||||||
// Single segment in a timeline.
|
// Single segment in a timeline.
|
||||||
struct timeline_part {
|
struct timeline_part {
|
||||||
// (end time must match with start time of the next part)
|
// (end time must match with start time of the next part)
|
||||||
|
@ -22,6 +24,12 @@ struct timeline_par {
|
||||||
bstr init_fragment;
|
bstr init_fragment;
|
||||||
bool dash, no_clip;
|
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.
|
// Segments to play, ordered by time.
|
||||||
struct timeline_part *parts;
|
struct timeline_part *parts;
|
||||||
int num_parts;
|
int num_parts;
|
||||||
|
|
|
@ -199,13 +199,16 @@ bool mp_decoder_wrapper_reinit(struct mp_decoder_wrapper *d)
|
||||||
const struct mp_decoder_fns *driver = NULL;
|
const struct mp_decoder_fns *driver = NULL;
|
||||||
struct mp_decoder_list *list = NULL;
|
struct mp_decoder_list *list = NULL;
|
||||||
char *user_list = NULL;
|
char *user_list = NULL;
|
||||||
|
char *fallback = NULL;
|
||||||
|
|
||||||
if (p->codec->type == STREAM_VIDEO) {
|
if (p->codec->type == STREAM_VIDEO) {
|
||||||
driver = &vd_lavc;
|
driver = &vd_lavc;
|
||||||
user_list = opts->video_decoders;
|
user_list = opts->video_decoders;
|
||||||
|
fallback = "h264";
|
||||||
} else if (p->codec->type == STREAM_AUDIO) {
|
} else if (p->codec->type == STREAM_AUDIO) {
|
||||||
driver = &ad_lavc;
|
driver = &ad_lavc;
|
||||||
user_list = opts->audio_decoders;
|
user_list = opts->audio_decoders;
|
||||||
|
fallback = "aac";
|
||||||
|
|
||||||
if (p->public.try_spdif && p->codec->codec) {
|
if (p->public.try_spdif && p->codec->codec) {
|
||||||
struct mp_decoder_list *spdif =
|
struct mp_decoder_list *spdif =
|
||||||
|
@ -223,7 +226,10 @@ bool mp_decoder_wrapper_reinit(struct mp_decoder_wrapper *d)
|
||||||
struct mp_decoder_list *full = talloc_zero(NULL, struct mp_decoder_list);
|
struct mp_decoder_list *full = talloc_zero(NULL, struct mp_decoder_list);
|
||||||
if (driver)
|
if (driver)
|
||||||
driver->add_decoders(full);
|
driver->add_decoders(full);
|
||||||
list = mp_select_decoders(p->log, full, p->codec->codec, user_list);
|
const char *codec = p->codec->codec;
|
||||||
|
if (codec && strcmp(codec, "null") == 0)
|
||||||
|
codec = fallback;
|
||||||
|
list = mp_select_decoders(p->log, full, codec, user_list);
|
||||||
talloc_free(full);
|
talloc_free(full);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -386,7 +386,9 @@ local function add_single_video(json)
|
||||||
end
|
end
|
||||||
|
|
||||||
if not (sub == nil) then
|
if not (sub == nil) then
|
||||||
mp.commandv("sub-add", sub,
|
local edl = "edl://!no_clip;!delay_open,media_type=sub;"
|
||||||
|
.. edl_escape(sub)
|
||||||
|
mp.commandv("sub-add", edl,
|
||||||
"auto", sub_info.ext, lang)
|
"auto", sub_info.ext, lang)
|
||||||
else
|
else
|
||||||
msg.verbose("No subtitle data/url for ["..lang.."]")
|
msg.verbose("No subtitle data/url for ["..lang.."]")
|
||||||
|
|
|
@ -155,7 +155,11 @@ static int init(struct sd *sd)
|
||||||
char *extradata = sd->codec->extradata;
|
char *extradata = sd->codec->extradata;
|
||||||
int extradata_size = sd->codec->extradata_size;
|
int extradata_size = sd->codec->extradata_size;
|
||||||
|
|
||||||
if (strcmp(sd->codec->codec, "ass") != 0) {
|
// Note: accept "null" as alias for "ass", so EDL delay_open subtitle
|
||||||
|
// streams work.
|
||||||
|
if (strcmp(sd->codec->codec, "ass") != 0 &&
|
||||||
|
strcmp(sd->codec->codec, "null") != 0)
|
||||||
|
{
|
||||||
ctx->is_converted = true;
|
ctx->is_converted = true;
|
||||||
ctx->converter = lavc_conv_create(sd->log, sd->codec->codec, extradata,
|
ctx->converter = lavc_conv_create(sd->log, sd->codec->codec, extradata,
|
||||||
extradata_size);
|
extradata_size);
|
||||||
|
|
Loading…
Reference in New Issue