Changes to aos/vision/debug in preparation for the competition.
- blob_log-source: Support multiple key-commands for seeking to a target
also added JustCheckForTarget which can be implemented to run faster
for slow computer (will implement in followup).
- camera-source + debug_framework: Takes in camera parameters from the
caller.
- debug_window -> Scale text up on smaller monitors.
- overlay.h: Ben changed width to measure point to point on the cross.
And added circles to the pixel-lines overlay.
- tcp-source: Drop packects when the computer can't keep up.
- debug_framework -> detect smaller monitors and scale down the viewport.
Change-Id: Iae65a0799231d006b38694a8a9cb3894e252033c
diff --git a/aos/vision/debug/blob_log-source.cc b/aos/vision/debug/blob_log-source.cc
index f2bfbb5..337a764 100644
--- a/aos/vision/debug/blob_log-source.cc
+++ b/aos/vision/debug/blob_log-source.cc
@@ -9,12 +9,28 @@
#include <string>
#include "aos/vision/blob/codec.h"
+#include "aos/vision/blob/stream_view.h"
+#include "aos/vision/debug/overlay.h"
namespace aos {
namespace vision {
namespace {
+__attribute__((format(printf, 1, 2))) std::string SPrintf(const char *format,
+ ...) {
+ va_list arglist;
+ va_start(arglist, format);
+ size_t count = vsnprintf(nullptr, 0, format, arglist);
+ va_end(arglist);
+
+ char out[count + 1];
+ va_start(arglist, format);
+ vsnprintf(out, count + 1, format, arglist);
+ va_end(arglist);
+ return std::string(&out[0], &out[count]);
+}
+
long GetFileSize(const std::string &filename) {
struct stat stat_buf;
int rc = stat(filename.c_str(), &stat_buf);
@@ -45,7 +61,8 @@
}
bool ReadNext(BlobList *blob_list, ImageFormat *fmt, uint64_t *timestamp) {
- if (buf_ - &tmp_buf_[0] >= len_) return false;
+ if (buf_ - &tmp_buf_[0] + sizeof(uint32_t) >= static_cast<size_t>(len_))
+ return false;
if (prev_ != nullptr) prev_frames_.emplace_back(prev_);
prev_ = buf_;
DoRead(blob_list, fmt, timestamp);
@@ -56,7 +73,6 @@
if (prev_frames_.empty()) return false;
buf_ = prev_frames_.back();
prev_frames_.pop_back();
- buf_ += sizeof(uint32_t);
DoRead(blob_list, fmt, timestamp);
prev_ = nullptr;
return true;
@@ -64,7 +80,11 @@
private:
void DoRead(BlobList *blob_list, ImageFormat *fmt, uint64_t *timestamp) {
- buf_ += sizeof(uint32_t);
+ uint32_t size_delta = Int32Codec::Read(&buf_);
+ if (buf_ - &tmp_buf_[0] + size_delta > len_) {
+ fprintf(stderr, "Corrupted last record.\n");
+ exit(-1);
+ }
*timestamp = Int64Codec::Read(&buf_);
fmt->w = Int32Codec::Read(&buf_);
fmt->h = Int32Codec::Read(&buf_);
@@ -132,6 +152,60 @@
std::function<bool()> callback_;
};
+class FrameStats {
+ public:
+ void UpdateStats(int64_t timestamp, bool has_target) {
+ if (has_target != last_has_target_) {
+ if (has_target && timestamp > last_timestamp_) {
+ ++frame_count_;
+ }
+ if (!has_target && timestamp < last_timestamp_) {
+ --frame_count_;
+ }
+ }
+ if (has_target && first_frame_timestamp_ == -1) {
+ first_frame_timestamp_ = timestamp;
+ }
+
+ last_timestamp_ = timestamp;
+ last_has_target_ = has_target;
+ }
+
+ void SetStartTimestamp(int64_t start_timestamp) {
+ start_timestamp_ = start_timestamp;
+ }
+
+ std::string Summary() const {
+ return SPrintf(" frame_count: %ld\n time_since_first_target: %7.3f",
+ frame_count_,
+ (last_timestamp_ - GetStartTimestamp()) / 1.0e9);
+ }
+
+ int64_t GetStartTimestamp() const {
+ if (first_frame_timestamp_ != -1) return first_frame_timestamp_;
+ return start_timestamp_;
+ }
+
+ private:
+ int64_t start_timestamp_;
+ int64_t frame_count_ = 0;
+ int64_t first_frame_timestamp_ = -1;
+ int64_t last_timestamp_ = -1;
+ bool last_has_target_ = 0;
+};
+
+// TODO: display this on the screen when they press help.
+const char *kHudText2 = &R"(
+commands:
+ h - display this message.
+ space - pause / unpause at normal speed (No extra mode).
+ s - Skip forward fast to the next target.
+ p - Skip backwards fast to the previous target.
+ left_arrow - single-step backwards.
+ right_arrow - single-step forwards.
+
+)"[1];
+
class BlobLogImageSource : public ImageSource {
public:
void Init(const std::string &blob_log_filename,
@@ -144,26 +218,95 @@
cb_.Reset(1000 / 25, [this]() { return Tick(); });
frame_.ReadNext(image_source_.get());
+ start_timestamp_ = frame_.timestamp;
+ frame_stats_.SetStartTimestamp(start_timestamp_);
+
interface_->NewBlobList(frame_.blob_list, frame_.fmt);
interface_->InstallKeyPress([this](uint32_t keyval) {
if (keyval == GDK_KEY_Left) {
- frame_.ReadPrev(image_source_.get());
- interface_->NewBlobList(frame_.blob_list, frame_.fmt);
+ ReadPrevFrame();
+ bool has_target = interface_->NewBlobList(frame_.blob_list, frame_.fmt);
+ frame_stats_.UpdateStats(frame_.timestamp, has_target);
} else if (keyval == GDK_KEY_Right) {
- frame_.ReadNext(image_source_.get());
- interface_->NewBlobList(frame_.blob_list, frame_.fmt);
+ ReadNextFrame();
+ bool has_target = interface_->NewBlobList(frame_.blob_list, frame_.fmt);
+ frame_stats_.UpdateStats(frame_.timestamp, has_target);
+ } else if (keyval == GDK_KEY_space) {
+ if (mode_ != PAUSED) {
+ mode_ = PAUSED;
+ } else {
+ mode_ = NORMAL_MODE;
+ }
+ } else if (keyval == GDK_KEY_s) {
+ controller_.reset(new FastForwardUntilFrameController(this));
+ mode_ = FAST_MODE;
+ } else if (keyval == GDK_KEY_p) {
+ controller_.reset(new FastForwardUntilFrameController(this));
+ mode_ = FAST_MODE_REV;
} else {
return;
}
});
+ interface_->viewer()->AddOverlay(&overlay_);
+ overlay_.draw_fn = [this](RenderInterface *cr, double w, double h) {
+ (void)w;
+ (void)h;
+ cr->SetSourceRGB(1, 0, 0);
+ auto text = SPrintf(" time: %7.3f\n",
+ (frame_.timestamp - start_timestamp_) / 1.0e9);
+ text += frame_stats_.Summary();
+ cr->Text(2, h - 100, 0, 0, text);
+ };
}
bool Tick() {
- frame_.ReadNext(image_source_.get());
- interface_->NewBlobList(frame_.blob_list, frame_.fmt);
+ if (need_timestamp_print_) {
+ fprintf(stderr, "time: %g\n",
+ (frame_.timestamp - start_timestamp_) / 1.0e9);
+ need_timestamp_print_ = false;
+ }
+ for (int i = 0; i < GetSpeed(); ++i) {
+ if (Direction()) {
+ ReadNextFrame();
+ } else {
+ ReadPrevFrame();
+ }
+ bool has_target =
+ interface_->JustCheckForTarget(frame_.blob_list, frame_.fmt);
+ frame_stats_.UpdateStats(frame_.timestamp, has_target);
+ if (controller_) {
+ controller_->NewFrame(has_target);
+ }
+ // Draw on the last frame:
+ if (i + 1 >= GetSpeed()) {
+ interface_->NewBlobList(frame_.blob_list, frame_.fmt);
+ }
+ }
return true;
}
+ int GetSpeed() {
+ if (mode_ == PAUSED) return 0;
+ if (mode_ == NORMAL_MODE) return 1;
+ if (mode_ == FAST_MODE || mode_ == FAST_MODE_REV) return 60;
+ return 0;
+ }
+
+ bool Direction() {
+ if (mode_ == FAST_MODE_REV) return false;
+ return true;
+ }
+
+ void ReadNextFrame() {
+ frame_.ReadNext(image_source_.get());
+ need_timestamp_print_ = true;
+ }
+
+ void ReadPrevFrame() {
+ frame_.ReadPrev(image_source_.get());
+ need_timestamp_print_ = true;
+ }
+
const char *GetHelpMessage() override {
return &R"(
format_spec is the name of a file in blob list format.
@@ -172,10 +315,50 @@
}
private:
+ bool need_timestamp_print_ = true;
+ uint64_t start_timestamp_ = 0;
+
+ class Controller {
+ public:
+ virtual ~Controller() {}
+ virtual void NewFrame(bool has_target) = 0;
+ };
+
+ class FastForwardUntilFrameController : public Controller {
+ public:
+ FastForwardUntilFrameController(BlobLogImageSource *proxy)
+ : proxy_(proxy) {}
+
+ void NewFrame(bool has_target) override {
+ if (!has_target) inside_target = false;
+ if (!inside_target && has_target) {
+ proxy_->mode_ = PAUSED;
+ proxy_->controller_.reset(nullptr);
+ }
+ }
+
+ BlobLogImageSource *proxy_;
+ bool inside_target = true;
+ };
+
+ std::unique_ptr<Controller> controller_;
+
+ FrameStats frame_stats_;
+
+ enum Mode {
+ PAUSED,
+ NORMAL_MODE,
+ FAST_MODE,
+ FAST_MODE_REV,
+ };
+ Mode mode_ = PAUSED;
+
+ // LambdaOverlay text_overlay_;
TimeoutCallback cb_;
DebugFrameworkInterface *interface_ = nullptr;
std::unique_ptr<InputFile> image_source_;
BlobStreamFrame frame_;
+ LambdaOverlay overlay_;
};
REGISTER_IMAGE_SOURCE("blob_log", BlobLogImageSource);
diff --git a/aos/vision/debug/camera-source.cc b/aos/vision/debug/camera-source.cc
index 77bd6ed..5eeabfc 100644
--- a/aos/vision/debug/camera-source.cc
+++ b/aos/vision/debug/camera-source.cc
@@ -14,17 +14,17 @@
public:
void Init(const std::string &jpeg_list_filename,
DebugFrameworkInterface *interface) override {
- // TODO: Get these params from a config file passed in through the
- // constructor.
- image_stream_.reset(new ImageStream(
- jpeg_list_filename, aos::vision::CameraParams(), interface));
+ // TODO: These camera params make this ugly and less generic.
+ image_stream_.reset(new ImageStream(jpeg_list_filename,
+ interface->camera_params(), interface));
}
const char *GetHelpMessage() override {
return &R"(
format_spec is filename of the camera device.
example: camera:/dev/video0
- This viewer source will stream video from a usb camera of your choice.)"[1];
+ This viewer source will stream video from a usb camera of your choice.
+)"[1];
}
class ImageStream : public ImageStreamEvent {
@@ -38,9 +38,9 @@
// Takes a picture when you press 'a'.
// TODO(parker): Allow setting directory.
if (keyval == GDK_KEY_a) {
- std::ofstream ofs(
- std::string("/tmp/out_jpegs/test") + std::to_string(i_) + ".jpg",
- std::ofstream::out);
+ std::ofstream ofs(std::string("/tmp/debug_viewer_jpeg_") +
+ std::to_string(i_) + ".jpg",
+ std::ofstream::out);
ofs << prev_data_;
ofs.close();
++i_;
diff --git a/aos/vision/debug/debug_framework.cc b/aos/vision/debug/debug_framework.cc
index 64f370c..d4ba0d2 100644
--- a/aos/vision/debug/debug_framework.cc
+++ b/aos/vision/debug/debug_framework.cc
@@ -12,6 +12,27 @@
namespace aos {
namespace vision {
+// Detect screen height on smaller monitors.
+int GetScreenHeight() {
+ fprintf(stderr, "gtk version_info: %d.%d.%d\n", gtk_get_major_version(),
+ gtk_get_minor_version(), gtk_get_micro_version());
+
+ GdkScreen *screen = gdk_screen_get_default();
+ GdkRectangle dimensions;
+// Deprecated in newer versions of GTK and missing from older versions.
+#if GTK_CHECK_VERSION(3, 22, 7)
+ GdkDisplay *display = gdk_screen_get_display(screen);
+ GdkMonitor *monitor = gdk_display_get_primary_monitor(display);
+ gdk_monitor_get_geometry(monitor, &dimensions);
+#else
+ dimensions.height = gdk_screen_get_height(screen);
+ dimensions.width = gdk_screen_get_width(screen);
+#endif
+ fprintf(stdout, "Monitor dimensions: %dx%d\n", dimensions.width,
+ dimensions.height);
+ return dimensions.height;
+}
+
bool DecodeJpeg(aos::vision::DataRef data,
aos::vision::BlobStreamViewer *view) {
auto fmt = aos::vision::GetFmt(data);
@@ -24,37 +45,55 @@
class DebugFramework : public DebugFrameworkInterface {
public:
- explicit DebugFramework(FilterHarness *filter) : filter_(filter) {
+ explicit DebugFramework(FilterHarness *filter, CameraParams camera_params)
+ : camera_params_(camera_params), filter_(filter) {
view_.key_press_event = [this](uint32_t keyval) {
for (const auto &event : key_press_events()) {
event(keyval);
}
};
filter->InstallViewer(&view_);
+ auto key_press = filter->RegisterKeyPress();
+ if (key_press) {
+ InstallKeyPress(key_press);
+ }
+ if (GetScreenHeight() < 1024) {
+ view_.SetScale(0.75);
+ }
}
// This the first stage in the pipeline that takes
- void NewJpeg(DataRef data) override {
+ bool NewJpeg(DataRef data) override {
DecodeJpeg(data, &view_);
auto fmt = view_.img().fmt();
- HandleBlobs(FindBlobs(filter_->Threshold(view_.img())), fmt);
+ return HandleBlobs(FindBlobs(filter_->Threshold(view_.img())), fmt);
}
- void NewBlobList(BlobList blob_list, ImageFormat fmt) override {
+ bool NewBlobList(BlobList blob_list, ImageFormat fmt) override {
view_.SetFormatAndClear(fmt);
- HandleBlobs(std::move(blob_list), fmt);
+ return HandleBlobs(std::move(blob_list), fmt);
}
- void HandleBlobs(BlobList blob_list, ImageFormat fmt) {
- filter_->HandleBlobs(std::move(blob_list), fmt);
+ bool JustCheckForTarget(BlobList blob_list, ImageFormat fmt) override {
+ return filter_->JustCheckForTarget(std::move(blob_list), fmt);
+ }
+
+ bool HandleBlobs(BlobList blob_list, ImageFormat fmt) {
+ bool result = filter_->HandleBlobs(std::move(blob_list), fmt);
view_.Redraw();
+ return result;
}
aos::events::EpollLoop *Loop() override { return &loop_; }
+ const CameraParams &camera_params() override { return camera_params_; }
+
+ BlobStreamViewer *viewer() override { return &view_; }
+
private:
+ CameraParams camera_params_;
FilterHarness *filter_;
BlobStreamViewer view_;
@@ -93,7 +132,8 @@
parameter. A single command line argument help will print this message.
)";
-void DebugFrameworkMain(int argc, char **argv, FilterHarness *filter) {
+void DebugFrameworkMain(int argc, char **argv, FilterHarness *filter,
+ CameraParams camera_params) {
::aos::logging::Init();
::aos::logging::AddImplementation(
new ::aos::logging::StreamLogImplementation(stdout));
@@ -116,7 +156,7 @@
exit(-1);
}
- DebugFramework replay(filter);
+ DebugFramework replay(filter, camera_params);
std::unique_ptr<ImageSource> image_source = MakeImageSource(argv[1], &replay);
diff --git a/aos/vision/debug/debug_framework.h b/aos/vision/debug/debug_framework.h
index 2f0fcd1..e838913 100644
--- a/aos/vision/debug/debug_framework.h
+++ b/aos/vision/debug/debug_framework.h
@@ -4,6 +4,7 @@
#include "aos/common/util/global_factory.h"
#include "aos/vision/blob/range_image.h"
#include "aos/vision/events/epoll_events.h"
+#include "aos/vision/image/camera_params.pb.h"
#include "aos/vision/image/image_types.h"
namespace aos {
@@ -27,6 +28,17 @@
// One frame worth of blobs. Returns if the frame is "interesting".
virtual bool HandleBlobs(BlobList imgs, ImageFormat fmt) = 0;
+
+ // One frame worth of blobs. Returns if the frame is "interesting".
+ // Fast version that does no drawing.
+ virtual bool JustCheckForTarget(BlobList imgs, ImageFormat fmt) {
+ return HandleBlobs(std::move(imgs), fmt);
+ }
+
+ // Register key press handler.
+ virtual std::function<void(uint32_t)> RegisterKeyPress() {
+ return std::function<void(uint32_t)>();
+ }
};
// For ImageSource implementations only. Allows registering key press events
@@ -39,13 +51,21 @@
key_press_events_.emplace_back(std::move(key_press_event));
}
- virtual void NewJpeg(DataRef data) = 0;
+ // The return value bool here for all of these is
+ // if the frame is "interesting" ie has a target.
+ virtual bool NewJpeg(DataRef data) = 0;
- virtual void NewBlobList(BlobList blob_list, ImageFormat fmt) = 0;
+ virtual bool NewBlobList(BlobList blob_list, ImageFormat fmt) = 0;
+
+ virtual bool JustCheckForTarget(BlobList imgs, ImageFormat fmt) = 0;
// Expose a EpollLoop to allow waiting for events.
virtual aos::events::EpollLoop *Loop() = 0;
+ virtual const CameraParams &camera_params() = 0;
+
+ virtual BlobStreamViewer *viewer() = 0;
+
protected:
const std::vector<std::function<void(uint32_t)>> &key_press_events() {
return key_press_events_;
@@ -77,7 +97,8 @@
// Runs loop and never returns.
// Feeds into a generic filter.
-void DebugFrameworkMain(int argc, char **argv, FilterHarness *filter);
+void DebugFrameworkMain(int argc, char **argv, FilterHarness *filter,
+ CameraParams camera_params);
} // namespace vision
} // namespace aos
diff --git a/aos/vision/debug/debug_window.cc b/aos/vision/debug/debug_window.cc
index acbaf8e..4729939 100644
--- a/aos/vision/debug/debug_window.cc
+++ b/aos/vision/debug/debug_window.cc
@@ -48,13 +48,19 @@
if (overlays) {
for (const auto &ov : *overlays) {
cairo_save(cr);
- CairoRender render(cr);
- // move the drawing to match the window size
+ CairoRender render(cr, 1.0 / scale_factor);
ov->Draw(&render, w, h);
cairo_restore(cr);
}
}
+ for (const auto &ov : overlays_internal_) {
+ cairo_save(cr);
+ CairoRender render(cr, 1.0 / scale_factor);
+ ov->Draw(&render, w, h);
+ cairo_restore(cr);
+ }
+
return FALSE;
}
@@ -64,6 +70,7 @@
bool needs_draw = true;
GtkWidget *window;
std::vector<OverlayBase *> *overlays = nullptr;
+ std::vector<OverlayBase *> overlays_internal_;
double scale_factor;
// flip the image rows on drawing
@@ -77,6 +84,10 @@
self->overlays = overlays;
}
+void DebugWindow::AddOverlay(OverlayBase *overlay) {
+ self->overlays_internal_.push_back(overlay);
+}
+
void DebugWindow::Redraw() {
if (!self->needs_draw) {
gtk_widget_queue_draw(self->drawing_area);
@@ -158,11 +169,15 @@
void CairoRender::Text(int x, int y, int /*text_x*/, int /*text_y*/,
const std::string &text) {
- auto *pango_lay = pango_cairo_create_layout(cr_);
+ cairo_save(cr_);
cairo_move_to(cr_, x, y);
+ cairo_scale(cr_, text_scale_, text_scale_);
+
+ auto *pango_lay = pango_cairo_create_layout(cr_);
pango_layout_set_text(pango_lay, text.data(), text.size());
pango_cairo_show_layout(cr_, pango_lay);
g_object_unref(pango_lay);
+ cairo_restore(cr_);
}
} // namespace vision
diff --git a/aos/vision/debug/debug_window.h b/aos/vision/debug/debug_window.h
index 906bf3b..aa31a8c 100644
--- a/aos/vision/debug/debug_window.h
+++ b/aos/vision/debug/debug_window.h
@@ -12,7 +12,8 @@
// Implement Cairo version of RenderInterface.
class CairoRender : public RenderInterface {
public:
- explicit CairoRender(cairo_t *cr) : cr_(cr) {}
+ explicit CairoRender(cairo_t *cr, double text_scale)
+ : cr_(cr), text_scale_(text_scale) {}
virtual ~CairoRender() {}
void Translate(double x, double y) override { cairo_translate(cr_, x, y); }
@@ -36,6 +37,7 @@
private:
cairo_t *cr_;
+ double text_scale_ = 1.0;
};
// Simple debug view window.
@@ -55,6 +57,13 @@
// See overlay.h for more info.
void SetOverlays(std::vector<OverlayBase *> *overlay);
+ void AddOverlay(OverlayBase *overlay);
+ void AddOverlays(const std::vector<OverlayBase *> &overlays) {
+ for (auto *overlay : overlays) {
+ AddOverlay(overlay);
+ }
+ }
+
// Resizes the window.
void SetScale(double scale_factor);
diff --git a/aos/vision/debug/overlay.h b/aos/vision/debug/overlay.h
index 5a9804f..0122c94 100644
--- a/aos/vision/debug/overlay.h
+++ b/aos/vision/debug/overlay.h
@@ -128,10 +128,10 @@
void DrawCross(aos::vision::Vector<2> center, int width,
aos::vision::PixelRef color) {
using namespace aos::vision;
- AddLine(Vector<2>(center.x() - width, center.y()),
- Vector<2>(center.x() + width, center.y()), color);
- AddLine(Vector<2>(center.x(), center.y() - width),
- Vector<2>(center.x(), center.y() + width), color);
+ AddLine(Vector<2>(center.x() - width / 2, center.y()),
+ Vector<2>(center.x() + width / 2, center.y()), color);
+ AddLine(Vector<2>(center.x(), center.y() - width / 2),
+ Vector<2>(center.x(), center.y() + width / 2), color);
}
void DrawBBox(const ImageBBox &box, aos::vision::PixelRef color) {
@@ -146,6 +146,12 @@
color);
}
+ // Build a circle as a point and radius.
+ void DrawCircle(Vector<2> center, double radius, PixelRef newColor) {
+ circles_.emplace_back(std::pair<Vector<2>, std::pair<double, PixelRef>>(
+ center, std::pair<double, PixelRef>(radius, newColor)));
+ }
+
void StartNewProfile() { start_profile = true; }
// add a new point connected to the last point in the line
@@ -171,14 +177,25 @@
render->LineTo(ln.first.B().x(), ln.first.B().y());
render->Stroke();
}
+ for (const auto &circle : circles_) {
+ PixelRef localColor = circle.second.second;
+ render->SetSourceRGB(localColor.r / 255.0, localColor.g / 255.0,
+ localColor.b / 255.0);
+ render->Circle(circle.first.x(), circle.first.y(), circle.second.first);
+ render->Stroke();
+ }
}
// Empting the list will blank the whole overlay.
- void Reset() override { lines_.clear(); }
+ void Reset() override {
+ lines_.clear();
+ circles_.clear();
+ }
private:
// Lines in this overlay.
std::vector<std::pair<Segment<2>, PixelRef>> lines_;
+ std::vector<std::pair<Vector<2>, std::pair<double, PixelRef>>> circles_;
bool start_profile = false;
};
diff --git a/aos/vision/debug/tcp-source.cc b/aos/vision/debug/tcp-source.cc
index 37c38d5..b95e189 100644
--- a/aos/vision/debug/tcp-source.cc
+++ b/aos/vision/debug/tcp-source.cc
@@ -15,6 +15,9 @@
namespace aos {
namespace vision {
+// Reads packets in the form:
+// uint32 length
+// string text (of size length)
class BufferedLengthDelimReader {
public:
union data_len {
@@ -27,33 +30,44 @@
}
template <typename Lamb>
void up(int fd, Lamb lam) {
- ssize_t count;
- if (img_read_ < 0) {
- count = read(fd, &len_.buf[num_read_], sizeof(len_.buf) - num_read_);
- if (count < 0) return;
- num_read_ += count;
- if (num_read_ < 4) return;
- num_read_ = 0;
- img_read_ = 0;
- data_.clear();
- if (len_.len > 200000) {
- printf("bad size: %d\n", len_.len);
- exit(-1);
+ // Drops older messages with this while loop until we've seeked to
+ // be current.
+ while (true) {
+ ssize_t count;
+ if (img_read_ < 0) {
+ count = read(fd, &len_.buf[num_read_], sizeof(len_.buf) - num_read_);
+ if (count < 0) break;
+ num_read_ += count;
+ if (num_read_ < 4) break;
+ num_read_ = 0;
+ img_read_ = 0;
+ data_.clear();
+ if (len_.len > 200000) {
+ printf("bad size: %d\n", len_.len);
+ exit(-1);
+ }
+ data_.resize(len_.len);
+ } else {
+ count = read(fd, &data_[img_read_], len_.len - img_read_);
+ if (count < 0) break;
+ img_read_ += count;
+ if (img_read_ < (int)len_.len) return;
+ std::swap(prev_data_, data_);
+ has_prev_ = true;
+ img_read_ = -1;
}
- data_.resize(len_.len);
- } else {
- count = read(fd, &data_[img_read_], len_.len - img_read_);
- if (count < 0) return;
- img_read_ += count;
- if (img_read_ < (int)len_.len) return;
- lam(DataRef{&data_[0], len_.len});
- img_read_ = -1;
+ }
+ if (has_prev_) {
+ lam(DataRef{&prev_data_[0], len_.len});
+ has_prev_ = false;
}
}
private:
data_len len_;
int num_read_;
+ bool has_prev_ = false;
+ std::vector<char> prev_data_;
std::vector<char> data_;
int img_read_;
};
@@ -92,6 +106,10 @@
buf = ParseBlobList(&blobl, buf);
interface_->NewBlobList(blobl, fmt);
});
+ if (errno != EAGAIN) {
+ fprintf(stderr, "disconnected\n");
+ loop()->Delete(this);
+ }
}
BufferedLengthDelimReader read_;
diff --git a/y2017/vision/debug_viewer.cc b/y2017/vision/debug_viewer.cc
index 83f306f..10dd57e 100644
--- a/y2017/vision/debug_viewer.cc
+++ b/y2017/vision/debug_viewer.cc
@@ -125,5 +125,6 @@
int main(int argc, char **argv) {
y2017::vision::FilterHarnessExample filter_harness;
- aos::vision::DebugFrameworkMain(argc, argv, &filter_harness);
+ aos::vision::DebugFrameworkMain(argc, argv, &filter_harness,
+ aos::vision::CameraParams());
}