summaryrefslogtreecommitdiffstats
path: root/demux/demux.c
diff options
context:
space:
mode:
Diffstat (limited to 'demux/demux.c')
-rw-r--r--demux/demux.c254
1 files changed, 142 insertions, 112 deletions
diff --git a/demux/demux.c b/demux/demux.c
index cb3d3a5efe..64c7c73b9f 100644
--- a/demux/demux.c
+++ b/demux/demux.c
@@ -45,7 +45,7 @@
#error MP_INPUT_BUFFER_PADDING_SIZE is too small!
#endif
-static void clear_parser(sh_common_t *sh);
+static void clear_parser(sh_audio_t *sh);
// Demuxer list
extern const struct demuxer_desc demuxer_desc_edl;
@@ -101,6 +101,18 @@ const demuxer_desc_t *const demuxer_list[] = {
NULL
};
+static void add_stream_chapters(struct demuxer *demuxer);
+
+static int packet_destroy(void *ptr)
+{
+ struct demux_packet *dp = ptr;
+ if (dp->avpacket)
+ talloc_free(dp->avpacket);
+ else
+ free(dp->buffer);
+ return 0;
+}
+
static struct demux_packet *create_packet(size_t len)
{
if (len > 1000000000) {
@@ -108,18 +120,14 @@ static struct demux_packet *create_packet(size_t len)
"over 1 GB!\n");
abort();
}
- struct demux_packet *dp = malloc(sizeof(struct demux_packet));
- dp->len = len;
- dp->next = NULL;
- dp->pts = MP_NOPTS_VALUE;
- dp->duration = -1;
- dp->stream_pts = MP_NOPTS_VALUE;
- dp->pos = 0;
- dp->keyframe = false;
- dp->refcount = 1;
- dp->master = NULL;
- dp->buffer = NULL;
- dp->avpacket = NULL;
+ struct demux_packet *dp = talloc(NULL, struct demux_packet);
+ talloc_set_destructor(dp, packet_destroy);
+ *dp = (struct demux_packet) {
+ .len = len,
+ .pts = MP_NOPTS_VALUE,
+ .duration = -1,
+ .stream_pts = MP_NOPTS_VALUE,
+ };
return dp;
}
@@ -131,11 +139,11 @@ struct demux_packet *new_demux_packet(size_t len)
mp_msg(MSGT_DEMUXER, MSGL_FATAL, "Memory allocation failure!\n");
abort();
}
- memset(dp->buffer + len, 0, 8);
+ memset(dp->buffer + len, 0, MP_INPUT_BUFFER_PADDING_SIZE);
return dp;
}
-// data must already have suitable padding
+// data must already have suitable padding, and does not copy the data
struct demux_packet *new_demux_packet_fromdata(void *data, size_t len)
{
struct demux_packet *dp = create_packet(len);
@@ -143,6 +151,13 @@ struct demux_packet *new_demux_packet_fromdata(void *data, size_t len)
return dp;
}
+struct demux_packet *new_demux_packet_from(void *data, size_t len)
+{
+ struct demux_packet *dp = new_demux_packet(len);
+ memcpy(dp->buffer, data, len);
+ return dp;
+}
+
void resize_demux_packet(struct demux_packet *dp, size_t len)
{
if (len > 1000000000) {
@@ -155,39 +170,13 @@ void resize_demux_packet(struct demux_packet *dp, size_t len)
mp_msg(MSGT_DEMUXER, MSGL_FATAL, "Memory allocation failure!\n");
abort();
}
- memset(dp->buffer + len, 0, 8);
+ memset(dp->buffer + len, 0, MP_INPUT_BUFFER_PADDING_SIZE);
dp->len = len;
}
-struct demux_packet *clone_demux_packet(struct demux_packet *pack)
-{
- struct demux_packet *dp = malloc(sizeof(struct demux_packet));
- while (pack->master)
- pack = pack->master; // find the master
- memcpy(dp, pack, sizeof(struct demux_packet));
- dp->next = NULL;
- dp->refcount = 0;
- dp->master = pack;
- pack->refcount++;
- return dp;
-}
-
void free_demux_packet(struct demux_packet *dp)
{
- if (dp->master == NULL) { //dp is a master packet
- dp->refcount--;
- if (dp->refcount == 0) {
- if (dp->avpacket)
- talloc_free(dp->avpacket);
- else
- free(dp->buffer);
- free(dp);
- }
- return;
- }
- // dp is a clone:
- free_demux_packet(dp->master);
- free(dp);
+ talloc_free(dp);
}
static void free_demuxer_stream(struct demux_stream *ds)
@@ -209,20 +198,6 @@ static struct demux_stream *new_demuxer_stream(struct demuxer *demuxer,
return ds;
}
-struct sh_stream *ds_gsh(struct demux_stream *ds)
-{
- // Ideally ds would have a gsh field, but since all the old demuxers set
- // ds->sh themselves and we don't want to change them, enjoy this hack.
- if (!ds->sh)
- return NULL;
- switch (ds->stream_type) {
- case STREAM_VIDEO: return ((struct sh_video *)ds->sh)->gsh;
- case STREAM_AUDIO: return ((struct sh_audio *)ds->sh)->gsh;
- case STREAM_SUB: return ((struct sh_sub *)ds->sh)->gsh;
- }
- assert(false);
-}
-
/**
* Get demuxer description structure for a given demuxer type
*
@@ -272,32 +247,21 @@ demuxer_t *new_demuxer(struct MPOpts *opts, stream_t *stream, int type,
return d;
}
-const char *sh_sub_type2str(int type)
+static struct sh_stream *new_sh_stream_id(demuxer_t *demuxer,
+ enum stream_type type,
+ int stream_index,
+ int demuxer_id)
{
- switch (type) {
- case 't': return "text";
- case 'm': return "movtext";
- case 'a': return "ass";
- case 'v': return "vobsub";
- case 'x': return "xsub";
- case 'b': return "dvb";
- case 'd': return "dvb-teletext";
- case 'p': return "hdmv pgs";
+ if (demuxer->num_streams > MAX_SH_STREAMS || stream_index > MAX_SH_STREAMS) {
+ mp_msg(MSGT_DEMUXER, MSGL_WARN, "Too many streams.");
+ return NULL;
}
- return "unknown";
-}
-static struct sh_stream *new_sh_stream(demuxer_t *demuxer,
- enum stream_type type,
- int stream_index,
- int tid)
-{
struct sh_stream *sh = talloc_struct(demuxer, struct sh_stream, {
.type = type,
.demuxer = demuxer,
.index = demuxer->num_streams,
- .demuxer_id = tid, // may be overwritten by demuxer
- .tid = tid,
+ .demuxer_id = demuxer_id, // may be overwritten by demuxer
.stream_index = stream_index,
.opts = demuxer->opts,
});
@@ -305,40 +269,49 @@ static struct sh_stream *new_sh_stream(demuxer_t *demuxer,
switch (sh->type) {
case STREAM_VIDEO: {
struct sh_video *sht = talloc_zero(demuxer, struct sh_video);
- sht->vid = sh->tid;
+ sht->gsh = sh;
+ sht->opts = sh->opts;
sht->ds = demuxer->video;
sh->video = sht;
- sh->common_header = (struct sh_common *) sht;
demuxer->v_streams[sh->stream_index] = sht;
break;
}
case STREAM_AUDIO: {
struct sh_audio *sht = talloc_zero(demuxer, struct sh_audio);
- sht->aid = tid;
+ sht->gsh = sh;
+ sht->opts = sh->opts;
sht->ds = demuxer->audio;
sht->samplesize = 2;
sht->sample_format = AF_FORMAT_S16_NE;
sh->audio = sht;
- sh->common_header = (struct sh_common *) sht;
demuxer->a_streams[sh->stream_index] = sht;
break;
}
case STREAM_SUB: {
struct sh_sub *sht = talloc_zero(demuxer, struct sh_sub);
- sht->sid = tid;
+ sht->gsh = sh;
+ sht->opts = sh->opts;
sht->ds = demuxer->sub;
sh->sub = sht;
- sh->common_header = (struct sh_common *) sht;
demuxer->s_streams[sh->stream_index] = sht;
break;
}
default: assert(false);
}
- sh->common_header->opts = sh->opts;
- sh->common_header->gsh = sh;
return sh;
}
+// This is what "modern" demuxers are supposed to use.
+struct sh_stream *new_sh_stream(demuxer_t *demuxer, enum stream_type type)
+{
+ int num = 0;
+ for (int n = 0; n < demuxer->num_streams; n++) {
+ if (demuxer->streams[n]->type == type)
+ num++;
+ }
+ return new_sh_stream_id(demuxer, type, demuxer->num_streams, num);
+}
+
static void free_sh_stream(struct sh_stream *sh)
{
if (sh->lav_headers) {
@@ -358,7 +331,7 @@ sh_sub_t *new_sh_sub_sid(demuxer_t *demuxer, int id, int sid)
if (demuxer->s_streams[id])
mp_msg(MSGT_DEMUXER, MSGL_WARN, "Sub stream %i redefined\n", id);
else {
- new_sh_stream(demuxer, STREAM_SUB, id, sid);
+ new_sh_stream_id(demuxer, STREAM_SUB, id, sid);
mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_SUBTITLE_ID=%d\n", sid);
}
return demuxer->s_streams[id];
@@ -379,7 +352,6 @@ static void free_sh_sub(sh_sub_t *sh)
{
mp_msg(MSGT_DEMUXER, MSGL_DBG2, "DEMUXER: freeing sh_sub at %p\n", sh);
free(sh->extradata);
- clear_parser((sh_common_t *)sh);
free_sh_stream(sh->gsh);
}
@@ -395,7 +367,7 @@ sh_audio_t *new_sh_audio_aid(demuxer_t *demuxer, int id, int aid)
mp_tmsg(MSGT_DEMUXER, MSGL_WARN, "WARNING: Audio stream header %d redefined.\n", id);
} else {
mp_tmsg(MSGT_DEMUXER, MSGL_V, "==> Found audio stream: %d\n", id);
- new_sh_stream(demuxer, STREAM_AUDIO, id, aid);
+ new_sh_stream_id(demuxer, STREAM_AUDIO, id, aid);
mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_AUDIO_ID=%d\n", aid);
}
return demuxer->a_streams[id];
@@ -408,7 +380,7 @@ static void free_sh_audio(demuxer_t *demuxer, int id)
mp_msg(MSGT_DEMUXER, MSGL_DBG2, "DEMUXER: freeing sh_audio at %p\n", sh);
free(sh->wf);
free(sh->codecdata);
- clear_parser((sh_common_t *)sh);
+ clear_parser(sh);
free_sh_stream(sh->gsh);
}
@@ -424,7 +396,7 @@ sh_video_t *new_sh_video_vid(demuxer_t *demuxer, int id, int vid)
mp_tmsg(MSGT_DEMUXER, MSGL_WARN, "WARNING: Video stream header %d redefined.\n", id);
else {
mp_tmsg(MSGT_DEMUXER, MSGL_V, "==> Found video stream: %d\n", id);
- new_sh_stream(demuxer, STREAM_VIDEO, id, vid);
+ new_sh_stream_id(demuxer, STREAM_VIDEO, id, vid);
mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_VIDEO_ID=%d\n", vid);
}
return demuxer->v_streams[id];
@@ -434,7 +406,6 @@ static void free_sh_video(sh_video_t *sh)
{
mp_msg(MSGT_DEMUXER, MSGL_DBG2, "DEMUXER: freeing sh_video at %p\n", sh);
free(sh->bih);
- clear_parser((sh_common_t *)sh);
free_sh_stream(sh->gsh);
}
@@ -463,6 +434,15 @@ void free_demuxer(demuxer_t *demuxer)
talloc_free(demuxer);
}
+void demuxer_add_packet(demuxer_t *demuxer, struct sh_stream *stream,
+ demux_packet_t *dp)
+{
+ if (!demuxer_stream_is_selected(demuxer, stream)) {
+ free_demux_packet(dp);
+ } else {
+ ds_add_packet(demuxer->ds[stream->type], dp);
+ }
+}
void ds_add_packet(demux_stream_t *ds, demux_packet_t *dp)
{
@@ -519,7 +499,7 @@ static void allocate_parser(AVCodecContext **avctx, AVCodecParserContext **parse
}
}
-static void get_parser(sh_common_t *sh, AVCodecContext **avctx, AVCodecParserContext **parser)
+static void get_parser(sh_audio_t *sh, AVCodecContext **avctx, AVCodecParserContext **parser)
{
*avctx = NULL;
*parser = NULL;
@@ -547,7 +527,7 @@ int ds_parse(demux_stream_t *ds, uint8_t **buffer, int *len, double pts, int64_t
return av_parser_parse2(parser, avctx, buffer, len, *buffer, *len, pts, pts, pos);
}
-static void clear_parser(sh_common_t *sh)
+static void clear_parser(sh_audio_t *sh)
{
av_parser_close(sh->parser);
sh->parser = NULL;
@@ -948,6 +928,13 @@ static struct demuxer *open_given_type(struct MPOpts *opts,
opts->correct_pts =
demux_control(demuxer, DEMUXER_CTRL_CORRECT_PTS,
NULL) == DEMUXER_CTRL_OK;
+ if (stream_manages_timeline(demuxer->stream)) {
+ // Incorrect, but fixes some behavior with DVD/BD
+ demuxer->ts_resets_possible = false;
+ // Doesn't work, because stream_pts is a "guess".
+ demuxer->accurate_seek = false;
+ }
+ add_stream_chapters(demuxer);
demuxer_sort_chapters(demuxer);
return demuxer;
} else {
@@ -998,7 +985,7 @@ struct demuxer *demux_open_withparams(struct MPOpts *opts,
// format, instead of reyling on libav to auto-detect the stream's format
// correctly.
switch (file_format) {
- //case DEMUXER_TYPE_MPEG_PS:
+ case DEMUXER_TYPE_MPEG_PS:
//case DEMUXER_TYPE_MPEG_TS:
case DEMUXER_TYPE_Y4M:
case DEMUXER_TYPE_NSV:
@@ -1097,7 +1084,7 @@ int demux_seek(demuxer_t *demuxer, float rel_seek_secs, float audio_delay,
* (nothing actually implements DEMUXER_CTRL_RESYNC now).
*/
struct stream *stream = demuxer->stream;
- if (stream->type == STREAMTYPE_DVD) {
+ if (stream_manages_timeline(stream)) {
double pts;
if (flags & SEEK_ABSOLUTE)
@@ -1224,7 +1211,11 @@ void demuxer_switch_track(struct demuxer *demuxer, enum stream_type type,
struct sh_stream *stream)
{
assert(!stream || stream->type == type);
- int index = stream ? stream->tid : -2;
+
+ int old_id = demuxer->ds[type]->id;
+
+ // legacy
+ int index = stream ? stream->stream_index : -2;
if (type == STREAM_AUDIO) {
if (demux_control(demuxer, DEMUXER_CTRL_SWITCH_AUDIO, &index)
== DEMUXER_CTRL_NOTIMPL)
@@ -1234,10 +1225,7 @@ void demuxer_switch_track(struct demuxer *demuxer, enum stream_type type,
== DEMUXER_CTRL_NOTIMPL)
demuxer->video->id = index;
} else if (type == STREAM_SUB) {
- int index2 = stream ? stream->stream_index : -2;
- if (demuxer->ds[type]->id != index2)
- ds_free_packs(demuxer->ds[type]);
- demuxer->ds[type]->id = index2;
+ demuxer->ds[type]->id = index;
} else {
abort();
}
@@ -1252,6 +1240,16 @@ void demuxer_switch_track(struct demuxer *demuxer, enum stream_type type,
}
}
demuxer->ds[type]->sh = new;
+
+ if (old_id != new_id) {
+ ds_free_packs(demuxer->ds[type]);
+ demux_control(demuxer, DEMUXER_CTRL_SWITCHED_TRACKS, NULL);
+ }
+}
+
+bool demuxer_stream_is_selected(struct demuxer *d, struct sh_stream *stream)
+{
+ return stream && d->ds[stream->type]->id == stream->stream_index;
}
int demuxer_add_attachment(demuxer_t *demuxer, struct bstr name,
@@ -1298,13 +1296,26 @@ int demuxer_add_chapter(demuxer_t *demuxer, struct bstr name,
.original_index = demuxer->num_chapters,
.start = start,
.end = end,
- .name = name.len ? bstrdup0(demuxer, name)
- : talloc_strdup(demuxer, mp_gtext("unknown")),
+ .name = name.len ? bstrdup0(demuxer, name) : NULL,
};
MP_TARRAY_APPEND(demuxer, demuxer->chapters, demuxer->num_chapters, new);
return 0;
}
+static void add_stream_chapters(struct demuxer *demuxer)
+{
+ if (demuxer->num_chapters)
+ return;
+ int num_chapters = demuxer_chapter_count(demuxer);
+ for (int n = 0; n < num_chapters; n++) {
+ double p = n;
+ if (stream_control(demuxer->stream, STREAM_CTRL_GET_CHAPTER_TIME, &p)
+ != STREAM_OK)
+ return;
+ demuxer_add_chapter(demuxer, bstr0(""), p * 1e9, 0);
+ }
+}
+
/**
* \brief demuxer_seek_chapter() seeks to a chapter in two possible ways:
* either using the demuxer->chapters structure set by the demuxer
@@ -1316,22 +1327,22 @@ int demuxer_add_chapter(demuxer_t *demuxer, struct bstr name,
int demuxer_seek_chapter(demuxer_t *demuxer, int chapter, double *seek_pts)
{
- int ris;
-
- if (!demuxer->num_chapters || !demuxer->chapters) {
- demux_flush(demuxer);
+ int ris = STREAM_UNSUPPORTED;
+ if (demuxer->num_chapters == 0)
ris = stream_control(demuxer->stream, STREAM_CTRL_SEEK_TO_CHAPTER,
&chapter);
- if (ris != STREAM_UNSUPPORTED)
- demux_control(demuxer, DEMUXER_CTRL_RESYNC, NULL);
+
+ if (ris != STREAM_UNSUPPORTED) {
+ demux_flush(demuxer);
+ demux_control(demuxer, DEMUXER_CTRL_RESYNC, NULL);
// exit status may be ok, but main() doesn't have to seek itself
// (because e.g. dvds depend on sectors, not on pts)
*seek_pts = -1.0;
- return ris != STREAM_UNSUPPORTED ? chapter : -1;
- } else { // chapters structure is set in the demuxer
+ return chapter;
+ } else {
if (chapter >= demuxer->num_chapters)
return -1;
if (chapter < 0)
@@ -1370,12 +1381,10 @@ char *demuxer_chapter_name(demuxer_t *demuxer, int chapter)
return NULL;
}
-float demuxer_chapter_time(demuxer_t *demuxer, int chapter, float *end)
+double demuxer_chapter_time(demuxer_t *demuxer, int chapter)
{
if (demuxer->num_chapters && demuxer->chapters && chapter >= 0
&& chapter < demuxer->num_chapters) {
- if (end)
- *end = demuxer->chapters[chapter].end / 1e9;
return demuxer->chapters[chapter].start / 1e9;
}
return -1.0;
@@ -1393,6 +1402,27 @@ int demuxer_chapter_count(demuxer_t *demuxer)
return demuxer->num_chapters;
}
+double demuxer_get_time_length(struct demuxer *demuxer)
+{
+ double len;
+ if (stream_control(demuxer->stream, STREAM_CTRL_GET_TIME_LENGTH, &len) > 0)
+ return len;
+ // <= 0 means DEMUXER_CTRL_NOTIMPL or DEMUXER_CTRL_DONTKNOW
+ if (demux_control(demuxer, DEMUXER_CTRL_GET_TIME_LENGTH, &len) > 0)
+ return len;
+ return -1;
+}
+
+double demuxer_get_start_time(struct demuxer *demuxer)
+{
+ double time;
+ if (stream_control(demuxer->stream, STREAM_CTRL_GET_START_TIME, &time) > 0)
+ return time;
+ if (demux_control(demuxer, DEMUXER_CTRL_GET_START_TIME, &time) > 0)
+ return time;
+ return 0;
+}
+
int demuxer_angles_count(demuxer_t *demuxer)
{
int ris, angles = -1;