mirror of
https://github.com/mpv-player/mpv
synced 2025-02-16 12:17:12 +00:00
demux: add option to create CC tracks eagerly
We don't hope to auto-detect them at load time, as that would be too much of a pain - even FFmpeg requires fetching and parsing of video packets, and exposes the information only via deprecated API. But there still needs to be a way to select them by default. This is also needed to get the first CC packet at all (without seeking back). This commit also attempts to clean up locking a bit, which is a PITA, but it's better be careful & clean.
This commit is contained in:
parent
99dd2f57f0
commit
57248915fa
@ -2134,6 +2134,18 @@ Subtitles
|
|||||||
|
|
||||||
Default: ``no``.
|
Default: ``no``.
|
||||||
|
|
||||||
|
``--sub-create-cc-track=<yes|no>``
|
||||||
|
For every video stream, create a closed captions track (default: no). The
|
||||||
|
only purpose is to make the track available for selection at the start of
|
||||||
|
playback, instead of creating it lazily. This applies only to
|
||||||
|
``ATSC A53 Part 4 Closed Captions`` (displayed by mpv as subtitle tracks
|
||||||
|
using the codec ``eia_608``). The CC track is marked "default" and selected
|
||||||
|
according to the normal subtitle track selection rules. You can then use
|
||||||
|
``--sid`` to explicitly select the correct track too.
|
||||||
|
|
||||||
|
If the video stream contains no closed captions, or if no video is being
|
||||||
|
decoded, the CC track will remain empty and will not show any text.
|
||||||
|
|
||||||
Window
|
Window
|
||||||
------
|
------
|
||||||
|
|
||||||
|
@ -91,6 +91,7 @@ struct demux_opts {
|
|||||||
double min_secs_cache;
|
double min_secs_cache;
|
||||||
int access_references;
|
int access_references;
|
||||||
int seekable_cache;
|
int seekable_cache;
|
||||||
|
int create_ccs;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define OPT_BASE_STRUCT struct demux_opts
|
#define OPT_BASE_STRUCT struct demux_opts
|
||||||
@ -104,6 +105,7 @@ const struct m_sub_options demux_conf = {
|
|||||||
OPT_DOUBLE("cache-secs", min_secs_cache, M_OPT_MIN, .min = 0),
|
OPT_DOUBLE("cache-secs", min_secs_cache, M_OPT_MIN, .min = 0),
|
||||||
OPT_FLAG("access-references", access_references, 0),
|
OPT_FLAG("access-references", access_references, 0),
|
||||||
OPT_FLAG("demuxer-seekable-cache", seekable_cache, 0),
|
OPT_FLAG("demuxer-seekable-cache", seekable_cache, 0),
|
||||||
|
OPT_FLAG("sub-create-cc-track", create_ccs, 0),
|
||||||
{0}
|
{0}
|
||||||
},
|
},
|
||||||
.size = sizeof(struct demux_opts),
|
.size = sizeof(struct demux_opts),
|
||||||
@ -301,11 +303,9 @@ struct sh_stream *demux_alloc_sh_stream(enum stream_type type)
|
|||||||
// Add a new sh_stream to the demuxer. Note that as soon as the stream has been
|
// Add a new sh_stream to the demuxer. Note that as soon as the stream has been
|
||||||
// added, it must be immutable, and must not be released (this will happen when
|
// added, it must be immutable, and must not be released (this will happen when
|
||||||
// the demuxer is destroyed).
|
// the demuxer is destroyed).
|
||||||
void demux_add_sh_stream(struct demuxer *demuxer, struct sh_stream *sh)
|
static void demux_add_sh_stream_locked(struct demux_internal *in,
|
||||||
|
struct sh_stream *sh)
|
||||||
{
|
{
|
||||||
struct demux_internal *in = demuxer->in;
|
|
||||||
pthread_mutex_lock(&in->lock);
|
|
||||||
|
|
||||||
assert(!sh->ds); // must not be added yet
|
assert(!sh->ds); // must not be added yet
|
||||||
|
|
||||||
sh->ds = talloc(sh, struct demux_stream);
|
sh->ds = talloc(sh, struct demux_stream);
|
||||||
@ -335,6 +335,14 @@ void demux_add_sh_stream(struct demuxer *demuxer, struct sh_stream *sh)
|
|||||||
in->events |= DEMUX_EVENT_STREAMS;
|
in->events |= DEMUX_EVENT_STREAMS;
|
||||||
if (in->wakeup_cb)
|
if (in->wakeup_cb)
|
||||||
in->wakeup_cb(in->wakeup_cb_ctx);
|
in->wakeup_cb(in->wakeup_cb_ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
// For demuxer implementations only.
|
||||||
|
void demux_add_sh_stream(struct demuxer *demuxer, struct sh_stream *sh)
|
||||||
|
{
|
||||||
|
struct demux_internal *in = demuxer->in;
|
||||||
|
pthread_mutex_lock(&in->lock);
|
||||||
|
demux_add_sh_stream_locked(in, sh);
|
||||||
pthread_mutex_unlock(&in->lock);
|
pthread_mutex_unlock(&in->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -468,30 +476,38 @@ const char *stream_type_name(enum stream_type type)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void demuxer_feed_caption(struct sh_stream *stream, demux_packet_t *dp)
|
static struct sh_stream *demuxer_get_cc_track_locked(struct sh_stream *stream)
|
||||||
{
|
{
|
||||||
struct demuxer *demuxer = stream->ds->in->d_thread;
|
|
||||||
struct demux_internal *in = demuxer->in;
|
|
||||||
struct sh_stream *sh = stream->ds->cc;
|
struct sh_stream *sh = stream->ds->cc;
|
||||||
|
|
||||||
if (!sh) {
|
if (!sh) {
|
||||||
sh = demux_alloc_sh_stream(STREAM_SUB);
|
sh = demux_alloc_sh_stream(STREAM_SUB);
|
||||||
if (!sh) {
|
if (!sh)
|
||||||
talloc_free(dp);
|
return NULL;
|
||||||
return;
|
|
||||||
}
|
|
||||||
sh->codec->codec = "eia_608";
|
sh->codec->codec = "eia_608";
|
||||||
|
sh->default_track = true;
|
||||||
stream->ds->cc = sh;
|
stream->ds->cc = sh;
|
||||||
demux_add_sh_stream(demuxer, sh);
|
demux_add_sh_stream_locked(stream->ds->in, sh);
|
||||||
|
sh->ds->ignore_eof = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_mutex_lock(&in->lock);
|
return sh;
|
||||||
|
}
|
||||||
|
|
||||||
sh->ds->ignore_eof = true;
|
void demuxer_feed_caption(struct sh_stream *stream, demux_packet_t *dp)
|
||||||
|
{
|
||||||
|
struct demux_internal *in = stream->ds->in;
|
||||||
|
|
||||||
|
pthread_mutex_lock(&in->lock);
|
||||||
|
struct sh_stream *sh = demuxer_get_cc_track_locked(stream);
|
||||||
|
if (!sh) {
|
||||||
|
pthread_mutex_unlock(&in->lock);
|
||||||
|
talloc_free(dp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
dp->pts = MP_ADD_PTS(dp->pts, -in->ts_offset);
|
dp->pts = MP_ADD_PTS(dp->pts, -in->ts_offset);
|
||||||
dp->dts = MP_ADD_PTS(dp->dts, -in->ts_offset);
|
dp->dts = MP_ADD_PTS(dp->dts, -in->ts_offset);
|
||||||
|
|
||||||
pthread_mutex_unlock(&in->lock);
|
pthread_mutex_unlock(&in->lock);
|
||||||
|
|
||||||
demux_add_packet(sh, dp);
|
demux_add_packet(sh, dp);
|
||||||
@ -1397,6 +1413,20 @@ static void demux_maybe_replace_stream(struct demuxer *demuxer)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void demux_init_ccs(struct demuxer *demuxer, struct demux_opts *opts)
|
||||||
|
{
|
||||||
|
struct demux_internal *in = demuxer->in;
|
||||||
|
if (!opts->create_ccs)
|
||||||
|
return;
|
||||||
|
pthread_mutex_lock(&in->lock);
|
||||||
|
for (int n = 0; n < in->num_streams; n++) {
|
||||||
|
struct sh_stream *sh = in->streams[n];
|
||||||
|
if (sh->type == STREAM_VIDEO)
|
||||||
|
demuxer_get_cc_track_locked(sh);
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&in->lock);
|
||||||
|
}
|
||||||
|
|
||||||
static struct demuxer *open_given_type(struct mpv_global *global,
|
static struct demuxer *open_given_type(struct mpv_global *global,
|
||||||
struct mp_log *log,
|
struct mp_log *log,
|
||||||
const struct demuxer_desc *desc,
|
const struct demuxer_desc *desc,
|
||||||
@ -1477,6 +1507,7 @@ static struct demuxer *open_given_type(struct mpv_global *global,
|
|||||||
}
|
}
|
||||||
demux_init_cuesheet(in->d_thread);
|
demux_init_cuesheet(in->d_thread);
|
||||||
demux_init_cache(demuxer);
|
demux_init_cache(demuxer);
|
||||||
|
demux_init_ccs(demuxer, opts);
|
||||||
demux_changed(in->d_thread, DEMUX_EVENT_ALL);
|
demux_changed(in->d_thread, DEMUX_EVENT_ALL);
|
||||||
demux_update(demuxer);
|
demux_update(demuxer);
|
||||||
stream_control(demuxer->stream, STREAM_CTRL_SET_READAHEAD,
|
stream_control(demuxer->stream, STREAM_CTRL_SET_READAHEAD,
|
||||||
|
Loading…
Reference in New Issue
Block a user