summaryrefslogtreecommitdiffstats
path: root/demux/demux_mkv.c
diff options
context:
space:
mode:
Diffstat (limited to 'demux/demux_mkv.c')
-rw-r--r--demux/demux_mkv.c79
1 files changed, 44 insertions, 35 deletions
diff --git a/demux/demux_mkv.c b/demux/demux_mkv.c
index 024f7e7e6e..c932b45f39 100644
--- a/demux/demux_mkv.c
+++ b/demux/demux_mkv.c
@@ -146,14 +146,14 @@ typedef struct mkv_track {
typedef struct mkv_index {
int tnum;
- uint64_t timecode, duration;
+ int64_t timecode, duration;
uint64_t filepos; // position of the cluster which contains the packet
} mkv_index_t;
struct block_info {
uint64_t duration, discardpadding;
bool simple, keyframe;
- uint64_t timecode;
+ int64_t timecode;
mkv_track_t *track;
bstr data;
void *alloc;
@@ -163,14 +163,14 @@ struct block_info {
typedef struct mkv_demuxer {
int64_t segment_start, segment_end;
- double duration, last_pts;
+ double duration;
mkv_track_t **tracks;
int num_tracks;
struct ebml_tags *tags;
- uint64_t tc_scale, cluster_tc;
+ int64_t tc_scale, cluster_tc;
uint64_t cluster_start;
uint64_t cluster_end;
@@ -186,7 +186,7 @@ typedef struct mkv_demuxer {
} *headers;
int num_headers;
- uint64_t skip_to_timecode;
+ int64_t skip_to_timecode;
int v_skip_to_keyframe, a_skip_to_keyframe;
int a_skip_preroll;
int subtitle_preroll;
@@ -706,7 +706,7 @@ static int demux_mkv_read_tracks(demuxer_t *demuxer)
}
static void cue_index_add(demuxer_t *demuxer, int track_id, uint64_t filepos,
- uint64_t timecode, uint64_t duration)
+ int64_t timecode, int64_t duration)
{
mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv;
@@ -724,7 +724,7 @@ static void cue_index_add(demuxer_t *demuxer, int track_id, uint64_t filepos,
static void add_block_position(demuxer_t *demuxer, struct mkv_track *track,
uint64_t filepos,
- uint64_t timecode, uint64_t duration)
+ int64_t timecode, int64_t duration)
{
mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv;
@@ -788,8 +788,8 @@ static int demux_mkv_read_cues(demuxer_t *demuxer)
time, trackpos->cue_duration);
mkv_d->index_has_durations |= trackpos->n_cue_duration > 0;
MP_DBG(demuxer, "|+ found cue point for track %" PRIu64
- ": timecode %" PRIu64 ", filepos: %" PRIu64
- " offset %" PRIu64 ", duration %" PRIu64 "\n",
+ ": timecode %" PRId64 ", filepos: %" PRIu64
+ " offset %" PRIu64 ", duration %" PRId64 "\n",
trackpos->cue_track, time, pos,
trackpos->cue_relative_position, trackpos->cue_duration);
}
@@ -1484,6 +1484,7 @@ static int demux_mkv_open_audio(demuxer_t *demuxer, mkv_track_t *track)
unsigned char *extradata = track->private_data;
unsigned int extradata_len = track->private_size;
+ uint64_t chmask = 0;
if (!track->a_osfreq)
track->a_osfreq = track->a_sfreq;
@@ -1516,6 +1517,9 @@ static int demux_mkv_open_audio(demuxer_t *demuxer, mkv_track_t *track)
extradata_len = track->private_size - 18;
sh_a->bits_per_coded_sample = track->a_bps;
mp_set_codec_from_tag(sh_a);
+ // WAVEFORMATEXTENSIBLE.dwChannelMask
+ if (sh_a->codec_tag == 0xfffe && extradata_len >= 6)
+ chmask = AV_RL32(extradata + 2);
} else if (!strcmp(track->codec_id, "A_PCM/INT/LIT")) {
bool sign = sh_a->bits_per_coded_sample > 8;
mp_set_pcm_codec(sh_a, sign, false, sh_a->bits_per_coded_sample, false);
@@ -1635,7 +1639,9 @@ static int demux_mkv_open_audio(demuxer_t *demuxer, mkv_track_t *track)
if (!sh_a->codec)
goto error;
- mp_chmap_set_unknown(&sh_a->channels, track->a_channels);
+ mp_chmap_from_waveext(&sh_a->channels, chmask);
+ if (sh_a->channels.num != track->a_channels)
+ mp_chmap_set_unknown(&sh_a->channels, track->a_channels);
const char *codec = sh_a->codec;
if (!strcmp(codec, "mp3") || !strcmp(codec, "truehd")) {
@@ -1673,13 +1679,17 @@ static int demux_mkv_open_audio(demuxer_t *demuxer, mkv_track_t *track)
AV_WL32(data + 10, track->a_osfreq);
// Bogus: last frame won't be played.
AV_WL32(data + 14, 0);
+ } else if (!strcmp(codec, "opus")) {
+ // Hardcode the rate libavcodec's opus decoder outputs, so that
+ // AV_PKT_DATA_SKIP_SAMPLES actually works. The Matroska header only
+ // has an arbitrary "input" samplerate, while libavcodec is fixed to
+ // output 48000.
+ sh_a->samplerate = 48000;
}
- // Some files have broken default DefaultDuration set, which will lead to
- // audio packets with incorrect timestamps. This follows FFmpeg commit
- // 6158a3b, sample see FFmpeg ticket 2508.
- if (sh_a->samplerate == 8000 && strcmp(codec, "ac3") == 0)
- track->default_duration = 0;
+ // This field tends to be broken, and our decoder can interpolate the
+ // missing timestamps anyway.
+ track->default_duration = 0;
sh_a->extradata = extradata;
sh_a->extradata_size = extradata_len;
@@ -1854,6 +1864,7 @@ static int demux_mkv_open(demuxer_t *demuxer, enum demux_check check)
mkv_d->segment_start = stream_tell(s);
mkv_d->segment_end = end_pos;
mkv_d->a_skip_preroll = 1;
+ mkv_d->skip_to_timecode = INT64_MIN;
if (demuxer->params && demuxer->params->matroska_was_valid)
*demuxer->params->matroska_was_valid = true;
@@ -2128,6 +2139,8 @@ static void mkv_seek_reset(demuxer_t *demuxer)
}
free_block(&mkv_d->tmp_block);
+
+ mkv_d->skip_to_timecode = INT64_MIN;
}
// Copied from libavformat/matroskadec.c (FFmpeg 310f9dd / 2013-05-30)
@@ -2379,7 +2392,7 @@ static int handle_block(demuxer_t *demuxer, struct block_info *block_info)
bstr data = block_info->data;
bool keyframe = block_info->keyframe;
uint64_t block_duration = block_info->duration;
- uint64_t tc = block_info->timecode;
+ int64_t tc = block_info->timecode;
mkv_track_t *track = block_info->track;
struct sh_stream *stream = track->stream;
uint32_t lace_size[MAX_NUM_LACES];
@@ -2428,7 +2441,6 @@ static int handle_block(demuxer_t *demuxer, struct block_info *block_info)
if (use_this_block) {
uint64_t filepos = block_info->filepos;
- mkv_d->last_pts = current_pts;
for (int i = 0; i < laces; i++) {
bstr block = bstr_splice(data, 0, lace_size[i]);
@@ -2446,13 +2458,13 @@ static int handle_block(demuxer_t *demuxer, struct block_info *block_info)
* values being the same). Also, don't use it for extra
* packets resulting from parsing. */
if (i == 0 || track->default_duration)
- dp->pts = mkv_d->last_pts + i * track->default_duration;
+ dp->pts = current_pts + i * track->default_duration;
if (stream->codec->avi_dts)
MPSWAP(double, dp->pts, dp->dts);
if (i == 0)
dp->duration = block_duration / 1e9;
if (stream->type == STREAM_AUDIO) {
- unsigned int srate = track->a_sfreq;
+ unsigned int srate = stream->codec->samplerate;
demux_packet_set_padding(dp,
mkv_d->a_skip_preroll ? track->codec_delay * srate : 0,
block_info->discardpadding / 1e9 * srate);
@@ -2466,7 +2478,7 @@ static int handle_block(demuxer_t *demuxer, struct block_info *block_info)
if (stream->type == STREAM_VIDEO) {
mkv_d->v_skip_to_keyframe = 0;
- mkv_d->skip_to_timecode = 0;
+ mkv_d->skip_to_timecode = INT64_MIN;
mkv_d->subtitle_preroll = 0;
} else if (stream->type == STREAM_AUDIO) {
mkv_d->a_skip_to_keyframe = 0;
@@ -2658,7 +2670,7 @@ static mkv_index_t *get_highest_index_entry(struct demuxer *demuxer)
return index;
}
-static int create_index_until(struct demuxer *demuxer, uint64_t timecode)
+static int create_index_until(struct demuxer *demuxer, int64_t timecode)
{
struct mkv_demuxer *mkv_d = demuxer->priv;
struct stream *s = demuxer->stream;
@@ -2672,7 +2684,7 @@ static int create_index_until(struct demuxer *demuxer, uint64_t timecode)
if (!index || index->timecode * mkv_d->tc_scale < timecode) {
stream_seek(s, index ? index->filepos : mkv_d->cluster_start);
- MP_VERBOSE(demuxer, "creating index until TC %" PRIu64 "\n", timecode);
+ MP_VERBOSE(demuxer, "creating index until TC %" PRId64 "\n", timecode);
for (;;) {
int res;
struct block_info block;
@@ -2708,8 +2720,7 @@ static struct mkv_index *seek_with_cues(struct demuxer *demuxer, int seek_id,
for (size_t i = 0; i < mkv_d->num_indexes; i++) {
if (seek_id < 0 || mkv_d->indexes[i].tnum == seek_id) {
int64_t diff =
- target_timecode -
- (int64_t) (mkv_d->indexes[i].timecode * mkv_d->tc_scale);
+ target_timecode - mkv_d->indexes[i].timecode * mkv_d->tc_scale;
if (flags & FLAG_BACKWARD)
diff = -diff;
if (min_diff != INT64_MIN) {
@@ -2732,10 +2743,10 @@ static struct mkv_index *seek_with_cues(struct demuxer *demuxer, int seek_id,
double secs = opts->demux_mkv->subtitle_preroll_secs;
if (mkv_d->index_has_durations)
secs = MPMAX(secs, opts->demux_mkv->subtitle_preroll_secs_index);
- uint64_t pre = MPMIN(INT64_MAX, secs * 1e9 / mkv_d->tc_scale);
- uint64_t min_tc = pre < index->timecode ? index->timecode - pre : 0;
+ int64_t pre = MPMIN(INT64_MAX, secs * 1e9 / mkv_d->tc_scale);
+ int64_t min_tc = pre < index->timecode ? index->timecode - pre : 0;
uint64_t prev_target = 0;
- uint64_t prev_tc = 0;
+ int64_t prev_tc = 0;
for (size_t i = 0; i < mkv_d->num_indexes; i++) {
if (seek_id < 0 || mkv_d->indexes[i].tnum == seek_id) {
struct mkv_index *cur = &mkv_d->indexes[i];
@@ -2772,7 +2783,7 @@ static struct mkv_index *seek_with_cues(struct demuxer *demuxer, int seek_id,
return index;
}
-static void demux_mkv_seek(demuxer_t *demuxer, double rel_seek_secs, int flags)
+static void demux_mkv_seek(demuxer_t *demuxer, double seek_pts, int flags)
{
mkv_demuxer_t *mkv_d = demuxer->priv;
int64_t old_pos = stream_tell(demuxer->stream);
@@ -2802,15 +2813,13 @@ static void demux_mkv_seek(demuxer_t *demuxer, double rel_seek_secs, int flags)
// Adjust the target a little bit to catch cases where the target position
// specifies a keyframe with high, but not perfect, precision.
- rel_seek_secs += flags & SEEK_FORWARD ? -0.005 : 0.005;
+ seek_pts += flags & SEEK_FORWARD ? -0.005 : 0.005;
if (!(flags & SEEK_FACTOR)) { /* time in secs */
mkv_index_t *index = NULL;
- if (!(flags & SEEK_ABSOLUTE)) /* relative seek */
- rel_seek_secs += mkv_d->last_pts;
- rel_seek_secs = FFMAX(rel_seek_secs, 0);
- int64_t target_timecode = rel_seek_secs * 1e9 + 0.5;
+ seek_pts = FFMAX(seek_pts, 0);
+ int64_t target_timecode = seek_pts * 1e9 + 0.5;
if (create_index_until(demuxer, target_timecode) >= 0) {
int seek_id = st_active[STREAM_VIDEO] ? v_tnum : a_tnum;
@@ -2826,7 +2835,7 @@ static void demux_mkv_seek(demuxer_t *demuxer, double rel_seek_secs, int flags)
mkv_d->skip_to_timecode = target_timecode;
} else {
mkv_d->skip_to_timecode = index ? index->timecode * mkv_d->tc_scale
- : 0;
+ : INT64_MIN;
}
} else {
stream_t *s = demuxer->stream;
@@ -2834,7 +2843,7 @@ static void demux_mkv_seek(demuxer_t *demuxer, double rel_seek_secs, int flags)
read_deferred_cues(demuxer);
int64_t size = stream_get_size(s);
- int64_t target_filepos = size * MPCLAMP(rel_seek_secs, 0, 1);
+ int64_t target_filepos = size * MPCLAMP(seek_pts, 0, 1);
mkv_index_t *index = NULL;
if (mkv_d->index_complete) {