diff options
Diffstat (limited to 'demux/demux_mkv.c')
-rw-r--r-- | demux/demux_mkv.c | 79 |
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) { |