summaryrefslogtreecommitdiffstats
path: root/demux
diff options
context:
space:
mode:
Diffstat (limited to 'demux')
-rw-r--r--demux/aviheader.c3
-rw-r--r--demux/codec_tags.c1
-rw-r--r--demux/demux.c290
-rw-r--r--demux/demux.h30
-rw-r--r--demux/demux_asf.c9
-rw-r--r--demux/demux_avi.c1
-rw-r--r--demux/demux_cue.c8
-rw-r--r--demux/demux_edl.c8
-rw-r--r--demux/demux_lavf.c170
-rw-r--r--demux/demux_libass.c121
-rw-r--r--demux/demux_mf.c2
-rw-r--r--demux/demux_mkv.c255
-rw-r--r--demux/demux_mpg.c2
-rw-r--r--demux/demux_packet.h1
-rw-r--r--demux/demux_rawaudio.c13
-rw-r--r--demux/demux_subreader.c1402
-rw-r--r--demux/demux_ts.c10
-rw-r--r--demux/ebml.c5
-rw-r--r--demux/matroska.h1
-rw-r--r--demux/stheader.h13
20 files changed, 2122 insertions, 223 deletions
diff --git a/demux/aviheader.c b/demux/aviheader.c
index 2226be25d4..c1b9c59692 100644
--- a/demux/aviheader.c
+++ b/demux/aviheader.c
@@ -479,7 +479,6 @@ if (priv->isodml && (index_mode==-1 || index_mode==0 || index_mode==1)) {
// read the standard indices
for (cx = &priv->suidx[0], i=0; i<priv->suidx_size; cx++, i++) {
- stream_reset(demuxer->stream);
for (j=0; j<cx->nEntriesInUse; j++) {
int ret1, ret2;
memset(&cx->stdidx[j], 0, 32);
@@ -543,7 +542,6 @@ if (priv->isodml && (index_mode==-1 || index_mode==0 || index_mode==1)) {
{
uint32_t id;
uint32_t db = 0;
- stream_reset (demuxer->stream);
// find out the video stream id. I have seen files with 01db.
for (idx = &((AVIINDEXENTRY *)priv->idx)[0], i=0; i<priv->idx_size; i++, idx++){
@@ -590,7 +588,6 @@ freeout:
if(index_mode>=2 || (priv->idx_size==0 && index_mode==1)){
int idx_pos = 0;
// build index for file:
- stream_reset(demuxer->stream);
stream_seek(demuxer->stream,demuxer->movi_start);
priv->idx_size=0;
diff --git a/demux/codec_tags.c b/demux/codec_tags.c
index 2af450ad07..cf7e0356be 100644
--- a/demux/codec_tags.c
+++ b/demux/codec_tags.c
@@ -102,6 +102,7 @@ static const struct mp_codec_tag mp_audio_codec_tags[] = {
{0x1 , "pcm"}, // lavf: pcm_s16le
{0x3 , "pcm"}, // lavf: pcm_f32le
{0xfffe , "pcm"},
+ {MKTAG('t', 'w', 'o', 's'), "pcm"},
// ------- internal mplayer FourCCs ------
{MKTAG('O', 'p', 'u', 's'), "opus"}, // demux_mkv.c
{MKTAG('a', 'L', 'a', 'C'), "alac"}, // demux_mkv.c
diff --git a/demux/demux.c b/demux/demux.c
index e1bb960e78..c783b0cbc2 100644
--- a/demux/demux.c
+++ b/demux/demux.c
@@ -40,7 +40,8 @@
#include "audio/format.h"
-#include "libavcodec/avcodec.h"
+#include <libavcodec/avcodec.h>
+
#if MP_INPUT_BUFFER_PADDING_SIZE < FF_INPUT_BUFFER_PADDING_SIZE
#error MP_INPUT_BUFFER_PADDING_SIZE is too small!
#endif
@@ -66,6 +67,8 @@ extern const demuxer_desc_t demuxer_desc_mpeg_es;
extern const demuxer_desc_t demuxer_desc_mpeg4_es;
extern const demuxer_desc_t demuxer_desc_h264_es;
extern const demuxer_desc_t demuxer_desc_mpeg_ts;
+extern const demuxer_desc_t demuxer_desc_libass;
+extern const demuxer_desc_t demuxer_desc_subreader;
/* Please do not add any new demuxers here. If you want to implement a new
* demuxer, add it to libavformat, except for wrappers around external
@@ -79,8 +82,12 @@ const demuxer_desc_t *const demuxer_list[] = {
#ifdef CONFIG_TV
&demuxer_desc_tv,
#endif
+#ifdef CONFIG_LIBASS
+ &demuxer_desc_libass,
+#endif
&demuxer_desc_matroska,
&demuxer_desc_lavf,
+ &demuxer_desc_subreader,
&demuxer_desc_avi,
&demuxer_desc_asf,
#ifdef CONFIG_MNG
@@ -101,6 +108,16 @@ 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;
+ talloc_free(dp->avpacket);
+ free(dp->allocation);
+ return 0;
+}
+
static struct demux_packet *create_packet(size_t len)
{
if (len > 1000000000) {
@@ -108,16 +125,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->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;
}
@@ -130,6 +145,7 @@ struct demux_packet *new_demux_packet(size_t len)
abort();
}
memset(dp->buffer + len, 0, MP_INPUT_BUFFER_PADDING_SIZE);
+ dp->allocation = dp->buffer;
return dp;
}
@@ -155,6 +171,7 @@ void resize_demux_packet(struct demux_packet *dp, size_t len)
"over 1 GB!\n");
abort();
}
+ assert(dp->allocation);
dp->buffer = realloc(dp->buffer, len + MP_INPUT_BUFFER_PADDING_SIZE);
if (!dp->buffer) {
mp_msg(MSGT_DEMUXER, MSGL_FATAL, "Memory allocation failure!\n");
@@ -162,15 +179,47 @@ void resize_demux_packet(struct demux_packet *dp, size_t len)
}
memset(dp->buffer + len, 0, MP_INPUT_BUFFER_PADDING_SIZE);
dp->len = len;
+ dp->allocation = dp->buffer;
}
void free_demux_packet(struct demux_packet *dp)
{
- if (dp->avpacket)
- talloc_free(dp->avpacket);
- else
- free(dp->buffer);
- free(dp);
+ talloc_free(dp);
+}
+
+static int destroy_avpacket(void *pkt)
+{
+ av_free_packet(pkt);
+ return 0;
+}
+
+struct demux_packet *demux_copy_packet(struct demux_packet *dp)
+{
+ struct demux_packet *new = NULL;
+ // No av_copy_packet() in Libav
+#if LIBAVCODEC_VERSION_MICRO >= 100
+ if (dp->avpacket) {
+ assert(dp->buffer == dp->avpacket->data);
+ assert(dp->len == dp->avpacket->size);
+ AVPacket *newavp = talloc_zero(NULL, AVPacket);
+ talloc_set_destructor(newavp, destroy_avpacket);
+ av_init_packet(newavp);
+ if (av_copy_packet(newavp, dp->avpacket) < 0)
+ abort();
+ new = new_demux_packet_fromdata(newavp->data, newavp->size);
+ new->avpacket = newavp;
+ }
+#endif
+ if (!new) {
+ new = new_demux_packet(dp->len);
+ memcpy(new->buffer, dp->buffer, new->len);
+ }
+ new->pts = dp->pts;
+ new->duration = dp->duration;
+ new->stream_pts = dp->stream_pts;
+ new->pos = dp->pos;
+ new->keyframe = dp->keyframe;
+ return new;
}
static void free_demuxer_stream(struct demux_stream *ds)
@@ -210,8 +259,8 @@ static const demuxer_desc_t *get_demuxer_desc_from_type(int file_format)
}
-demuxer_t *new_demuxer(struct MPOpts *opts, stream_t *stream, int type,
- int a_id, int v_id, int s_id, char *filename)
+static demuxer_t *new_demuxer(struct MPOpts *opts, stream_t *stream, int type,
+ int a_id, int v_id, int s_id, char *filename)
{
struct demuxer *d = talloc_zero(NULL, struct demuxer);
d->stream = stream;
@@ -222,8 +271,8 @@ demuxer_t *new_demuxer(struct MPOpts *opts, stream_t *stream, int type,
d->seekable = 1;
d->synced = 0;
d->filepos = -1;
- d->audio = new_demuxer_stream(d, STREAM_VIDEO, a_id);
- d->video = new_demuxer_stream(d, STREAM_AUDIO, v_id);
+ d->audio = new_demuxer_stream(d, STREAM_AUDIO, a_id);
+ d->video = new_demuxer_stream(d, STREAM_VIDEO, v_id);
d->sub = new_demuxer_stream(d, STREAM_SUB, s_id);
d->ds[STREAM_VIDEO] = d->video;
d->ds[STREAM_AUDIO] = d->audio;
@@ -308,10 +357,6 @@ struct sh_stream *new_sh_stream(demuxer_t *demuxer, enum stream_type type)
static void free_sh_stream(struct sh_stream *sh)
{
- if (sh->lav_headers) {
- avcodec_close(sh->lav_headers);
- av_free(sh->lav_headers);
- }
}
sh_sub_t *new_sh_sub_sid(demuxer_t *demuxer, int id, int sid)
@@ -428,13 +473,16 @@ void free_demuxer(demuxer_t *demuxer)
talloc_free(demuxer);
}
-void demuxer_add_packet(demuxer_t *demuxer, struct sh_stream *stream,
- demux_packet_t *dp)
+// Returns the same value as demuxer->fill_buffer: 1 ok, 0 EOF/not selected.
+int demuxer_add_packet(demuxer_t *demuxer, struct sh_stream *stream,
+ demux_packet_t *dp)
{
- if (!demuxer_stream_is_selected(demuxer, stream)) {
+ if (!dp || !demuxer_stream_is_selected(demuxer, stream)) {
free_demux_packet(dp);
+ return 0;
} else {
ds_add_packet(demuxer->ds[stream->type], dp);
+ return 1;
}
}
@@ -581,7 +629,7 @@ static bool demux_check_queue_full(demuxer_t *demux)
int demux_fill_buffer(demuxer_t *demux, demux_stream_t *ds)
{
// Note: parameter 'ds' can be NULL!
- return demux->desc->fill_buffer(demux, ds);
+ return demux->desc->fill_buffer ? demux->desc->fill_buffer(demux, ds) : 0;
}
// return value:
@@ -739,8 +787,7 @@ void ds_free_packs(demux_stream_t *ds)
}
if (ds->asf_packet) {
// free unfinished .asf fragments:
- free(ds->asf_packet->buffer);
- free(ds->asf_packet);
+ free_demux_packet(ds->asf_packet);
ds->asf_packet = NULL;
}
ds->first = ds->last = NULL;
@@ -784,28 +831,34 @@ int ds_get_packet_pts(demux_stream_t *ds, unsigned char **start, double *pts)
return len;
}
-int ds_get_packet_sub(demux_stream_t *ds, unsigned char **start)
+struct demux_packet *ds_get_packet_sub(demux_stream_t *ds)
{
- int len;
if (ds->buffer_pos >= ds->buffer_size) {
- *start = NULL;
if (!ds->packs)
- return -1; // no sub
+ return NULL; // no sub
if (!ds_fill_buffer(ds))
- return -1; // EOF
+ return NULL; // EOF
}
- len = ds->buffer_size - ds->buffer_pos;
- *start = &ds->buffer[ds->buffer_pos];
- ds->buffer_pos += len;
- return len;
+ if (ds->buffer_pos < ds->buffer_size) {
+ ds->current->buffer += ds->buffer_pos;
+ ds->buffer_size -= ds->buffer_pos;
+ }
+ ds->buffer_pos = ds->buffer_size;
+ return ds->current;
}
struct demux_packet *ds_get_packet2(struct demux_stream *ds, bool repeat_last)
{
- // This shouldn't get used together with partial reads
- assert(ds->buffer_pos == 0 || ds->buffer_pos >= ds->buffer_size);
if (!repeat_last)
ds_fill_buffer(ds);
+ // This shouldn't get used together with partial reads
+ // However, some old demuxers return parsed packets with an offset in
+ // -correct-pts mode (at least mpegts).
+ // Not all old demuxers will actually work.
+ if (ds->buffer_pos < ds->buffer_size) {
+ ds->current->buffer += ds->buffer_pos;
+ ds->buffer_size -= ds->buffer_pos;
+ }
ds->buffer_pos = ds->buffer_size;
return ds->current;
}
@@ -917,12 +970,15 @@ static struct demuxer *open_given_type(struct MPOpts *opts,
demuxer = demux2;
}
demuxer->file_format = fformat;
- opts->correct_pts = opts->user_correct_pts;
- if (opts->correct_pts < 0)
- 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);
+ demux_info_update(demuxer);
return demuxer;
} else {
// demux_mov can return playlist instead of mov
@@ -1071,7 +1127,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)
@@ -1174,6 +1230,18 @@ char *demux_info_get(demuxer_t *demuxer, const char *opt)
return NULL;
}
+void demux_info_update(struct demuxer *demuxer)
+{
+ demux_control(demuxer, DEMUXER_CTRL_UPDATE_INFO, NULL);
+ // Take care of stream metadata as well
+ char **meta;
+ if (stream_control(demuxer->stream, STREAM_CTRL_GET_METADATA, &meta) > 0) {
+ for (int n = 0; meta[n + 0]; n += 2)
+ demux_info_add(demuxer, meta[n + 0], meta[n + 1]);
+ talloc_free(meta);
+ }
+}
+
int demux_control(demuxer_t *demuxer, int cmd, void *arg)
{
@@ -1199,6 +1267,10 @@ void demuxer_switch_track(struct demuxer *demuxer, enum stream_type type,
{
assert(!stream || stream->type == type);
+ // don't flush buffers if stream is already selected
+ if (stream && demuxer_stream_is_selected(demuxer, stream))
+ return;
+
int old_id = demuxer->ds[type]->id;
// legacy
@@ -1283,13 +1355,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
@@ -1301,22 +1386,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)
@@ -1355,12 +1440,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;
@@ -1378,6 +1461,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;
@@ -1416,3 +1520,69 @@ int demuxer_set_angle(demuxer_t *demuxer, int angle)
return angle;
}
+
+static int packet_sort_compare(const void *p1, const void *p2)
+{
+ struct demux_packet *c1 = *(struct demux_packet **)p1;
+ struct demux_packet *c2 = *(struct demux_packet **)p2;
+
+ if (c1->pts > c2->pts)
+ return 1;
+ else if (c1->pts < c2->pts)
+ return -1;
+ return 0;
+}
+
+void demux_packet_list_sort(struct demux_packet **pkts, int num_pkts)
+{
+ qsort(pkts, num_pkts, sizeof(struct demux_packet *), packet_sort_compare);
+}
+
+void demux_packet_list_seek(struct demux_packet **pkts, int num_pkts,
+ int *current, float rel_seek_secs, int flags)
+{
+ double ref_time = 0;
+ if (*current >= 0 && *current < num_pkts) {
+ ref_time = pkts[*current]->pts;
+ } else if (*current == num_pkts && num_pkts > 0) {
+ ref_time = pkts[num_pkts - 1]->pts + pkts[num_pkts - 1]->duration;
+ }
+
+ if (flags & SEEK_ABSOLUTE)
+ ref_time = 0;
+
+ if (flags & SEEK_FACTOR) {
+ ref_time += demux_packet_list_duration(pkts, num_pkts) * rel_seek_secs;
+ } else {
+ ref_time += rel_seek_secs;
+ }
+
+ // Could do binary search, but it's probably not worth the complexity.
+ int last_index = 0;
+ for (int n = 0; n < num_pkts; n++) {
+ if (pkts[n]->pts > ref_time)
+ break;
+ last_index = n;
+ }
+ *current = last_index;
+}
+
+double demux_packet_list_duration(struct demux_packet **pkts, int num_pkts)
+{
+ if (num_pkts > 0)
+ return pkts[num_pkts - 1]->pts + pkts[num_pkts - 1]->duration;
+ return 0;
+}
+
+struct demux_packet *demux_packet_list_fill(struct demux_packet **pkts,
+ int num_pkts, int *current)
+{
+ if (*current < 0)
+ *current = 0;
+ if (*current >= num_pkts)
+ return NULL;
+ struct demux_packet *new = talloc(NULL, struct demux_packet);
+ *new = *pkts[*current];
+ *current += 1;
+ return new;
+}
diff --git a/demux/demux.h b/demux/demux.h
index 3d66139d69..20e6ba7a66 100644
--- a/demux/demux.h
+++ b/demux/demux.h
@@ -71,6 +71,8 @@ enum demuxer_type {
DEMUXER_TYPE_MNG,
DEMUXER_TYPE_EDL,
DEMUXER_TYPE_CUE,
+ DEMUXER_TYPE_SUBREADER,
+ DEMUXER_TYPE_LIBASS,
/* Values after this are for internal use and can not be selected
* as demuxer type by the user (-demuxer option). */
@@ -91,6 +93,7 @@ enum timestamp_type {
#define DEMUXER_CTRL_OK 1
#define DEMUXER_CTRL_GUESS 2
+#define DEMUXER_CTRL_UPDATE_INFO 8
#define DEMUXER_CTRL_SWITCHED_TRACKS 9
#define DEMUXER_CTRL_GET_TIME_LENGTH 10
#define DEMUXER_CTRL_GET_START_TIME 11
@@ -215,6 +218,7 @@ struct demuxer_params {
unsigned char (*matroska_wanted_uids)[16];
int matroska_wanted_segment;
bool *matroska_was_valid;
+ struct ass_library *ass_library;
};
typedef struct demuxer {
@@ -290,6 +294,7 @@ struct demux_packet *new_demux_packet_fromdata(void *data, size_t len);
struct demux_packet *new_demux_packet_from(void *data, size_t len);
void resize_demux_packet(struct demux_packet *dp, size_t len);
void free_demux_packet(struct demux_packet *dp);
+struct demux_packet *demux_copy_packet(struct demux_packet *dp);
#ifndef SIZE_MAX
#define SIZE_MAX ((size_t)-1)
@@ -304,13 +309,10 @@ static inline void *realloc_struct(void *ptr, size_t nmemb, size_t size)
return realloc(ptr, nmemb * size);
}
-struct demuxer *new_demuxer(struct MPOpts *opts, struct stream *stream,
- int type, int a_id, int v_id, int s_id,
- char *filename);
void free_demuxer(struct demuxer *demuxer);
-void demuxer_add_packet(demuxer_t *demuxer, struct sh_stream *stream,
- demux_packet_t *dp);
+int demuxer_add_packet(demuxer_t *demuxer, struct sh_stream *stream,
+ demux_packet_t *dp);
void ds_add_packet(struct demux_stream *ds, struct demux_packet *dp);
void ds_read_packet(struct demux_stream *ds, struct stream *stream, int len,
double pts, int64_t pos, bool keyframe);
@@ -343,7 +345,7 @@ void ds_free_packs(struct demux_stream *ds);
int ds_get_packet(struct demux_stream *ds, unsigned char **start);
int ds_get_packet_pts(struct demux_stream *ds, unsigned char **start,
double *pts);
-int ds_get_packet_sub(struct demux_stream *ds, unsigned char **start);
+struct demux_packet *ds_get_packet_sub(demux_stream_t *ds);
struct demux_packet *ds_get_packet2(struct demux_stream *ds, bool repeat_last);
double ds_get_next_pts(struct demux_stream *ds);
int ds_parse(struct demux_stream *sh, uint8_t **buffer, int *len, double pts,
@@ -384,6 +386,8 @@ int demux_info_add_bstr(struct demuxer *demuxer, struct bstr opt,
struct bstr param);
char *demux_info_get(struct demuxer *demuxer, const char *opt);
int demux_info_print(struct demuxer *demuxer);
+void demux_info_update(struct demuxer *demuxer);
+
int demux_control(struct demuxer *demuxer, int cmd, void *arg);
void demuxer_switch_track(struct demuxer *demuxer, enum stream_type type,
@@ -401,12 +405,15 @@ int demuxer_seek_chapter(struct demuxer *demuxer, int chapter,
double *seek_pts);
void demuxer_sort_chapters(demuxer_t *demuxer);
+double demuxer_get_time_length(struct demuxer *demuxer);
+double demuxer_get_start_time(struct demuxer *demuxer);
+
/// Get current chapter index if available.
int demuxer_get_current_chapter(struct demuxer *demuxer, double time_now);
/// Get chapter name by index if available.
char *demuxer_chapter_name(struct demuxer *demuxer, int chapter);
-/// Get chapter start time and end time by index if available.
-float demuxer_chapter_time(struct demuxer *demuxer, int chapter, float *end);
+/// Get chapter start time by index if available.
+double demuxer_chapter_time(struct demuxer *demuxer, int chapter);
/// Get total chapter number.
int demuxer_chapter_count(struct demuxer *demuxer);
/// Get current angle index.
@@ -421,4 +428,11 @@ struct sh_stream *demuxer_stream_by_demuxer_id(struct demuxer *d,
bool demuxer_stream_is_selected(struct demuxer *d, struct sh_stream *stream);
+void demux_packet_list_sort(struct demux_packet **pkts, int num_pkts);
+void demux_packet_list_seek(struct demux_packet **pkts, int num_pkts,
+ int *current, float rel_seek_secs, int flags);
+double demux_packet_list_duration(struct demux_packet **pkts, int num_pkts);
+struct demux_packet *demux_packet_list_fill(struct demux_packet **pkts,
+ int num_pkts, int *current);
+
#endif /* MPLAYER_DEMUXER_H */
diff --git a/demux/demux_asf.c b/demux/demux_asf.c
index 1d181eac67..f800e09dc3 100644
--- a/demux/demux_asf.c
+++ b/demux/demux_asf.c
@@ -100,11 +100,9 @@ static void init_priv (struct asf_priv* asf){
static void demux_asf_append_to_packet(demux_packet_t* dp,unsigned char *data,int len,int offs)
{
if(dp->len!=offs && offs!=-1) mp_msg(MSGT_DEMUX,MSGL_V,"warning! fragment.len=%d BUT next fragment offset=%d \n",dp->len,offs);
- dp->buffer=realloc(dp->buffer,dp->len+len+MP_INPUT_BUFFER_PADDING_SIZE);
- memcpy(dp->buffer+dp->len,data,len);
- memset(dp->buffer+dp->len+len, 0, MP_INPUT_BUFFER_PADDING_SIZE);
- mp_dbg(MSGT_DEMUX,MSGL_DBG4,"data appended! %d+%d\n",dp->len,len);
- dp->len+=len;
+ size_t old_len = dp->len;
+ resize_demux_packet(dp, dp->len + len);
+ memcpy(dp->buffer + old_len, data, len);
}
static int demux_asf_read_packet(demuxer_t *demux,unsigned char *data,int len,int id,int seq,uint64_t time,unsigned short dur,int offs,int keyframe){
@@ -630,7 +628,6 @@ static demuxer_t* demux_open_asf(demuxer_t* demuxer)
init_priv(asf);
if (!read_asf_header(demuxer,asf))
return NULL;
- stream_reset(demuxer->stream);
stream_seek(demuxer->stream,demuxer->movi_start);
// demuxer->idx_pos=0;
// demuxer->endpos=avi_header.movi_end;
diff --git a/demux/demux_avi.c b/demux/demux_avi.c
index daf542bfac..a07f022cde 100644
--- a/demux/demux_avi.c
+++ b/demux/demux_avi.c
@@ -456,7 +456,6 @@ static demuxer_t* demux_open_avi(demuxer_t* demuxer){
demuxer->video->id=-1; // autodetect
}
- stream_reset(demuxer->stream);
stream_seek(demuxer->stream,demuxer->movi_start);
if(priv->idx_size>1){
// decide index format:
diff --git a/demux/demux_cue.c b/demux/demux_cue.c
index 31a3e00e40..073fa9d336 100644
--- a/demux/demux_cue.c
+++ b/demux/demux_cue.c
@@ -39,7 +39,7 @@ static int try_open_file(struct demuxer *demuxer)
if (!mp_probe_cue((struct bstr) { buf, len }))
return 0;
stream_seek(s, 0);
- demuxer->file_contents = stream_read_complete(s, demuxer, 1000000, 0);
+ demuxer->file_contents = stream_read_complete(s, demuxer, 1000000);
if (demuxer->file_contents.start == NULL)
return 0;
if (!mp_probe_cue((struct bstr) { buf, len }))
@@ -47,11 +47,6 @@ static int try_open_file(struct demuxer *demuxer)
return DEMUXER_TYPE_CUE;
}
-static int dummy_fill_buffer(struct demuxer *demuxer, struct demux_stream *ds)
-{
- return 0;
-}
-
const struct demuxer_desc demuxer_desc_cue = {
.info = "CUE file demuxer",
.name = "cue",
@@ -61,5 +56,4 @@ const struct demuxer_desc demuxer_desc_cue = {
.type = DEMUXER_TYPE_CUE,
.safe_check = true,
.check_file = try_open_file, // no separate .open
- .fill_buffer = dummy_fill_buffer,
};
diff --git a/demux/demux_edl.c b/demux/demux_edl.c
index 1e1db5be93..c35137ffb2 100644
--- a/demux/demux_edl.c
+++ b/demux/demux_edl.c
@@ -34,17 +34,12 @@ static int try_open_file(struct demuxer *demuxer)
if (strncmp(buf, header, len))
return 0;
stream_seek(s, 0);
- demuxer->file_contents = stream_read_complete(s, demuxer, 1000000, 0);
+ demuxer->file_contents = stream_read_complete(s, demuxer, 1000000);
if (demuxer->file_contents.start == NULL)
return 0;
return DEMUXER_TYPE_EDL;
}
-static int dummy_fill_buffer(struct demuxer *demuxer, struct demux_stream *ds)
-{
- return 0;
-}
-
const struct demuxer_desc demuxer_desc_edl = {
.info = "EDL file demuxer",
.name = "edl",
@@ -54,5 +49,4 @@ const struct demuxer_desc demuxer_desc_edl = {
.type = DEMUXER_TYPE_EDL,
.safe_check = true,
.check_file = try_open_file, // no separate .open
- .fill_buffer = dummy_fill_buffer,
};
diff --git a/demux/demux_lavf.c b/demux/demux_lavf.c
index 8a8b003680..39e1cb28c5 100644
--- a/demux/demux_lavf.c
+++ b/demux/demux_lavf.c
@@ -47,24 +47,28 @@
#include "core/m_option.h"
#define INITIAL_PROBE_SIZE STREAM_BUFFER_SIZE
-#define PROBE_BUF_SIZE (2 * 1024 * 1024)
+#define PROBE_BUF_SIZE FFMIN(STREAM_MAX_BUFFER_SIZE, 2 * 1024 * 1024)
#define OPT_BASE_STRUCT struct MPOpts
const m_option_t lavfdopts_conf[] = {
OPT_INTRANGE("probesize", lavfdopts.probesize, 0, 32, INT_MAX),
OPT_STRING("format", lavfdopts.format, 0),
- OPT_INTRANGE("analyzeduration", lavfdopts.analyzeduration, 0, 0, INT_MAX),
+ OPT_FLOATRANGE("analyzeduration", lavfdopts.analyzeduration, 0, 0, 3600),
+ OPT_FLAG("allow-mimetype", lavfdopts.allow_mimetype, 0),
OPT_INTRANGE("probescore", lavfdopts.probescore, 0, 0, 100),
OPT_STRING("cryptokey", lavfdopts.cryptokey, 0),
OPT_STRING("o", lavfdopts.avopt, 0),
{NULL, NULL, 0, 0, 0, 0, NULL}
};
+// Should correspond to IO_BUFFER_SIZE in libavformat/aviobuf.c (not public)
+// libavformat (almost) always reads data in blocks of this size.
#define BIO_BUFFER_SIZE 32768
typedef struct lavf_priv {
char *filename;
+ const struct format_hack *format_hack;
AVInputFormat *avif;
AVFormatContext *avfc;
AVIOContext *pb;
@@ -80,16 +84,25 @@ typedef struct lavf_priv {
char *mime_type;
} lavf_priv_t;
-static const char *map_demuxer_mime_type[][2] = {
- {"audio/aacp", "aac"},
+struct format_hack {
+ const char *ff_name;
+ const char *mime_type;
+ int probescore;
+ float analyzeduration;
+};
+
+static const struct format_hack format_hacks[] = {
+ {"aac", "audio/aacp", 25, 0.5},
+ {"aac", "audio/aac", 25, 0.5},
+ {"mp3", "audio/mpeg", 25, 0.5},
{0}
};
-static const char *find_demuxer_from_mime_type(char *mime_type)
+static const struct format_hack *find_format_from_mime_type(char *mime_type)
{
- for (int n = 0; map_demuxer_mime_type[n][0]; n++) {
- if (strcasecmp(map_demuxer_mime_type[n][0], mime_type) == 0)
- return map_demuxer_mime_type[n][1];
+ for (int n = 0; format_hacks[n].ff_name; n++) {
+ if (strcasecmp(format_hacks[n].mime_type, mime_type) == 0)
+ return &format_hacks[n];
}
return NULL;
}
@@ -131,7 +144,6 @@ static int64_t mp_seek(void *opaque, int64_t pos, int whence)
return -1;
current_pos = stream_tell(stream);
if (stream_seek(stream, pos) == 0) {
- stream_reset(stream);
stream_seek(stream, current_pos);
return -1;
}
@@ -178,18 +190,15 @@ static int lavf_check_file(demuxer_t *demuxer)
{
struct MPOpts *opts = demuxer->opts;
struct lavfdopts *lavfdopts = &opts->lavfdopts;
- AVProbeData avpd;
+ struct stream *s = demuxer->stream;
lavf_priv_t *priv;
- int probe_data_size = 0;
- int read_size = INITIAL_PROBE_SIZE;
- int score;
assert(!demuxer->priv);
demuxer->priv = talloc_zero(NULL, lavf_priv_t);
priv = demuxer->priv;
priv->autoselect_sub = -1;
- priv->filename = demuxer->stream->url;
+ priv->filename = s->url;
if (!priv->filename) {
priv->filename = "mp:unknown";
mp_msg(MSGT_DEMUX, MSGL_WARN, "Stream