kopia lustrzana https://gitlab.com/sane-project/backends
genesys: Allow limiting the amount of data read from pipeline sources
rodzic
663e3a99ed
commit
c3e7411aca
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
Ładowanie…
Reference in New Issue