genesys: Allow limiting the amount of data read from pipeline sources

merge-requests/190/head
Povilas Kanapickas 2019-09-16 09:34:11 +03:00
rodzic 663e3a99ed
commit c3e7411aca
6 zmienionych plików z 117 dodań i 13 usunięć

Wyświetl plik

@ -66,6 +66,11 @@ void Genesys_Device::clear()
dark_average_data.clear();
}
ImagePipelineNodeBytesSource& Genesys_Device::get_pipeline_source()
{
return static_cast<ImagePipelineNodeBytesSource&>(pipeline.front());
}
uint8_t Genesys_Device::read_register(uint16_t address)
{
uint8_t value;

Wyświetl plik

@ -343,6 +343,8 @@ struct Genesys_Device
// whenever a register is written or read to the scanner.
Genesys_Register_Set physical_regs;
ImagePipelineNodeBytesSource& get_pipeline_source();
uint8_t read_register(uint16_t address);
void write_register(uint16_t address, uint8_t value);
void write_registers(Genesys_Register_Set& regs);

Wyświetl plik

@ -101,6 +101,8 @@ public:
std::size_t remaining_size() const { return remaining_size_; }
void set_remaining_size(std::size_t bytes) { remaining_size_ = bytes; }
std::size_t available() const { return buffer_end_ - buffer_offset_; }
bool get_data(std::size_t size, std::uint8_t* out_data);

Wyświetl plik

@ -50,6 +50,15 @@
ImagePipelineNode::~ImagePipelineNode() {}
std::size_t ImagePipelineNodeBytesSource::consume_remaining_bytes(std::size_t bytes)
{
if (bytes > remaining_bytes_) {
bytes = remaining_bytes_;
}
remaining_bytes_ -= bytes;
return bytes;
}
ImagePipelineNodeBufferedCallableSource::ImagePipelineNodeBufferedCallableSource(
std::size_t width, std::size_t height, PixelFormat format, std::size_t input_batch_size,
ProducerCallback producer) :
@ -58,6 +67,7 @@ ImagePipelineNodeBufferedCallableSource::ImagePipelineNodeBufferedCallableSource
format_{format},
buffer_{input_batch_size, producer}
{
set_remaining_bytes(height_ * get_row_bytes());
}
bool ImagePipelineNodeBufferedCallableSource::get_next_row_data(std::uint8_t* out_data)
@ -68,7 +78,16 @@ bool ImagePipelineNodeBufferedCallableSource::get_next_row_data(std::uint8_t* ou
eof_ = true;
return false;
}
bool got_data = buffer_.get_data(get_row_bytes(), out_data);
bool got_data = true;
auto row_bytes = get_row_bytes();
auto bytes_to_ask = consume_remaining_bytes(row_bytes);
if (bytes_to_ask < row_bytes) {
got_data = false;
}
got_data &= buffer_.get_data(bytes_to_ask, out_data);
curr_row_++;
if (!got_data) {
eof_ = true;
@ -84,11 +103,23 @@ ImagePipelineNodeBufferedGenesysUsb::ImagePipelineNodeBufferedGenesysUsb(
height_{height},
format_{format},
buffer_{total_size, buffer_model, producer}
{}
{
set_remaining_bytes(total_size);
}
bool ImagePipelineNodeBufferedGenesysUsb::get_next_row_data(std::uint8_t* out_data)
{
bool got_data = buffer_.get_data(get_row_bytes(), out_data);
if (remaining_bytes() != buffer_.remaining_size() + buffer_.available()) {
buffer_.set_remaining_size(remaining_bytes() - buffer_.available());
}
bool got_data = true;
std::size_t row_bytes = get_row_bytes();
std::size_t ask_bytes = consume_remaining_bytes(row_bytes);
if (ask_bytes < row_bytes) {
got_data = false;
}
got_data &= buffer_.get_data(ask_bytes, out_data);
if (!got_data) {
eof_ = true;
}
@ -104,22 +135,36 @@ ImagePipelineNodeArraySource::ImagePipelineNodeArraySource(std::size_t width, st
data_{std::move(data)},
next_row_{0}
{
auto min_size = get_row_bytes() * height_;
if (data_.size() < min_size) {
auto size = get_row_bytes() * height_;
if (data_.size() < size) {
throw SaneException("The given array is too small (%zu bytes). Need at least %zu",
data_.size(), min_size);
data_.size(), size);
}
set_remaining_bytes(size);
}
bool ImagePipelineNodeArraySource::get_next_row_data(std::uint8_t* out_data)
{
if (next_row_ >= height_) {
eof_ = true;
return false;
}
std::memcpy(out_data, data_.data() + get_row_bytes() * next_row_, get_row_bytes());
bool got_data = true;
auto row_bytes = get_row_bytes();
auto bytes_to_ask = consume_remaining_bytes(row_bytes);
if (bytes_to_ask < row_bytes) {
got_data = false;
}
std::memcpy(out_data, data_.data() + get_row_bytes() * next_row_, bytes_to_ask);
next_row_++;
return true;
if (!got_data) {
eof_ = true;
}
return got_data;
}

Wyświetl plik

@ -73,6 +73,18 @@ public:
virtual bool get_next_row_data(std::uint8_t* out_data) = 0;
};
class ImagePipelineNodeBytesSource : public ImagePipelineNode
{
public:
std::size_t remaining_bytes() const { return remaining_bytes_; }
void set_remaining_bytes(std::size_t bytes) { remaining_bytes_ = bytes; }
std::size_t consume_remaining_bytes(std::size_t bytes);
private:
std::size_t remaining_bytes_ = 0;
};
// A pipeline node that produces data from a callable
class ImagePipelineNodeCallableSource : public ImagePipelineNode
{
@ -80,7 +92,7 @@ public:
using ProducerCallback = std::function<bool(std::size_t size, std::uint8_t* out_data)>;
ImagePipelineNodeCallableSource(std::size_t width, std::size_t height, PixelFormat format,
ProducerCallback producer) :
ProducerCallback producer) :
producer_{producer},
width_{width},
height_{height},
@ -110,7 +122,7 @@ private:
};
// A pipeline node that produces data from a callable requesting fixed-size chunks.
class ImagePipelineNodeBufferedCallableSource : public ImagePipelineNode
class ImagePipelineNodeBufferedCallableSource : public ImagePipelineNodeBytesSource
{
public:
using ProducerCallback = std::function<bool(std::size_t size, std::uint8_t* out_data)>;
@ -142,7 +154,7 @@ private:
ImageBuffer buffer_;
};
class ImagePipelineNodeBufferedGenesysUsb : public ImagePipelineNode
class ImagePipelineNodeBufferedGenesysUsb : public ImagePipelineNodeBytesSource
{
public:
using ProducerCallback = std::function<void(std::size_t size, std::uint8_t* out_data)>;
@ -174,7 +186,7 @@ private:
};
// A pipeline node that produces data from the given array.
class ImagePipelineNodeArraySource : public ImagePipelineNode
class ImagePipelineNodeArraySource : public ImagePipelineNodeBytesSource
{
public:
ImagePipelineNodeArraySource(std::size_t width, std::size_t height, PixelFormat format,
@ -184,7 +196,7 @@ public:
std::size_t get_height() const override { return height_; }
PixelFormat get_format() const override { return format_; }
bool eof() const override { return next_row_ >= height_; }
bool eof() const override { return eof_; }
bool get_next_row_data(std::uint8_t* out_data) override;
@ -193,6 +205,8 @@ private:
std::size_t height_ = 0;
PixelFormat format_ = PixelFormat::UNKNOWN;
bool eof_ = false;
std::vector<std::uint8_t> data_;
std::size_t next_row_ = 0;
};
@ -495,6 +509,8 @@ public:
PixelFormat get_output_format() const;
std::size_t get_output_row_bytes() const;
ImagePipelineNode& front() { return *(nodes_.front().get()); }
bool eof() const { return nodes_.back()->eof(); }
void clear();

Wyświetl plik

@ -67,6 +67,39 @@ void test_image_buffer_genesys_usb()
ASSERT_EQ(requests, expected);
}
void test_image_buffer_genesys_usb_capped_remaining_bytes()
{
std::vector<std::size_t> requests;
auto on_read_usb = [&](std::size_t x, std::uint8_t* data)
{
(void) data;
requests.push_back(x);
};
FakeBufferModel model;
model.push_step(453120, 1);
model.push_step(56640, 3540);
ImageBufferGenesysUsb buffer{1086780, model, on_read_usb};
std::vector<std::uint8_t> dummy;
dummy.resize(1086780);
ASSERT_TRUE(buffer.get_data(453120, dummy.data()));
ASSERT_TRUE(buffer.get_data(56640, dummy.data()));
ASSERT_TRUE(buffer.get_data(56640, dummy.data()));
ASSERT_TRUE(buffer.get_data(56640, dummy.data()));
ASSERT_TRUE(buffer.get_data(56640, dummy.data()));
buffer.set_remaining_size(10000);
ASSERT_FALSE(buffer.get_data(56640, dummy.data()));
std::vector<std::size_t> expected = {
// note that the sizes are rounded-up to 256 bytes
453120, 56576, 56576, 56576, 56832, 10240
};
ASSERT_EQ(requests, expected);
}
void test_node_buffered_callable_source()
{
using Data = std::vector<std::uint8_t>;
@ -394,6 +427,7 @@ void test_node_pixel_shift_lines()
void test_image_pipeline()
{
test_image_buffer_genesys_usb();
test_image_buffer_genesys_usb_capped_remaining_bytes();
test_node_buffered_callable_source();
test_node_format_convert();
test_node_desegment_1_line();