Adding //aos/vision/debug:debug_framework.
This will allow easy construction of year-specific debug viewers.
Currently supported source types are:
- blobs over tcp
- jpegs from a camera
- blobs from a log
- a random list of jpegs
Change-Id: I1d73f82f98ca5f60b0135ea0dd588759056e0c40
diff --git a/aos/vision/debug/tcp-source.cc b/aos/vision/debug/tcp-source.cc
new file mode 100644
index 0000000..28feff3
--- /dev/null
+++ b/aos/vision/debug/tcp-source.cc
@@ -0,0 +1,137 @@
+#include "aos/vision/debug/debug_framework.h"
+
+#include <gdk/gdk.h>
+#include <gtk/gtk.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <cstdlib>
+#include <fstream>
+#include <functional>
+#include <string>
+
+#include "aos/vision/blob/codec.h"
+#include "aos/vision/events/tcp_client.h"
+
+namespace aos {
+namespace vision {
+
+class BufferedLengthDelimReader {
+ public:
+ union data_len {
+ uint32_t len;
+ char buf[4];
+ };
+ BufferedLengthDelimReader() {
+ num_read_ = 0;
+ img_read_ = -1;
+ }
+ 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);
+ }
+ 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;
+ }
+ }
+
+ private:
+ data_len len_;
+ int num_read_;
+ std::vector<char> data_;
+ int img_read_;
+};
+
+bool ParsePort(const std::string &port, int *portno) {
+ if (port.empty()) return false;
+ int value = 0;
+ if (port[0] == '0') return false;
+ for (char item : port) {
+ if (item < '0' || item > '9') return false;
+ value = value * 10 + (item - '0');
+ }
+ *portno = value;
+ return true;
+}
+
+class TCPImageSource : public ImageSource {
+ public:
+ class Impl : public aos::events::TcpClient {
+ public:
+ Impl(const std::string &hostname, int portno,
+ DebugFrameworkInterface *interface)
+ : aos::events::TcpClient(hostname.c_str(), portno), interface_(interface) {}
+
+ void ReadEvent() override {
+ read_.up(fd(), [&](DataRef data) {
+ BlobList blobl;
+ const char *buf = data.data();
+ buf += sizeof(uint32_t);
+
+ ImageFormat fmt;
+ Int64Codec::Read(&buf);
+ fmt.w = Int32Codec::Read(&buf);
+ fmt.h = Int32Codec::Read(&buf);
+ buf = ParseBlobList(&blobl, buf);
+ interface_->NewBlobList(blobl, fmt);
+ });
+ }
+
+ BufferedLengthDelimReader read_;
+ DebugFrameworkInterface *interface_ = nullptr;
+ };
+
+ void Init(const std::string &addr_and_port,
+ DebugFrameworkInterface *interface) override {
+ auto it = addr_and_port.rfind(':');
+ if (it == std::string::npos) {
+ fprintf(stderr, "usage is: tcp:hostname:port\n");
+ exit(-1);
+ }
+ auto hostname = addr_and_port.substr(0, it);
+ auto port = addr_and_port.substr(it + 1);
+ int portno = 0;
+ if (!ParsePort(port, &portno)) {
+ fprintf(stderr, "usage is: tcp:hostname:port\n");
+ exit(-1);
+ }
+
+ impl_.reset(new Impl(hostname, portno, interface));
+
+ interface->Loop()->Add(impl_.get());
+
+ interface->InstallKeyPress([this](uint32_t /*keyval*/) {});
+ }
+
+ const char *GetHelpMessage() override {
+ return &R"(
+ format_spec is in ipaddr:port format.
+ This viewer soure connects to a target_sender binary and views the live
+ blob-stream.
+)"[1];
+ }
+
+ private:
+ std::unique_ptr<Impl> impl_;
+};
+
+REGISTER_IMAGE_SOURCE("tcp", TCPImageSource);
+
+} // namespace vision
+} // namespace aos