diff options
author | Daniil Cherednik <dan.cherednik@gmail.com> | 2025-04-19 14:07:51 +0200 |
---|---|---|
committer | Daniil Cherednik <dan.cherednik@gmail.com> | 2025-04-19 14:59:17 +0200 |
commit | e4de6009fbe23bb19a0f8135250ac2b514e0db3b (patch) | |
tree | e5aeec735503d4f701477417a009ba9036ba8355 /src/lib/bs_encode | |
parent | 0696e23b2beef4a5525acd5a7013c7d1f3fd2f8e (diff) | |
download | atracdenc-e4de6009fbe23bb19a0f8135250ac2b514e0db3b.tar.gz |
Minimal implementation of AT3P bitstream for residual signal.
* Write scale factor index, wordlen, codetable directly (without VLC)
* Use huffman tables for mantisas
* Some draft of the library to simplify bit allocation code
* Tonal encoding teporary disabled
* Allow c++14
Diffstat (limited to 'src/lib/bs_encode')
-rw-r--r-- | src/lib/bs_encode/encode.cpp | 164 | ||||
-rw-r--r-- | src/lib/bs_encode/encode.h | 67 | ||||
-rw-r--r-- | src/lib/bs_encode/encode_ut.cpp | 162 |
3 files changed, 393 insertions, 0 deletions
diff --git a/src/lib/bs_encode/encode.cpp b/src/lib/bs_encode/encode.cpp new file mode 100644 index 0000000..4c17ce9 --- /dev/null +++ b/src/lib/bs_encode/encode.cpp @@ -0,0 +1,164 @@ +/* + * This file is part of AtracDEnc. + * + * AtracDEnc is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * AtracDEnc is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with AtracDEnc; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "encode.h" + +#include <iostream> + +namespace NAtracDEnc { + +using NBitStream::TBitStream; + +class TBitStreamEncoder::TImpl : public TBitAllocHandler { +public: + explicit TImpl(std::vector<IBitStreamPartEncoder::TPtr>&& encoders); + void DoStart(size_t targetBits, float minLambda, float maxLambda) noexcept; + float DoContinue() noexcept; + void DoSubmit(size_t gotBits) noexcept; + bool DoCheck(size_t gotBits) const noexcept; + void DoRun(void* frameData, TBitStream& bs); +private: + std::vector<IBitStreamPartEncoder::TPtr> Encoders; + size_t CurEncPos; + size_t RepeatEncPos; + + size_t TargetBits; + float MinLambda; + float MaxLambda; + float CurLambda; + float LastLambda; + + bool NeedRepeat = false; +}; + +TBitStreamEncoder::TImpl::TImpl(std::vector<IBitStreamPartEncoder::TPtr>&& encoders) + : Encoders(std::move(encoders)) + , CurEncPos(0) + , RepeatEncPos(0) +{ +} + +void TBitStreamEncoder::TImpl::DoStart(size_t targetBits, float minLambda, float maxLambda) noexcept +{ + TargetBits = targetBits; + MinLambda = minLambda; + MaxLambda = maxLambda; +} + +float TBitStreamEncoder::TImpl::DoContinue() noexcept +{ + if (MaxLambda <= MinLambda) { + return LastLambda; + } + + CurLambda = (MaxLambda + MinLambda) / 2.0; + RepeatEncPos = CurEncPos; + return CurLambda; +} + +void TBitStreamEncoder::TImpl::DoSubmit(size_t gotBits) noexcept +{ + if (MaxLambda <= MinLambda) { + NeedRepeat = false; + } else { + if (gotBits < TargetBits) { + LastLambda = CurLambda; + MaxLambda = CurLambda - 0.01f; + NeedRepeat = true; + } else if (gotBits > TargetBits) { + MinLambda = CurLambda + 0.01f; + NeedRepeat = true; + } else { + NeedRepeat = false; + } + } +} + +bool TBitStreamEncoder::TImpl::DoCheck(size_t gotBits) const noexcept +{ + return gotBits < TargetBits; +} + +void TBitStreamEncoder::TImpl::DoRun(void* frameData, TBitStream& bs) +{ + bool cont = false; + do { + for (CurEncPos = RepeatEncPos; CurEncPos < Encoders.size(); CurEncPos++) { + auto status = Encoders[CurEncPos]->Encode(frameData, *this); + if (NeedRepeat) { + NeedRepeat = false; + cont = true; + break; + } else { + cont = false; + } + if (status == IBitStreamPartEncoder::EStatus::Repeat) { + cont = true; + RepeatEncPos = 0; + break; + } + } + } while (cont); + + for (size_t i = 0; i < Encoders.size(); i++) { + Encoders[i]->Dump(bs); + } +} + +///// + +TBitStreamEncoder::TBitStreamEncoder(std::vector<IBitStreamPartEncoder::TPtr>&& encoders) + : Impl(new TBitStreamEncoder::TImpl(std::move(encoders))) +{} + +TBitStreamEncoder::~TBitStreamEncoder() +{ + delete Impl; +} + +void TBitStreamEncoder::Do(void* frameData, TBitStream& bs) +{ + Impl->DoRun(frameData, bs); +} + +///// + +void TBitAllocHandler::Start(size_t targetBits, float minLambda, float maxLambda) noexcept +{ + TBitStreamEncoder::TImpl* self = static_cast<TBitStreamEncoder::TImpl*>(this); + self->DoStart(targetBits, minLambda, maxLambda); +} + +float TBitAllocHandler::Continue() noexcept +{ + TBitStreamEncoder::TImpl* self = static_cast<TBitStreamEncoder::TImpl*>(this); + return self->DoContinue(); +} + +void TBitAllocHandler::Submit(size_t gotBits) noexcept +{ + TBitStreamEncoder::TImpl* self = static_cast<TBitStreamEncoder::TImpl*>(this); + self->DoSubmit(gotBits); +} + +bool TBitAllocHandler::Check(size_t gotBits) const noexcept +{ + const TBitStreamEncoder::TImpl* self = static_cast<const TBitStreamEncoder::TImpl*>(this); + return self->DoCheck(gotBits); +} +} diff --git a/src/lib/bs_encode/encode.h b/src/lib/bs_encode/encode.h new file mode 100644 index 0000000..9671e10 --- /dev/null +++ b/src/lib/bs_encode/encode.h @@ -0,0 +1,67 @@ +/* + * This file is part of AtracDEnc. + * + * AtracDEnc is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * AtracDEnc is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with AtracDEnc; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#pragma once + +#include <memory> +#include <vector> +#include <functional> + +namespace NBitStream { +class TBitStream; +} + +namespace NAtracDEnc { + +class TBitAllocHandler { +public: + void Start(size_t targetBits, float minLambda, float maxLambda) noexcept; + float Continue() noexcept; + bool Check(size_t gitBits) const noexcept; + void Submit(size_t gotBits) noexcept; +}; + +class IBitStreamPartEncoder { +public: + using TPtr = std::unique_ptr<IBitStreamPartEncoder>; + enum class EStatus { + Ok, // Ok, go to the next stage + Repeat, // Repeat from first stage + }; + + virtual ~IBitStreamPartEncoder() = default; + virtual EStatus Encode(void* frameData, TBitAllocHandler& ba) = 0; + virtual void Dump(NBitStream::TBitStream& bs) = 0; + +}; + +class TBitStreamEncoder { +public: + class TImpl; + explicit TBitStreamEncoder(std::vector<IBitStreamPartEncoder::TPtr>&& encoders); + ~TBitStreamEncoder(); + + void Do(void* frameData, NBitStream::TBitStream& bs); + TBitStreamEncoder(const TBitStreamEncoder&) = delete; + TBitStreamEncoder& operator=(const TBitStreamEncoder&) = delete; +private: + std::vector<IBitStreamPartEncoder::TPtr> Encoders; + TImpl* Impl; +}; + +} diff --git a/src/lib/bs_encode/encode_ut.cpp b/src/lib/bs_encode/encode_ut.cpp new file mode 100644 index 0000000..e9293a2 --- /dev/null +++ b/src/lib/bs_encode/encode_ut.cpp @@ -0,0 +1,162 @@ +/* + * This file is part of AtracDEnc. + * + * AtracDEnc is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * AtracDEnc is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with AtracDEnc; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "encode.h" +#include <gtest/gtest.h> +#include <cmath> +#include <memory> +#include <bitstream/bitstream.h> + +using namespace NAtracDEnc; + +static size_t SomeBitFn1(float lambda) { + return sqrt(lambda * (-1.0f)) * 300; +} + +static size_t SomeBitFn2(float lambda) { + return 1 + (SomeBitFn1(lambda) & (~(size_t)7)); +} + +class TPartEncoder1 : public IBitStreamPartEncoder { +public: + explicit TPartEncoder1(size_t expCalls) + : ExpCalls(expCalls) + {} + + EStatus Encode(void* frameData, TBitAllocHandler& ba) override { + EncCalls++; + ba.Start(1000, -15, -1); + return EStatus::Ok; + } + + void Dump(NBitStream::TBitStream& bs) override { + EXPECT_EQ(EncCalls, ExpCalls); + } +private: + const size_t ExpCalls; + size_t EncCalls = 0; +}; + +template<size_t (*F)(float)> +class TPartEncoder2 : public IBitStreamPartEncoder { +public: + explicit TPartEncoder2(size_t expCalls) + : ExpCalls(expCalls) + {} + + EStatus Encode(void* frameData, TBitAllocHandler& ba) override { + EncCalls++; + auto lambda = ba.Continue(); + auto bits = F(lambda); + ba.Submit(bits); + Bits = bits; + return EStatus::Ok; + } + + void Dump(NBitStream::TBitStream& bs) override { + EXPECT_EQ(EncCalls, ExpCalls); + for (size_t i = 0; i < Bits; i++) { + bs.Write(1, 1); + } + } +private: + const size_t ExpCalls; + size_t EncCalls = 0; + size_t Bits = 0; +}; + +class TPartEncoder3 : public IBitStreamPartEncoder { +public: + explicit TPartEncoder3(size_t expCalls) + : ExpCalls(expCalls) + {} + + EStatus Encode(void* frameData, TBitAllocHandler& ba) override { + EncCalls++; + return EStatus::Ok; + } + + void Dump(NBitStream::TBitStream& bs) override { + EXPECT_EQ(EncCalls, ExpCalls); + } +private: + const size_t ExpCalls; + size_t EncCalls = 0; +}; + +class TPartEncoder4 : public IBitStreamPartEncoder { +public: + TPartEncoder4() = default; + + EStatus Encode(void* frameData, TBitAllocHandler& ba) override { + if (EncCalls == 0) { + EncCalls++; + return EStatus::Repeat; + } + + return EStatus::Ok; + } + + void Dump(NBitStream::TBitStream& bs) override { + EXPECT_EQ(EncCalls, 1); + } +private: + size_t EncCalls = 0; +}; + +TEST(BsEncode, SimpleAlloc) { + std::vector<IBitStreamPartEncoder::TPtr> encoders; + encoders.emplace_back(std::make_unique<TPartEncoder1>(1)); + encoders.emplace_back(std::make_unique<TPartEncoder2<SomeBitFn1>>(8)); + encoders.emplace_back(std::make_unique<TPartEncoder3>(1)); + + NBitStream::TBitStream bs; + TBitStreamEncoder encoder(std::move(encoders)); + encoder.Do(nullptr, bs); + + EXPECT_EQ(bs.GetSizeInBits(), 1000); +} + +TEST(BsEncode, AllocWithRepeat) { + std::vector<IBitStreamPartEncoder::TPtr> encoders; + encoders.emplace_back(std::make_unique<TPartEncoder1>(2)); + encoders.emplace_back(std::make_unique<TPartEncoder2<SomeBitFn1>>(16)); + encoders.emplace_back(std::make_unique<TPartEncoder3>(2)); + encoders.emplace_back(std::make_unique<TPartEncoder4>()); + + NBitStream::TBitStream bs; + TBitStreamEncoder encoder(std::move(encoders)); + encoder.Do(nullptr, bs); + + EXPECT_EQ(bs.GetSizeInBits(), 1000); +} + +TEST(BsEncode, NotExactAlloc) { + std::vector<IBitStreamPartEncoder::TPtr> encoders; + encoders.emplace_back(std::make_unique<TPartEncoder1>(1)); + encoders.emplace_back(std::make_unique<TPartEncoder2<SomeBitFn2>>(11)); + encoders.emplace_back(std::make_unique<TPartEncoder3>(1)); + + NBitStream::TBitStream bs; + TBitStreamEncoder encoder(std::move(encoders)); + encoder.Do(nullptr, bs); + + EXPECT_EQ(bs.GetSizeInBits(), 993); +} + + |