diff options
Diffstat (limited to 'demux')
-rw-r--r-- | demux/cache.c | 25 | ||||
-rw-r--r-- | demux/codec_tags.c | 93 | ||||
-rw-r--r-- | demux/demux.c | 474 | ||||
-rw-r--r-- | demux/demux.h | 34 | ||||
-rw-r--r-- | demux/demux_cue.c | 21 | ||||
-rw-r--r-- | demux/demux_disc.c | 2 | ||||
-rw-r--r-- | demux/demux_edl.c | 17 | ||||
-rw-r--r-- | demux/demux_lavf.c | 272 | ||||
-rw-r--r-- | demux/demux_libarchive.c | 6 | ||||
-rw-r--r-- | demux/demux_mf.c | 94 | ||||
-rw-r--r-- | demux/demux_mkv.c | 274 | ||||
-rw-r--r-- | demux/demux_playlist.c | 209 | ||||
-rw-r--r-- | demux/demux_raw.c | 5 | ||||
-rw-r--r-- | demux/demux_timeline.c | 1 | ||||
-rw-r--r-- | demux/ebml.c | 8 | ||||
-rw-r--r-- | demux/ebml.h | 2 | ||||
-rw-r--r-- | demux/packet.c | 66 | ||||
-rw-r--r-- | demux/packet.h | 6 | ||||
-rw-r--r-- | demux/stheader.h | 21 | ||||
-rw-r--r-- | demux/timeline.h | 1 |
20 files changed, 1141 insertions, 490 deletions
diff --git a/demux/cache.c b/demux/cache.c index f48598807c..6398f61823 100644 --- a/demux/cache.c +++ b/demux/cache.c @@ -26,6 +26,7 @@ #include "common/msg.h" #include "common/av_common.h" #include "demux.h" +#include "misc/io_utils.h" #include "options/path.h" #include "options/m_config.h" #include "options/m_option.h" @@ -40,10 +41,12 @@ struct demux_cache_opts { const struct m_sub_options demux_cache_conf = { .opts = (const struct m_option[]){ - {"cache-dir", OPT_STRING(cache_dir), .flags = M_OPT_FILE}, - {"cache-unlink-files", OPT_CHOICE(unlink_files, + {"demuxer-cache-dir", OPT_STRING(cache_dir), .flags = M_OPT_FILE}, + {"demuxer-cache-unlink-files", OPT_CHOICE(unlink_files, {"immediate", 2}, {"whendone", 1}, {"no", 0}), }, + {"cache-dir", OPT_REPLACED("demuxer-cache-dir")}, + {"cache-unlink-files", OPT_REPLACED("demuxer-cache-unlink-files")}, {0} }, .size = sizeof(struct demux_cache_opts), @@ -100,11 +103,16 @@ struct demux_cache *demux_cache_create(struct mpv_global *global, cache->fd = -1; char *cache_dir = cache->opts->cache_dir; - if (!(cache_dir && cache_dir[0])) { - MP_ERR(cache, "No cache data directory supplied.\n"); - goto fail; + if (cache_dir && cache_dir[0]) { + cache_dir = mp_get_user_path(NULL, global, cache_dir); + } else { + cache_dir = mp_find_user_file(NULL, global, "cache", ""); } + if (!cache_dir || !cache_dir[0]) + goto fail; + + mp_mkdirp(cache_dir); cache->filename = mp_path_join(cache, cache_dir, "mpv-cache-XXXXXX.dat"); cache->fd = mp_mkostemps(cache->filename, 4, O_CLOEXEC); if (cache->fd < 0) { @@ -207,7 +215,7 @@ int64_t demux_cache_write(struct demux_cache *cache, struct demux_packet *dp) } assert(!dp->is_cached); - assert(dp->len >= 0 && dp->len <= INT32_MAX); + assert(dp->len <= INT32_MAX); assert(dp->avpacket->flags >= 0 && dp->avpacket->flags <= INT32_MAX); assert(dp->avpacket->side_data_elems >= 0 && dp->avpacket->side_data_elems <= INT32_MAX); @@ -253,7 +261,7 @@ int64_t demux_cache_write(struct demux_cache *cache, struct demux_packet *dp) for (int n = 0; n < dp->avpacket->side_data_elems; n++) { AVPacketSideData *sd = &dp->avpacket->side_data[n]; - assert(sd->size >= 0 && sd->size <= INT32_MAX); + assert(sd->size <= INT32_MAX); assert(sd->type >= 0 && sd->type <= INT32_MAX); struct sd_header sd_hd = { @@ -286,9 +294,6 @@ struct demux_packet *demux_cache_read(struct demux_cache *cache, uint64_t pos) if (!read_raw(cache, &hd, sizeof(hd))) return NULL; - if (hd.data_len >= (size_t)-1) - return NULL; - struct demux_packet *dp = new_demux_packet(hd.data_len); if (!dp) goto fail; diff --git a/demux/codec_tags.c b/demux/codec_tags.c index 8f8c97ec38..d118fbe560 100644 --- a/demux/codec_tags.c +++ b/demux/codec_tags.c @@ -44,15 +44,69 @@ static const char *lookup_tag(int type, uint32_t tag) return id == AV_CODEC_ID_NONE ? NULL : mp_codec_from_av_codec_id(id); } -// Corresponds to WMMEDIASUBTYPE_Base. -static const unsigned char guid_ext_base[16] = + +/* + * As seen in the following page: + * + * <https://web.archive.org/web/20220406060153/ + * http://dream.cs.bath.ac.uk/researchdev/wave-ex/bformat.html> + * + * Note that the GUID struct in the above citation has its + * integers encoded in little-endian format, which means that + * the unsigned short and unsigned long entries need to be + * byte-flipped for this encoding. + * + * In theory only the first element of this array should be used, + * however some encoders incorrectly encoded the GUID byte-for-byte + * and thus the second one exists as a fallback. + */ +static const unsigned char guid_ext_base[][16] = { + // MEDIASUBTYPE_BASE_GUID {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, - 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71}; + 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71}, + // SUBTYPE_AMBISONIC_B_FORMAT_PCM + {0x01, 0x00, 0x00, 0x00, 0x21, 0x07, 0xD3, 0x11, + 0x86, 0x44, 0xC8, 0xC1, 0xCA, 0x00, 0x00, 0x00} +}; + +struct mp_waveformatex_guid { + const char *codec; + const unsigned char guid[16]; +}; + +static const struct mp_waveformatex_guid guid_ext_other[] = { + {"ac3", + {0x2C, 0x80, 0x6D, 0xE0, 0x46, 0xDB, 0xCF, 0x11, + 0xB4, 0xD1, 0x00, 0x80, 0x5F, 0x6C, 0xBB, 0xEA}}, + {"adpcm_agm", + {0x82, 0xEC, 0x1F, 0x6A, 0xCA, 0xDB, 0x19, 0x45, + 0xBD, 0xE7, 0x56, 0xD3, 0xB3, 0xEF, 0x98, 0x1D}}, + {"atrac3p", + {0xBF, 0xAA, 0x23, 0xE9, 0x58, 0xCB, 0x71, 0x44, + 0xA1, 0x19, 0xFF, 0xFA, 0x01, 0xE4, 0xCE, 0x62}}, + {"atrac9", + {0xD2, 0x42, 0xE1, 0x47, 0xBA, 0x36, 0x8D, 0x4D, + 0x88, 0xFC, 0x61, 0x65, 0x4F, 0x8C, 0x83, 0x6C}}, + {"dfpwm", + {0x3A, 0xC1, 0xFA, 0x38, 0x81, 0x1D, 0x43, 0x61, + 0xA4, 0x0D, 0xCE, 0x53, 0xCA, 0x60, 0x7C, 0xD1}}, + {"eac3", + {0xAF, 0x87, 0xFB, 0xA7, 0x02, 0x2D, 0xFB, 0x42, + 0xA4, 0xD4, 0x05, 0xCD, 0x93, 0x84, 0x3B, 0xDD}}, + {"mp2", + {0x2B, 0x80, 0x6D, 0xE0, 0x46, 0xDB, 0xCF, 0x11, + 0xB4, 0xD1, 0x00, 0x80, 0x5F, 0x6C, 0xBB, 0xEA}} +}; static void map_audio_pcm_tag(struct mp_codec_params *c) { // MS PCM, Extended if (c->codec_tag == 0xfffe && c->extradata_size >= 22) { + // WAVEFORMATEXTENSIBLE.wBitsPerSample + int bits_per_sample = AV_RL16(c->extradata); + if (bits_per_sample) + c->bits_per_coded_sample = bits_per_sample; + // WAVEFORMATEXTENSIBLE.dwChannelMask uint64_t chmask = AV_RL32(c->extradata + 2); struct mp_chmap chmap; @@ -62,9 +116,23 @@ static void map_audio_pcm_tag(struct mp_codec_params *c) // WAVEFORMATEXTENSIBLE.SubFormat unsigned char *subformat = c->extradata + 6; - if (memcmp(subformat + 4, guid_ext_base + 4, 12) == 0) { - c->codec_tag = AV_RL32(subformat); - c->codec = lookup_tag(c->type, c->codec_tag); + for (int i = 0; i < MP_ARRAY_SIZE(guid_ext_base); i++) { + if (memcmp(subformat + 4, guid_ext_base[i] + 4, 12) == 0) { + c->codec_tag = AV_RL32(subformat); + c->codec = lookup_tag(c->type, c->codec_tag); + break; + } + } + + // extra subformat, not a base one + if (c->codec_tag == 0xfffe) { + for (int i = 0; i < MP_ARRAY_SIZE(guid_ext_other); i++) { + if (memcmp(subformat, &guid_ext_other[i].guid, 16) == 0) { + c->codec = guid_ext_other[i].codec; + c->codec_tag = mp_codec_to_av_codec_id(c->codec); + break; + } + } } // Compressed formats might use this. @@ -73,6 +141,9 @@ static void map_audio_pcm_tag(struct mp_codec_params *c) } int bits = c->bits_per_coded_sample; + if (!bits) + return; + int bytes = (bits + 7) / 8; switch (c->codec_tag) { case 0x0: // Microsoft PCM @@ -89,8 +160,7 @@ static void map_audio_pcm_tag(struct mp_codec_params *c) void mp_set_codec_from_tag(struct mp_codec_params *c) { c->codec = lookup_tag(c->type, c->codec_tag); - - if (c->type == STREAM_AUDIO && c->bits_per_coded_sample) + if (c->type == STREAM_AUDIO) map_audio_pcm_tag(c); } @@ -111,8 +181,15 @@ void mp_set_pcm_codec(struct mp_codec_params *c, bool sign, bool is_float, } static const char *const mimetype_to_codec[][2] = { + {"image/apng", "apng"}, + {"image/avif", "av1"}, + {"image/bmp", "bmp"}, + {"image/gif", "gif"}, {"image/jpeg", "mjpeg"}, + {"image/jxl", "jpegxl"}, {"image/png", "png"}, + {"image/tiff", "tiff"}, + {"image/webp", "webp"}, {0} }; diff --git a/demux/demux.c b/demux/demux.c index e4dda43cf0..5997a96ed6 100644 --- a/demux/demux.c +++ b/demux/demux.c @@ -15,20 +15,18 @@ * 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 <unistd.h> #include "cache.h" #include "config.h" @@ -42,7 +40,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 +81,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,20 +89,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)}, - {"cache-secs", OPT_DOUBLE(min_secs_cache), M_RANGE(0, DBL_MAX), - .deprecation_message = "will use unlimited time"}, - {"access-references", OPT_FLAG(access_references)}, + {"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_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)}, @@ -139,8 +118,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), @@ -148,11 +125,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, @@ -160,7 +139,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, }; @@ -180,15 +159,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; @@ -211,6 +187,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; @@ -389,7 +367,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) @@ -452,7 +430,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); @@ -468,7 +446,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; @@ -538,7 +516,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); } @@ -685,7 +663,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); @@ -878,7 +856,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); } } @@ -941,9 +919,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, @@ -975,6 +953,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), }; @@ -1024,7 +1003,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 || @@ -1034,7 +1013,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; @@ -1056,9 +1035,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 @@ -1068,10 +1047,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; } @@ -1079,9 +1058,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; } @@ -1120,8 +1099,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); } @@ -1152,11 +1131,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 } @@ -1180,9 +1159,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; @@ -1211,7 +1190,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; } } @@ -1222,11 +1201,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; } @@ -1236,10 +1215,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) @@ -1247,10 +1226,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) @@ -1273,6 +1252,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; @@ -1285,10 +1266,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; } @@ -1298,7 +1279,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) @@ -1335,8 +1316,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. @@ -1460,7 +1441,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; @@ -1507,7 +1488,7 @@ static void find_backward_restart_pos(struct demux_stream *ds) // Or if preroll is involved, the first preroll packet. while (ds->reader_head != target) { if (!advance_reader_head(ds)) - assert(0); // target must be in list + MP_ASSERT_UNREACHABLE(); // target must be in list } double seek_pts; @@ -1570,9 +1551,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; } } @@ -1686,7 +1667,7 @@ static void attempt_range_joining(struct demux_internal *in) // Try to find a join point, where packets obviously overlap. (It would be // better and faster to do this incrementally, but probably too complex.) // The current range can overlap arbitrarily with the next one, not only by - // by the seek overlap, but for arbitrary packet readahead as well. + // the seek overlap, but for arbitrary packet readahead as well. // We also drop the overlapping packets (if joining fails, we discard the // entire next range anyway, so this does no harm). for (int n = 0; n < in->num_streams; n++) { @@ -1945,9 +1926,18 @@ static struct mp_recorder *recorder_create(struct demux_internal *in, if (stream->ds->selected) MP_TARRAY_APPEND(NULL, streams, num_streams, stream); } + + struct demuxer *demuxer = in->d_thread; + struct demux_attachment **attachments = talloc_array(NULL, struct demux_attachment*, demuxer->num_attachments); + for (int n = 0; n < demuxer->num_attachments; n++) { + attachments[n] = &demuxer->attachments[n]; + } + struct mp_recorder *res = mp_recorder_create(in->d_thread->global, dst, - streams, num_streams); + streams, num_streams, + attachments, demuxer->num_attachments); talloc_free(streams); + talloc_free(attachments); return res; } @@ -1970,13 +1960,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"); } @@ -2000,6 +1990,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; @@ -2055,7 +2046,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); @@ -2109,7 +2100,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); @@ -2160,7 +2151,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); @@ -2198,16 +2189,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"); @@ -2218,7 +2216,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, @@ -2237,8 +2235,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++) { @@ -2253,7 +2253,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; @@ -2262,7 +2262,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) { |