Decoder: when we known there's a mismatch between the fountain chunk size...

... and the fountain *stream* (sink)'s chunk size, we shouldn't send it
the decoded bytes. It's not going to be able to do anything useful with
them. Instead, we'll have a /dev/null style "null_stream" that just
tracks how many bytes were written to it.
This commit is contained in:
sz 2024-02-29 23:35:03 -06:00
parent f5607a3761
commit f1e136f143
No known key found for this signature in database
GPG Key ID: 056CD84A187C0C44
4 changed files with 52 additions and 7 deletions

View File

@ -8,6 +8,7 @@
#include "cimb_translator/Config.h"
#include "cimb_translator/Interleave.h"
#include "util/File.h"
#include "util/null_stream.h"
#include <opencv2/opencv.hpp>
#include <functional>
@ -166,8 +167,22 @@ template <typename MAT, typename FOUNTAINSTREAM>
inline unsigned Decoder::decode_fountain(const MAT& img, FOUNTAINSTREAM& ostream, unsigned color_mode, bool should_preprocess, int color_correction)
{
CimbReader reader(img, _decoder, color_mode, should_preprocess, color_correction);
aligned_stream aligner(ostream, ostream.chunk_size(), 0, std::bind(&CimbReader::update_metadata, &reader, std::placeholders::_1, std::placeholders::_2));
return do_decode(reader, aligner, color_mode==0);
bool legacy_mode = color_mode == 0;
unsigned chunk_size = cimbar::Config::fountain_chunk_size(_eccBytes, _bitsPerOp, legacy_mode);
auto update_md_fun = std::bind(&CimbReader::update_metadata, &reader, std::placeholders::_1, std::placeholders::_2);
// we don't want to feed the fountain stream bad data, so we eat the decode if we have a mismatch
// we still might succeed the decode, in which case (hopefully) the positive bytes we return will
// tell our caller to fix the underlying ostream so the next round will work.
if (ostream.chunk_size() != chunk_size)
{
null_stream devnull;
aligned_stream aligner(devnull, chunk_size, 0, update_md_fun);
return do_decode(reader, aligner, legacy_mode);
}
aligned_stream aligner(ostream, ostream.chunk_size(), 0, update_md_fun);
return do_decode(reader, aligner, legacy_mode);
}
inline unsigned Decoder::decode(std::string filename, std::string output, unsigned color_mode)

View File

@ -88,7 +88,7 @@ protected:
bool _good;
};
inline std::ifstream& operator<<(std::ifstream& s, const ReedSolomon::BadChunk& chunk)
inline std::ifstream& operator<<(std::ifstream& s, const ReedSolomon::BadChunk&)
{
return s;
}

View File

@ -64,9 +64,10 @@ TEST_CASE( "EncoderRoundTripTest/testFountain.SinkMismatch", "[unit]" )
// will be padded so the fountain encoding is happy. The encoded image looks suspiciously non-random!
Encoder enc(30, 4, 2);
enc.set_legacy_mode();
assertEquals( 1, enc.encode_fountain(inputFile, outPrefix) );
uint64_t hash = 0xeecc8800efce8c48;
uint64_t hash = 0xaecc8c00efce8c28;
std::string path = fmt::format("{}_0.png", outPrefix);
cv::Mat encodedImg = cv::imread(path);
cv::cvtColor(encodedImg, encodedImg, cv::COLOR_BGR2RGB);
@ -75,10 +76,11 @@ TEST_CASE( "EncoderRoundTripTest/testFountain.SinkMismatch", "[unit]" )
// decoder
Decoder dec(30);
// sink with a mismatched fountain_chunk_size
// importantly, the sink expects a *larger* chunk than we'll give it...
fountain_decoder_sink<cimbar::zstd_decompressor<std::ofstream>> fds(tempdir.path(), cimbar::Config::fountain_chunk_size(30, 6, true));
// importantly, the sink expects a *smaller* chunk than we'll give it...
// because that's a more interesting test...
fountain_decoder_sink<cimbar::zstd_decompressor<std::ofstream>> fds(tempdir.path(), cimbar::Config::fountain_chunk_size(30, 6, false));
unsigned bytesDecoded = dec.decode_fountain(encodedImg, fds, 1);
unsigned bytesDecoded = dec.decode_fountain(encodedImg, fds, 0);
assertEquals( 7500, bytesDecoded );
assertEquals( 0, fds.num_done() );

View File

@ -0,0 +1,28 @@
/* This code is subject to the terms of the Mozilla Public License, v.2.0. http://mozilla.org/MPL/2.0/. */
#pragma once
class null_stream
{
public:
null_stream()
{}
null_stream& write(const char*, unsigned length)
{
_count += length;
return *this;
}
bool good() const
{
return true;
}
long tellp() const
{
return _count;
}
protected:
long _count = 0;
};