From 4e87ac823108a670a1a0c5f67ab9bcd6980bac33 Mon Sep 17 00:00:00 2001 From: wm4 Date: Mon, 3 Nov 2014 20:00:34 +0100 Subject: demux_mkv: implement audio skipping/trimming This mechanism was introduced for Opus, and allows correct skipping of "preroll" data, as well as discarding trailing audio if the file's length isn't a multiple of the audio frame size. Not sure how to handle seeking. I don't understand the purpose of the SeekPreRoll element. This was tested with correctness_trimming_nobeeps.opus, remuxed to mka with mkvmerge v7.2.0. It seems to be correct, although the reported file duration is incorrect (maybe a mkvmerge issue). --- demux/demux_mkv.c | 25 +++++++++++++++++++++++-- demux/packet.c | 16 ++++++++++++++++ demux/packet.h | 2 ++ 3 files changed, 41 insertions(+), 2 deletions(-) (limited to 'demux') diff --git a/demux/demux_mkv.c b/demux/demux_mkv.c index 72020ce123..55748ad36c 100644 --- a/demux/demux_mkv.c +++ b/demux/demux_mkv.c @@ -112,6 +112,7 @@ typedef struct mkv_track { float a_osfreq; double default_duration; + double codec_delay; int default_track; @@ -182,6 +183,7 @@ typedef struct mkv_demuxer { uint64_t skip_to_timecode; int v_skip_to_keyframe, a_skip_to_keyframe; + int a_skip_preroll; int subtitle_preroll; } mkv_demuxer_t; @@ -626,6 +628,9 @@ static void parse_trackentry(struct demuxer *demuxer, if (entry->n_content_encodings) parse_trackencodings(demuxer, track, &entry->content_encodings); + if (entry->n_codec_delay) + track->codec_delay = entry->codec_delay / 1e9; + mkv_d->tracks[mkv_d->num_tracks++] = track; } @@ -1750,6 +1755,7 @@ static int demux_mkv_open(demuxer_t *demuxer, enum demux_check check) mkv_d->tc_scale = 1000000; mkv_d->segment_start = stream_tell(s); mkv_d->segment_end = end_pos; + mkv_d->a_skip_preroll = 1; if (demuxer->params && demuxer->params->matroska_was_valid) *demuxer->params->matroska_was_valid = true; @@ -2258,7 +2264,7 @@ static bool mkv_parse_packet(mkv_track_t *track, bstr *raw, bstr *out) } struct block_info { - uint64_t duration; + uint64_t duration, discardpadding; bool simple, keyframe; uint64_t timecode; mkv_track_t *track; @@ -2358,7 +2364,7 @@ static int handle_block(demuxer_t *demuxer, struct block_info *block_info) return 0; } - current_pts = tc / 1e9; + current_pts = tc / 1e9 - track->codec_delay; if (track->type == MATROSKA_TRACK_AUDIO) { if (mkv_d->a_skip_to_keyframe) @@ -2418,6 +2424,13 @@ static int handle_block(demuxer_t *demuxer, struct block_info *block_info) MPSWAP(double, dp->pts, dp->dts); if (p == 0) dp->duration = block_duration / 1e9; + if (stream->type == STREAM_AUDIO) { + unsigned int srate = track->a_sfreq; + demux_packet_set_padding(dp, + mkv_d->a_skip_preroll ? track->codec_delay * srate : 0, + block_info->discardpadding / 1e9 * srate); + mkv_d->a_skip_preroll = 0; + } demux_add_packet(stream, dp); p++; } @@ -2456,6 +2469,12 @@ static int read_block_group(demuxer_t *demuxer, int64_t end, block->duration *= mkv_d->tc_scale; break; + case MATROSKA_ID_DISCARDPADDING: + block->discardpadding = ebml_read_uint(s); + if (block->discardpadding == EBML_UINT_INVALID) + goto error; + break; + case MATROSKA_ID_BLOCK: if (read_block(demuxer, end, block) < 0) goto error; @@ -2745,6 +2764,7 @@ static void demux_mkv_seek(demuxer_t *demuxer, double rel_seek_secs, int flags) mkv_d->v_skip_to_keyframe = st_active[STREAM_VIDEO]; mkv_d->a_skip_to_keyframe = st_active[STREAM_AUDIO]; + mkv_d->a_skip_preroll = mkv_d->a_skip_to_keyframe; if (flags & SEEK_FORWARD) { mkv_d->skip_to_timecode = target_timecode; @@ -2781,6 +2801,7 @@ static void demux_mkv_seek(demuxer_t *demuxer, double rel_seek_secs, int flags) mkv_d->v_skip_to_keyframe = st_active[STREAM_VIDEO]; mkv_d->a_skip_to_keyframe = st_active[STREAM_AUDIO]; + mkv_d->a_skip_preroll = mkv_d->a_skip_to_keyframe; if (index) { stream_seek(s, index->filepos); diff --git a/demux/packet.c b/demux/packet.c index 959c707732..968427dee5 100644 --- a/demux/packet.c +++ b/demux/packet.c @@ -20,6 +20,7 @@ #include #include +#include #include "common/av_common.h" #include "common/common.h" @@ -113,3 +114,18 @@ struct demux_packet *demux_copy_packet(struct demux_packet *dp) new->duration = dp->duration; return new; } + +int demux_packet_set_padding(struct demux_packet *dp, int start, int end) +{ + if (!start && !end) + return 0; + if (!dp->avpacket) + return -1; + uint8_t *p = av_packet_new_side_data(dp->avpacket, AV_PKT_DATA_SKIP_SAMPLES, 10); + if (!p) + return -1; + + AV_WL32(p + 0, start); + AV_WL32(p + 4, end); + return 0; +} diff --git a/demux/packet.h b/demux/packet.h index 9c4e560e05..4bd724aa93 100644 --- a/demux/packet.h +++ b/demux/packet.h @@ -44,4 +44,6 @@ void demux_packet_shorten(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); +int demux_packet_set_padding(struct demux_packet *dp, int start, int end); + #endif /* MPLAYER_DEMUX_PACKET_H */ -- cgit v1.2.3