mirror of
https://github.com/mpv-player/mpv
synced 2025-02-16 12:17:12 +00:00
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:
parent
93e1db0bff
commit
4e87ac8231
@ -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'),
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user