disable breaking the loop in multi-frame if storage is insufficient

This commit is contained in:
Vladislav Mikhalin 2024-11-12 20:16:17 +03:00
parent 5f63f46204
commit 4d4d9d5e2c
7 changed files with 44 additions and 27 deletions

View File

@ -123,14 +123,16 @@ AjmSidebandFormat AjmAt9Decoder::GetFormat() const {
.channel_mask = GetChannelMask(u32(m_codec_info.channels)),
.sampl_freq = u32(m_codec_info.samplingRate),
.sample_encoding = m_format,
.bitrate = u32(m_codec_info.samplingRate * GetPCMSize(m_format) * 8),
.bitrate = u32((m_codec_info.samplingRate * m_codec_info.superframeSize * 8) /
(m_codec_info.framesInSuperframe * m_codec_info.frameSamples)),
.reserved = 0,
};
}
u32 AjmAt9Decoder::GetNextFrameSize(u32 max_samples) const {
return std::min(u32(m_codec_info.frameSamples), max_samples) * m_codec_info.channels *
GetPCMSize(m_format);
u32 AjmAt9Decoder::GetNextFrameSize(u32 skip_samples, u32 max_samples) const {
skip_samples = std::min({skip_samples, u32(m_codec_info.frameSamples), max_samples});
return (std::min(u32(m_codec_info.frameSamples), max_samples) - skip_samples) *
m_codec_info.channels * GetPCMSize(m_format);
}
} // namespace Libraries::Ajm

View File

@ -35,7 +35,7 @@ struct AjmAt9Decoder final : AjmCodec {
void Initialize(const void* buffer, u32 buffer_size) override;
void GetInfo(void* out_info) const override;
AjmSidebandFormat GetFormat() const override;
u32 GetNextFrameSize(u32 max_samples) const override;
u32 GetNextFrameSize(u32 skip_samples, u32 max_samples) const override;
std::tuple<u32, u32> ProcessData(std::span<u8>& input, SparseOutputBuffer& output,
AjmSidebandGaplessDecode& gapless,
std::optional<u32> max_samples) override;

View File

@ -135,7 +135,10 @@ AjmJob AjmJobFromBatchBuffer(u32 instance_id, AjmBatchBuffer batch_buffer) {
case Identifier::AjmIdentInputControlBuf: {
ASSERT_MSG(!input_control_buffer.has_value(),
"Only one instance of input control buffer is allowed per job");
input_control_buffer = batch_buffer.Consume<AjmChunkBuffer>();
const auto& buffer = batch_buffer.Consume<AjmChunkBuffer>();
if (buffer.p_address != nullptr && buffer.size != 0) {
input_control_buffer = buffer;
}
break;
}
case Identifier::AjmIdentControlFlags:
@ -155,19 +158,27 @@ AjmJob AjmJobFromBatchBuffer(u32 instance_id, AjmBatchBuffer batch_buffer) {
case Identifier::AjmIdentInlineBuf: {
ASSERT_MSG(!output_control_buffer.has_value(),
"Only one instance of inline buffer is allowed per job");
inline_buffer = batch_buffer.Consume<AjmChunkBuffer>();
const auto& buffer = batch_buffer.Consume<AjmChunkBuffer>();
if (buffer.p_address != nullptr && buffer.size != 0) {
inline_buffer = buffer;
}
break;
}
case Identifier::AjmIdentOutputRunBuf: {
auto& buffer = batch_buffer.Consume<AjmChunkBuffer>();
u8* p_begin = reinterpret_cast<u8*>(buffer.p_address);
job.output.buffers.emplace_back(std::span<u8>(p_begin, p_begin + buffer.size));
if (p_begin != nullptr && buffer.size != 0) {
job.output.buffers.emplace_back(std::span<u8>(p_begin, p_begin + buffer.size));
}
break;
}
case Identifier::AjmIdentOutputControlBuf: {
ASSERT_MSG(!output_control_buffer.has_value(),
"Only one instance of output control buffer is allowed per job");
output_control_buffer = batch_buffer.Consume<AjmChunkBuffer>();
const auto& buffer = batch_buffer.Consume<AjmChunkBuffer>();
if (buffer.p_address != nullptr && buffer.size != 0) {
output_control_buffer = buffer;
}
break;
}
default:

View File

@ -78,8 +78,12 @@ void AjmInstance::ExecuteJob(AjmJob& job) {
}
if (job.input.gapless_decode.has_value()) {
auto& params = job.input.gapless_decode.value();
m_gapless.total_samples = params.total_samples;
m_gapless.skip_samples = params.skip_samples;
if (params.total_samples != 0) {
m_gapless.total_samples = std::max(params.total_samples, m_gapless.total_samples);
}
if (params.skip_samples != 0) {
m_gapless.skip_samples = std::max(params.skip_samples, m_gapless.skip_samples);
}
}
if (!job.input.buffer.empty() && !job.output.buffers.empty()) {
@ -90,16 +94,14 @@ void AjmInstance::ExecuteJob(AjmJob& job) {
auto in_size = in_buf.size();
auto out_size = out_buf.Size();
while (!in_buf.empty() && !out_buf.IsEmpty() && !IsGaplessEnd()) {
const auto samples_remain = GetNumRemainingSamples();
if (!HasEnoughSpace(out_buf, samples_remain)) {
if (job.output.p_mframe == nullptr) {
LOG_ERROR(Lib_Ajm, "Single-frame job buffer too small.");
if (!HasEnoughSpace(out_buf)) {
if (job.output.p_mframe == nullptr || frames_decoded == 0) {
job.output.p_result->result = ORBIS_AJM_RESULT_NOT_ENOUGH_ROOM;
break;
}
break;
}
const auto [nframes, nsamples] =
m_codec->ProcessData(in_buf, out_buf, m_gapless, samples_remain);
m_codec->ProcessData(in_buf, out_buf, m_gapless, GetNumRemainingSamples());
frames_decoded += nframes;
m_total_samples += nsamples;
m_gapless_samples += nsamples;
@ -138,10 +140,11 @@ bool AjmInstance::IsGaplessEnd() const {
return m_gapless.total_samples != 0 && m_gapless_samples >= m_gapless.total_samples;
}
bool AjmInstance::HasEnoughSpace(const SparseOutputBuffer& output,
std::optional<u32> opt_samples_remain) const {
const auto remain = opt_samples_remain.value_or(std::numeric_limits<u32>::max());
return output.Size() >= m_codec->GetNextFrameSize(remain);
bool AjmInstance::HasEnoughSpace(const SparseOutputBuffer& output) const {
const auto skip =
m_gapless.skip_samples - std::min(m_gapless.skip_samples, m_gapless.skipped_samples);
const auto remain = GetNumRemainingSamples().value_or(std::numeric_limits<u32>::max());
return output.Size() >= m_codec->GetNextFrameSize(skip, remain);
}
std::optional<u32> AjmInstance::GetNumRemainingSamples() const {

View File

@ -66,7 +66,7 @@ public:
virtual void Reset() = 0;
virtual void GetInfo(void* out_info) const = 0;
virtual AjmSidebandFormat GetFormat() const = 0;
virtual u32 GetNextFrameSize(u32 max_samples) const = 0;
virtual u32 GetNextFrameSize(u32 skip_samples, u32 max_samples) const = 0;
virtual std::tuple<u32, u32> ProcessData(std::span<u8>& input, SparseOutputBuffer& output,
AjmSidebandGaplessDecode& gapless,
std::optional<u32> max_samples_per_channel) = 0;
@ -80,7 +80,7 @@ public:
private:
bool IsGaplessEnd() const;
bool HasEnoughSpace(const SparseOutputBuffer& output, std::optional<u32> samples_remain) const;
bool HasEnoughSpace(const SparseOutputBuffer& output) const;
std::optional<u32> GetNumRemainingSamples() const;
AjmInstanceFlags m_flags{};

View File

@ -219,9 +219,10 @@ std::tuple<u32, u32> AjmMp3Decoder::ProcessData(std::span<u8>& in_buf, SparseOut
return {frames_decoded, samples_decoded / m_codec_context->ch_layout.nb_channels};
}
u32 AjmMp3Decoder::GetNextFrameSize(u32 max_samples) const {
return std::min(m_frame_samples, max_samples) * m_codec_context->ch_layout.nb_channels *
GetPCMSize(m_format);
u32 AjmMp3Decoder::GetNextFrameSize(u32 skip_samples, u32 max_samples) const {
skip_samples = std::min({skip_samples, m_frame_samples, max_samples});
return (std::min(m_frame_samples, max_samples) - skip_samples) *
m_codec_context->ch_layout.nb_channels * GetPCMSize(m_format);
}
class BitReader {

View File

@ -70,7 +70,7 @@ public:
void Initialize(const void* buffer, u32 buffer_size) override {}
void GetInfo(void* out_info) const override;
AjmSidebandFormat GetFormat() const override;
u32 GetNextFrameSize(u32 max_samples) const override;
u32 GetNextFrameSize(u32 skip_samples, u32 max_samples) const override;
std::tuple<u32, u32> ProcessData(std::span<u8>& input, SparseOutputBuffer& output,
AjmSidebandGaplessDecode& gapless,
std::optional<u32> max_samples_per_channel) override;