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).
This commit is contained in:
wm4 2014-11-03 20:00:34 +01:00
parent 93e1db0bff
commit 4e87ac8231
4 changed files with 44 additions and 2 deletions

View File

@ -232,6 +232,7 @@ sub define_matroska {
elem('Block', 'a1', 'binary'),
elem('BlockDuration', '9b', 'uint'),
elem('ReferenceBlock*', 'fb', 'sint'),
elem('DiscardPadding', '75A2', 'sint'),
}),
elem('SimpleBlock*', 'a3', 'binary'),
}),
@ -256,6 +257,8 @@ sub define_matroska {
elem('CodecPrivate', '63a2', 'binary'),
elem('CodecName', '258688', 'str'),
elem('CodecDecodeAll', 'aa', 'uint'),
elem('CodecDelay', '56AA', 'uint'),
elem('SeekPreRoll', '56BB', 'uint'),
elem('Video', 'e0', {
elem('FlagInterlaced', '9a', 'uint'),
elem('PixelWidth', 'b0', 'uint'),

View File

@ -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);

View File

@ -20,6 +20,7 @@
#include <assert.h>
#include <libavcodec/avcodec.h>
#include <libavutil/intreadwrite.h>
#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;
}

View File

@ -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 */