summaryrefslogtreecommitdiffstats
path: root/demux
diff options
context:
space:
mode:
authorMartin Herkt <lachs0r@srsfckn.biz>2016-01-18 07:27:03 +0100
committerMartin Herkt <lachs0r@srsfckn.biz>2016-01-18 07:27:03 +0100
commitba9b2f1e49732d597009ba514b0132a50562cd10 (patch)
treefa05f5feb181823ac9d3b5682a835ff825de6914 /demux
parente1993d5ad2bdf3dd4c26474aaa2370cbc9c1cd1b (diff)
parent7b4ccb3e9f58a0745b58e473ee6e60b381242813 (diff)
downloadmpv-ba9b2f1e49732d597009ba514b0132a50562cd10.tar.bz2
mpv-ba9b2f1e49732d597009ba514b0132a50562cd10.tar.xz
Merge branch 'master' into release/current
Diffstat (limited to 'demux')
-rw-r--r--demux/codec_tags.c16
-rw-r--r--demux/codec_tags.h8
-rw-r--r--demux/cue.c17
-rw-r--r--demux/cue.h1
-rw-r--r--demux/demux.c251
-rw-r--r--demux/demux.h12
-rw-r--r--demux/demux_cue.c16
-rw-r--r--demux/demux_disc.c45
-rw-r--r--demux/demux_edl.c2
-rw-r--r--demux/demux_lavf.c189
-rw-r--r--demux/demux_mf.c29
-rw-r--r--demux/demux_mkv.c152
-rw-r--r--demux/demux_mkv_timeline.c14
-rw-r--r--demux/demux_raw.c48
-rw-r--r--demux/demux_tv.c45
-rw-r--r--demux/ebml.c2
-rw-r--r--demux/stheader.h57
17 files changed, 518 insertions, 386 deletions
diff --git a/demux/codec_tags.c b/demux/codec_tags.c
index c7b48f6038..7e91291e9e 100644
--- a/demux/codec_tags.c
+++ b/demux/codec_tags.c
@@ -70,20 +70,20 @@ static const char *map_audio_pcm_tag(uint32_t tag, int bits)
}
}
-void mp_set_codec_from_tag(struct sh_stream *sh)
+void mp_set_codec_from_tag(struct mp_codec_params *c)
{
- sh->codec = lookup_tag(sh->type, sh->codec_tag);
+ c->codec = lookup_tag(c->type, c->codec_tag);
- if (sh->audio && sh->audio->bits_per_coded_sample) {
+ if (c->type == STREAM_AUDIO && c->bits_per_coded_sample) {
const char *codec =
- map_audio_pcm_tag(sh->codec_tag, sh->audio->bits_per_coded_sample);
+ map_audio_pcm_tag(c->codec_tag, c->bits_per_coded_sample);
if (codec)
- sh->codec = codec;
+ c->codec = codec;
}
}
-void mp_set_pcm_codec(struct sh_stream *sh, bool sign, bool is_float, int bits,
- bool is_be)
+void mp_set_pcm_codec(struct mp_codec_params *c, bool sign, bool is_float,
+ int bits, bool is_be)
{
// This uses libavcodec pcm codec names, e.g. "pcm_u16le".
char codec[64] = "pcm_";
@@ -95,7 +95,7 @@ void mp_set_pcm_codec(struct sh_stream *sh, bool sign, bool is_float, int bits,
mp_snprintf_cat(codec, sizeof(codec), "%d", bits);
if (bits != 8)
mp_snprintf_cat(codec, sizeof(codec), is_be ? "be" : "le");
- sh->codec = talloc_strdup(sh->audio, codec);
+ c->codec = talloc_strdup(c, codec);
}
static const char *const mimetype_to_codec[][2] = {
diff --git a/demux/codec_tags.h b/demux/codec_tags.h
index 3489f0da5c..294759a299 100644
--- a/demux/codec_tags.h
+++ b/demux/codec_tags.h
@@ -21,12 +21,12 @@
#include <stdint.h>
#include <stdbool.h>
-struct sh_stream;
+struct mp_codec_params;
-void mp_set_codec_from_tag(struct sh_stream *sh);
+void mp_set_codec_from_tag(struct mp_codec_params *c);
-void mp_set_pcm_codec(struct sh_stream *sh, bool sign, bool is_float, int bits,
- bool is_be);
+void mp_set_pcm_codec(struct mp_codec_params *c, bool sign, bool is_float,
+ int bits, bool is_be);
const char *mp_map_mimetype_to_video_codec(const char *mimetype);
diff --git a/demux/cue.c b/demux/cue.c
index d72e84249b..4a84107db7 100644
--- a/demux/cue.c
+++ b/demux/cue.c
@@ -20,7 +20,7 @@
#include <string.h>
#include <inttypes.h>
-#include "talloc.h"
+#include "mpv_talloc.h"
#include "misc/bstr.h"
#include "common/common.h"
@@ -218,3 +218,18 @@ struct cue_file *mp_parse_cue(struct bstr data)
return f;
}
+
+int mp_check_embedded_cue(struct cue_file *f)
+{
+ char *fn0 = f->tracks[0].filename;
+ for (int n = 1; n < f->num_tracks; n++) {
+ char *fn = f->tracks[n].filename;
+ // both filenames have the same address (including NULL)
+ if (fn0 == fn)
+ continue;
+ // only one filename is NULL, or the strings don't match
+ if (!fn0 || !fn || strcmp(fn0, fn) != 0)
+ return -1;
+ }
+ return 0;
+}
diff --git a/demux/cue.h b/demux/cue.h
index cf4b4c1a08..1ae5f0a203 100644
--- a/demux/cue.h
+++ b/demux/cue.h
@@ -38,5 +38,6 @@ struct cue_track {
bool mp_probe_cue(struct bstr data);
struct cue_file *mp_parse_cue(struct bstr data);
+int mp_check_embedded_cue(struct cue_file *f);
#endif
diff --git a/demux/demux.c b/demux/demux.c
index dcad692be5..19ad6970b0 100644
--- a/demux/demux.c
+++ b/demux/demux.c
@@ -29,7 +29,7 @@
#include "config.h"
#include "options/options.h"
-#include "talloc.h"
+#include "mpv_talloc.h"
#include "common/msg.h"
#include "common/global.h"
#include "osdep/threads.h"
@@ -103,6 +103,11 @@ struct demux_internal {
void (*wakeup_cb)(void *ctx);
void *wakeup_cb_ctx;
+ struct sh_stream **streams;
+ int num_streams;
+
+ int events;
+
bool warned_queue_overflow;
bool last_eof; // last actual global EOF status
bool eof; // whether we're in EOF state (reset for retry)
@@ -198,42 +203,84 @@ void demux_set_ts_offset(struct demuxer *demuxer, double offset)
pthread_mutex_unlock(&in->lock);
}
-struct sh_stream *new_sh_stream(demuxer_t *demuxer, enum stream_type type)
+// Allocate a new sh_stream of the given type. It either has to be released
+// with talloc_free(), or added to a demuxer with demux_add_sh_stream(). You
+// cannot add or read packets from the stream before it has been added.
+struct sh_stream *demux_alloc_sh_stream(enum stream_type type)
{
- assert(demuxer == demuxer->in->d_thread);
-
- if (demuxer->num_streams > MAX_SH_STREAMS) {
- MP_WARN(demuxer, "Too many streams.\n");
- return NULL;
- }
-
- int demuxer_id = 0;
- for (int n = 0; n < demuxer->num_streams; n++) {
- if (demuxer->streams[n]->type == type)
- demuxer_id++;
- }
-
- struct sh_stream *sh = talloc_ptrtype(demuxer, sh);
+ struct sh_stream *sh = talloc_ptrtype(NULL, sh);
*sh = (struct sh_stream) {
.type = type,
- .index = demuxer->num_streams,
- .ff_index = demuxer->num_streams,
- .demuxer_id = demuxer_id, // may be overwritten by demuxer
- .ds = talloc(sh, struct demux_stream),
+ .index = -1,
+ .ff_index = -1, // may be overwritten by demuxer
+ .demuxer_id = -1, // ... same
+ .codec = talloc_zero(sh, struct mp_codec_params),
};
+ sh->codec->type = type;
+ return sh;
+}
+
+// Add a new sh_stream to the demuxer. Note that as soon as the stream has been
+// added, it must be immutable, and must not be released (this will happen when
+// the demuxer is destroyed).
+void demux_add_sh_stream(struct demuxer *demuxer, struct sh_stream *sh)
+{
+ struct demux_internal *in = demuxer->in;
+ pthread_mutex_lock(&in->lock);
+
+ assert(!sh->ds); // must not be added yet
+
+ sh->ds = talloc(sh, struct demux_stream);
*sh->ds = (struct demux_stream) {
- .in = demuxer->in,
+ .in = in,
.type = sh->type,
- .selected = demuxer->in->autoselect,
+ .selected = in->autoselect,
};
- MP_TARRAY_APPEND(demuxer, demuxer->streams, demuxer->num_streams, sh);
- switch (sh->type) {
- case STREAM_VIDEO: sh->video = talloc_zero(demuxer, struct sh_video); break;
- case STREAM_AUDIO: sh->audio = talloc_zero(demuxer, struct sh_audio); break;
- case STREAM_SUB: sh->sub = talloc_zero(demuxer, struct sh_sub); break;
+
+ if (!sh->codec->codec)
+ sh->codec->codec = "";
+
+ sh->index = in->num_streams;
+ if (sh->ff_index < 0)
+ sh->ff_index = sh->index;
+ if (sh->demuxer_id < 0) {
+ sh->demuxer_id = 0;
+ for (int n = 0; n < in->num_streams; n++) {
+ if (in->streams[n]->type == sh->type)
+ sh->demuxer_id += 1;
+ }
}
- return sh;
+ MP_TARRAY_APPEND(in, in->streams, in->num_streams, sh);
+
+ in->events |= DEMUX_EVENT_STREAMS;
+ if (in->wakeup_cb)
+ in->wakeup_cb(in->wakeup_cb_ctx);
+ pthread_mutex_unlock(&in->lock);
+}
+
+// Return a stream with the given index. Since streams can only be added during
+// the lifetime of the demuxer, it is guaranteed that an index within the valid
+// range [0, demux_get_num_stream()) always returns a valid sh_stream pointer,
+// which will be valid until the demuxer is destroyed.
+struct sh_stream *demux_get_stream(struct demuxer *demuxer, int index)
+{
+ struct demux_internal *in = demuxer->in;
+ pthread_mutex_lock(&in->lock);
+ assert(index >= 0 && index < in->num_streams);
+ struct sh_stream *r = in->streams[index];
+ pthread_mutex_unlock(&in->lock);
+ return r;
+}
+
+// See demux_get_stream().
+int demux_get_num_stream(struct demuxer *demuxer)
+{
+ struct demux_internal *in = demuxer->in;
+ pthread_mutex_lock(&in->lock);
+ int r = in->num_streams;
+ pthread_mutex_unlock(&in->lock);
+ return r;
}
void free_demuxer(demuxer_t *demuxer)
@@ -247,8 +294,10 @@ void free_demuxer(demuxer_t *demuxer)
if (demuxer->desc->close)
demuxer->desc->close(in->d_thread);
- for (int n = 0; n < demuxer->num_streams; n++)
- ds_flush(demuxer->streams[n]->ds);
+ for (int n = in->num_streams - 1; n >= 0; n--) {
+ ds_flush(in->streams[n]->ds);
+ talloc_free(in->streams[n]);
+ }
pthread_mutex_destroy(&in->lock);
pthread_cond_destroy(&in->wakeup);
talloc_free(demuxer);
@@ -388,8 +437,8 @@ static bool read_packet(struct demux_internal *in)
// safe-guards against packet queue overflow.
bool active = false, read_more = false;
size_t packs = 0, bytes = 0;
- for (int n = 0; n < in->d_buffer->num_streams; n++) {
- struct demux_stream *ds = in->d_buffer->streams[n]->ds;
+ for (int n = 0; n < in->num_streams; n++) {
+ struct demux_stream *ds = in->streams[n]->ds;
active |= ds->active;
read_more |= ds->active && !ds->head;
packs += ds->packs;
@@ -404,16 +453,16 @@ static bool read_packet(struct demux_internal *in)
if (!in->warned_queue_overflow) {
in->warned_queue_overflow = true;
MP_ERR(in, "Too many packets in the demuxer packet queues:\n");
- for (int n = 0; n < in->d_buffer->num_streams; n++) {
- struct demux_stream *ds = in->d_buffer->streams[n]->ds;
+ for (int n = 0; n < in->num_streams; n++) {
+ struct demux_stream *ds = in->streams[n]->ds;
if (ds->selected) {
MP_ERR(in, " %s/%d: %zd packets, %zd bytes\n",
stream_type_name(ds->type), n, ds->packs, ds->bytes);
}
}
}
- for (int n = 0; n < in->d_buffer->num_streams; n++) {
- struct demux_stream *ds = in->d_buffer->streams[n]->ds;
+ for (int n = 0; n < in->num_streams; n++) {
+ struct demux_stream *ds = in->streams[n]->ds;
ds->eof |= !ds->head;
}
pthread_cond_signal(&in->wakeup);
@@ -433,8 +482,8 @@ static bool read_packet(struct demux_internal *in)
pthread_mutex_lock(&in->lock);
if (eof) {
- for (int n = 0; n < in->d_buffer->num_streams; n++)
- in->d_buffer->streams[n]->ds->eof = true;
+ for (int n = 0; n < in->num_streams; n++)
+ in->streams[n]->ds->eof = true;
// If we had EOF previously, then don't wakeup (avoids wakeup loop)
if (!in->last_eof) {
if (in->wakeup_cb)
@@ -478,8 +527,8 @@ static void start_refreshing(struct demux_internal *in)
in->start_refresh_seek = false;
double start_ts = MP_NOPTS_VALUE;
- for (int n = 0; n < demux->num_streams; n++) {
- struct demux_stream *ds = demux->streams[n]->ds;
+ for (int n = 0; n < in->num_streams; n++) {
+ struct demux_stream *ds = in->streams[n]->ds;
if (ds->type == STREAM_VIDEO || ds->type == STREAM_AUDIO)
start_ts = MP_PTS_MIN(start_ts, ds->base_ts);
}
@@ -488,8 +537,8 @@ static void start_refreshing(struct demux_internal *in)
demux->partially_seekable || !demux->allow_refresh_seeks)
return;
- for (int n = 0; n < demux->num_streams; n++) {
- struct demux_stream *ds = demux->streams[n]->ds;
+ for (int n = 0; n < in->num_streams; n++) {
+ struct demux_stream *ds = in->streams[n]->ds;
// Streams which didn't read any packets yet can return all packets,
// or they'd be stuck forever; affects newly selected streams too.
if (ds->last_pos != -1)
@@ -635,15 +684,33 @@ struct demux_packet *demux_read_packet(struct sh_stream *sh)
return pkt;
}
+// Sparse packets (Subtitles) interleaved with other non-sparse packets (video,
+// audio) should never be read actively, meaning the demuxer thread does not
+// try to exceed default readahead in order to find a new packet.
+static bool use_lazy_subtitle_reading(struct demux_stream *ds)
+{
+ if (ds->type != STREAM_SUB)
+ return false;
+ for (int n = 0; n < ds->in->num_streams; n++) {
+ struct demux_stream *s = ds->in->streams[n]->ds;
+ if (s->type != STREAM_SUB && s->selected && !s->eof)
+ return true;
+ }
+ return false;
+}
+
// Poll the demuxer queue, and if there's a packet, return it. Otherwise, just
// make the demuxer thread read packets for this stream, and if there's at
// least one packet, call the wakeup callback.
-// Unlike demux_read_packet(), this always enables readahead (which means you
-// must not use it on interleaved subtitle streams).
+// Unlike demux_read_packet(), this always enables readahead (except for
+// interleaved subtitles).
// Returns:
// < 0: EOF was reached, *out_pkt=NULL
// == 0: no new packet yet, but maybe later, *out_pkt=NULL
// > 0: new packet read, *out_pkt is set
+// Note: when reading interleaved subtitles, the demuxer won't try to forcibly
+// read ahead to get the next subtitle packet (as the next packet could be
+// minutes away). In this situation, this function will just return -1.
int demux_read_packet_async(struct sh_stream *sh, struct demux_packet **out_pkt)
{
struct demux_stream *ds = sh ? sh->ds : NULL;
@@ -653,10 +720,14 @@ int demux_read_packet_async(struct sh_stream *sh, struct demux_packet **out_pkt)
if (ds->in->threading) {
pthread_mutex_lock(&ds->in->lock);
*out_pkt = dequeue_packet(ds);
- r = *out_pkt ? 1 : ((ds->eof || !ds->selected) ? -1 : 0);
- ds->active = ds->selected; // enable readahead
- ds->in->eof = false; // force retry
- pthread_cond_signal(&ds->in->wakeup); // possibly read more
+ if (use_lazy_subtitle_reading(ds)) {
+ r = *out_pkt ? 1 : -1;
+ } else {
+ r = *out_pkt ? 1 : ((ds->eof || !ds->selected) ? -1 : 0);
+ ds->active = ds->selected; // enable readahead
+ ds->in->eof = false; // force retry
+ pthread_cond_signal(&ds->in->wakeup); // possibly read more
+ }
pthread_mutex_unlock(&ds->in->lock);
} else {
*out_pkt = demux_read_packet(sh);
@@ -666,22 +737,6 @@ int demux_read_packet_async(struct sh_stream *sh, struct demux_packet **out_pkt)
return r;
}
-// Return the pts of the next packet that demux_read_packet() would return.
-// Might block. Sometimes used to force a packet read, without removing any
-// packets from the queue.
-double demux_get_next_pts(struct sh_stream *sh)
-{
- double res = MP_NOPTS_VALUE;
- if (sh) {
- pthread_mutex_lock(&sh->ds->in->lock);
- ds_get_packets(sh->ds);
- if (sh->ds->head)
- res = MP_ADD_PTS(sh->ds->head->pts, sh->ds->in->ts_offset);
- pthread_mutex_unlock(&sh->ds->in->lock);
- }
- return res;
-}
-
// Return whether a packet is queued. Never blocks, never forces any reads.
bool demux_has_packet(struct sh_stream *sh)
{
@@ -697,21 +752,22 @@ bool demux_has_packet(struct sh_stream *sh)
// Read and return any packet we find.
struct demux_packet *demux_read_any_packet(struct demuxer *demuxer)
{
- assert(!demuxer->in->threading); // doesn't work with threading
+ struct demux_internal *in = demuxer->in;
+ assert(!in->threading); // doesn't work with threading
bool read_more = true;
while (read_more) {
- for (int n = 0; n < demuxer->num_streams; n++) {
- struct sh_stream *sh = demuxer->streams[n];
+ for (int n = 0; n < in->num_streams; n++) {
+ struct sh_stream *sh = in->streams[n];
sh->ds->active = sh->ds->selected; // force read_packet() to read
struct demux_packet *pkt = dequeue_packet(sh->ds);
if (pkt)
return pkt;
}
// retry after calling this
- pthread_mutex_lock(&demuxer->in->lock);
- read_more = read_packet(demuxer->in);
- read_more &= !demuxer->in->eof;
- pthread_mutex_unlock(&demuxer->in->lock);
+ pthread_mutex_lock(&in->lock); // lock only because read_packet unlocks
+ read_more = read_packet(in);
+ read_more &= !in->eof;
+ pthread_mutex_unlock(&in->lock);
}
return NULL;
}
@@ -795,13 +851,14 @@ static int decode_peak(demuxer_t *demuxer, const char *tag, float *out)
static void apply_replaygain(demuxer_t *demuxer, struct replaygain_data *rg)
{
- for (int n = 0; n < demuxer->num_streams; n++) {
- struct sh_stream *sh = demuxer->streams[n];
- if (sh->audio && !sh->audio->replaygain_data) {
+ struct demux_internal *in = demuxer->in;
+ for (int n = 0; n < in->num_streams; n++) {
+ struct sh_stream *sh = in->streams[n];
+ if (sh->type == STREAM_AUDIO && !sh->codec->replaygain_data) {
MP_VERBOSE(demuxer, "Replaygain: Track=%f/%f Album=%f/%f\n",
rg->track_gain, rg->track_peak,
rg->album_gain, rg->album_peak);
- sh->audio->replaygain_data = talloc_memdup(demuxer, rg, sizeof(*rg));
+ sh->codec->replaygain_data = talloc_memdup(in, rg, sizeof(*rg));
}
}
}
@@ -853,11 +910,6 @@ static void demux_copy(struct demuxer *dst, struct demuxer *src)
dst->start_time = src->start_time;
dst->priv = src->priv;
}
- if (src->events & DEMUX_EVENT_STREAMS) {
- // The stream structs themselves are immutable.
- for (int n = dst->num_streams; n < src->num_streams; n++)
- MP_TARRAY_APPEND(dst, dst->streams, dst->num_streams, src->streams[n]);
- }
if (src->events & DEMUX_EVENT_METADATA) {
talloc_free(dst->metadata);
dst->metadata = mp_tags_dup(dst, src->metadata);
@@ -905,6 +957,8 @@ void demux_update(demuxer_t *demuxer)
pthread_mutex_lock(&in->lock);
demux_copy(demuxer, in->d_buffer);
+ demuxer->events |= in->events;
+ in->events = 0;
if (in->stream_metadata && (demuxer->events & DEMUX_EVENT_METADATA))
mp_tags_merge(demuxer->metadata, in->stream_metadata);
pthread_mutex_unlock(&in->lock);
@@ -926,10 +980,15 @@ static void demux_init_cuesheet(struct demuxer *demuxer)
if (cue && !demuxer->num_chapters) {
struct cue_file *f = mp_parse_cue(bstr0(cue));
if (f) {
- 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 (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);
@@ -1108,8 +1167,8 @@ struct demuxer *demux_open_url(const char *url,
static void flush_locked(demuxer_t *demuxer)
{
- for (int n = 0; n < demuxer->num_streams; n++)
- ds_flush(demuxer->streams[n]->ds);
+ for (int n = 0; n < demuxer->in->num_streams; n++)
+ ds_flush(demuxer->in->streams[n]->ds);
demuxer->in->warned_queue_overflow = false;
demuxer->in->eof = false;
demuxer->in->last_eof = false;
@@ -1187,10 +1246,11 @@ void demux_set_enable_refresh_seeks(struct demuxer *demuxer, bool enabled)
struct sh_stream *demuxer_stream_by_demuxer_id(struct demuxer *d,
enum stream_type t, int id)
{
- for (int n = 0; n < d->num_streams; n++) {
- struct sh_stream *s = d->streams[n];
+ int num = demux_get_num_stream(d);
+ for (int n = 0; n < num; n++) {
+ struct sh_stream *s = demux_get_stream(d, n);
if (s->type == t && s->demuxer_id == id)
- return d->streams[n];
+ return s;
}
return NULL;
}
@@ -1200,8 +1260,9 @@ void demuxer_switch_track(struct demuxer *demuxer, enum stream_type type,
{
assert(!stream || stream->type == type);
- for (int n = 0; n < demuxer->num_streams; n++) {
- struct sh_stream *cur = demuxer->streams[n];
+ int num = demux_get_num_stream(demuxer);
+ for (int n = 0; n < num; n++) {
+ struct sh_stream *cur = demux_get_stream(demuxer, n);
if (cur->type == type)
demuxer_select_track(demuxer, cur, cur == stream);
}
@@ -1403,8 +1464,8 @@ static int cached_demux_control(struct demux_internal *in, int cmd, void *arg)
double *rates = arg;
for (int n = 0; n < STREAM_TYPE_COUNT; n++)
rates[n] = -1;
- for (int n = 0; n < in->d_user->num_streams; n++) {
- struct demux_stream *ds = in->d_user->streams[n]->ds;
+ for (int n = 0; n < in->num_streams; n++) {
+ struct demux_stream *ds = in->streams[n]->ds;
if (ds->selected && ds->bitrate >= 0)
rates[ds->type] = MPMAX(0, rates[ds->type]) + ds->bitrate;
}
@@ -1418,8 +1479,8 @@ static int cached_demux_control(struct demux_internal *in, int cmd, void *arg)
.ts_duration = -1,
};
int num_packets = 0;
- for (int n = 0; n < in->d_user->num_streams; n++) {
- struct demux_stream *ds = in->d_user->streams[n]->ds;
+ for (int n = 0; n < in->num_streams; n++) {
+ struct demux_stream *ds = in->streams[n]->ds;
if (ds->active) {
r->underrun |= !ds->head && !ds->eof;
r->ts_range[0] = MP_PTS_MAX(r->ts_range[0], ds->base_ts);
diff --git a/demux/demux.h b/demux/demux.h
index 96717d5eeb..d274be5ae7 100644
--- a/demux/demux.h
+++ b/demux/demux.h
@@ -86,8 +86,6 @@ enum demux_event {
DEMUX_EVENT_ALL = 0xFFFF,
};
-#define MAX_SH_STREAMS 256
-
struct demuxer;
struct timeline;
@@ -199,9 +197,6 @@ typedef struct demuxer {
// Bitmask of DEMUX_EVENT_*
int events;
- struct sh_stream **streams;
- int num_streams;
-
struct demux_edition *editions;
int num_editions;
int edition;
@@ -247,11 +242,14 @@ void demux_add_packet(struct sh_stream *stream, demux_packet_t *dp);
struct demux_packet *demux_read_packet(struct sh_stream *sh);
int demux_read_packet_async(struct sh_stream *sh, struct demux_packet **out_pkt);
bool demux_stream_is_selected(struct sh_stream *stream);
-double demux_get_next_pts(struct sh_stream *sh);
bool demux_has_packet(struct sh_stream *sh);
struct demux_packet *demux_read_any_packet(struct demuxer *demuxer);
-struct sh_stream *new_sh_stream(struct demuxer *demuxer, enum stream_type type);
+struct sh_stream *demux_get_stream(struct demuxer *demuxer, int index);
+int demux_get_num_stream(struct demuxer *demuxer);
+
+struct sh_stream *demux_alloc_sh_stream(enum stream_type type);
+void demux_add_sh_stream(struct demuxer *demuxer, struct sh_stream *sh);
struct demuxer *demux_open(struct stream *stream, struct demuxer_params *params,
struct mpv_global *global);
diff --git a/demux/demux_cue.c b/demux/demux_cue.c
index 43420573ec..bef1516057 100644
--- a/demux/demux_cue.c
+++ b/demux/demux_cue.c
@@ -23,7 +23,7 @@
#include <dirent.h>
#include <inttypes.h>
-#include "talloc.h"
+#include "mpv_talloc.h"
#include "misc/bstr.h"
#include "common/msg.h"
@@ -150,8 +150,18 @@ static void build_timeline(struct timeline *tl)
add_source(tl, tl->demuxer);
- struct cue_track *tracks = p->f->tracks;
- size_t track_count = p->f->num_tracks;
+ struct cue_track *tracks = NULL;
+ size_t track_count = 0;
+
+ for (size_t n = 0; n < p->f->num_tracks; n++) {
+ struct cue_track *track = &p->f->tracks[n];
+ if (track->filename) {
+ MP_TARRAY_APPEND(ctx, tracks, track_count, *track);
+ } else {
+ MP_WARN(tl->demuxer, "No file specified for track entry %zd. "
+ "It will be removed\n", n + 1);
+ }
+ }
if (track_count == 0) {
MP_ERR(tl, "CUE: no tracks found!\n");
diff --git a/demux/demux_disc.c b/demux/demux_disc.c
index b994b3cf11..dcc3e7c79f 100644
--- a/demux/demux_disc.c
+++ b/demux/demux_disc.c
@@ -23,6 +23,7 @@
#include "common/msg.h"
#include "stream/stream.h"
+#include "video/mp_image.h"
#include "demux.h"
#include "stheader.h"
@@ -53,9 +54,10 @@ struct priv {
static void reselect_streams(demuxer_t *demuxer)
{
struct priv *p = demuxer->priv;
- for (int n = 0; n < MPMIN(p->slave->num_streams, p->num_streams); n++) {
+ int num_slave = demux_get_num_stream(p->slave);
+ for (int n = 0; n < MPMIN(num_slave, p->num_streams); n++) {
if (p->streams[n]) {
- demuxer_select_track(p->slave, p->slave->streams[n],
+ demuxer_select_track(p->slave, demux_get_stream(p->slave, n),
demux_stream_is_selected(p->streams[n]));
}
}
@@ -80,11 +82,9 @@ static void add_dvd_streams(demuxer_t *demuxer)
struct stream_dvd_info_req info;
if (stream_control(stream, STREAM_CTRL_GET_DVD_INFO, &info) > 0) {
for (int n = 0; n < MPMIN(32, info.num_subs); n++) {
- struct sh_stream *sh = new_sh_stream(demuxer, STREAM_SUB);
- if (!sh)
- break;
+ struct sh_stream *sh = demux_alloc_sh_stream(STREAM_SUB);
sh->demuxer_id = n + 0x20;
- sh->codec = "dvd_subtitle";
+ sh->codec->codec = "dvd_subtitle";
get_disc_lang(stream, sh);
// p->streams _must_ match with p->slave->streams, so we can't add
// it yet - it has to be done when the real stream appears, which
@@ -111,8 +111,10 @@ static void add_dvd_streams(demuxer_t *demuxer)
}
s = talloc_asprintf_append(s, "\n");
- sh->extradata = s;
- sh->extradata_size = strlen(s);
+ sh->codec->extradata = s;
+ sh->codec->extradata_size = strlen(s);
+
+ demux_add_sh_stream(demuxer, sh);
}
}
}
@@ -121,9 +123,9 @@ static void add_streams(demuxer_t *demuxer)
{
struct priv *p = demuxer->priv;
- for (int n = p->num_streams; n < p->slave->num_streams; n++) {
- struct sh_stream *src = p->slave->streams[n];
- if (src->sub) {
+ for (int n = p->num_streams; n < demux_get_num_stream(p->slave); n++) {
+ struct sh_stream *src = demux_get_stream(p->slave, n);
+ if (src->type == STREAM_SUB) {
struct sh_stream *sub = NULL;
if (src->demuxer_id >= 0x20 && src->demuxer_id <= 0x3F)
sub = p->dvd_subs[src->demuxer_id - 0x20];
@@ -133,25 +135,26 @@ static void add_streams(demuxer_t *demuxer)
continue;
}
}
- struct sh_stream *sh = new_sh_stream(demuxer, src->type);
- if (!sh)
- break;
+ struct sh_stream *sh = demux_alloc_sh_stream(src->type);
assert(p->num_streams == n); // directly mapped
MP_TARRAY_APPEND(p, p->streams, p->num_streams, sh);
// Copy all stream fields that might be relevant
- sh->codec = talloc_strdup(sh, src->codec);
- sh->codec_tag = src->codec_tag;
- sh->lav_headers = src->lav_headers;
+ *sh->codec = *src->codec;
sh->demuxer_id = src->demuxer_id;
- if (src->video) {
+ if (src->type == STREAM_VIDEO) {
double ar;
if (stream_control(demuxer->stream, STREAM_CTRL_GET_ASPECT_RATIO, &ar)
== STREAM_OK)
- sh->video->aspect = ar;
+ {
+ struct mp_image_params f = {.w = src->codec->disp_w,
+ .h = src->codec->disp_h};
+ mp_image_params_set_dsize(&f, 1728 * ar, 1728);
+ sh->codec->par_w = f.p_w;
+ sh->codec->par_h = f.p_h;
+ }
}
- if (src->audio)
- sh->audio = src->audio;
get_disc_lang(demuxer->stream, sh);
+ demux_add_sh_stream(demuxer, sh);
}
reselect_streams(demuxer);
}
diff --git a/demux/demux_edl.c b/demux/demux_edl.c
index 9ba0307487..74ce7aef66 100644
--- a/demux/demux_edl.c
+++ b/demux/demux_edl.c
@@ -23,7 +23,7 @@
#include <inttypes.h>
#include <math.h>
-#include "talloc.h"
+#include "mpv_talloc.h"
#include "demux.h"
#include "timeline.h"
diff --git a/demux/demux_lavf.c b/demux/demux_lavf.c
index 2d12f5cfa2..1b3105170d 100644
--- a/demux/demux_lavf.c
+++ b/demux/demux_lavf.c
@@ -40,6 +40,7 @@
#include "common/tags.h"
#include "common/av_common.h"
#include "misc/bstr.h"
+#include "misc/charset_conv.h"
#include "stream/stream.h"
#include "demux.h"
@@ -108,6 +109,7 @@ struct format_hack {
bool no_stream : 1; // do not wrap struct stream as AVIOContext
bool use_stream_ids : 1; // export the native stream IDs
bool fully_read : 1; // set demuxer.fully_read flag
+ bool detect_charset : 1; // format is a small text file, possibly not UTF8
bool image_format : 1; // expected to contain exactly 1 frame
// Do not confuse player's position estimation (position is into external
// segment, with e.g. HLS, player knows about the playlist main file only).
@@ -115,8 +117,8 @@ struct format_hack {
};
#define BLACKLIST(fmt) {fmt, .ignore = true}
-#define TEXTSUB(fmt) {fmt, .fully_read = true}
-#define IMAGEFMT(fmt) {fmt, .image_format = true}
+#define TEXTSUB(fmt) {fmt, .fully_read = true, .detect_charset = true}
+#define TEXTSUB_UTF8(fmt) {fmt, .fully_read = true}
static const struct format_hack format_hacks[] = {
// for webradios
@@ -135,10 +137,12 @@ static const struct format_hack format_hacks[] = {
{"h264", .if_flags = AVFMT_NOTIMESTAMPS },
{"hevc", .if_flags = A