diff options
Diffstat (limited to 'demux/demux.c')
-rw-r--r-- | demux/demux.c | 464 |
1 files changed, 248 insertions, 216 deletions
diff --git a/demux/demux.c b/demux/demux.c index 29b5dccfc7..6feb97e998 100644 --- a/demux/demux.c +++ b/demux/demux.c @@ -15,20 +15,17 @@ * License along with mpv. If not, see <http://www.gnu.org/licenses/>. */ +#include <assert.h> #include <float.h> +#include <limits.h> +#include <math.h> +#include <stdatomic.h> +#include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <assert.h> -#include <unistd.h> -#include <limits.h> -#include <pthread.h> -#include <stdint.h> - -#include <math.h> - -#include <sys/types.h> #include <sys/stat.h> +#include <sys/types.h> #include "cache.h" #include "config.h" @@ -42,7 +39,6 @@ #include "common/stats.h" #include "misc/charset_conv.h" #include "misc/thread_tools.h" -#include "osdep/atomic.h" #include "osdep/timer.h" #include "osdep/threads.h" @@ -84,27 +80,6 @@ static const demuxer_desc_t *const demuxer_list[] = { NULL }; -struct demux_opts { - int enable_cache; - int disk_cache; - int64_t max_bytes; - int64_t max_bytes_bw; - int donate_fw; - double min_secs; - int force_seekable; - double min_secs_cache; - int access_references; - int seekable_cache; - int create_ccs; - char *record_file; - int video_back_preroll; - int audio_back_preroll; - int back_batch[STREAM_TYPE_COUNT]; - double back_seek_size; - char *meta_cp; - int force_retry_eof; -}; - #define OPT_BASE_STRUCT struct demux_opts static bool get_demux_sub_opts(int index, const struct m_sub_options **sub); @@ -113,19 +88,23 @@ const struct m_sub_options demux_conf = { .opts = (const struct m_option[]){ {"cache", OPT_CHOICE(enable_cache, {"no", 0}, {"auto", -1}, {"yes", 1})}, - {"cache-on-disk", OPT_FLAG(disk_cache)}, + {"cache-on-disk", OPT_BOOL(disk_cache)}, {"demuxer-readahead-secs", OPT_DOUBLE(min_secs), M_RANGE(0, DBL_MAX)}, + {"demuxer-hysteresis-secs", OPT_DOUBLE(hyst_secs), M_RANGE(0, DBL_MAX)}, {"demuxer-max-bytes", OPT_BYTE_SIZE(max_bytes), M_RANGE(0, M_MAX_MEM_BYTES)}, {"demuxer-max-back-bytes", OPT_BYTE_SIZE(max_bytes_bw), M_RANGE(0, M_MAX_MEM_BYTES)}, - {"demuxer-donate-buffer", OPT_FLAG(donate_fw)}, - {"force-seekable", OPT_FLAG(force_seekable)}, + {"demuxer-donate-buffer", OPT_BOOL(donate_fw)}, + {"force-seekable", OPT_BOOL(force_seekable)}, {"cache-secs", OPT_DOUBLE(min_secs_cache), M_RANGE(0, DBL_MAX)}, - {"access-references", OPT_FLAG(access_references)}, + {"access-references", OPT_BOOL(access_references)}, {"demuxer-seekable-cache", OPT_CHOICE(seekable_cache, {"auto", -1}, {"no", 0}, {"yes", 1})}, - {"sub-create-cc-track", OPT_FLAG(create_ccs)}, + {"index", OPT_CHOICE(index_mode, {"default", 1}, {"recreate", 0})}, + {"mf-fps", OPT_DOUBLE(mf_fps)}, + {"mf-type", OPT_STRING(mf_type)}, + {"sub-create-cc-track", OPT_BOOL(create_ccs)}, {"stream-record", OPT_STRING(record_file)}, {"video-backward-overlap", OPT_CHOICE(video_back_preroll, {"auto", -1}), M_RANGE(0, 1024)}, @@ -138,8 +117,6 @@ const struct m_sub_options demux_conf = { {"demuxer-backward-playback-step", OPT_DOUBLE(back_seek_size), M_RANGE(0, DBL_MAX)}, {"metadata-codepage", OPT_STRING(meta_cp)}, - {"demuxer-force-retry-on-eof", OPT_FLAG(force_retry_eof), - .deprecation_message = "temporary debug option, no replacement"}, {0} }, .size = sizeof(struct demux_opts), @@ -147,11 +124,13 @@ const struct m_sub_options demux_conf = { .enable_cache = -1, // auto .max_bytes = 150 * 1024 * 1024, .max_bytes_bw = 50 * 1024 * 1024, - .donate_fw = 1, + .donate_fw = true, .min_secs = 1.0, .min_secs_cache = 1000.0 * 60 * 60, .seekable_cache = -1, - .access_references = 1, + .index_mode = 1, + .mf_fps = 1.0, + .access_references = true, .video_back_preroll = -1, .audio_back_preroll = -1, .back_seek_size = 60, @@ -159,7 +138,7 @@ const struct m_sub_options demux_conf = { [STREAM_VIDEO] = 1, [STREAM_AUDIO] = 10, }, - .meta_cp = "utf-8", + .meta_cp = "auto", }, .get_sub_options = get_demux_sub_opts, }; @@ -179,15 +158,12 @@ struct demux_internal { // The lock protects the packet queues (struct demux_stream), // and the fields below. - pthread_mutex_t lock; - pthread_cond_t wakeup; - pthread_t thread; + mp_mutex lock; + mp_cond wakeup; + mp_thread thread; // -- All the following fields are protected by lock. - struct demux_opts *opts; - struct m_config_cache *opts_cache; - bool thread_terminate; bool threading; bool shutdown_async; @@ -210,6 +186,8 @@ struct demux_internal { bool warned_queue_overflow; bool eof; // whether we're in EOF state double min_secs; + double hyst_secs; // stop reading till there's hyst_secs remaining + bool hyst_active; size_t max_bytes; size_t max_bytes_bw; bool seekable_cache; @@ -388,7 +366,7 @@ struct demux_stream { bool eager; // try to keep at least 1 packet queued // if false, this stream is disabled, or passively // read (like subtitles) - bool still_image; // stream has still video images + bool still_image; // stream consists of multiple sparse still images bool refreshing; // finding old position after track switches bool eof; // end of demuxed stream? (true if no more packets) @@ -451,7 +429,7 @@ struct demux_stream { static void switch_to_fresh_cache_range(struct demux_internal *in); static void demuxer_sort_chapters(demuxer_t *demuxer); -static void *demux_thread(void *pctx); +static MP_THREAD_VOID demux_thread(void *pctx); static void update_cache(struct demux_internal *in); static void add_packet_locked(struct sh_stream *stream, demux_packet_t *dp); static struct demux_packet *advance_reader_head(struct demux_stream *ds); @@ -467,7 +445,7 @@ static void prune_old_packets(struct demux_internal *in); static void dumper_close(struct demux_internal *in); static void demux_convert_tags_charset(struct demuxer *demuxer); -static uint64_t get_foward_buffered_bytes(struct demux_stream *ds) +static uint64_t get_forward_buffered_bytes(struct demux_stream *ds) { if (!ds->reader_head) return 0; @@ -537,7 +515,7 @@ static void check_queue_consistency(struct demux_internal *in) // ...reader_head and others must be in the queue. assert(is_forward == !!queue->ds->reader_head); assert(kf_found == !!queue->keyframe_latest); - uint64_t fw_bytes2 = get_foward_buffered_bytes(queue->ds); + uint64_t fw_bytes2 = get_forward_buffered_bytes(queue->ds); assert(fw_bytes == fw_bytes2); } @@ -684,7 +662,7 @@ static void update_seek_ranges(struct demux_cached_range *range) } } - if (range->seek_start >= range->seek_end) + if (range->seek_start >= range->seek_end && !(range->is_bof && range->is_eof)) goto broken; prune_metadata(range); @@ -877,7 +855,7 @@ static void wakeup_ds(struct demux_stream *ds) ds->in->wakeup_cb(ds->in->wakeup_cb_ctx); } ds->need_wakeup = false; - pthread_cond_signal(&ds->in->wakeup); + mp_cond_signal(&ds->in->wakeup); } } @@ -940,9 +918,9 @@ static void update_stream_selection_state(struct demux_internal *in, void demux_set_ts_offset(struct demuxer *demuxer, double offset) { struct demux_internal *in = demuxer->in; - pthread_mutex_lock(&in->lock); + mp_mutex_lock(&in->lock); in->ts_offset = offset; - pthread_mutex_unlock(&in->lock); + mp_mutex_unlock(&in->lock); } static void add_missing_streams(struct demux_internal *in, @@ -974,6 +952,7 @@ struct sh_stream *demux_alloc_sh_stream(enum stream_type type) .index = -1, .ff_index = -1, // may be overwritten by demuxer .demuxer_id = -1, // ... same + .program_id = -1, // ... same .codec = talloc_zero(sh, struct mp_codec_params), .tags = talloc_zero(sh, struct mp_tags), }; @@ -1023,7 +1002,7 @@ static void demux_add_sh_stream_locked(struct demux_internal *in, switch (ds->type) { case STREAM_AUDIO: - ds->back_preroll = in->opts->audio_back_preroll; + ds->back_preroll = in->d_user->opts->audio_back_preroll; if (ds->back_preroll < 0) { // auto ds->back_preroll = mp_codec_is_lossless(sh->codec->codec) ? 0 : 1; if (sh->codec->codec && (strcmp(sh->codec->codec, "opus") == 0 || @@ -1033,7 +1012,7 @@ static void demux_add_sh_stream_locked(struct demux_internal *in, } break; case STREAM_VIDEO: - ds->back_preroll = in->opts->video_back_preroll; + ds->back_preroll = in->d_user->opts->video_back_preroll; if (ds->back_preroll < 0) ds->back_preroll = 0; // auto break; @@ -1055,9 +1034,9 @@ void demux_add_sh_stream(struct demuxer *demuxer, struct sh_stream *sh) { struct demux_internal *in = demuxer->in; assert(demuxer == in->d_thread); - pthread_mutex_lock(&in->lock); + mp_mutex_lock(&in->lock); demux_add_sh_stream_locked(in, sh); - pthread_mutex_unlock(&in->lock); + mp_mutex_unlock(&in->lock); } // Return a stream with the given index. Since streams can only be added during @@ -1067,10 +1046,10 @@ void demux_add_sh_stream(struct demuxer *demuxer, struct sh_stream *sh) struct sh_stream *demux_get_stream(struct demuxer *demuxer, int index) { struct demux_internal *in = demuxer->in; - pthread_mutex_lock(&in->lock); + mp_mutex_lock(&in->lock); assert(index >= 0 && index < in->num_streams); struct sh_stream *r = in->streams[index]; - pthread_mutex_unlock(&in->lock); + mp_mutex_unlock(&in->lock); return r; } @@ -1078,9 +1057,9 @@ struct sh_stream *demux_get_stream(struct demuxer *demuxer, int index) int demux_get_num_stream(struct demuxer *demuxer) { struct demux_internal *in = demuxer->in; - pthread_mutex_lock(&in->lock); + mp_mutex_lock(&in->lock); int r = in->num_streams; - pthread_mutex_unlock(&in->lock); + mp_mutex_unlock(&in->lock); return r; } @@ -1119,8 +1098,8 @@ static void demux_dealloc(struct demux_internal *in) { for (int n = 0; n < in->num_streams; n++) talloc_free(in->streams[n]); - pthread_mutex_destroy(&in->lock); - pthread_cond_destroy(&in->wakeup); + mp_mutex_destroy(&in->lock); + mp_cond_destroy(&in->wakeup); talloc_free(in->d_user); } @@ -1151,11 +1130,11 @@ struct demux_free_async_state *demux_free_async(struct demuxer *demuxer) if (!in->threading) return NULL; - pthread_mutex_lock(&in->lock); + mp_mutex_lock(&in->lock); in->thread_terminate = true; in->shutdown_async = true; - pthread_cond_signal(&in->wakeup); - pthread_mutex_unlock(&in->lock); + mp_cond_signal(&in->wakeup); + mp_mutex_unlock(&in->lock); return (struct demux_free_async_state *)demuxer->in; // lies } @@ -1179,9 +1158,9 @@ bool demux_free_async_finish(struct demux_free_async_state *state) { struct demux_internal *in = (struct demux_internal *)state; // reverse lies - pthread_mutex_lock(&in->lock); + mp_mutex_lock(&in->lock); bool busy = in->shutdown_async; - pthread_mutex_unlock(&in->lock); + mp_mutex_unlock(&in->lock); if (busy) return false; @@ -1210,7 +1189,7 @@ void demux_start_thread(struct demuxer *demuxer) if (!in->threading) { in->threading = true; - if (pthread_create(&in->thread, NULL, demux_thread, in)) + if (mp_thread_create(&in->thread, demux_thread, in)) in->threading = false; } } @@ -1221,11 +1200,11 @@ void demux_stop_thread(struct demuxer *demuxer) assert(demuxer == in->d_user); if (in->threading) { - pthread_mutex_lock(&in->lock); + mp_mutex_lock(&in->lock); in->thread_terminate = true; - pthread_cond_signal(&in->wakeup); - pthread_mutex_unlock(&in->lock); - pthread_join(in->thread, NULL); + mp_cond_signal(&in->wakeup); + mp_mutex_unlock(&in->lock); + mp_thread_join(in->thread); in->threading = false; in->thread_terminate = false; } @@ -1235,10 +1214,10 @@ void demux_stop_thread(struct demuxer *demuxer) void demux_set_wakeup_cb(struct demuxer *demuxer, void (*cb)(void *ctx), void *ctx) { struct demux_internal *in = demuxer->in; - pthread_mutex_lock(&in->lock); + mp_mutex_lock(&in->lock); in->wakeup_cb = cb; in->wakeup_cb_ctx = ctx; - pthread_mutex_unlock(&in->lock); + mp_mutex_unlock(&in->lock); } void demux_start_prefetch(struct demuxer *demuxer) @@ -1246,10 +1225,10 @@ void demux_start_prefetch(struct demuxer *demuxer) struct demux_internal *in = demuxer->in; assert(demuxer == in->d_user); - pthread_mutex_lock(&in->lock); + mp_mutex_lock(&in->lock); in->reading = true; - pthread_cond_signal(&in->wakeup); - pthread_mutex_unlock(&in->lock); + mp_cond_signal(&in->wakeup); + mp_mutex_unlock(&in->lock); } const char *stream_type_name(enum stream_type type) @@ -1272,6 +1251,8 @@ static struct sh_stream *demuxer_get_cc_track_locked(struct sh_stream *stream) return NULL; sh->codec->codec = "eia_608"; sh->default_track = true; + sh->hls_bitrate = stream->hls_bitrate; + sh->program_id = stream->program_id; stream->ds->cc = sh; demux_add_sh_stream_locked(stream->ds->in, sh); sh->ds->ignore_eof = true; @@ -1284,10 +1265,10 @@ void demuxer_feed_caption(struct sh_stream *stream, demux_packet_t *dp) { struct demux_internal *in = stream->ds->in; - pthread_mutex_lock(&in->lock); + mp_mutex_lock(&in->lock); struct sh_stream *sh = demuxer_get_cc_track_locked(stream); if (!sh) { - pthread_mutex_unlock(&in->lock); + mp_mutex_unlock(&in->lock); talloc_free(dp); return; } @@ -1297,7 +1278,7 @@ void demuxer_feed_caption(struct sh_stream *stream, demux_packet_t *dp) dp->dts = MP_ADD_PTS(dp->dts, -in->ts_offset); dp->stream = sh->index; add_packet_locked(sh, dp); - pthread_mutex_unlock(&in->lock); + mp_mutex_unlock(&in->lock); } static void error_on_backward_demuxing(struct demux_internal *in) @@ -1334,8 +1315,8 @@ static void perform_backward_seek(struct demux_internal *in) in->reading = true; // Don't starve other threads. - pthread_mutex_unlock(&in->lock); - pthread_mutex_lock(&in->lock); + mp_mutex_unlock(&in->lock); + mp_mutex_lock(&in->lock); } // For incremental backward demuxing search work. @@ -1459,7 +1440,7 @@ static void find_backward_restart_pos(struct demux_stream *ds) // Number of renderable keyframes to return to user. // (Excludes preroll, which is decoded by user, but then discarded.) - int batch = MPMAX(in->opts->back_batch[ds->type], 1); + int batch = MPMAX(in->d_user->opts->back_batch[ds->type], 1); // Number of keyframes to return to the user in total. int total = batch + ds->back_preroll; @@ -1569,9 +1550,9 @@ resume_earlier: ds->reader_head = t; ds->back_need_recheck = true; in->back_any_need_recheck = true; - pthread_cond_signal(&in->wakeup); + mp_cond_signal(&in->wakeup); } else { - ds->back_seek_pos -= in->opts->back_seek_size; + ds->back_seek_pos -= in->d_user->opts->back_seek_size; in->need_back_seek = true; } } @@ -1978,13 +1959,13 @@ static void record_packet(struct demux_internal *in, struct demux_packet *dp) { // (should preferably be outside of the lock) if (in->enable_recording && !in->recorder && - in->opts->record_file && in->opts->record_file[0]) + in->d_user->opts->record_file && in->d_user->opts->record_file[0]) { // Later failures shouldn't make it retry and overwrite the previously // recorded file. in->enable_recording = false; - in->recorder = recorder_create(in, in->opts->record_file); + in->recorder = recorder_create(in, in->d_user->opts->record_file); if (!in->recorder) MP_ERR(in, "Disabling recording.\n"); } @@ -2008,6 +1989,7 @@ static void record_packet(struct demux_internal *in, struct demux_packet *dp) static void add_packet_locked(struct sh_stream *stream, demux_packet_t *dp) { struct demux_stream *ds = stream ? stream->ds : NULL; + assert(ds && ds->in); if (!dp->len || demux_cancel_test(ds->in->d_thread)) { talloc_free(dp); return; @@ -2063,7 +2045,7 @@ static void add_packet_locked(struct sh_stream *stream, demux_packet_t *dp) record_packet(in, dp); - if (in->cache && in->opts->disk_cache) { + if (in->cache && in->d_user->opts->disk_cache) { int64_t pos = demux_cache_write(in->cache, dp); if (pos >= 0) { demux_packet_unref_contents(dp); @@ -2117,7 +2099,7 @@ static void add_packet_locked(struct sh_stream *stream, demux_packet_t *dp) ds->base_ts = queue->last_ts; const char *num_pkts = queue->head == queue->tail ? "1" : ">1"; - uint64_t fw_bytes = get_foward_buffered_bytes(ds); + uint64_t fw_bytes = get_forward_buffered_bytes(ds); MP_TRACE(in, "append packet to %s: size=%zu pts=%f dts=%f pos=%"PRIi64" " "[num=%s size=%zd]\n", stream_type_name(stream->type), dp->len, dp->pts, dp->dts, dp->pos, num_pkts, (size_t)fw_bytes); @@ -2168,7 +2150,7 @@ static bool lazy_stream_needs_wait(struct demux_stream *ds) struct demux_internal *in = ds->in; // Attempt to read until force_read_until was reached, or reading has // stopped for some reason (true EOF, queue overflow). - return !ds->eager && !ds->reader_head && !in->back_demuxing && + return !ds->eager && !in->back_demuxing && !in->eof && ds->force_read_until != MP_NOPTS_VALUE && (in->demux_ts == MP_NOPTS_VALUE || in->demux_ts <= ds->force_read_until); @@ -2206,16 +2188,23 @@ static bool read_packet(struct demux_internal *in) in->min_secs > 0 && ds->base_ts != MP_NOPTS_VALUE && ds->queue->last_ts >= ds->base_ts && !in->back_demuxing) - prefetch_more |= ds->queue->last_ts - ds->base_ts < in->min_secs; - total_fw_bytes += get_foward_buffered_bytes(ds); + { + if (ds->queue->last_ts - ds->base_ts <= in->hyst_secs) + in->hyst_active = false; + if (!in->hyst_active) + prefetch_more |= ds->queue->last_ts - ds->base_ts < in->min_secs; + } + total_fw_bytes += get_forward_buffered_bytes(ds); } MP_TRACE(in, "bytes=%zd, read_more=%d prefetch_more=%d, refresh_more=%d\n", (size_t)total_fw_bytes, read_more, prefetch_more, refresh_more); if (total_fw_bytes >= in->max_bytes) { // if we hit the limit just by prefetching, simply stop prefetching - if (!read_more) + if (!read_more) { + in->hyst_active = !!in->hyst_secs; return false; + } if (!in->warned_queue_overflow) { in->warned_queue_overflow = true; MP_WARN(in, "Too many packets in the demuxer packet queues:\n"); @@ -2226,7 +2215,7 @@ static bool read_packet(struct demux_internal *in) for (struct demux_packet *dp = ds->reader_head; dp; dp = dp->next) num_pkts++; - uint64_t fw_bytes = get_foward_buffered_bytes(ds); + uint64_t fw_bytes = get_forward_buffered_bytes(ds); MP_WARN(in, " %s/%d: %zd packets, %zd bytes%s%s\n", stream_type_name(ds->type), n, num_pkts, (size_t)fw_bytes, @@ -2245,8 +2234,10 @@ static bool read_packet(struct demux_internal *in) return false; } - if (!read_more && !prefetch_more && !refresh_more) + if (!read_more && !prefetch_more && !refresh_more) { + in->hyst_active = !!in->hyst_secs; return false; + } if (in->after_seek_to_start) { for (int n = 0; n < in->num_streams; n++) { @@ -2261,7 +2252,7 @@ static bool read_packet(struct demux_internal *in) in->reading = true; in->after_seek = false; in->after_seek_to_start = false; - pthread_mutex_unlock(&in->lock); + mp_mutex_unlock(&in->lock); struct demuxer *demux = in->d_thread; struct demux_packet *pkt = NULL; @@ -2270,7 +2261,7 @@ static bool read_packet(struct demux_internal *in) if (demux->desc->read_packet && !demux_cancel_test(demux)) eof = !demux->desc->read_packet(demux, &pkt); - pthread_mutex_lock(&in->lock); + mp_mutex_lock(&in->lock); update_cache(in); if (pkt) { @@ -2286,7 +2277,7 @@ static bool read_packet(struct demux_internal *in) if (!in->eof) { if (in->wakeup_cb) in->wakeup_cb(in->wakeup_cb_ctx); - pthread_cond_signal(&in->wakeup); + mp_cond_signal(&in->wakeup); MP_VERBOSE(in, "EOF reached.\n"); } } @@ -2307,12 +2298,12 @@ static void prune_old_packets(struct demux_internal *in) uint64_t fw_bytes = 0; for (int n = 0; n < in->num_streams; n++) { struct demux_stream *ds = in->streams[n]->ds; - fw_bytes += get_foward_buffered_bytes(ds); + fw_bytes += get_forward_buffered_bytes(ds); } uint64_t max_avail = in->max_bytes_bw; // Backward cache (if enabled at all) can use unused forward cache. // Still leave 1 byte free, so the read_packet logic doesn't get stuck. - if (max_avail && in->max_bytes > (fw_bytes + 1) && in->opts->donate_fw) + if (max_avail && in->max_bytes > (fw_bytes + 1) && in->d_user->opts->donate_fw) max_avail += in->max_bytes - (fw_bytes + 1); if (in->total_bytes - fw_bytes <= max_avail) break; @@ -2415,16 +2406,12 @@ static void execute_trackswitch(struct demux_internal *in) { in->tracks_switched = false; - bool any_selected = false; - for (int n = 0; n < in->num_streams; n++) - any_selected |= in->streams[n]->ds->selected; - - pthread_mutex_unlock(&in->lock); + mp_mutex_unlock(&in->lock); if (in->d_thread->desc->switched_tracks) in->d_thread->desc->switched_tracks(in->d_thread); - pthread_mutex_lock(&in->lock); + mp_mutex_lock(&in->lock); } static void execute_seek(struct demux_internal *in) @@ -2447,7 +2434,7 @@ static void execute_seek(struct demux_internal *in) if (in->recorder) mp_recorder_mark_discontinuity(in->recorder); - pthread_mutex_unlock(&in->lock); + mp_mutex_unlock(&in->lock); MP_VERBOSE(in, "execute seek (to %f flags %d)\n", pts, flags); @@ -2456,16 +2443,18 @@ static void execute_seek(struct demux_internal *in) MP_VERBOSE(in, "seek done\n"); - pthread_mutex_lock(&in->lock); + mp_mutex_lock(&in->lock); in->seeking_in_progress = MP_NOPTS_VALUE; } -static void update_opts(struct demux_internal *in) +static void update_opts(struct demuxer *demuxer) { - struct demux_opts *opts = in->opts; + struct demux_opts *opts = demuxer->opts; + struct demux_internal *in = demuxer->in; in->min_secs = opts->min_secs; + in->hyst_secs = opts->hyst_secs; in->max_bytes = opts->max_bytes; in->max_bytes_bw = opts->max_bytes_bw; @@ -2528,8 +2517,8 @@ static void update_opts(struct demux_internal *in) // Make demuxing progress. Return whether progress was made. static bool thread_work(struct demux_internal *in) { - if (m_config_cache_update(in->opts_cache)) - update_opts(in); + if (m_config_cache_update(in->d_user->opts_cache)) + update_opts(in->d_user); if (in->tracks_switched) { execute_trackswitch(in); return true; @@ -2548,33 +2537,32 @@ static bool thread_work(struct demux_internal *in) } if (read_packet(in)) return true; // read_packet unlocked, so recheck conditions - if (mp_time_us() >= in->next_cache_update) { + if (mp_time_ns() >= in->next_cache_update) { update_cache(in); return true; } return false; } -static void *demux_thread(void *pctx) +static MP_THREAD_VOID demux_thread(void *pctx) { struct demux_internal *in = pctx; - mpthread_set_name("demux"); - pthread_mutex_lock(&in->lock); + mp_thread_set_name("demux"); + mp_mutex_lock(&in->lock); stats_register_thread_cputime(in->stats, "thread"); while (!in->thread_terminate) { if (thread_work(in)) continue; - pthread_cond_signal(&in->wakeup); - struct timespec until = mp_time_us_to_timespec(in->next_cache_update); - pthread_cond_timedwait(&in->wakeup, &in->lock, &until); + mp_cond_signal(&in->wakeup); + mp_cond_timedwait_until(&in->wakeup, &in->lock, in->next_cache_update); } if (in->shutdown_async) { - pthread_mutex_unlock(&in->lock); + mp_mutex_unlock(&in->lock); demux_shutdown(in); - pthread_mutex_lock(&in->lock); + mp_mutex_lock(&in->lock); in->shutdown_async = false; if (in->wakeup_cb) in->wakeup_cb(in->wakeup_cb_ctx); @@ -2582,8 +2570,8 @@ static void *demux_thread(void *pctx) stats_unregister_thread(in->stats, "thread"); - pthread_mutex_unlock(&in->lock); - return NULL; + mp_mutex_unlock(&in->lock); + MP_THREAD_RETURN(); } // Low-level part of dequeueing a packet. @@ -2647,16 +2635,15 @@ static int dequeue_packet(struct demux_stream *ds, double min_pts, return -1; ds->attached_picture_added = true; struct demux_packet *pkt = demux_copy_packet(ds->sh->attached_picture); - if (!pkt) - abort(); + MP_HANDLE_OOM(pkt); pkt->stream = ds->sh->index; *res = pkt; return 1; } - if (!in->reading && (!in->eof || in->opts->force_retry_eof)) { + if (!in->reading && !in->eof) { in->reading = true; // enable demuxer thread prefetching - pthread_cond_signal(&in->wakeup); + mp_cond_signal(&in->wakeup); } ds->force_read_until = min_pts; @@ -2795,7 +2782,7 @@ int demux_read_packet_async_until(struct sh_stream *sh, double min_pts, return -1; struct demux_internal *in = ds->in; - pthread_mutex_lock(&in->lock); + mp_mutex_lock(&in->lock); int r = -1; while (1) { r = dequeue_packet(ds, min_pts, out_pkt); @@ -2804,7 +2791,7 @@ int demux_read_packet_async_until(struct sh_stream *sh, double min_pts, // Needs to actually read packets until we got a packet or EOF. thread_work(in); } - pthread_mutex_unlock(&in->lock); + mp_mutex_unlock(&in->lock); return r; } @@ -2813,7 +2800,7 @@ int demux_read_packet_async_until(struct sh_stream *sh, double min_pts, struct demux_packet *demux_read_any_packet(struct demuxer *demuxer) { struct demux_internal *in = demuxer->in; - pthread_mutex_lock(&in->lock); + mp_mutex_lock(&in->lock); assert(!in->threading); // doesn't work with threading struct demux_packet *out_pkt = NULL; bool read_more = true; @@ -2831,7 +2818,7 @@ struct demux_packet *demux_read_any_packet(struct demuxer *demuxer) read_more &= !all_eof; } done: - pthread_mutex_unlock(&in->lock); + mp_mutex_unlock(&in->lock); return out_pkt; } @@ -2858,7 +2845,7 @@ static const char *d_level(enum demux_check level) case DEMUX_CHECK_REQUEST:return "request"; case DEMUX_CHECK_NORMAL: return "normal"; } - abort(); + MP_ASSERT_UNREACHABLE(); } static int decode_float(char *str, float *out) @@ -2952,6 +2939,11 @@ static struct replaygain_data *decode_rgain(struct mp_log *log, } rg.track_gain /= 256.; rg.album_gain /= 256.; + + // Add 5dB to compensate for the different reference levels between + // our reference of ReplayGain 2 (-18 LUFS) and EBU R128 (-23 LUFS). + rg.track_gain += 5.; + rg.album_gain += 5.; return talloc_dup(NULL, &rg); } @@ -3049,7 +3041,7 @@ void demux_stream_tags_changed(struct demuxer *demuxer, struct sh_stream *sh, struct demux_stream *ds = sh ? sh->ds : NULL; assert(!sh || ds); // stream must have been added - pthread_mutex_lock(&in->lock); + mp_mutex_lock(&in->lock); if (pts == MP_NOPTS_VALUE) { MP_WARN(in, "Discarding timed metadata without timestamp.\n"); @@ -3058,7 +3050,7 @@ void demux_stream_tags_changed(struct demuxer *demuxer, struct sh_stream *sh, } talloc_free(tags); - pthread_mutex_unlock(&in->lock); + mp_mutex_unlock(&in->lock); } // This is called by demuxer implementations if demuxer->metadata changed. @@ -3068,9 +3060,9 @@ void demux_metadata_changed(demuxer_t *demuxer) assert(demuxer == demuxer->in->d_thread); // call from demuxer impl. only struct demux_internal *in = demuxer->in; - pthread_mutex_lock(&in->lock); + mp_mutex_lock(&in->lock); add_timed_metadata(in, demuxer->metadata, NULL, MP_NOPTS_VALUE); - pthread_mutex_unlock(&in->lock); + mp_mutex_unlock(&in->lock); } // Called locked, with user demuxer. @@ -3148,7 +3140,7 @@ void demux_update(demuxer_t *demuxer, double pts) assert(demuxer == demuxer->in->d_user); struct demux_internal *in = demuxer->in; - pthread_mutex_lock(&in->lock); + mp_mutex_lock(&in->lock); if (!in->threading) update_cache(in); @@ -3175,24 +3167,31 @@ void demux_update(demuxer_t *demuxer, double pts) if (demuxer->events & DEMUX_EVENT_DURATION) demuxer->duration = in->duration; - pthread_mutex_unlock(&in->lock); + mp_mutex_unlock(&in->lock); } static void demux_init_cuesheet(struct demuxer *demuxer) { + if (demuxer->num_chapters) + return; + + struct sh_stream *sh = demuxer->in->metadata_stream; char *cue = mp_tags_get_str(demuxer->metadata, "cuesheet"); - if (cue && !demuxer->num_chapters) { - struct cue_file *f = mp_parse_cue(bstr0(cue)); - if (f) { - if (mp_check_embedded_cue(f) < 0) { - MP_WARN(demuxer, "Embedded cue sheet references more than one file. " - "Ignoring it.\n"); - } else { - for (int n = 0; n < f->num_tracks; n++) { - struct cue_track *t = &f->tracks[n]; - int idx = demuxer_add_chapter(demuxer, "", t->start, -1); - mp_tags_merge(demuxer->chapters[idx].metadata, t->tags); - } + if (!cue && sh) + cue = mp_tags_get_str(sh->tags, "cuesheet"); + if (!cue) + return; + + struct cue_file *f = mp_parse_cue(bstr0(cue)); + if (f) { + if (mp_check_embedded_cue(f) < 0) { + MP_WARN(demuxer, "Embedded cue sheet references more than one file. " + "Ignoring it.\n"); + } else { + for (int n = 0; n < f->num_tracks; n++) { + struct cue_track *t = &f->tracks[n]; + int idx = demuxer_add_chapter(demuxer, "", t->start, -1); + mp_tags_merge(demuxer->chapters[idx].metadata, t->tags); } } talloc_free(f); @@ -3224,13 +3223,13 @@ 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); + mp_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 && !sh->attached_picture) demuxer_get_cc_track_locked(sh); } - pthread_mutex_unlock(&in->lock); + mp_mutex_unlock(&in->lock); } // Return whether "heavy" caching on this stream is enabled. By default, this @@ -3240,9 +3239,9 @@ static void demux_init_ccs(struct demuxer *demuxer, struct demux_opts *opts) bool demux_is_network_cached(demuxer_t *demuxer) { struct demux_internal *in = demuxer->in; - pthread_mutex_lock(&in->lock); + mp_mutex_lock(&in->lock); bool r = in->using_network_cache_opts; - pthread_mutex_unlock(&in->lock); + mp_mutex_unlock(&in->lock); return r; } @@ -3284,6 +3283,8 @@ static struct demuxer *open_given_type(struct mpv_global *global, .is_streaming = sinfo->is_streaming, .stream_origin = sinfo->stream_origin, .access_references = opts->access_references, + .opts = opts, + .opts_cache = opts_cache, .events = DEMUX_EVENT_ALL, .duration = -1, }; @@ -3295,8 +3296,6 @@ static struct demuxer *open_given_type(struct mpv_global *global, .stats = stats_ctx_create(in, global, "demuxer"), .can_cache = params && params->is_top_level, .can_record = params && params->stream_record, - .opts = opts, - .opts_cache = opts_cache, .d_thread = talloc(demuxer, struct demuxer), .d_user = demuxer, .after_seek = true, // (assumed identical to initial demuxer state) @@ -3306,8 +3305,8 @@ static struct demuxer *open_given_type(struct mpv_global *global, .demux_ts = MP_NOPTS_VALUE, .owns_stream = !params->external_stream, }; - pthread_mutex_init(&in->lock, NULL); - pthread_cond_init(&in->wakeup, NULL); + mp_mutex_init(&in->lock); + mp_cond_init(&in->wakeup); *in->d_thread = *demuxer; @@ -3365,7 +3364,7 @@ static struct demuxer *open_given_type(struct mpv_global *global, switch_to_fresh_cache_range(in); - update_opts(in); + update_opts(demuxer); demux_update(demuxer, MP_NOPTS_VALUE); @@ -3395,6 +3394,15 @@ static struct demuxer *demux_open(struct stream *stream, struct demuxer *demuxer = NULL; char *force_format = params ? params->force_format : NULL; + struct parent_stream_info sinfo = { + .seekable = stream->seekable, + .is_network = stream->is_network, + .is_streaming = stream->streaming, + .stream_origin = stream->stream_origin, + .cancel = cancel, + .filename = talloc_strdup(NULL, stream->url), + }; + if (!force_format) force_format = stream->demuxer; @@ -3416,15 +3424,6 @@ static struct demuxer *demux_open(struct stream *stream, } } - struct parent_stream_info sinfo = { - .seekable = stream->seekable, - .is_network = stream->is_network, - .is_streaming = stream->streaming, - .stream_origin = stream->stream_origin, - |