/* Copyright 2020 InterDigital Communications, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* Rans64 extensions from: * https://fgiesen.wordpress.com/2015/12/21/rans-in-practice/ * Unbounded range coding from: * https://github.com/tensorflow/compression/blob/master/tensorflow_compression/cc/kernels/unbounded_index_range_coding_kernels.cc **/ #include "rans.h" #include #include #include constexpr uint16_t bypass_precision = 2; /* number of bits in bypass mode */ constexpr uint16_t max_bypass_val = (1 << bypass_precision) - 1; inline void RansEncPutBits(RansState& r, uint8_t*& ptr, uint32_t val) { RansAssert(bypass_precision <= 8); RansAssert(val < (1u << bypass_precision)); constexpr uint32_t freq = 1 << (SCALE_BITS - bypass_precision); constexpr uint32_t x_max = freq << ENC_RENORM_SHIFT_BITS; while (r >= x_max) { *(--ptr) = static_cast(r & 0xff); r >>= 8; } r = (r << bypass_precision) | val; } inline uint32_t RansDecGetBits(RansState& r, uint8_t*& ptr) { uint32_t val = r & ((1u << bypass_precision) - 1); /* Re-normalize */ r = r >> bypass_precision; if (r < RANS_BYTE_L) { r = (r << 8) | *ptr++; RansAssert(r >= RANS_BYTE_L); } return val; } RansEncoderLib::RansEncoderLib() { _stream = std::make_shared>(); } int RansEncoderLib::add_cdf(const std::shared_ptr>> cdfs, const std::shared_ptr> cdfs_sizes, const std::shared_ptr> offsets) { auto ransSymbols = std::make_shared>>(cdfs->size()); for (int i = 0; i < static_cast(cdfs->size()); i++) { const int32_t* cdf = cdfs->at(i).data(); std::vector ransSym(cdfs->at(i).size()); const int ransSize = static_cast(ransSym.size() - 1); for (int j = 0; j < ransSize; j++) { ransSym[j] = RansSymbol( { static_cast(cdf[j]), static_cast(cdf[j + 1] - cdf[j]) }); } ransSymbols->at(i) = ransSym; } _ransSymbols.push_back(ransSymbols); _cdfs_sizes.push_back(cdfs_sizes); _offsets.push_back(offsets); return static_cast(_ransSymbols.size()) - 1; } void RansEncoderLib::empty_cdf_buffer() { _ransSymbols.clear(); _cdfs_sizes.clear(); _offsets.clear(); } FORCE_INLINE void RansEncoderLib::encode_one_symbol(uint8_t*& ptr, RansState& rans, const int32_t symbol, const int32_t cdf_size, const int32_t offset, const std::vector& ransSymbols) { const int32_t max_value = cdf_size - 2; int32_t value = symbol - offset; uint32_t raw_val = 0; if (value < 0) { raw_val = -2 * value - 1; value = max_value; } else if (value >= max_value) { raw_val = 2 * (value - max_value); value = max_value; } if (value == max_value) { std::vector bypassBins; bypassBins.reserve(20); /* Determine the number of bypasses (in bypass_precision size) needed to * encode the raw value. */ int32_t n_bypass = 0; while ((raw_val >> (n_bypass * bypass_precision)) != 0) { ++n_bypass; } /* Encode number of bypasses */ int32_t val = n_bypass; while (val >= max_bypass_val) { bypassBins.push_back(max_bypass_val); val -= max_bypass_val; } bypassBins.push_back(static_cast(val)); /* Encode raw value */ for (int32_t j = 0; j < n_bypass; ++j) { const int32_t val1 = (raw_val >> (j * bypass_precision)) & max_bypass_val; bypassBins.push_back(static_cast(val1)); } for (auto it = bypassBins.rbegin(); it < bypassBins.rend(); it++) { RansEncPutBits(rans, ptr, *it); } } RansEncPut(rans, ptr, ransSymbols[value].start, ransSymbols[value].range); } void RansEncoderLib::encode_y(const std::shared_ptr> symbols, const int cdf_group_index) { PendingTask p; p.workType = WorkType::EncodeDecodeY; p.symbols_y = symbols; p.cdf_group_index = cdf_group_index; m_pendingEncodingList.push_back(p); } void RansEncoderLib::encode_z(const std::shared_ptr> symbols, const int cdf_group_index, const int start_offset, const int per_channel_size) { PendingTask p; p.workType = WorkType::EncodeDecodeZ; p.symbols_z = symbols; p.cdf_group_index = cdf_group_index; p.start_offset = start_offset; p.per_channel_size = per_channel_size; m_pendingEncodingList.push_back(p); } #include FORCE_INLINE void RansEncoderLib::encode_y_internal(uint8_t*& ptr, RansState& rans, const std::shared_ptr> symbols, const int cdf_group_index) { // backward loop on symbols from the end; const int16_t* symbols_ptr = symbols->data(); const int32_t* cdfs_sizes_ptr = _cdfs_sizes[cdf_group_index]->data(); const int32_t* offsets_ptr = _offsets[cdf_group_index]->data(); const int symbol_size = static_cast(symbols->size()); for (int i = symbol_size - 1; i >= 0; i--) { const int32_t combined_symbol = symbols_ptr[i]; const int32_t cdf_idx = combined_symbol & 0xff; const int32_t s = combined_symbol >> 8; encode_one_symbol(ptr, rans, s, cdfs_sizes_ptr[cdf_idx], offsets_ptr[cdf_idx], _ransSymbols[cdf_group_index]->at(cdf_idx)); } } FORCE_INLINE void RansEncoderLib::encode_z_internal(uint8_t*& ptr, RansState& rans, const std::shared_ptr> symbols, const int cdf_group_index, const int start_offset, const int per_channel_size) { // backward loop on symbols from the end; const int8_t* symbols_ptr = symbols->data(); const int32_t* cdfs_sizes_ptr = _cdfs_sizes[cdf_group_index]->data(); const int32_t* offsets_ptr = _offsets[cdf_group_index]->data(); const int symbol_size = static_cast(symbols->size()); for (int i = symbol_size - 1; i >= 0; i--) { const int32_t cdf_idx = i / per_channel_size + start_offset; encode_one_symbol(ptr, rans, symbols_ptr[i], cdfs_sizes_ptr[cdf_idx], offsets_ptr[cdf_idx], _ransSymbols[cdf_group_index]->at(cdf_idx)); } } void RansEncoderLib::flush() { RansState rans; RansEncInit(rans); int32_t total_symbol_size = 0; for (auto it = m_pendingEncodingList.begin(); it != m_pendingEncodingList.end(); it++) { if (it->workType == WorkType::EncodeDecodeY) { total_symbol_size += static_cast(it->symbols_y->size()); } else if (it->workType == WorkType::EncodeDecodeZ) { total_symbol_size += static_cast(it->symbols_z->size()); } } if (total_symbol_size == 0) { _stream->resize(0); return; } uint8_t* output = new uint8_t[total_symbol_size]; // too much space ? uint8_t* ptrEnd = output + total_symbol_size; uint8_t* ptr = ptrEnd; assert(ptr != nullptr); for (auto it = m_pendingEncodingList.rbegin(); it != m_pendingEncodingList.rend(); it++) { PendingTask p = *it; if (p.workType == WorkType::EncodeDecodeY) { encode_y_internal(ptr, rans, p.symbols_y, p.cdf_group_index); } else if (p.workType == WorkType::EncodeDecodeZ) { encode_z_internal(ptr, rans, p.symbols_z, p.cdf_group_index, p.start_offset, p.per_channel_size); } } RansEncFlush(rans, ptr); const int nbytes = static_cast(std::distance(ptr, ptrEnd)); _stream->resize(nbytes); memcpy(_stream->data(), ptr, nbytes); delete[] output; } std::shared_ptr> RansEncoderLib::get_encoded_stream() { return _stream; } void RansEncoderLib::reset() { m_pendingEncodingList.clear(); _stream->clear(); } RansEncoderLibMultiThread::RansEncoderLibMultiThread() : RansEncoderLib() , m_finish(false) , m_result_ready(false) { m_thread = std::thread(&RansEncoderLibMultiThread::worker, this); } RansEncoderLibMultiThread::~RansEncoderLibMultiThread() { { std::lock_guard lk(m_mutex_pending); std::lock_guard lk1(m_mutex_result); m_finish = true; } m_cv_pending.notify_one(); m_cv_result.notify_one(); m_thread.join(); } void RansEncoderLibMultiThread::flush() { PendingTask p; p.workType = WorkType::Flush; { std::unique_lock lk(m_mutex_pending); m_pending.push_back(p); } m_cv_pending.notify_one(); } std::shared_ptr> RansEncoderLibMultiThread::get_encoded_stream() { std::unique_lock lk(m_mutex_result); m_cv_result.wait(lk, [this] { return m_result_ready || m_finish; }); return RansEncoderLib::get_encoded_stream(); } void RansEncoderLibMultiThread::reset() { RansEncoderLib::reset(); std::lock_guard lk(m_mutex_result); m_result_ready = false; } void RansEncoderLibMultiThread::worker() { while (!m_finish) { std::unique_lock lk(m_mutex_pending); m_cv_pending.wait(lk, [this] { return m_pending.size() > 0 || m_finish; }); if (m_finish) { lk.unlock(); break; } if (m_pending.size() == 0) { lk.unlock(); // std::cout << "contine in worker" << std::endl; continue; } while (m_pending.size() > 0) { auto p = m_pending.front(); m_pending.pop_front(); lk.unlock(); if (p.workType == WorkType::Flush) { RansEncoderLib::flush(); { std::lock_guard lk_result(m_mutex_result); m_result_ready = true; } m_cv_result.notify_one(); } lk.lock(); } lk.unlock(); } } void RansDecoderLib::set_stream(const std::shared_ptr> encoded) { _stream = encoded; _ptr8 = (uint8_t*)(_stream->data()); RansDecInit(_rans, _ptr8); } int RansDecoderLib::add_cdf(const std::shared_ptr>> cdfs, const std::shared_ptr> cdfs_sizes, const std::shared_ptr> offsets) { _cdfs.push_back(cdfs); _cdfs_sizes.push_back(cdfs_sizes); _offsets.push_back(offsets); return static_cast(_cdfs.size()) - 1; } void RansDecoderLib::empty_cdf_buffer() { _cdfs.clear(); _cdfs_sizes.clear(); _offsets.clear(); } FORCE_INLINE int8_t RansDecoderLib::decode_one_symbol(const int32_t* cdf, const int32_t cdf_size, const int32_t offset) { const int32_t max_value = cdf_size - 2; const int32_t cum_freq = static_cast(RansDecGet(_rans)); int s = 1; while (cdf[s++] <= cum_freq) { } s -= 2; RansDecAdvance(_rans, _ptr8, cdf[s], cdf[s + 1] - cdf[s]); int32_t value = static_cast(s); if (value == max_value) { /* Bypass decoding mode */ int32_t val = RansDecGetBits(_rans, _ptr8); int32_t n_bypass = val; while (val == max_bypass_val) { val = RansDecGetBits(_rans, _ptr8); n_bypass += val; } int32_t raw_val = 0; for (int j = 0; j < n_bypass; ++j) { val = RansDecGetBits(_rans, _ptr8); raw_val |= val << (j * bypass_precision); } value = raw_val >> 1; if (raw_val & 1) { value = -value - 1; } else { value += max_value; } } return static_cast(value + offset); } void RansDecoderLib::decode_y(const std::shared_ptr> indexes, const int cdf_group_index) { int index_size = static_cast(indexes->size()); m_decoded = std::make_shared>(index_size); int8_t* outout_ptr = m_decoded->data(); const uint8_t* indexes_ptr = indexes->data(); const int32_t* cdfs_sizes_ptr = _cdfs_sizes[cdf_group_index]->data(); const int32_t* offsets_ptr = _offsets[cdf_group_index]->data(); const auto& cdfs = _cdfs[cdf_group_index]; for (int i = 0; i < index_size; ++i) { const int32_t cdf_idx = indexes_ptr[i]; outout_ptr[i] = decode_one_symbol(cdfs->at(cdf_idx).data(), cdfs_sizes_ptr[cdf_idx], offsets_ptr[cdf_idx]); } } void RansDecoderLib::decode_z(const int total_size, const int cdf_group_index, const int start_offset, const int per_channel_size) { m_decoded = std::make_shared>(total_size); int8_t* outout_ptr = m_decoded->data(); const int32_t* cdfs_sizes_ptr = _cdfs_sizes[cdf_group_index]->data(); const int32_t* offsets_ptr = _offsets[cdf_group_index]->data(); const auto& cdfs = _cdfs[cdf_group_index]; for (int i = 0; i < total_size; ++i) { const int32_t cdf_idx = i / per_channel_size + start_offset; outout_ptr[i] = decode_one_symbol(cdfs->at(cdf_idx).data(), cdfs_sizes_ptr[cdf_idx], offsets_ptr[cdf_idx]); } } std::shared_ptr> RansDecoderLib::get_decoded_tensor() { return m_decoded; } RansDecoderLibMultiThread::RansDecoderLibMultiThread() : RansDecoderLib() , m_finish(false) , m_result_ready(false) { m_thread = std::thread(&RansDecoderLibMultiThread::worker, this); } RansDecoderLibMultiThread::~RansDecoderLibMultiThread() { { std::lock_guard lk(m_mutex_pending); std::lock_guard lk1(m_mutex_result); m_finish = true; } m_cv_pending.notify_one(); m_cv_result.notify_one(); m_thread.join(); } void RansDecoderLibMultiThread::decode_y(const std::shared_ptr> indexes, const int cdf_group_index) { { std::lock_guard lk(m_mutex_result); m_result_ready = false; } PendingTask p; p.workType = WorkType::EncodeDecodeY; p.indexes = indexes; p.cdf_group_index = cdf_group_index; { std::unique_lock lk(m_mutex_pending); m_pending.push_back(p); } m_cv_pending.notify_one(); } void RansDecoderLibMultiThread::decode_z(const int total_size, const int cdf_group_index, const int start_offset, const int per_channel_size) { { std::lock_guard lk(m_mutex_result); m_result_ready = false; } PendingTask p; p.workType = WorkType::EncodeDecodeZ; p.total_size = total_size; p.cdf_group_index = cdf_group_index; p.start_offset = start_offset; p.per_channel_size = per_channel_size; { std::unique_lock lk(m_mutex_pending); m_pending.push_back(p); } m_cv_pending.notify_one(); } std::shared_ptr> RansDecoderLibMultiThread::get_decoded_tensor() { std::unique_lock lk(m_mutex_result); m_cv_result.wait(lk, [this] { return m_result_ready || m_finish; }); return RansDecoderLib::get_decoded_tensor(); } void RansDecoderLibMultiThread::worker() { while (!m_finish) { std::unique_lock lk(m_mutex_pending); m_cv_pending.wait(lk, [this] { return m_pending.size() > 0 || m_finish; }); if (m_finish) { lk.unlock(); break; } if (m_pending.size() == 0) { lk.unlock(); // std::cout << "contine in worker" << std::endl; continue; } while (m_pending.size() > 0) { auto p = m_pending.front(); m_pending.pop_front(); lk.unlock(); if (p.workType == WorkType::EncodeDecodeY) { RansDecoderLib::decode_y(p.indexes, p.cdf_group_index); } else if (p.workType == WorkType::EncodeDecodeZ) { RansDecoderLib::decode_z(p.total_size, p.cdf_group_index, p.start_offset, p.per_channel_size); } { std::lock_guard lk_result(m_mutex_result); m_result_ready = true; } m_cv_result.notify_one(); lk.lock(); } lk.unlock(); } }