mirror of https://github.com/procxx/kepka.git
Always specify seek position in TimeMs.
This way it won't rely on the sample rate of the audio file. Fixes #4139.
This commit is contained in:
parent
9fff2bf4c7
commit
4ef3de5287
|
@ -1707,7 +1707,9 @@ void HistoryDocument::clickHandlerPressedChanged(const ClickHandlerPtr &p, bool
|
||||||
auto state = Media::Player::mixer()->currentState(type);
|
auto state = Media::Player::mixer()->currentState(type);
|
||||||
if (state.id == AudioMsgId(_data, _parent->fullId()) && state.length) {
|
if (state.id == AudioMsgId(_data, _parent->fullId()) && state.length) {
|
||||||
auto currentProgress = voice->seekingCurrent();
|
auto currentProgress = voice->seekingCurrent();
|
||||||
auto currentPosition = qRound(currentProgress * state.length);
|
auto currentPosition = state.frequency
|
||||||
|
? qRound(currentProgress * state.length * 1000. / state.frequency)
|
||||||
|
: 0;
|
||||||
Media::Player::mixer()->seek(type, currentPosition);
|
Media::Player::mixer()->seek(type, currentPosition);
|
||||||
|
|
||||||
voice->ensurePlayback(this);
|
voice->ensurePlayback(this);
|
||||||
|
|
|
@ -619,12 +619,15 @@ bool Mixer::fadedStop(AudioMsgId::Type type, bool *fadedStart) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mixer::play(const AudioMsgId &audio, int64 position) {
|
void Mixer::play(const AudioMsgId &audio, TimeMs positionMs) {
|
||||||
setSongVolume(Global::SongVolume());
|
setSongVolume(Global::SongVolume());
|
||||||
play(audio, nullptr, position);
|
play(audio, nullptr, positionMs);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mixer::play(const AudioMsgId &audio, std::unique_ptr<VideoSoundData> videoData, int64 position) {
|
void Mixer::play(
|
||||||
|
const AudioMsgId &audio,
|
||||||
|
std::unique_ptr<VideoSoundData> videoData,
|
||||||
|
TimeMs positionMs) {
|
||||||
Expects(!videoData || audio.playId() != 0);
|
Expects(!videoData || audio.playId() != 0);
|
||||||
|
|
||||||
auto type = audio.type();
|
auto type = audio.type();
|
||||||
|
@ -700,10 +703,11 @@ void Mixer::play(const AudioMsgId &audio, std::unique_ptr<VideoSoundData> videoD
|
||||||
auto newState = (type == AudioMsgId::Type::Song) ? State::Stopped : State::StoppedAtError;
|
auto newState = (type == AudioMsgId::Type::Song) ? State::Stopped : State::StoppedAtError;
|
||||||
setStoppedState(current, newState);
|
setStoppedState(current, newState);
|
||||||
} else {
|
} else {
|
||||||
current->state.position = position;
|
current->state.position = (positionMs * current->state.frequency)
|
||||||
|
/ 1000LL;
|
||||||
current->state.state = current->videoData ? State::Paused : fadedStart ? State::Starting : State::Playing;
|
current->state.state = current->videoData ? State::Paused : fadedStart ? State::Starting : State::Playing;
|
||||||
current->loading = true;
|
current->loading = true;
|
||||||
emit loaderOnStart(current->state.id, position);
|
emit loaderOnStart(current->state.id, positionMs);
|
||||||
if (type == AudioMsgId::Type::Voice) {
|
if (type == AudioMsgId::Type::Voice) {
|
||||||
emit suppressSong();
|
emit suppressSong();
|
||||||
}
|
}
|
||||||
|
@ -871,20 +875,31 @@ void Mixer::resume(const AudioMsgId &audio, bool fast) {
|
||||||
if (current) emit updated(current);
|
if (current) emit updated(current);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mixer::seek(AudioMsgId::Type type, int64 position) {
|
void Mixer::seek(AudioMsgId::Type type, TimeMs positionMs) {
|
||||||
QMutexLocker lock(&AudioMutex);
|
QMutexLocker lock(&AudioMutex);
|
||||||
|
|
||||||
auto current = trackForType(type);
|
const auto current = trackForType(type);
|
||||||
auto audio = current->state.id;
|
const auto audio = current->state.id;
|
||||||
|
|
||||||
Audio::AttachToDevice();
|
Audio::AttachToDevice();
|
||||||
auto streamCreated = current->isStreamCreated();
|
const auto streamCreated = current->isStreamCreated();
|
||||||
auto fastSeek = (position >= current->bufferedPosition && position < current->bufferedPosition + current->bufferedLength - (current->loaded ? 0 : kDefaultFrequency));
|
const auto position = (positionMs * current->frequency) / 1000LL;
|
||||||
if (!streamCreated) {
|
const auto fastSeek = [&] {
|
||||||
fastSeek = false;
|
const auto loadedStart = current->bufferedPosition;
|
||||||
} else if (IsStoppedOrStopping(current->state.state)) {
|
const auto loadedLength = current->bufferedLength;
|
||||||
fastSeek = false;
|
const auto skipBack = (current->loaded ? 0 : kDefaultFrequency);
|
||||||
}
|
const auto availableEnd = loadedStart + loadedLength - skipBack;
|
||||||
|
if (position < loadedStart) {
|
||||||
|
return false;
|
||||||
|
} else if (position >= availableEnd) {
|
||||||
|
return false;
|
||||||
|
} else if (!streamCreated) {
|
||||||
|
return false;
|
||||||
|
} else if (IsStoppedOrStopping(current->state.state)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}();
|
||||||
if (fastSeek) {
|
if (fastSeek) {
|
||||||
alSourcei(current->stream.source, AL_SAMPLE_OFFSET, position - current->bufferedPosition);
|
alSourcei(current->stream.source, AL_SAMPLE_OFFSET, position - current->bufferedPosition);
|
||||||
if (!checkCurrentALError(type)) return;
|
if (!checkCurrentALError(type)) return;
|
||||||
|
@ -921,7 +936,7 @@ void Mixer::seek(AudioMsgId::Type type, int64 position) {
|
||||||
case State::StoppedAtError:
|
case State::StoppedAtError:
|
||||||
case State::StoppedAtStart: {
|
case State::StoppedAtStart: {
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
} return play(audio, position);
|
} return play(audio, positionMs);
|
||||||
}
|
}
|
||||||
emit faderOnTimer();
|
emit faderOnTimer();
|
||||||
}
|
}
|
||||||
|
@ -1386,8 +1401,8 @@ public:
|
||||||
FFMpegAttributesReader(const FileLocation &file, const QByteArray &data) : AbstractFFMpegLoader(file, data, base::byte_vector()) {
|
FFMpegAttributesReader(const FileLocation &file, const QByteArray &data) : AbstractFFMpegLoader(file, data, base::byte_vector()) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool open(qint64 &position) override {
|
bool open(TimeMs positionMs) override {
|
||||||
if (!AbstractFFMpegLoader::open(position)) {
|
if (!AbstractFFMpegLoader::open(positionMs)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1487,8 +1502,8 @@ namespace Player {
|
||||||
FileLoadTask::Song PrepareForSending(const QString &fname, const QByteArray &data) {
|
FileLoadTask::Song PrepareForSending(const QString &fname, const QByteArray &data) {
|
||||||
auto result = FileLoadTask::Song();
|
auto result = FileLoadTask::Song();
|
||||||
FFMpegAttributesReader reader(FileLocation(fname), data);
|
FFMpegAttributesReader reader(FileLocation(fname), data);
|
||||||
qint64 position = 0;
|
const auto positionMs = TimeMs(0);
|
||||||
if (reader.open(position) && reader.samplesCount() > 0) {
|
if (reader.open(positionMs) && reader.samplesCount() > 0) {
|
||||||
result.duration = reader.samplesCount() / reader.samplesFrequency();
|
result.duration = reader.samplesCount() / reader.samplesFrequency();
|
||||||
result.title = reader.title();
|
result.title = reader.title();
|
||||||
result.performer = reader.performer();
|
result.performer = reader.performer();
|
||||||
|
@ -1505,8 +1520,8 @@ public:
|
||||||
FFMpegWaveformCounter(const FileLocation &file, const QByteArray &data) : FFMpegLoader(file, data, base::byte_vector()) {
|
FFMpegWaveformCounter(const FileLocation &file, const QByteArray &data) : FFMpegLoader(file, data, base::byte_vector()) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool open(qint64 &position) override {
|
bool open(TimeMs positionMs) override {
|
||||||
if (!FFMpegLoader::open(position)) {
|
if (!FFMpegLoader::open(positionMs)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1584,8 +1599,8 @@ private:
|
||||||
|
|
||||||
VoiceWaveform audioCountWaveform(const FileLocation &file, const QByteArray &data) {
|
VoiceWaveform audioCountWaveform(const FileLocation &file, const QByteArray &data) {
|
||||||
FFMpegWaveformCounter counter(file, data);
|
FFMpegWaveformCounter counter(file, data);
|
||||||
qint64 position = 0;
|
const auto positionMs = TimeMs(0);
|
||||||
if (counter.open(position)) {
|
if (counter.open(positionMs)) {
|
||||||
return counter.waveform();
|
return counter.waveform();
|
||||||
}
|
}
|
||||||
return VoiceWaveform();
|
return VoiceWaveform();
|
||||||
|
|
|
@ -121,11 +121,11 @@ class Mixer : public QObject, private base::Subscriber {
|
||||||
public:
|
public:
|
||||||
Mixer();
|
Mixer();
|
||||||
|
|
||||||
void play(const AudioMsgId &audio, int64 position = 0);
|
void play(const AudioMsgId &audio, TimeMs positionMs = 0);
|
||||||
void play(const AudioMsgId &audio, std::unique_ptr<VideoSoundData> videoData, int64 position = 0);
|
void play(const AudioMsgId &audio, std::unique_ptr<VideoSoundData> videoData, TimeMs positionMs = 0);
|
||||||
void pause(const AudioMsgId &audio, bool fast = false);
|
void pause(const AudioMsgId &audio, bool fast = false);
|
||||||
void resume(const AudioMsgId &audio, bool fast = false);
|
void resume(const AudioMsgId &audio, bool fast = false);
|
||||||
void seek(AudioMsgId::Type type, int64 position); // type == AudioMsgId::Type::Song
|
void seek(AudioMsgId::Type type, TimeMs positionMs); // type == AudioMsgId::Type::Song
|
||||||
void stop(const AudioMsgId &audio);
|
void stop(const AudioMsgId &audio);
|
||||||
void stop(const AudioMsgId &audio, State state);
|
void stop(const AudioMsgId &audio, State state);
|
||||||
|
|
||||||
|
@ -165,7 +165,7 @@ private slots:
|
||||||
signals:
|
signals:
|
||||||
void updated(const AudioMsgId &audio);
|
void updated(const AudioMsgId &audio);
|
||||||
void stoppedOnError(const AudioMsgId &audio);
|
void stoppedOnError(const AudioMsgId &audio);
|
||||||
void loaderOnStart(const AudioMsgId &audio, qint64 position);
|
void loaderOnStart(const AudioMsgId &audio, qint64 positionMs);
|
||||||
void loaderOnCancel(const AudioMsgId &audio);
|
void loaderOnCancel(const AudioMsgId &audio);
|
||||||
|
|
||||||
void faderOnTimer();
|
void faderOnTimer();
|
||||||
|
|
|
@ -37,7 +37,7 @@ bool IsPlanarFormat(int format) {
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
bool AbstractFFMpegLoader::open(qint64 &position) {
|
bool AbstractFFMpegLoader::open(TimeMs positionMs) {
|
||||||
if (!AudioPlayerLoader::openFile()) {
|
if (!AudioPlayerLoader::openFile()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -192,8 +192,8 @@ FFMpegLoader::FFMpegLoader(const FileLocation &file, const QByteArray &data, bas
|
||||||
frame = av_frame_alloc();
|
frame = av_frame_alloc();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FFMpegLoader::open(qint64 &position) {
|
bool FFMpegLoader::open(TimeMs positionMs) {
|
||||||
if (!AbstractFFMpegLoader::open(position)) {
|
if (!AbstractFFMpegLoader::open(positionMs)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -295,7 +295,6 @@ bool FFMpegLoader::open(qint64 &position) {
|
||||||
sampleSize = AudioToChannels * sizeof(short);
|
sampleSize = AudioToChannels * sizeof(short);
|
||||||
_samplesFrequency = dstRate;
|
_samplesFrequency = dstRate;
|
||||||
_samplesCount = av_rescale_rnd(_samplesCount, dstRate, srcRate, AV_ROUND_UP);
|
_samplesCount = av_rescale_rnd(_samplesCount, dstRate, srcRate, AV_ROUND_UP);
|
||||||
position = av_rescale_rnd(position, dstRate, srcRate, AV_ROUND_DOWN);
|
|
||||||
fmt = AL_FORMAT_STEREO16;
|
fmt = AL_FORMAT_STEREO16;
|
||||||
|
|
||||||
maxResampleSamples = av_rescale_rnd(AVBlockSize / sampleSize, dstRate, srcRate, AV_ROUND_UP);
|
maxResampleSamples = av_rescale_rnd(AVBlockSize / sampleSize, dstRate, srcRate, AV_ROUND_UP);
|
||||||
|
@ -304,10 +303,12 @@ bool FFMpegLoader::open(qint64 &position) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (position) {
|
if (positionMs) {
|
||||||
int64 ts = (position * fmtContext->streams[streamId]->time_base.den) / (_samplesFrequency * fmtContext->streams[streamId]->time_base.num);
|
const auto timeBase = fmtContext->streams[streamId]->time_base;
|
||||||
if (av_seek_frame(fmtContext, streamId, ts, AVSEEK_FLAG_ANY) < 0) {
|
const auto timeStamp = (positionMs * timeBase.den)
|
||||||
if (av_seek_frame(fmtContext, streamId, ts, 0) < 0) {
|
/ (1000LL * timeBase.num);
|
||||||
|
if (av_seek_frame(fmtContext, streamId, timeStamp, AVSEEK_FLAG_ANY) < 0) {
|
||||||
|
if (av_seek_frame(fmtContext, streamId, timeStamp, 0) < 0) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ public:
|
||||||
AbstractFFMpegLoader(const FileLocation &file, const QByteArray &data, base::byte_vector &&bytes) : AudioPlayerLoader(file, data, std::move(bytes)) {
|
AbstractFFMpegLoader(const FileLocation &file, const QByteArray &data, base::byte_vector &&bytes) : AudioPlayerLoader(file, data, std::move(bytes)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool open(qint64 &position) override;
|
bool open(TimeMs positionMs) override;
|
||||||
|
|
||||||
int64 samplesCount() override {
|
int64 samplesCount() override {
|
||||||
return _samplesCount;
|
return _samplesCount;
|
||||||
|
@ -75,7 +75,7 @@ class FFMpegLoader : public AbstractFFMpegLoader {
|
||||||
public:
|
public:
|
||||||
FFMpegLoader(const FileLocation &file, const QByteArray &data, base::byte_vector &&bytes);
|
FFMpegLoader(const FileLocation &file, const QByteArray &data, base::byte_vector &&bytes);
|
||||||
|
|
||||||
bool open(qint64 &position) override;
|
bool open(TimeMs positionMs) override;
|
||||||
|
|
||||||
int32 format() override {
|
int32 format() override {
|
||||||
return fmt;
|
return fmt;
|
||||||
|
|
|
@ -31,7 +31,7 @@ public:
|
||||||
|
|
||||||
virtual bool check(const FileLocation &file, const QByteArray &data);
|
virtual bool check(const FileLocation &file, const QByteArray &data);
|
||||||
|
|
||||||
virtual bool open(qint64 &position) = 0;
|
virtual bool open(TimeMs positionMs) = 0;
|
||||||
virtual int64 samplesCount() = 0;
|
virtual int64 samplesCount() = 0;
|
||||||
virtual int32 samplesFrequency() = 0;
|
virtual int32 samplesFrequency() = 0;
|
||||||
virtual int32 format() = 0;
|
virtual int32 format() = 0;
|
||||||
|
|
|
@ -98,7 +98,7 @@ void Loaders::clearFromVideoQueue() {
|
||||||
void Loaders::onInit() {
|
void Loaders::onInit() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Loaders::onStart(const AudioMsgId &audio, qint64 position) {
|
void Loaders::onStart(const AudioMsgId &audio, qint64 positionMs) {
|
||||||
auto type = audio.type();
|
auto type = audio.type();
|
||||||
clear(type);
|
clear(type);
|
||||||
{
|
{
|
||||||
|
@ -111,7 +111,7 @@ void Loaders::onStart(const AudioMsgId &audio, qint64 position) {
|
||||||
track->loading = true;
|
track->loading = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
loadData(audio, position);
|
loadData(audio, positionMs);
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioMsgId Loaders::clear(AudioMsgId::Type type) {
|
AudioMsgId Loaders::clear(AudioMsgId::Type type) {
|
||||||
|
@ -133,13 +133,13 @@ void Loaders::emitError(AudioMsgId::Type type) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Loaders::onLoad(const AudioMsgId &audio) {
|
void Loaders::onLoad(const AudioMsgId &audio) {
|
||||||
loadData(audio, 0);
|
loadData(audio, TimeMs(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Loaders::loadData(AudioMsgId audio, qint64 position) {
|
void Loaders::loadData(AudioMsgId audio, TimeMs positionMs) {
|
||||||
auto err = SetupNoErrorStarted;
|
auto err = SetupNoErrorStarted;
|
||||||
auto type = audio.type();
|
auto type = audio.type();
|
||||||
auto l = setupLoader(audio, err, position);
|
auto l = setupLoader(audio, err, positionMs);
|
||||||
if (!l) {
|
if (!l) {
|
||||||
if (err == SetupErrorAtStart) {
|
if (err == SetupErrorAtStart) {
|
||||||
emitError(type);
|
emitError(type);
|
||||||
|
@ -210,12 +210,13 @@ void Loaders::loadData(AudioMsgId audio, qint64 position) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
track->format = l->format();
|
||||||
|
track->frequency = l->samplesFrequency();
|
||||||
|
|
||||||
|
const auto position = (positionMs * track->frequency) / 1000LL;
|
||||||
track->bufferedPosition = position;
|
track->bufferedPosition = position;
|
||||||
track->state.position = position;
|
track->state.position = position;
|
||||||
track->fadeStartPosition = position;
|
track->fadeStartPosition = position;
|
||||||
|
|
||||||
track->format = l->format();
|
|
||||||
track->frequency = l->samplesFrequency();
|
|
||||||
}
|
}
|
||||||
if (samplesCount) {
|
if (samplesCount) {
|
||||||
track->ensureStreamCreated();
|
track->ensureStreamCreated();
|
||||||
|
@ -291,7 +292,10 @@ void Loaders::loadData(AudioMsgId audio, qint64 position) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioPlayerLoader *Loaders::setupLoader(const AudioMsgId &audio, SetupError &err, qint64 &position) {
|
AudioPlayerLoader *Loaders::setupLoader(
|
||||||
|
const AudioMsgId &audio,
|
||||||
|
SetupError &err,
|
||||||
|
TimeMs positionMs) {
|
||||||
err = SetupErrorAtStart;
|
err = SetupErrorAtStart;
|
||||||
QMutexLocker lock(internal::audioPlayerMutex());
|
QMutexLocker lock(internal::audioPlayerMutex());
|
||||||
if (!mixer()) return nullptr;
|
if (!mixer()) return nullptr;
|
||||||
|
@ -339,7 +343,7 @@ AudioPlayerLoader *Loaders::setupLoader(const AudioMsgId &audio, SetupError &err
|
||||||
}
|
}
|
||||||
l = loader->get();
|
l = loader->get();
|
||||||
|
|
||||||
if (!l->open(position)) {
|
if (!l->open(positionMs)) {
|
||||||
track->state.state = State::StoppedAtStart;
|
track->state.state = State::StoppedAtStart;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -350,7 +354,6 @@ AudioPlayerLoader *Loaders::setupLoader(const AudioMsgId &audio, SetupError &err
|
||||||
}
|
}
|
||||||
track->state.length = length;
|
track->state.length = length;
|
||||||
track->state.frequency = l->samplesFrequency();
|
track->state.frequency = l->samplesFrequency();
|
||||||
if (!track->state.frequency) track->state.frequency = kDefaultFrequency;
|
|
||||||
err = SetupNoErrorStarted;
|
err = SetupNoErrorStarted;
|
||||||
} else if (track->loaded) {
|
} else if (track->loaded) {
|
||||||
err = SetupErrorLoadedFull;
|
err = SetupErrorLoadedFull;
|
||||||
|
|
|
@ -45,7 +45,7 @@ signals:
|
||||||
public slots:
|
public slots:
|
||||||
void onInit();
|
void onInit();
|
||||||
|
|
||||||
void onStart(const AudioMsgId &audio, qint64 position);
|
void onStart(const AudioMsgId &audio, qint64 positionMs);
|
||||||
void onLoad(const AudioMsgId &audio);
|
void onLoad(const AudioMsgId &audio);
|
||||||
void onCancel(const AudioMsgId &audio);
|
void onCancel(const AudioMsgId &audio);
|
||||||
|
|
||||||
|
@ -72,8 +72,11 @@ private:
|
||||||
SetupErrorLoadedFull = 2,
|
SetupErrorLoadedFull = 2,
|
||||||
SetupNoErrorStarted = 3,
|
SetupNoErrorStarted = 3,
|
||||||
};
|
};
|
||||||
void loadData(AudioMsgId audio, qint64 position);
|
void loadData(AudioMsgId audio, TimeMs positionMs);
|
||||||
AudioPlayerLoader *setupLoader(const AudioMsgId &audio, SetupError &err, qint64 &position);
|
AudioPlayerLoader *setupLoader(
|
||||||
|
const AudioMsgId &audio,
|
||||||
|
SetupError &err,
|
||||||
|
TimeMs positionMs);
|
||||||
Mixer::Track *checkLoader(AudioMsgId::Type type);
|
Mixer::Track *checkLoader(AudioMsgId::Type type);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -37,7 +37,7 @@ ChildFFMpegLoader::ChildFFMpegLoader(std::unique_ptr<VideoSoundData> &&data) : A
|
||||||
_frame = av_frame_alloc();
|
_frame = av_frame_alloc();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ChildFFMpegLoader::open(qint64 &position) {
|
bool ChildFFMpegLoader::open(TimeMs positionMs) {
|
||||||
int res = 0;
|
int res = 0;
|
||||||
char err[AV_ERROR_MAX_STRING_SIZE] = { 0 };
|
char err[AV_ERROR_MAX_STRING_SIZE] = { 0 };
|
||||||
|
|
||||||
|
@ -106,7 +106,6 @@ bool ChildFFMpegLoader::open(qint64 &position) {
|
||||||
_sampleSize = AudioToChannels * sizeof(short);
|
_sampleSize = AudioToChannels * sizeof(short);
|
||||||
_parentData->frequency = _dstRate;
|
_parentData->frequency = _dstRate;
|
||||||
_parentData->length = av_rescale_rnd(_parentData->length, _dstRate, _srcRate, AV_ROUND_UP);
|
_parentData->length = av_rescale_rnd(_parentData->length, _dstRate, _srcRate, AV_ROUND_UP);
|
||||||
position = av_rescale_rnd(position, _dstRate, _srcRate, AV_ROUND_DOWN);
|
|
||||||
_format = AL_FORMAT_STEREO16;
|
_format = AL_FORMAT_STEREO16;
|
||||||
|
|
||||||
_maxResampleSamples = av_rescale_rnd(AVBlockSize / _sampleSize, _dstRate, _srcRate, AV_ROUND_UP);
|
_maxResampleSamples = av_rescale_rnd(AVBlockSize / _sampleSize, _dstRate, _srcRate, AV_ROUND_UP);
|
||||||
|
|
|
@ -85,7 +85,7 @@ class ChildFFMpegLoader : public AudioPlayerLoader {
|
||||||
public:
|
public:
|
||||||
ChildFFMpegLoader(std::unique_ptr<VideoSoundData> &&data);
|
ChildFFMpegLoader(std::unique_ptr<VideoSoundData> &&data);
|
||||||
|
|
||||||
bool open(qint64 &position) override;
|
bool open(TimeMs positionMs) override;
|
||||||
|
|
||||||
bool check(const FileLocation &file, const QByteArray &data) override {
|
bool check(const FileLocation &file, const QByteArray &data) override {
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -400,9 +400,11 @@ bool FFMpegReaderImplementation::start(Mode mode, TimeMs &positionMs) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (positionMs > 0) {
|
if (positionMs > 0) {
|
||||||
auto ts = (positionMs * _fmtContext->streams[_streamId]->time_base.den) / (1000LL * _fmtContext->streams[_streamId]->time_base.num);
|
const auto timeBase = _fmtContext->streams[_streamId]->time_base;
|
||||||
if (av_seek_frame(_fmtContext, _streamId, ts, 0) < 0) {
|
const auto timeStamp = (positionMs * timeBase.den)
|
||||||
if (av_seek_frame(_fmtContext, _streamId, ts, AVSEEK_FLAG_BACKWARD) < 0) {
|
/ (1000LL * timeBase.num);
|
||||||
|
if (av_seek_frame(_fmtContext, _streamId, timeStamp, 0) < 0) {
|
||||||
|
if (av_seek_frame(_fmtContext, _streamId, timeStamp, AVSEEK_FLAG_BACKWARD) < 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -415,8 +417,7 @@ bool FFMpegReaderImplementation::start(Mode mode, TimeMs &positionMs) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasAudio()) {
|
if (hasAudio()) {
|
||||||
auto position = (positionMs * soundData->frequency) / 1000LL;
|
Player::mixer()->play(_audioMsgId, std::move(soundData), positionMs);
|
||||||
Player::mixer()->play(_audioMsgId, std::move(soundData), position);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (readResult == PacketResult::Ok) {
|
if (readResult == PacketResult::Ok) {
|
||||||
|
@ -428,9 +429,11 @@ bool FFMpegReaderImplementation::start(Mode mode, TimeMs &positionMs) {
|
||||||
|
|
||||||
bool FFMpegReaderImplementation::inspectAt(TimeMs &positionMs) {
|
bool FFMpegReaderImplementation::inspectAt(TimeMs &positionMs) {
|
||||||
if (positionMs > 0) {
|
if (positionMs > 0) {
|
||||||
auto ts = (positionMs * _fmtContext->streams[_streamId]->time_base.den) / (1000LL * _fmtContext->streams[_streamId]->time_base.num);
|
const auto timeBase = _fmtContext->streams[_streamId]->time_base;
|
||||||
if (av_seek_frame(_fmtContext, _streamId, ts, 0) < 0) {
|
const auto timeStamp = (positionMs * timeBase.den)
|
||||||
if (av_seek_frame(_fmtContext, _streamId, ts, AVSEEK_FLAG_BACKWARD) < 0) {
|
/ (1000LL * timeBase.num);
|
||||||
|
if (av_seek_frame(_fmtContext, _streamId, timeStamp, 0) < 0) {
|
||||||
|
if (av_seek_frame(_fmtContext, _streamId, timeStamp, AVSEEK_FLAG_BACKWARD) < 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -173,8 +173,8 @@ void CoverWidget::handleSeekFinished(float64 progress) {
|
||||||
|
|
||||||
auto type = AudioMsgId::Type::Song;
|
auto type = AudioMsgId::Type::Song;
|
||||||
auto state = Media::Player::mixer()->currentState(type);
|
auto state = Media::Player::mixer()->currentState(type);
|
||||||
if (state.id && state.length) {
|
if (state.id && state.length && state.frequency) {
|
||||||
Media::Player::mixer()->seek(type, qRound(progress * state.length));
|
Media::Player::mixer()->seek(type, qRound(progress * state.length * 1000. / state.frequency));
|
||||||
}
|
}
|
||||||
|
|
||||||
instance()->stopSeeking(type);
|
instance()->stopSeeking(type);
|
||||||
|
|
|
@ -248,8 +248,8 @@ void Widget::handleSeekFinished(float64 progress) {
|
||||||
_seekPositionMs = -1;
|
_seekPositionMs = -1;
|
||||||
|
|
||||||
auto state = mixer()->currentState(_type);
|
auto state = mixer()->currentState(_type);
|
||||||
if (state.id && state.length) {
|
if (state.id && state.length && state.frequency) {
|
||||||
mixer()->seek(_type, qRound(progress * state.length));
|
mixer()->seek(_type, qRound(progress * state.length * 1000. / state.frequency));
|
||||||
}
|
}
|
||||||
|
|
||||||
instance()->stopSeeking(_type);
|
instance()->stopSeeking(_type);
|
||||||
|
|
Loading…
Reference in New Issue