summaryrefslogtreecommitdiffstats
path: root/demux/demux.c
diff options
context:
space:
mode:
Diffstat (limited to 'demux/demux.c')
-rw-r--r--demux/demux.c217
1 files changed, 98 insertions, 119 deletions
diff --git a/demux/demux.c b/demux/demux.c
index a99a050ee2..e1bb960e78 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;
@@ -116,8 +116,6 @@ static struct demux_packet *create_packet(size_t len)
dp->stream_pts = MP_NOPTS_VALUE;
dp->pos = 0;
dp->keyframe = false;
- dp->refcount = 1;
- dp->master = NULL;
dp->buffer = NULL;
dp->avpacket = NULL;
return dp;
@@ -131,11 +129,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 +141,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,38 +160,16 @@ 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);
+ if (dp->avpacket)
+ talloc_free(dp->avpacket);
+ else
+ free(dp->buffer);
free(dp);
}
@@ -209,20 +192,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 +241,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 +263,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 +325,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 +346,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 +361,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 +374,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 +390,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 +400,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 +428,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)
{
@@ -496,18 +470,18 @@ void ds_add_packet(demux_stream_t *ds, demux_packet_t *dp)
static void allocate_parser(AVCodecContext **avctx, AVCodecParserContext **parser, const char *format)
{
- enum CodecID codec_id = mp_codec_to_av_codec_id(format);
+ enum AVCodecID codec_id = mp_codec_to_av_codec_id(format);
switch (codec_id) {
- case CODEC_ID_AAC_LATM:
- case CODEC_ID_AC3:
- case CODEC_ID_EAC3:
- case CODEC_ID_DTS:
- case CODEC_ID_FLAC:
- case CODEC_ID_MLP:
- case CODEC_ID_MP3:
- case CODEC_ID_MP2:
- case CODEC_ID_TRUEHD:
+ case AV_CODEC_ID_AAC_LATM:
+ case AV_CODEC_ID_AC3:
+ case AV_CODEC_ID_EAC3:
+ case AV_CODEC_ID_DTS:
+ case AV_CODEC_ID_FLAC:
+ case AV_CODEC_ID_MLP:
+ case AV_CODEC_ID_MP3:
+ case AV_CODEC_ID_MP2:
+ case AV_CODEC_ID_TRUEHD:
*avctx = avcodec_alloc_context3(NULL);
if (!*avctx)
return;
@@ -519,7 +493,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 +521,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;
@@ -678,9 +652,9 @@ int ds_fill_buffer(demux_stream_t *ds)
break; // EOF
}
- if (demux->type == DEMUXER_TYPE_LAVF ||
- demux->type == DEMUXER_TYPE_MATROSKA)
- {
+ struct sh_video *sh_video = demux->video->sh;
+
+ if (sh_video && sh_video->gsh->attached_picture) {
if (demux->audio)
ds->fill_count += demux->audio->packs - apacks;
if (demux->video && demux->video->packs > vpacks)
@@ -948,6 +922,7 @@ static struct demuxer *open_given_type(struct MPOpts *opts,
opts->correct_pts =
demux_control(demuxer, DEMUXER_CTRL_CORRECT_PTS,
NULL) == DEMUXER_CTRL_OK;
+ demuxer_sort_chapters(demuxer);
return demuxer;
} else {
// demux_mov can return playlist instead of mov
@@ -1223,7 +1198,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)
@@ -1233,11 +1212,11 @@ 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();
}
+
int new_id = demuxer->ds[type]->id;
void *new = NULL;
if (new_id >= 0) {
@@ -1248,6 +1227,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,
@@ -1278,10 +1267,10 @@ static int chapter_compare(const void *p1, const void *p2)
return 1;
else if (c1->start < c2->start)
return -1;
- return 0;
+ return c1->original_index > c2->original_index ? 1 :-1; // never equal
}
-static void demuxer_sort_chapters(demuxer_t *demuxer)
+void demuxer_sort_chapters(demuxer_t *demuxer)
{
qsort(demuxer->chapters, demuxer->num_chapters,
sizeof(struct demux_chapter), chapter_compare);
@@ -1290,24 +1279,14 @@ static void demuxer_sort_chapters(demuxer_t *demuxer)
int demuxer_add_chapter(demuxer_t *demuxer, struct bstr name,
uint64_t start, uint64_t end)
{
- if (!(demuxer->num_chapters % 32))
- demuxer->chapters = talloc_realloc(demuxer, demuxer->chapters,
- struct demux_chapter,
- demuxer->num_chapters + 32);
-
- demuxer->chapters[demuxer->num_chapters].start = start;
- demuxer->chapters[demuxer->num_chapters].end = end;
- demuxer->chapters[demuxer->num_chapters].name = name.len ?
- talloc_strndup(demuxer->chapters, name.start, name.len) :
- talloc_strdup(demuxer->chapters, mp_gtext("unknown"));
-
- demuxer->num_chapters++;
-
- if (demuxer->num_chapters > 1
- && demuxer->chapters[demuxer->num_chapters - 2].start
- < demuxer->chapters[demuxer->num_chapters - 1].start)
- demuxer_sort_chapters(demuxer);
-
+ struct demux_chapter new = {
+ .original_index = demuxer->num_chapters,
+ .start = start,
+ .end = end,
+ .name = name.len ? bstrdup0(demuxer, name)
+ : talloc_strdup(demuxer, mp_gtext("unknown")),
+ };
+ MP_TARRAY_APPEND(demuxer, demuxer->chapters, demuxer->num_chapters, new);
return 0;
}