From 3275dac50f36b407cf81e78d980f00e0dea0df66 Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Mon, 3 Oct 2022 15:30:52 -0700 Subject: [PATCH] decoder: fixed longstanding audio sync issue Wow this has probably been a bug for 3 years straight --- app/codec/decoder.cpp | 10 +++++----- app/codec/decoder.h | 4 +++- app/codec/ffmpeg/ffmpegdecoder.cpp | 18 ++++++++++++++++-- app/codec/ffmpeg/ffmpegdecoder.h | 4 +++- 4 files changed, 27 insertions(+), 9 deletions(-) diff --git a/app/codec/decoder.cpp b/app/codec/decoder.cpp index 666cec629..3e6998f88 100644 --- a/app/codec/decoder.cpp +++ b/app/codec/decoder.cpp @@ -217,14 +217,11 @@ DecoderPtr Decoder::CreateFromID(const QString &id) int64_t Decoder::GetTimeInTimebaseUnits(const rational &time, const rational &timebase, int64_t start_time) { - int64_t t = Timecode::time_to_timestamp(time, timebase); - t += start_time; - return t; + return Timecode::time_to_timestamp(time, timebase); } rational Decoder::GetTimestampInTimeUnits(int64_t time, const rational &timebase, int64_t start_time) { - time -= start_time; return Timecode::timestamp_to_time(time, timebase); } @@ -294,10 +291,13 @@ bool Decoder::ConformAudioInternal(const QVector &filenames, const Audi return false; } -bool Decoder::RetrieveAudioFromConform(SampleBuffer &sample_buffer, const QVector &conform_filenames, const TimeRange& range, LoopMode loop_mode, const AudioParams &input_params) +bool Decoder::RetrieveAudioFromConform(SampleBuffer &sample_buffer, const QVector &conform_filenames, TimeRange range, LoopMode loop_mode, const AudioParams &input_params) { PlanarFileDevice input; if (input.open(conform_filenames, QFile::ReadOnly)) { + // Offset range by audio start offset + range -= GetAudioStartOffset(); + qint64 read_index = input_params.time_to_bytes(range.in()) / input_params.channel_count(); qint64 write_index = 0; diff --git a/app/codec/decoder.h b/app/codec/decoder.h index 983efb753..c6aac3ecb 100644 --- a/app/codec/decoder.h +++ b/app/codec/decoder.h @@ -297,6 +297,8 @@ protected: static int64_t GetTimeInTimebaseUnits(const rational& time, const rational& timebase, int64_t start_time); static rational GetTimestampInTimeUnits(int64_t time, const rational& timebase, int64_t start_time); + virtual rational GetAudioStartOffset() const { return 0; } + signals: /** * @brief While indexing, this signal will provide progress as a percentage (0-100 inclusive) if @@ -307,7 +309,7 @@ signals: private: void UpdateLastAccessed(); - bool RetrieveAudioFromConform(SampleBuffer &sample_buffer, const QVector &conform_filenames, const TimeRange &range, LoopMode loop_mode, const AudioParams ¶ms); + bool RetrieveAudioFromConform(SampleBuffer &sample_buffer, const QVector &conform_filenames, TimeRange range, LoopMode loop_mode, const AudioParams ¶ms); CodecStream stream_; diff --git a/app/codec/ffmpeg/ffmpegdecoder.cpp b/app/codec/ffmpeg/ffmpegdecoder.cpp index e4168479d..179666090 100644 --- a/app/codec/ffmpeg/ffmpegdecoder.cpp +++ b/app/codec/ffmpeg/ffmpegdecoder.cpp @@ -143,7 +143,7 @@ bool FFmpegDecoder::OpenInternal() TexturePtr FFmpegDecoder::RetrieveVideoInternal(const RetrieveVideoParams &p) { - if (AVFramePtr f = RetrieveFrame(p.time, p.cancelled)) { + if (AVFramePtr f = RetrieveFrame(p.time, p.src_interlacing, p.cancelled)) { if (p.cancelled && p.cancelled->IsCancelled()) { return nullptr; } @@ -311,6 +311,16 @@ void FFmpegDecoder::CloseInternal() native_output_pix_fmt_ = VideoParams::kFormatInvalid; } +rational FFmpegDecoder::GetAudioStartOffset() const +{ + AVStream *s = this->instance_.avstream(); + if (s) { + return rational(s->start_time * s->time_base.num, s->time_base.den); + } else { + return 0; + } +} + QString FFmpegDecoder::id() const { return QStringLiteral("ffmpeg"); @@ -787,10 +797,14 @@ void FFmpegDecoder::ClearFrameCache() } } -AVFramePtr FFmpegDecoder::RetrieveFrame(const rational& time, CancelAtom *cancelled) +AVFramePtr FFmpegDecoder::RetrieveFrame(const rational& time, VideoParams::Interlacing interlacing, CancelAtom *cancelled) { int64_t target_ts = GetTimeInTimebaseUnits(time, instance_.avstream()->time_base, instance_.avstream()->start_time); + if (interlacing != VideoParams::kInterlaceNone) { + target_ts *= 2; + } + const int64_t min_seek = -instance_.avstream()->start_time; int64_t seek_ts = std::max(min_seek, target_ts - MaximumQueueSize()); bool still_seeking = false; diff --git a/app/codec/ffmpeg/ffmpegdecoder.h b/app/codec/ffmpeg/ffmpegdecoder.h index e018cfc75..cd60c5d05 100644 --- a/app/codec/ffmpeg/ffmpegdecoder.h +++ b/app/codec/ffmpeg/ffmpegdecoder.h @@ -67,6 +67,8 @@ protected: virtual bool ConformAudioInternal(const QVector& filenames, const AudioParams ¶ms, CancelAtom *cancelled) override; virtual void CloseInternal() override; + virtual rational GetAudioStartOffset() const override; + private: class Instance { @@ -148,7 +150,7 @@ private: void ClearFrameCache(); - AVFramePtr RetrieveFrame(const rational &time, CancelAtom *cancelled); + AVFramePtr RetrieveFrame(const rational &time, VideoParams::Interlacing interlacing, CancelAtom *cancelled); void RemoveFirstFrame();