diff options
author | Daniil Cherednik <dan.cherednik@gmail.com> | 2025-05-03 22:07:17 +0200 |
---|---|---|
committer | Daniil Cherednik <dan.cherednik@gmail.com> | 2025-05-03 22:07:17 +0200 |
commit | 98338613d8821f592682928c1096550596cb2550 (patch) | |
tree | abc2318c96ee2a14f06ba1028fb8663f6a6ee35a /src | |
parent | 177622ee9513784a21d9f10ab0c1e9774c0ddc71 (diff) | |
download | atracdenc-98338613d8821f592682928c1096550596cb2550.tar.gz |
[AT3P] Adjust number of quant units during encoding.
Diffstat (limited to 'src')
-rw-r--r-- | src/atrac/at3p/at3p_bitstream.cpp | 172 | ||||
-rw-r--r-- | src/atrac/at3p/at3p_bitstream.h | 1 | ||||
-rw-r--r-- | src/atrac/at3p/at3p_bitstream_impl.h | 34 | ||||
-rw-r--r-- | src/atrac/at3p/at3p_bitstream_ut.cpp | 2 | ||||
-rw-r--r-- | src/lib/bs_encode/encode.cpp | 20 | ||||
-rw-r--r-- | src/lib/bs_encode/encode.h | 6 | ||||
-rw-r--r-- | src/lib/bs_encode/encode_ut.cpp | 16 |
7 files changed, 179 insertions, 72 deletions
diff --git a/src/atrac/at3p/at3p_bitstream.cpp b/src/atrac/at3p/at3p_bitstream.cpp index f00fe31..f95018b 100644 --- a/src/atrac/at3p/at3p_bitstream.cpp +++ b/src/atrac/at3p/at3p_bitstream.cpp @@ -92,32 +92,30 @@ TTonePackResult CreateFreqBitPack(const TAt3PGhaData::TWaveParam* const param, i } } -size_t TDumper::GetConsumption() const noexcept +uint32_t TDumper::GetConsumption() const noexcept { return std::accumulate(Buf.begin(), Buf.end(), 0, - [](size_t acc, const std::pair<uint8_t, uint8_t>& x) noexcept -> size_t { return acc + x.second; }); + [](uint32_t acc, const std::pair<uint16_t, uint8_t>& x) noexcept -> uint32_t { return acc + x.second; }); } IBitStreamPartEncoder::EStatus TConfigure::Encode(void* frameData, TBitAllocHandler&) { TSpecFrame* frame = TSpecFrame::Cast(frameData); - size_t numQuantUnits = 28; - frame->NumQuantUnits = numQuantUnits; - frame->WordLen.resize(numQuantUnits); + frame->WordLen.resize(frame->NumQuantUnits); for (size_t i = 0; i < frame->WordLen.size(); i++) { static uint8_t allocTable[32] = { - 7, 7, 7, 7, 7, 6, 6, 6, - 6, 6, 6, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 4, - 3, 2, 1, 1, 1, 1, 1, 1 + 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, + 7, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 5, 5, 4, 3, 2, 1 }; frame->WordLen[i].first = allocTable[i]; frame->WordLen[i].second = allocTable[i]; } - frame->SfIdx.resize(numQuantUnits); + frame->SfIdx.resize(frame->NumQuantUnits); for (size_t i = 0; i < frame->SfIdx.size(); i++) { frame->SfIdx[i].first = frame->Chs[0].ScaledBlocks.at(i).ScaleFactorIndex; @@ -125,9 +123,9 @@ IBitStreamPartEncoder::EStatus TConfigure::Encode(void* frameData, TBitAllocHand frame->SfIdx[i].second = frame->Chs[1].ScaledBlocks.at(i).ScaleFactorIndex; } - frame->SpecTabIdx.resize(numQuantUnits); + frame->SpecTabIdx.resize(frame->NumQuantUnits); - Insert(numQuantUnits - 1, 5); + Insert(frame->NumQuantUnits - 1, 5); Insert(0, 1); //mute flag frame->AllocatedBits = GetConsumption(); @@ -381,6 +379,7 @@ static std::vector<IBitStreamPartEncoder::TPtr> CreateEncParts() parts.emplace_back(new TWordLenEncoder()); parts.emplace_back(new TSfIdxEncoder()); parts.emplace_back(new TQuantUnitsEncoder()); + parts.emplace_back(new TTonalComponentEncoder()); return parts; } @@ -388,52 +387,53 @@ static std::vector<IBitStreamPartEncoder::TPtr> CreateEncParts() TAt3PBitStream::TAt3PBitStream(ICompressedOutput* container, uint16_t frameSz) : Container(container) , Encoder(CreateEncParts()) + , FrameSzToAllocBits((uint32_t)frameSz * 8 - 3) //Size of frame in bits for allocation. 3 bits is start bit and channel configuration , FrameSz(frameSz) { NEnv::SetRoundFloat(); } -static void WriteSubbandFlags(NBitStream::TBitStream& bs, const bool* flags, int numFlags) +void TTonalComponentEncoder::WriteSubbandFlags(const bool* flags, size_t numFlags) { - int sum = 0; - for (int i = 0; i < numFlags; i++) { + size_t sum = 0; + for (size_t i = 0; i < numFlags; i++) { sum += (uint32_t)flags[i]; } if (sum == 0) { - bs.Write(0, 1); + Insert(0, 1); } else if (sum == numFlags) { - bs.Write(1, 1); - bs.Write(0, 1); + Insert(1, 1); + Insert(0, 1); } else { - bs.Write(1, 1); - bs.Write(1, 1); - for (int i = 0; i < numFlags; i++) { - bs.Write(flags[i], 1); + Insert(1, 1); + Insert(1, 1); + for (size_t i = 0; i < numFlags; i++) { + Insert(flags[i], 1); } } } -static void WriteTonalBlock(NBitStream::TBitStream& bs, int channels, const TAt3PGhaData* tonalBlock) +void TTonalComponentEncoder::WriteTonalBlock(size_t channels, const TAt3PGhaData* tonalBlock) { //GHA amplidude mode 1 - bs.Write(1, 1); + Insert(1, 1); //Num tone bands const TVlcElement& tbHuff = HuffTabs.NumToneBands[tonalBlock->NumToneBands - 1]; - bs.Write(tbHuff.Code, tbHuff.Len); + Insert(tbHuff.Code, tbHuff.Len); if (channels == 2) { - WriteSubbandFlags(bs, tonalBlock->ToneSharing, tonalBlock->NumToneBands); - WriteSubbandFlags(bs, &tonalBlock->SecondIsLeader, 1); - bs.Write(0, 1); + WriteSubbandFlags(tonalBlock->ToneSharing, tonalBlock->NumToneBands); + WriteSubbandFlags(&tonalBlock->SecondIsLeader, 1); + Insert(0, 1); } - for (int ch = 0; ch < channels; ch++) { + for (size_t ch = 0; ch < channels; ch++) { if (ch) { // each channel has own envelope - bs.Write(0, 1); + Insert(0, 1); } // Envelope data for (int i = 0; i < tonalBlock->NumToneBands; i++) { @@ -445,35 +445,35 @@ static void WriteTonalBlock(NBitStream::TBitStream& bs, int channels, const TAt3 if (envelope.first != TAt3PGhaData::EMPTY_POINT) { // start point present - bs.Write(1, 1); - bs.Write(envelope.first, 5); + Insert(1, 1); + Insert(envelope.first, 5); } else { - bs.Write(0, 1); + Insert(0, 1); } if (envelope.second != TAt3PGhaData::EMPTY_POINT) { // stop point present - bs.Write(1, 1); - bs.Write(envelope.second, 5); + Insert(1, 1); + Insert(envelope.second, 5); } else { - bs.Write(0, 1); + Insert(0, 1); } } // Num waves int mode = 0; //TODO: Calc mode - bs.Write(mode, ch + 1); + Insert(mode, ch + 1); for (int i = 0; i < tonalBlock->NumToneBands; i++) { if (ch && tonalBlock->ToneSharing[i]) { continue; } - bs.Write(tonalBlock->GetNumWaves(ch, i), 4); + Insert(tonalBlock->GetNumWaves(ch, i), 4); } // Tones freq if (ch) { // 0 - independed // 1 - delta to leader - bs.Write(0, 1); + Insert(0, 1); } for (int i = 0; i < tonalBlock->NumToneBands; i++) { @@ -490,17 +490,17 @@ static void WriteTonalBlock(NBitStream::TBitStream& bs, int channels, const TAt3 const auto pkt = CreateFreqBitPack(w.first, w.second); if (numWaves > 1) { - bs.Write(static_cast<bool>(pkt.Order), 1); + Insert(static_cast<bool>(pkt.Order), 1); } for (const auto& d : pkt.Data) { - bs.Write(d.Code, d.Bits); + Insert(d.Code, d.Bits); } } // Amplitude mode = 0; //TODO: Calc mode - bs.Write(mode, ch + 1); + Insert(mode, ch + 1); for (int i = 0; i < tonalBlock->NumToneBands; i++) { if (ch && tonalBlock->ToneSharing[i]) { @@ -514,7 +514,7 @@ static void WriteTonalBlock(NBitStream::TBitStream& bs, int channels, const TAt3 const auto w = tonalBlock->GetWaves(ch, i); for (size_t j = 0; j < numWaves; j++) { - bs.Write(w.first[j].AmpSf, 6); + Insert(w.first[j].AmpSf, 6); } } @@ -531,52 +531,92 @@ static void WriteTonalBlock(NBitStream::TBitStream& bs, int channels, const TAt3 const auto w = tonalBlock->GetWaves(ch, i); for (size_t j = 0; j < w.second; j++) { - bs.Write(w.first[j].PhaseIndex, 5); + Insert(w.first[j].PhaseIndex, 5); } } } } -void TAt3PBitStream::WriteFrame(int channels, const TAt3PGhaData* tonalBlock, const std::vector<std::vector<TScaledBlock>>& scaledBlocks) +IBitStreamPartEncoder::EStatus TTonalComponentEncoder::CheckFrameDone(TSpecFrame* frame, TBitAllocHandler& ba) noexcept { - NBitStream::TBitStream bitStream; - // First bit must be zero - bitStream.Write(0, 1); - // Channel block type - // 0 - MONO block - // 1 - STEREO block - // 2 - Nobody know - bitStream.Write(channels - 1, 2); + uint32_t totalConsumption = BitsUsed + ba.GetCurGlobalConsumption(); - TSpecFrame frame(FrameSz * 8, channels, scaledBlocks); + if (totalConsumption > frame->SizeBits) { + if (frame->NumQuantUnits == 32) { + frame->NumQuantUnits = 28; + } else { + frame->NumQuantUnits--; + } + return EStatus::Repeat; + } + return EStatus::Ok; +} - Encoder.Do(&frame, bitStream); +IBitStreamPartEncoder::EStatus TTonalComponentEncoder::Encode(void* frameData, TBitAllocHandler& ba) +{ + auto specFrame = TSpecFrame::Cast(frameData); + auto tonalBlock = specFrame->TonalBlock; - if (channels == 2) { - bitStream.Write(0, 2); //swap_channels and negate_coeffs + // Check tonal component already encoded + if (BitsUsed != 0) { + if (tonalBlock && tonalBlock->NumToneBands > specFrame->NumQuantUnits) { + std::cerr << "TODO" << std::endl; + abort(); + } + return CheckFrameDone(specFrame, ba); + } + + const size_t chNum = specFrame->Chs.size(); + + if (chNum == 2) { + Insert(0, 2); //swap_channels and negate_coeffs } - for (size_t ch = 0; ch < frame.Chs.size(); ch++) { - bitStream.Write(0, 1); // window shape + for (size_t ch = 0; ch < chNum; ch++) { + Insert(0, 1); // window shape } - for (size_t ch = 0; ch < frame.Chs.size(); ch++) { - bitStream.Write(0, 1); //gain comp + for (size_t ch = 0; ch < chNum; ch++) { + Insert(0, 1); //gain comp } if (tonalBlock && tonalBlock->NumToneBands) { - bitStream.Write(1, 1); - WriteTonalBlock(bitStream, channels, tonalBlock); + Insert(1, 1); + WriteTonalBlock(chNum, tonalBlock); } else { - bitStream.Write(0, 1); + Insert(0, 1); } - bitStream.Write(0, 1); // no noise info + Insert(0, 1); // no noise info // Terminator - bitStream.Write(3, 2); + Insert(3, 2); + + BitsUsed = GetConsumption(); + + return CheckFrameDone(specFrame, ba); +} + +void TAt3PBitStream::WriteFrame(int channels, const TAt3PGhaData* tonalBlock, const std::vector<std::vector<TScaledBlock>>& scaledBlocks) +{ + NBitStream::TBitStream bitStream; + // First bit must be zero + bitStream.Write(0, 1); + // Channel block type + // 0 - MONO block + // 1 - STEREO block + // 2 - Nobody know + bitStream.Write(channels - 1, 2); + + const uint32_t initialNumQuantUnits = 32; + + TSpecFrame frame(FrameSzToAllocBits, initialNumQuantUnits, channels, tonalBlock, scaledBlocks); + + Encoder.Do(&frame, bitStream); std::vector<char> buf = bitStream.GetBytes(); + ASSERT(bitStream.GetSizeInBits() > FrameSz * 8); + buf.resize(FrameSz); Container->WriteFrame(buf); } diff --git a/src/atrac/at3p/at3p_bitstream.h b/src/atrac/at3p/at3p_bitstream.h index 4baba4d..c42a151 100644 --- a/src/atrac/at3p/at3p_bitstream.h +++ b/src/atrac/at3p/at3p_bitstream.h @@ -52,6 +52,7 @@ public: private: ICompressedOutput* Container; TBitStreamEncoder Encoder; + const uint32_t FrameSzToAllocBits; const uint16_t FrameSz; }; diff --git a/src/atrac/at3p/at3p_bitstream_impl.h b/src/atrac/at3p/at3p_bitstream_impl.h index 52a86a5..91b2df2 100644 --- a/src/atrac/at3p/at3p_bitstream_impl.h +++ b/src/atrac/at3p/at3p_bitstream_impl.h @@ -18,6 +18,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "atrac/at3p/at3p_gha.h" #include <lib/bitstream/bitstream.h> #include <lib/bs_encode/encode.h> #include <atrac/atrac_scale.h> @@ -26,9 +27,12 @@ namespace NAtracDEnc { struct TSpecFrame { - TSpecFrame(size_t sz, size_t channels, + TSpecFrame(uint32_t sz, uint32_t numQuantUnits, size_t channels, + const TAt3PGhaData* tonalBlock, const std::vector<std::vector<TScaledBlock>>& scaledBlocks) : SizeBits(sz) + , NumQuantUnits(numQuantUnits) + , TonalBlock(tonalBlock) , AllocatedBits(0) { Chs.reserve(channels); @@ -37,8 +41,9 @@ struct TSpecFrame { } } - const size_t SizeBits; - size_t NumQuantUnits; + const uint32_t SizeBits; + uint32_t NumQuantUnits; + const TAt3PGhaData* TonalBlock; std::vector<std::pair<uint8_t, uint8_t>> WordLen; std::vector<std::pair<uint8_t, uint8_t>> SfIdx; std::vector<std::pair<uint8_t, uint8_t>> SpecTabIdx; @@ -63,8 +68,12 @@ public: } Buf.clear(); } + void Reset() noexcept override { + Buf.clear(); + } + uint32_t GetConsumption() const noexcept override; protected: - size_t GetConsumption() const noexcept; + // value, nbits void Insert(uint16_t value, uint8_t nbits) { Buf.emplace_back(std::make_pair(value, nbits)); } std::vector<std::pair<uint16_t, uint8_t>> Buf; @@ -120,4 +129,21 @@ private: std::map<size_t, TUnit> UnitBuffers; }; +class TTonalComponentEncoder : public TDumper { +public: + TTonalComponentEncoder() = default; + EStatus Encode(void* frameData, TBitAllocHandler& ba) override; + //TODO: find the common way + void Dump(NBitStream::TBitStream& bs) override { + TDumper::Dump(bs); + BitsUsed = 0; + } +private: + EStatus CheckFrameDone(TSpecFrame* frame, TBitAllocHandler& ba) noexcept; + void WriteTonalBlock(size_t channels, const TAt3PGhaData* tonalBlock); + void WriteSubbandFlags(const bool* flags, size_t numFlags); + size_t BitsUsed = 0; +}; + + } diff --git a/src/atrac/at3p/at3p_bitstream_ut.cpp b/src/atrac/at3p/at3p_bitstream_ut.cpp index ddc33f3..a4d7bd7 100644 --- a/src/atrac/at3p/at3p_bitstream_ut.cpp +++ b/src/atrac/at3p/at3p_bitstream_ut.cpp @@ -128,7 +128,7 @@ TEST(AT3PBitstream, Wordlen) { std::vector<std::vector<TScaledBlock>> scaledBlocks; scaledBlocks.resize(2); - TSpecFrame frame(444, 2, scaledBlocks); + TSpecFrame frame(444, 28, 2, nullptr, scaledBlocks); FillFrameData(frame); diff --git a/src/lib/bs_encode/encode.cpp b/src/lib/bs_encode/encode.cpp index 4c17ce9..230ae0f 100644 --- a/src/lib/bs_encode/encode.cpp +++ b/src/lib/bs_encode/encode.cpp @@ -32,6 +32,7 @@ public: void DoSubmit(size_t gotBits) noexcept; bool DoCheck(size_t gotBits) const noexcept; void DoRun(void* frameData, TBitStream& bs); + uint32_t DoGetCurGlobalConsumption() const noexcept; private: std::vector<IBitStreamPartEncoder::TPtr> Encoders; size_t CurEncPos; @@ -109,6 +110,9 @@ void TBitStreamEncoder::TImpl::DoRun(void* frameData, TBitStream& bs) } if (status == IBitStreamPartEncoder::EStatus::Repeat) { cont = true; + for (size_t i = 0; i < CurEncPos; i++) { + Encoders[i]->Reset(); + } RepeatEncPos = 0; break; } @@ -120,6 +124,15 @@ void TBitStreamEncoder::TImpl::DoRun(void* frameData, TBitStream& bs) } } +uint32_t TBitStreamEncoder::TImpl::DoGetCurGlobalConsumption() const noexcept +{ + uint32_t consumption = 0; + for (size_t i = 0; i < CurEncPos; i++) { + consumption += Encoders[i]->GetConsumption(); + } + return consumption; +} + ///// TBitStreamEncoder::TBitStreamEncoder(std::vector<IBitStreamPartEncoder::TPtr>&& encoders) @@ -161,4 +174,11 @@ bool TBitAllocHandler::Check(size_t gotBits) const noexcept const TBitStreamEncoder::TImpl* self = static_cast<const TBitStreamEncoder::TImpl*>(this); return self->DoCheck(gotBits); } + +uint32_t TBitAllocHandler::GetCurGlobalConsumption() const noexcept +{ + const TBitStreamEncoder::TImpl* self = static_cast<const TBitStreamEncoder::TImpl*>(this); + return self->DoGetCurGlobalConsumption(); +} + } diff --git a/src/lib/bs_encode/encode.h b/src/lib/bs_encode/encode.h index 9671e10..3302d10 100644 --- a/src/lib/bs_encode/encode.h +++ b/src/lib/bs_encode/encode.h @@ -34,6 +34,9 @@ public: float Continue() noexcept; bool Check(size_t gitBits) const noexcept; void Submit(size_t gotBits) noexcept; + + // Returns consumption of all previous encoded parts (except part from this method called) + uint32_t GetCurGlobalConsumption() const noexcept; }; class IBitStreamPartEncoder { @@ -47,7 +50,8 @@ public: virtual ~IBitStreamPartEncoder() = default; virtual EStatus Encode(void* frameData, TBitAllocHandler& ba) = 0; virtual void Dump(NBitStream::TBitStream& bs) = 0; - + virtual void Reset() noexcept {}; + virtual uint32_t GetConsumption() const noexcept = 0; }; class TBitStreamEncoder { diff --git a/src/lib/bs_encode/encode_ut.cpp b/src/lib/bs_encode/encode_ut.cpp index e9293a2..39f0ff1 100644 --- a/src/lib/bs_encode/encode_ut.cpp +++ b/src/lib/bs_encode/encode_ut.cpp @@ -47,6 +47,10 @@ public: void Dump(NBitStream::TBitStream& bs) override { EXPECT_EQ(EncCalls, ExpCalls); } + + uint32_t GetConsumption() const noexcept override { + return 0; + } private: const size_t ExpCalls; size_t EncCalls = 0; @@ -74,6 +78,10 @@ public: bs.Write(1, 1); } } + + uint32_t GetConsumption() const noexcept override { + return 1 * Bits; + } private: const size_t ExpCalls; size_t EncCalls = 0; @@ -94,6 +102,10 @@ public: void Dump(NBitStream::TBitStream& bs) override { EXPECT_EQ(EncCalls, ExpCalls); } + + uint32_t GetConsumption() const noexcept override { + return 0; + } private: const size_t ExpCalls; size_t EncCalls = 0; @@ -115,6 +127,10 @@ public: void Dump(NBitStream::TBitStream& bs) override { EXPECT_EQ(EncCalls, 1); } + + uint32_t GetConsumption() const noexcept override { + return 0; + } private: size_t EncCalls = 0; }; |