Skip to content

Commit

Permalink
Decoder: when we known there's a mismatch between the fountain chunk …
Browse files Browse the repository at this point in the history
…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.
  • Loading branch information
sz3 committed Mar 2, 2024
1 parent f5607a3 commit f1e136f
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 7 deletions.
19 changes: 17 additions & 2 deletions src/lib/encoder/Decoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion src/lib/encoder/reed_solomon_stream.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ class reed_solomon_stream
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;
}
Expand Down
10 changes: 6 additions & 4 deletions src/lib/encoder/test/EncoderRoundTripTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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() );
Expand Down
28 changes: 28 additions & 0 deletions src/lib/util/null_stream.h
Original file line number Diff line number Diff line change
@@ -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;
};

0 comments on commit f1e136f

Please sign in to comment.