demux_mkv: probe start time

MKV files can very well start with timestamps other than 0. While mpv
has support for such files in general, and demux_lavf enables this
feature, demux_mkv didn't export a start time.

Implement this by simply reading the first cluster timestamp. This in
turn is done by reading 1 block. While we don't need the block for this
prupose at all, it's the easiest way to get the cluster timestamp read
correctly without code duplication. In theory this could be wrong, and
a packet could start at a much later time, but in practice this won't
happen.

This commit also adds an option to disable this feature. It's not
documented because nobody should use it. (But I happen to have a need
for this.)
This commit is contained in:
wm4 2015-10-16 16:49:23 +02:00
parent 8d414e2fe7
commit 76bfd5b4a2
1 changed files with 43 additions and 10 deletions

View File

@ -149,6 +149,16 @@ typedef struct mkv_index {
uint64_t filepos; // position of the cluster which contains the packet uint64_t filepos; // position of the cluster which contains the packet
} mkv_index_t; } mkv_index_t;
struct block_info {
uint64_t duration, discardpadding;
bool simple, keyframe;
uint64_t timecode;
mkv_track_t *track;
bstr data;
void *alloc;
int64_t filepos;
};
typedef struct mkv_demuxer { typedef struct mkv_demuxer {
int64_t segment_start, segment_end; int64_t segment_start, segment_end;
@ -183,6 +193,8 @@ typedef struct mkv_demuxer {
bool index_has_durations; bool index_has_durations;
bool eof_warning; bool eof_warning;
struct block_info tmp_block;
} mkv_demuxer_t; } mkv_demuxer_t;
#define OPT_BASE_STRUCT struct demux_mkv_opts #define OPT_BASE_STRUCT struct demux_mkv_opts
@ -190,6 +202,7 @@ struct demux_mkv_opts {
int subtitle_preroll; int subtitle_preroll;
double subtitle_preroll_secs; double subtitle_preroll_secs;
int probe_duration; int probe_duration;
int probe_start_time;
int fix_timestamps; int fix_timestamps;
}; };
@ -200,12 +213,14 @@ const struct m_sub_options demux_mkv_conf = {
M_OPT_MIN, .min = 0), M_OPT_MIN, .min = 0),
OPT_CHOICE("probe-video-duration", probe_duration, 0, OPT_CHOICE("probe-video-duration", probe_duration, 0,
({"no", 0}, {"yes", 1}, {"full", 2})), ({"no", 0}, {"yes", 1}, {"full", 2})),
OPT_FLAG("probe-start-time", probe_start_time, 0),
OPT_FLAG("fix-timestamps", fix_timestamps, 0), OPT_FLAG("fix-timestamps", fix_timestamps, 0),
{0} {0}
}, },
.size = sizeof(struct demux_mkv_opts), .size = sizeof(struct demux_mkv_opts),
.defaults = &(const struct demux_mkv_opts){ .defaults = &(const struct demux_mkv_opts){
.subtitle_preroll_secs = 1.0, .subtitle_preroll_secs = 1.0,
.probe_start_time = 1,
.fix_timestamps = 0, .fix_timestamps = 0,
}, },
}; };
@ -220,6 +235,8 @@ const struct m_sub_options demux_mkv_conf = {
#define NUM_SUB_PREROLL_PACKETS 500 #define NUM_SUB_PREROLL_PACKETS 500
static void probe_last_timestamp(struct demuxer *demuxer); static void probe_last_timestamp(struct demuxer *demuxer);
static void probe_first_timestamp(struct demuxer *demuxer);
static void free_block(struct block_info *block);
#define AAC_SYNC_EXTENSION_TYPE 0x02b7 #define AAC_SYNC_EXTENSION_TYPE 0x02b7
static int aac_get_sample_rate_index(uint32_t sample_rate) static int aac_get_sample_rate_index(uint32_t sample_rate)
@ -1884,6 +1901,7 @@ static int demux_mkv_open(demuxer_t *demuxer, enum demux_check check)
add_coverart(demuxer); add_coverart(demuxer);
demuxer->allow_refresh_seeks = true; demuxer->allow_refresh_seeks = true;
probe_first_timestamp(demuxer);
if (opts->demux_mkv->probe_duration) if (opts->demux_mkv->probe_duration)
probe_last_timestamp(demuxer); probe_last_timestamp(demuxer);
@ -2095,6 +2113,8 @@ static void mkv_seek_reset(demuxer_t *demuxer)
} }
track->av_parser_codec = NULL; track->av_parser_codec = NULL;
} }
free_block(&mkv_d->tmp_block);
} }
// Copied from libavformat/matroskadec.c (FFmpeg 310f9dd / 2013-05-30) // Copied from libavformat/matroskadec.c (FFmpeg 310f9dd / 2013-05-30)
@ -2268,16 +2288,6 @@ static void mkv_parse_and_add_packet(demuxer_t *demuxer, mkv_track_t *track,
} }
} }
struct block_info {
uint64_t duration, discardpadding;
bool simple, keyframe;
uint64_t timecode;
mkv_track_t *track;
bstr data;
void *alloc;
int64_t filepos;
};
static void free_block(struct block_info *block) static void free_block(struct block_info *block)
{ {
free(block->alloc); free(block->alloc);
@ -2526,6 +2536,12 @@ static int read_next_block(demuxer_t *demuxer, struct block_info *block)
mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv; mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv;
stream_t *s = demuxer->stream; stream_t *s = demuxer->stream;
if (mkv_d->tmp_block.alloc) {
*block = mkv_d->tmp_block;
mkv_d->tmp_block = (struct block_info){0};
return 1;
}
while (1) { while (1) {
while (stream_tell(s) < mkv_d->cluster_end) { while (stream_tell(s) < mkv_d->cluster_end) {
int64_t start_filepos = stream_tell(s); int64_t start_filepos = stream_tell(s);
@ -2923,6 +2939,23 @@ static void probe_last_timestamp(struct demuxer *demuxer)
mkv_d->cluster_start = mkv_d->cluster_end = 0; mkv_d->cluster_start = mkv_d->cluster_end = 0;
} }
static void probe_first_timestamp(struct demuxer *demuxer)
{
mkv_demuxer_t *mkv_d = demuxer->priv;
if (!demuxer->opts->demux_mkv->probe_start_time)
return;
struct block_info block;
if (read_next_block(demuxer, &block) > 0)
mkv_d->tmp_block = block;
demuxer->start_time = mkv_d->cluster_tc / 1e9;
if (demuxer->start_time > 0)
MP_VERBOSE(demuxer, "Start PTS: %f\n", demuxer->start_time);
}
static int demux_mkv_control(demuxer_t *demuxer, int cmd, void *arg) static int demux_mkv_control(demuxer_t *demuxer, int cmd, void *arg)
{ {
mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv; mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv;