fix: preserve audio sample continuity across timestamp rounding
This commit is contained in:
@@ -404,6 +404,7 @@ struct Player {
|
||||
}
|
||||
|
||||
void convertAudio() {
|
||||
const bool continuing = resampler != nullptr;
|
||||
auto &track = tracks[0];
|
||||
const int rate = decoded->sample_rate > 0 ? decoded->sample_rate : track.codec->sample_rate;
|
||||
const AVChannelLayout *layout = decoded->ch_layout.nb_channels > 0 ?
|
||||
@@ -424,8 +425,13 @@ struct Player {
|
||||
throw std::runtime_error("Audio format changes within a track are not supported");
|
||||
}
|
||||
const double timestamp = framePts(track, decoded);
|
||||
track.nextPts = timestamp + static_cast<double>(decoded->nb_samples) / rate;
|
||||
pcmPts = timestamp - static_cast<double>(swr_get_delay(resampler, rate)) / rate;
|
||||
const double tick = av_q2d(format->streams[track.index]->time_base);
|
||||
const bool contiguous = continuing && std::abs(timestamp - track.nextPts) <= tick + 1.0 / rate;
|
||||
// Quantized packet PTS and rounded resampler delay must not insert/drop PCM samples.
|
||||
const int64_t delayBase = static_cast<int64_t>(rate) * sampleRate;
|
||||
pcmPts = contiguous ? resampleNextPts :
|
||||
timestamp - static_cast<double>(swr_get_delay(resampler, delayBase)) / delayBase;
|
||||
track.nextPts = (contiguous ? track.nextPts : timestamp) + static_cast<double>(decoded->nb_samples) / rate;
|
||||
const int capacity = swr_get_out_samples(resampler, decoded->nb_samples);
|
||||
check(capacity, "Sizing resampled audio");
|
||||
if (capacity > audioFrameLimit)
|
||||
|
||||
@@ -17,6 +17,11 @@ extern "C" {
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
|
||||
#ifdef PLAYER_AUDIO_CHECK
|
||||
// Check builds observe the actual callback samples; release builds have no hook.
|
||||
extern void player_check_audio(const float *samples, size_t frames);
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
constexpr size_t capacity = 48000;
|
||||
double host_seconds(uint64_t ticks) {
|
||||
@@ -258,6 +263,9 @@ struct Output::Impl {
|
||||
size_t first = std::min(frames, capacity - size_t(r % capacity));
|
||||
std::memcpy(destination, self.samples.data() + (r % capacity) * 2, first * 2 * sizeof(float));
|
||||
std::memcpy(destination + first * 2, self.samples.data(), (frames - first) * 2 * sizeof(float));
|
||||
#ifdef PLAYER_AUDIO_CHECK
|
||||
player_check_audio(destination, count);
|
||||
#endif
|
||||
if (frames) {
|
||||
self.clockVersion.fetch_add(1, std::memory_order_acq_rel);
|
||||
self.anchorPTS.store(self.origin + double(r) / 48000, std::memory_order_relaxed);
|
||||
|
||||
Reference in New Issue
Block a user