summaryrefslogtreecommitdiffstats
path: root/demux
diff options
context:
space:
mode:
Diffstat (limited to 'demux')
-rw-r--r--demux/cache.c28
-rw-r--r--demux/codec_tags.c93
-rw-r--r--demux/demux.c638
-rw-r--r--demux/demux.h38
-rw-r--r--demux/demux_cue.c21
-rw-r--r--demux/demux_disc.c2
-rw-r--r--demux/demux_edl.c68
-rw-r--r--demux/demux_lavf.c351
-rw-r--r--demux/demux_libarchive.c8
-rw-r--r--demux/demux_mf.c100
-rw-r--r--demux/demux_mkv.c307
-rw-r--r--demux/demux_mkv_timeline.c5
-rw-r--r--demux/demux_playlist.c209
-rw-r--r--demux/demux_raw.c61
-rw-r--r--demux/demux_timeline.c56
-rw-r--r--demux/ebml.c8
-rw-r--r--demux/ebml.h3
-rw-r--r--demux/packet.c122
-rw-r--r--demux/packet.h6
-rw-r--r--demux/stheader.h21
-rw-r--r--demux/timeline.h9
21 files changed, 1517 insertions, 637 deletions
diff --git a/demux/cache.c b/demux/cache.c
index 4404c870de..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,9 +41,12 @@ struct demux_cache_opts {
const struct m_sub_options demux_cache_conf = {
.opts = (const struct m_option[]){
- OPT_STRING("cache-dir", cache_dir, M_OPT_FILE),
- OPT_CHOICE("cache-unlink-files", unlink_files, 0,
- ({"immediate", 2}, {"whendone", 1}, {"no", 0})),
+ {"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),
@@ -99,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) {
@@ -206,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);
@@ -252,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 = {
@@ -285,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 75d74d0beb..5997a96ed6 100644
--- a/demux/demux.c
+++ b/demux/demux.c
@@ -15,19 +15,18 @@
* License along with mpv. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
#include <assert.h>
-#include <unistd.h>
+#include <float.h>
#include <limits.h>
-#include <pthread.h>
-#include <stdint.h>
-
#include <math.h>
-
-#include <sys/types.h>
+#include <stdatomic.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
#include "cache.h"
#include "config.h"
@@ -38,9 +37,9 @@
#include "common/msg.h"
#include "common/global.h"
#include "common/recorder.h"
+#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"
@@ -82,59 +81,43 @@ 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;
-};
-
#define OPT_BASE_STRUCT struct demux_opts
-#define MAX_BYTES MPMIN(INT64_MAX, SIZE_MAX / 2)
-
static bool get_demux_sub_opts(int index, const struct m_sub_options **sub);
const struct m_sub_options demux_conf = {
.opts = (const struct m_option[]){
- OPT_CHOICE("cache", enable_cache, 0,
- ({"no", 0}, {"auto", -1}, {"yes", 1})),
- OPT_FLAG("cache-on-disk", disk_cache, 0),
- OPT_DOUBLE("demuxer-readahead-secs", min_secs, M_OPT_MIN, .min = 0),
- // (The MAX_BYTES sizes may not be accurate because the max field is
- // of double type.)
- OPT_BYTE_SIZE("demuxer-max-bytes", max_bytes, 0, 0, MAX_BYTES),
- OPT_BYTE_SIZE("demuxer-max-back-bytes", max_bytes_bw, 0, 0, MAX_BYTES),
- OPT_FLAG("demuxer-donate-buffer", donate_fw, 0),
- OPT_FLAG("force-seekable", force_seekable, 0),
- OPT_DOUBLE("cache-secs", min_secs_cache, M_OPT_MIN, .min = 0),
- OPT_FLAG("access-references", access_references, 0),
- OPT_CHOICE("demuxer-seekable-cache", seekable_cache, 0,
- ({"auto", -1}, {"no", 0}, {"yes", 1})),
- OPT_FLAG("sub-create-cc-track", create_ccs, 0),
- OPT_STRING("stream-record", record_file, 0),
- OPT_CHOICE_OR_INT("video-backward-overlap", video_back_preroll, 0, 0,
- 1024, ({"auto", -1})),
- OPT_CHOICE_OR_INT("audio-backward-overlap", audio_back_preroll, 0, 0,
- 1024, ({"auto", -1})),
- OPT_INTRANGE("video-backward-batch", back_batch[STREAM_VIDEO], 0, 0, 1024),
- OPT_INTRANGE("audio-backward-batch", back_batch[STREAM_AUDIO], 0, 0, 1024),
- OPT_DOUBLE("demuxer-backward-playback-step", back_seek_size, M_OPT_MIN,
- .min = 0),
- OPT_STRING("metadata-codepage", meta_cp, 0),
+ {"cache", OPT_CHOICE(enable_cache,
+ {"no", 0}, {"auto", -1}, {"yes", 1})},
+ {"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_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})},
+ {"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)},
+ {"audio-backward-overlap", OPT_CHOICE(audio_back_preroll, {"auto", -1}),
+ M_RANGE(0, 1024)},
+ {"video-backward-batch", OPT_INT(back_batch[STREAM_VIDEO]),
+ M_RANGE(0, 1024)},
+ {"audio-backward-batch", OPT_INT(back_batch[STREAM_AUDIO]),
+ M_RANGE(0, 1024)},
+ {"demuxer-backward-playback-step", OPT_DOUBLE(back_seek_size),
+ M_RANGE(0, DBL_MAX)},
+ {"metadata-codepage", OPT_STRING(meta_cp)},
{0}
},
.size = sizeof(struct demux_opts),
@@ -142,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 = 10.0 * 60 * 60,
+ .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,
@@ -154,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,
};
@@ -162,6 +147,7 @@ const struct m_sub_options demux_conf = {
struct demux_internal {
struct mp_log *log;
struct mpv_global *global;
+ struct stats_ctx *stats;
bool can_cache; // not a slave demuxer; caching makes sense
bool can_record; // stream recording is allowed
@@ -173,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;
@@ -202,18 +185,21 @@ struct demux_internal {
struct demux_cache *cache;
bool warned_queue_overflow;
- bool last_eof; // last actual global EOF status
- bool eof; // whether we're in EOF state (reset for retry)
- bool idle;
+ 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;
bool using_network_cache_opts;
char *record_filename;
- // At least one decoder actually requested data since init or the last seek.
- // Do this to allow the decoder thread to select streams before starting.
+ // Whether the demuxer thread should prefetch packets. This is set to false
+ // if EOF was reached or the demuxer cache is full. This is also important
+ // in the initial state: the decoder thread needs to select streams before
+ // the first packet is read, so this is set to true by packet reading only.
+ // Reset to false again on EOF or if prefetching is done.
bool reading;
// Set if we just performed a seek, without reading packets yet. Used to
@@ -266,6 +252,7 @@ struct demux_internal {
// Cached state.
int64_t stream_size;
int64_t last_speed_query;
+ double speed_query_prev_sample;
uint64_t bytes_per_second;
int64_t next_cache_update;
@@ -380,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)
@@ -400,6 +387,7 @@ struct demux_stream {
bool skip_to_keyframe;
bool attached_picture_added;
bool need_wakeup; // call wakeup_cb on next reader_head state change
+ double force_read_until;// eager=false streams (subs): force read-ahead
// For demux_internal.dumper. Currently, this is used only temporarily
// during blocking dumping.
@@ -442,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);
@@ -458,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;
@@ -528,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);
}
@@ -626,7 +614,9 @@ static void update_seek_ranges(struct demux_cached_range *range)
range->is_bof &= queue->is_bof;
bool empty = queue->is_eof && !queue->head;
- if (queue->seek_start >= queue->seek_end && !empty)
+ if (queue->seek_start >= queue->seek_end && !empty &&
+ !(queue->seek_start == queue->seek_end &&
+ queue->seek_start != MP_NOPTS_VALUE))
goto broken;
}
}
@@ -673,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);
@@ -824,6 +814,7 @@ static void ds_clear_reader_state(struct demux_stream *ds,
ds->attached_picture_added = false;
ds->last_ret_pos = -1;
ds->last_ret_dts = MP_NOPTS_VALUE;
+ ds->force_read_until = MP_NOPTS_VALUE;
if (clear_back_state) {
ds->back_restart_pos = -1;
@@ -865,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);
}
}
@@ -928,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,
@@ -962,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),
};
@@ -1011,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 ||
@@ -1021,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;
@@ -1043,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
@@ -1055,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;
}
@@ -1066,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;
}
@@ -1107,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);
}
@@ -1139,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
}
@@ -1167,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;
@@ -1198,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;
}
}
@@ -1209,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;
}
@@ -1223,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)
@@ -1234,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)
@@ -1260,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;
@@ -1272,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;
}
@@ -1285,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)
@@ -1322,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.
@@ -1447,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;
@@ -1494,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;
@@ -1557,8 +1551,9 @@ resume_earlier:
ds->reader_head = t;
ds->back_need_recheck = true;
in->back_any_need_recheck = true;
+ 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;
}
}
@@ -1569,7 +1564,7 @@ static void back_demux_see_packets(struct demux_stream *ds)
{
struct demux_internal *in = ds->in;
- if (!ds->selected || !in->back_demuxing)
+ if (!ds->selected || !in->back_demuxing || !ds->eager)
return;
assert(!(ds->back_resuming && ds->back_restarting));
@@ -1672,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++) {
@@ -1844,7 +1839,8 @@ static struct demux_packet *compute_keyframe_times(struct demux_packet *pkt,
break;
double ts = MP_PTS_OR_DEF(pkt->pts, pkt->dts);
- if (pkt->segmented && (ts < pkt->start || ts > pkt->end))
+ if (pkt->segmented && ((pkt->start != MP_NOPTS_VALUE && ts < pkt->start) ||
+ (pkt->end != MP_NOPTS_VALUE && ts > pkt->end)))
ts = MP_NOPTS_VALUE;
min = MP_PTS_MIN(min, ts);
@@ -1913,7 +1909,8 @@ static void adjust_seek_range_on_packet(struct demux_stream *ds,
queue->keyframe_latest = dp;
}
- if (update_ranges) {
+ // Adding a sparse packet never changes the seek range.
+ if (update_ranges && ds->eager) {
update_seek_ranges(queue->range);
attempt_range_joining(ds->in);
}
@@ -1929,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;
}
@@ -1954,13 +1960,13 @@ static void record_packet(struct demux_internal *in, struct demux_packet *dp