summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2014-11-03 20:00:34 +0100
committerwm4 <wm4@nowhere>2014-11-03 20:20:28 +0100
commit4e87ac823108a670a1a0c5f67ab9bcd6980bac33 (patch)
tree4e71fa69834ce2e7886f3870abc3b8766d1605c3
parent93e1db0bff5fc48dffeb2dc94801436bdb459cd3 (diff)
downloadmpv-4e87ac823108a670a1a0c5f67ab9bcd6980bac33.tar.bz2
mpv-4e87ac823108a670a1a0c5f67ab9bcd6980bac33.tar.xz
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).
-rw-r--r--TOOLS/lib/Parse/Matroska/Definitions.pm3
-rw-r--r--demux/demux_mkv.c25
-rw-r--r--demux/packet.c16
-rw-r--r--demux/packet.h2
4 files changed, 44 insertions, 2 deletions
diff --git a/TOOLS/lib/Parse/Matroska/Definitions.pm b/TOOLS/lib/Parse/Matroska/Definitions.pm
index 081fe5bb97..b320e1f6c8 100644
--- a/TOOLS/lib/Parse/Matroska/Definitions.pm
+++ b/TOOLS/lib/Parse/Matroska/Definitions.pm
@@ -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'),
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 <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;
+}
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 */