diff --git a/demux/demux.c b/demux/demux.c index 87c9879a59..3a3d9978f9 100644 --- a/demux/demux.c +++ b/demux/demux.c @@ -173,7 +173,6 @@ struct demux_internal { // Cached state. bool force_cache_update; - double time_length; struct mp_tags *stream_metadata; struct stream_cache_info stream_cache_info; int64_t stream_size; @@ -1085,6 +1084,7 @@ static void demux_copy(struct demuxer *dst, struct demuxer *src) dst->ts_resets_possible = src->ts_resets_possible; dst->fully_read = src->fully_read; dst->start_time = src->start_time; + dst->duration = src->duration; dst->is_network = src->is_network; dst->priv = src->priv; } @@ -1572,14 +1572,6 @@ int demuxer_add_chapter(demuxer_t *demuxer, char *name, return demuxer->num_chapters - 1; } -double demuxer_get_time_length(struct demuxer *demuxer) -{ - double len; - if (demux_control(demuxer, DEMUXER_CTRL_GET_TIME_LENGTH, &len) > 0) - return len; - return -1; -} - // must be called not locked static void update_cache(struct demux_internal *in) { @@ -1587,21 +1579,14 @@ static void update_cache(struct demux_internal *in) struct stream *stream = demuxer->stream; // Don't lock while querying the stream. - double time_length = -1; struct mp_tags *stream_metadata = NULL; struct stream_cache_info stream_cache_info = {.size = -1}; - if (demuxer->desc->control) { - demuxer->desc->control(demuxer, DEMUXER_CTRL_GET_TIME_LENGTH, - &time_length); - } - int64_t stream_size = stream_get_size(stream); stream_control(stream, STREAM_CTRL_GET_METADATA, &stream_metadata); stream_control(stream, STREAM_CTRL_GET_CACHE_INFO, &stream_cache_info); pthread_mutex_lock(&in->lock); - in->time_length = time_length; in->stream_size = stream_size; in->stream_cache_info = stream_cache_info; if (stream_metadata) { @@ -1645,11 +1630,6 @@ static int cached_stream_control(struct demux_internal *in, int cmd, void *arg) static int cached_demux_control(struct demux_internal *in, int cmd, void *arg) { switch (cmd) { - case DEMUXER_CTRL_GET_TIME_LENGTH: - if (in->time_length < 0) - return CONTROL_FALSE; - *(double *)arg = in->time_length; - return CONTROL_OK; case DEMUXER_CTRL_STREAM_CTRL: { struct demux_ctrl_stream_ctrl *c = arg; int r = cached_stream_control(in, c->ctrl, c->arg); diff --git a/demux/demux.h b/demux/demux.h index b1b83b3156..d3eed2bd28 100644 --- a/demux/demux.h +++ b/demux/demux.h @@ -32,7 +32,6 @@ enum demux_ctrl { DEMUXER_CTRL_SWITCHED_TRACKS = 1, - DEMUXER_CTRL_GET_TIME_LENGTH, DEMUXER_CTRL_RESYNC, DEMUXER_CTRL_IDENTIFY_PROGRAM, DEMUXER_CTRL_STREAM_CTRL, @@ -175,6 +174,7 @@ typedef struct demuxer { bool seekable; bool partially_seekable; // true if _maybe_ seekable; implies seekable=true double start_time; + double duration; // -1 if unknown // File format allows PTS resets (even if the current file is without) bool ts_resets_possible; // The file data was fully read, and there is no need to keep the stream @@ -280,8 +280,6 @@ int demuxer_add_chapter(demuxer_t *demuxer, char *name, void demux_set_stream_tags(struct demuxer *demuxer, struct sh_stream *sh, struct mp_tags *tags); -double demuxer_get_time_length(struct demuxer *demuxer); - int demux_stream_control(demuxer_t *demuxer, int ctrl, void *arg); void demux_changed(demuxer_t *demuxer, int events); diff --git a/demux/demux_cue.c b/demux/demux_cue.c index a8d1176163..941f2a88d9 100644 --- a/demux/demux_cue.c +++ b/demux/demux_cue.c @@ -130,20 +130,6 @@ out: return res; } -// return length of the source in seconds, or -1 if unknown -static double source_get_length(struct demuxer *demuxer) -{ - double get_time_ans; - // <= 0 means DEMUXER_CTRL_NOTIMPL or DEMUXER_CTRL_DONTKNOW - if (demuxer && demux_control(demuxer, DEMUXER_CTRL_GET_TIME_LENGTH, - (void *) &get_time_ans) > 0) - { - return get_time_ans; - } else { - return -1; - } -} - static void build_timeline(struct timeline *tl) { struct priv *p = tl->demuxer->priv; @@ -210,7 +196,7 @@ static void build_timeline(struct timeline *tl) if (i + 1 < track_count && tracks[i].source == tracks[i + 1].source) { duration = tracks[i + 1].start - tracks[i].start; } else { - duration = source_get_length(source); + duration = source->duration; // Two cases: 1) last track of a single-file cue, or 2) any track of // a multi-file cue. We need to do this for 1) only because the // timeline needs to be terminated with the length of the last diff --git a/demux/demux_disc.c b/demux/demux_disc.c index f4c9c34332..6c88bc1adc 100644 --- a/demux/demux_disc.c +++ b/demux/demux_disc.c @@ -338,6 +338,10 @@ static int d_open(demuxer_t *demuxer, enum demux_check check) add_streams(demuxer); add_stream_chapters(demuxer); + double len; + if (stream_control(demuxer->stream, STREAM_CTRL_GET_TIME_LENGTH, &len) >= 1) + demuxer->duration = len; + return 0; } @@ -352,13 +356,6 @@ static int d_control(demuxer_t *demuxer, int cmd, void *arg) struct priv *p = demuxer->priv; switch (cmd) { - case DEMUXER_CTRL_GET_TIME_LENGTH: { - double len; - if (stream_control(demuxer->stream, STREAM_CTRL_GET_TIME_LENGTH, &len) < 1) - break; - *(double *)arg = len; - return CONTROL_OK; - } case DEMUXER_CTRL_RESYNC: demux_flush(p->slave); break; // relay to slave demuxer diff --git a/demux/demux_edl.c b/demux/demux_edl.c index 8b6f402b27..5bab4ae983 100644 --- a/demux/demux_edl.c +++ b/demux/demux_edl.c @@ -199,16 +199,6 @@ static void copy_chapters(struct demux_chapter **chapters, int *num_chapters, } } -// return length of the source in seconds, or -1 if unknown -static double source_get_length(struct demuxer *demuxer) -{ - double time; - // <= 0 means DEMUXER_CTRL_NOTIMPL or DEMUXER_CTRL_DONTKNOW - if (demux_control(demuxer, DEMUXER_CTRL_GET_TIME_LENGTH, &time) <= 0) - time = -1; - return time; -} - static void resolve_timestamps(struct tl_part *part, struct demuxer *demuxer) { if (part->chapter_ts) { @@ -279,7 +269,7 @@ static void build_timeline(struct timeline *tl, struct tl_parts *parts) resolve_timestamps(part, source); - double end_time = source_get_length(source); + double end_time = source->duration; if (end_time >= 0) end_time += source->start_time; diff --git a/demux/demux_lavf.c b/demux/demux_lavf.c index e2b6ca673d..da0dbd46aa 100644 --- a/demux/demux_lavf.c +++ b/demux/demux_lavf.c @@ -939,6 +939,26 @@ static int demux_open_lavf(demuxer_t *demuxer, enum demux_check check) demuxer->fully_read = priv->format_hack.fully_read; + if (priv->avfc->duration > 0) { + demuxer->duration = (double)priv->avfc->duration / AV_TIME_BASE; + } else { + double total_duration = 0; + double av_duration = 0; + for (int n = 0; n < priv->avfc->nb_streams; n++) { + AVStream *st = priv->avfc->streams[n]; + if (st->duration <= 0) + continue; + double f_duration = st->duration * av_q2d(st->time_base); + total_duration = MPMAX(total_duration, f_duration); + if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO || + st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) + av_duration = MPMAX(av_duration, f_duration); + } + double duration = av_duration > 0 ? av_duration : total_duration; + if (duration > 0) + demuxer->duration = duration; + } + return 0; } @@ -1045,30 +1065,6 @@ static int demux_lavf_control(demuxer_t *demuxer, int cmd, void *arg) lavf_priv_t *priv = demuxer->priv; switch (cmd) { - case DEMUXER_CTRL_GET_TIME_LENGTH: - if (priv->avfc->duration <= 0) { - double total_duration = 0; - double av_duration = 0; - for (int n = 0; n < priv->avfc->nb_streams; n++) { - AVStream *st = priv->avfc->streams[n]; - if (st->duration <= 0) - continue; - double f_duration = st->duration * av_q2d(st->time_base); - total_duration = MPMAX(total_duration, f_duration); - if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO || - st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) - av_duration = MPMAX(av_duration, f_duration); - } - double duration = av_duration > 0 ? av_duration : total_duration; - if (duration <= 0) - return CONTROL_FALSE; - *(double *)arg = duration; - return CONTROL_OK; - } - - *((double *)arg) = (double)priv->avfc->duration / AV_TIME_BASE; - return CONTROL_OK; - case DEMUXER_CTRL_SWITCHED_TRACKS: { select_tracks(demuxer, 0); diff --git a/demux/demux_mf.c b/demux/demux_mf.c index 859a59925f..4b09ad8e86 100644 --- a/demux/demux_mf.c +++ b/demux/demux_mf.c @@ -335,6 +335,7 @@ static int demux_open_mf(demuxer_t *demuxer, enum demux_check check) mf->sh = sh; demuxer->priv = (void *)mf; demuxer->seekable = true; + demuxer->duration = mf->nr_of_files / mf->sh->codec->fps; return 0; @@ -346,20 +347,6 @@ static void demux_close_mf(demuxer_t *demuxer) { } -static int demux_control_mf(demuxer_t *demuxer, int cmd, void *arg) -{ - mf_t *mf = demuxer->priv; - - switch (cmd) { - case DEMUXER_CTRL_GET_TIME_LENGTH: - *((double *)arg) = (double)mf->nr_of_files / mf->sh->codec->fps; - return CONTROL_OK; - - default: - return CONTROL_UNKNOWN; - } -} - const demuxer_desc_t demuxer_desc_mf = { .name = "mf", .desc = "image files (mf)", @@ -367,5 +354,4 @@ const demuxer_desc_t demuxer_desc_mf = { .open = demux_open_mf, .close = demux_close_mf, .seek = demux_seek_mf, - .control = demux_control_mf, }; diff --git a/demux/demux_mkv.c b/demux/demux_mkv.c index b040c45f23..3861aaf60a 100644 --- a/demux/demux_mkv.c +++ b/demux/demux_mkv.c @@ -411,6 +411,7 @@ static int demux_mkv_read_info(demuxer_t *demuxer) mkv_d->duration = info.duration * mkv_d->tc_scale / 1e9; MP_VERBOSE(demuxer, "| + duration: %.3fs\n", mkv_d->duration); + demuxer->duration = mkv_d->duration; } if (info.title) { mp_tags_set_str(demuxer->metadata, "TITLE", info.title); @@ -3090,8 +3091,10 @@ static void probe_last_timestamp(struct demuxer *demuxer, int64_t start_pos) if (!last_ts[STREAM_VIDEO]) last_ts[STREAM_VIDEO] = mkv_d->cluster_tc; - if (last_ts[STREAM_VIDEO]) + if (last_ts[STREAM_VIDEO]) { mkv_d->duration = last_ts[STREAM_VIDEO] / 1e9 - demuxer->start_time; + demuxer->duration = mkv_d->duration; + } stream_seek(demuxer->stream, start_pos); mkv_d->cluster_start = mkv_d->cluster_end = 0; @@ -3116,22 +3119,6 @@ static void probe_first_timestamp(struct demuxer *demuxer) MP_VERBOSE(demuxer, "Start PTS: %f\n", demuxer->start_time); } -static int demux_mkv_control(demuxer_t *demuxer, int cmd, void *arg) -{ - mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv; - - switch (cmd) { - case DEMUXER_CTRL_GET_TIME_LENGTH: - if (mkv_d->duration == 0) - return CONTROL_FALSE; - - *((double *) arg) = (double) mkv_d->duration; - return CONTROL_OK; - default: - return CONTROL_UNKNOWN; - } -} - static void mkv_free(struct demuxer *demuxer) { struct mkv_demuxer *mkv_d = demuxer->priv; @@ -3149,7 +3136,6 @@ const demuxer_desc_t demuxer_desc_matroska = { .fill_buffer = demux_mkv_fill_buffer, .close = mkv_free, .seek = demux_mkv_seek, - .control = demux_mkv_control, .load_timeline = build_ordered_chapter_timeline, }; diff --git a/demux/demux_mkv_timeline.c b/demux/demux_mkv_timeline.c index de7b2e0853..3ad24eb8a5 100644 --- a/demux/demux_mkv_timeline.c +++ b/demux/demux_mkv_timeline.c @@ -384,8 +384,7 @@ static void build_timeline_loop(struct tl_ctx *ctx, /* If we're the source or it's a non-ordered edition reference, * just add a timeline part from the source. */ if (current_source == j || !linked_m->uid.edition) { - uint64_t source_full_length = - demuxer_get_time_length(linked_source) * 1e9; + uint64_t source_full_length = linked_source->duration * 1e9; uint64_t source_length = source_full_length - c->start; int64_t join_diff = 0; diff --git a/demux/demux_raw.c b/demux/demux_raw.c index d9e7ebb63a..f2b20c597c 100644 --- a/demux/demux_raw.c +++ b/demux/demux_raw.c @@ -132,6 +132,18 @@ struct priv { double frame_rate; }; +static int generic_open(struct demuxer *demuxer) +{ + struct stream *s = demuxer->stream; + struct priv *p = demuxer->priv; + + int64_t end = 0; + if (stream_control(s, STREAM_CTRL_GET_SIZE, &end) == STREAM_OK) + demuxer->duration = (end / p->frame_size) / p->frame_rate; + + return 0; +} + static int demux_rawaudio_open(demuxer_t *demuxer, enum demux_check check) { struct demux_rawaudio_opts *opts = @@ -170,7 +182,7 @@ static int demux_rawaudio_open(demuxer_t *demuxer, enum demux_check check) .read_frames = c->samplerate / 8, }; - return 0; + return generic_open(demuxer); } static int demux_rawvideo_open(demuxer_t *demuxer, enum demux_check check) @@ -255,7 +267,7 @@ static int demux_rawvideo_open(demuxer_t *demuxer, enum demux_check check) .read_frames = 1, }; - return 0; + return generic_open(demuxer); } static int raw_fill_buffer(demuxer_t *demuxer) @@ -297,32 +309,12 @@ static void raw_seek(demuxer_t *demuxer, double seek_pts, int flags) stream_seek(s, (pos / p->frame_size) * p->frame_size); } -static int raw_control(demuxer_t *demuxer, int cmd, void *arg) -{ - struct priv *p = demuxer->priv; - - switch (cmd) { - case DEMUXER_CTRL_GET_TIME_LENGTH: { - stream_t *s = demuxer->stream; - int64_t end = 0; - if (stream_control(s, STREAM_CTRL_GET_SIZE, &end) != STREAM_OK) - return CONTROL_FALSE; - - *((double *) arg) = (end / p->frame_size) / p->frame_rate; - return CONTROL_OK; - } - default: - return CONTROL_UNKNOWN; - } -} - const demuxer_desc_t demuxer_desc_rawaudio = { .name = "rawaudio", .desc = "Uncompressed audio", .open = demux_rawaudio_open, .fill_buffer = raw_fill_buffer, .seek = raw_seek, - .control = raw_control, }; const demuxer_desc_t demuxer_desc_rawvideo = { @@ -331,5 +323,4 @@ const demuxer_desc_t demuxer_desc_rawvideo = { .open = demux_rawvideo_open, .fill_buffer = raw_fill_buffer, .seek = raw_seek, - .control = raw_control, }; diff --git a/demux/demux_timeline.c b/demux/demux_timeline.c index 359f97f2bc..d7a5c36d70 100644 --- a/demux/demux_timeline.c +++ b/demux/demux_timeline.c @@ -363,6 +363,7 @@ static int d_open(struct demuxer *demuxer, enum demux_check check) demuxer->editions = meta->editions; demuxer->num_editions = meta->num_editions; demuxer->edition = meta->edition; + demuxer->duration = p->duration; int num_streams = demux_get_num_stream(meta); for (int n = 0; n < num_streams; n++) { @@ -431,17 +432,11 @@ static void d_close(struct demuxer *demuxer) static int d_control(struct demuxer *demuxer, int cmd, void *arg) { - struct priv *p = demuxer->priv; - - switch (cmd) { - case DEMUXER_CTRL_GET_TIME_LENGTH: { - *(double *)arg = p->duration; - return CONTROL_OK; - } - case DEMUXER_CTRL_SWITCHED_TRACKS: + if (cmd == DEMUXER_CTRL_SWITCHED_TRACKS) { reselect_streams(demuxer); return CONTROL_OK; } + return CONTROL_UNKNOWN; } diff --git a/player/playloop.c b/player/playloop.c index 09387ed66f..19ff2f2f2e 100644 --- a/player/playloop.c +++ b/player/playloop.c @@ -441,14 +441,7 @@ void execute_queued_seek(struct MPContext *mpctx) double get_time_length(struct MPContext *mpctx) { struct demuxer *demuxer = mpctx->demuxer; - if (!demuxer) - return -1; - - double len = demuxer_get_time_length(demuxer); - if (len >= 0) - return len; - - return -1; // unknown + return demuxer ? demuxer->duration : -1; } double get_current_time(struct MPContext *mpctx)