blob: acf4d4b691a1c36b116cf0f34c7441f2b8379cc8 [file] [log] [blame]
Parker Schuhd7db83d2017-02-08 20:49:15 -08001#include <stdio.h>
2#include <stdlib.h>
3
4#include <vector>
5#include <memory>
6#include <endian.h>
Parker Schuh24ee58d2017-03-11 16:13:23 -08007#include <sys/stat.h>
Parker Schuhd7db83d2017-02-08 20:49:15 -08008#include <fstream>
9#include <gdk/gdk.h>
10#include <gtk/gtk.h>
11
12#include "aos/vision/image/reader.h"
13#include "aos/vision/image/jpeg_routines.h"
14#include "aos/vision/image/image_stream.h"
15#include "aos/vision/events/epoll_events.h"
16#include "aos/vision/events/tcp_server.h"
Parker Schuhd7db83d2017-02-08 20:49:15 -080017#include "aos/vision/blob/stream_view.h"
18#include "y2016/vision/blob_filters.h"
19// #include "y2016/vision/process_targets.h"
20
21namespace y2016 {
22namespace vision {
23using namespace aos::vision;
24
25::aos::vision::Vector<2> CreateCenterFromTarget(double lx, double ly, double rx, double ry) {
26 return ::aos::vision::Vector<2>((lx + rx) / 2.0, (ly + ry) / 2.0);
27}
28
29double TargetWidth(double lx, double ly, double rx, double ry) {
30 double dx = lx - rx;
31 double dy = ly - ry;
32 return ::std::hypot(dx, dy);
33}
34
35void SelectTargets(std::vector<std::pair<Vector<2>, Vector<2>>>& left_target,
36 std::vector<std::pair<Vector<2>, Vector<2>>>&right_target,
37 ::aos::vision::Vector<2> *center_left,
38 ::aos::vision::Vector<2> *center_right) {
39 // No good targets. Let the caller decide defaults.
40 if (right_target.size() == 0 || left_target.size() == 0) {
41 return;
42 }
43
44 // Only one option, we have to go with it.
45 if (right_target.size() == 1 && left_target.size() == 1) {
46 *center_left =
47 CreateCenterFromTarget(left_target[0].first.x(), left_target[0].first.y(),
48 left_target[0].second.x(), left_target[0].second.y());
49 *center_right = CreateCenterFromTarget(
50 right_target[0].first.x(), right_target[0].first.y(), right_target[0].second.x(),
51 right_target[0].second.y());
52 return;
53 }
54
55 // Now we have to make a decision.
56 double min_angle = -1.0;
57 int left_index = 0;
58 // First pick the widest target from the left.
59 for (size_t i = 0; i < left_target.size(); i++) {
60 const double h = left_target[i].first.y() -
61 left_target[i].second.y();
62 const double wid1 = TargetWidth(left_target[i].first.x(),
63 left_target[i].first.y(),
64 left_target[i].second.x(),
65 left_target[i].second.y());
66 const double angle = h / wid1;
67 if (min_angle == -1.0 || ::std::abs(angle) < ::std::abs(min_angle)) {
68 min_angle = angle;
69 left_index = i;
70 }
71 }
72 // Calculate the angle of the bottom edge for the left.
73 double h = left_target[left_index].first.y() -
74 left_target[left_index].second.y();
75
76 double good_ang = min_angle;
77 double min_ang_err = -1.0;
78 int right_index = -1;
79 // Now pick the bottom edge angle from the right that lines up best with the left.
80 for (size_t j = 0; j < right_target.size(); j++) {
81 double wid2 = TargetWidth(right_target[j].first.x(),
82 right_target[j].first.y(),
83 right_target[j].second.x(),
84 right_target[j].second.y());
85 h = right_target[j].first.y() -
86 right_target[j].second.y();
87 double ang = h/ wid2;
88 double ang_err = ::std::abs(good_ang - ang);
89 if (min_ang_err == -1.0 || min_ang_err > ang_err) {
90 min_ang_err = ang_err;
91 right_index = j;
92 }
93 }
94
95 *center_left =
96 CreateCenterFromTarget(left_target[left_index].first.x(),
97 left_target[left_index].first.y(),
98 left_target[left_index].second.x(),
99 left_target[left_index].second.y());
100 *center_right =
101 CreateCenterFromTarget(right_target[right_index].first.x(),
102 right_target[right_index].first.y(),
103 right_target[right_index].second.x(),
104 right_target[right_index].second.y());
105}
106
107
108long GetFileSize(std::string filename) {
109 struct stat stat_buf;
110 int rc = stat(filename.c_str(), &stat_buf);
111 return rc == 0 ? stat_buf.st_size : -1;
112}
113
114class OutputFile {
115 public:
116 OutputFile(const std::string &fname) : ofs(fname, std::ofstream::out) {}
117
118 void Emit(const BlobList &blobl, int64_t timestamp) {
119 int tmp_size = CalculateSize(blobl) + sizeof(int32_t) + sizeof(uint64_t);
120 tmp_buf.resize(tmp_size, 0);
121 {
122 char *buf = Int64Codec::Write(&tmp_buf[0], tmp_size);
123 buf = Int64Codec::Write(buf, timestamp);
124 SerializeBlob(blobl, buf);
125 }
126 ofs.write(&tmp_buf[0], tmp_size);
127 printf("blob_size: %d\n", tmp_size);
128 }
129
130 std::vector<char> tmp_buf;
131
132 std::ofstream ofs;
133};
134
135class InputFile {
136 public:
137 InputFile(const std::string &fname)
138 : ifs_(fname, std::ifstream::in), len_(GetFileSize(fname)) {
139 if (len_ <= 0) {
140 printf("File (%s) not found. Size (%d)\n", fname.c_str(), (int)len_);
141 fflush(stdout);
142 }
143 assert(len_ > 0);
144 tmp_buf_.resize(len_, 0);
145 ifs_.read(&tmp_buf_[0], len_);
146 buf_ = &tmp_buf_[0];
147 }
148
149 bool ReadNext(BlobList *blob_list, uint64_t *timestamp) {
150 if (buf_ - &tmp_buf_[0] >= len_) return false;
151 if (prev_ != nullptr) prev_frames_.emplace_back(prev_);
152 prev_ = buf_;
153 buf_ += sizeof(uint32_t);
154 *timestamp = Int64Codec::Read(&buf_);
155// auto* buf_tmp = buf_;
156 buf_ = ParseBlobList(blob_list, buf_);
157// fprintf(stderr, "read frame: %lu, buf_size: %lu\n", *timestamp, buf_ - buf_tmp);
158 return true;
159 }
160
161 bool ReadPrev(BlobList *blob_list, uint64_t *timestamp) {
162 if (prev_frames_.empty()) return false;
163 buf_ = prev_frames_.back();
164 prev_frames_.pop_back();
165 buf_ += sizeof(uint32_t);
166 *timestamp = Int64Codec::Read(&buf_);
167 buf_ = ParseBlobList(blob_list, buf_);
168 prev_ = nullptr;
169 return true;
170 }
171
172 private:
173 std::vector<const char *> prev_frames_;
174 const char *buf_;
175 const char *prev_ = nullptr;
176 std::ifstream ifs_;
177
178 long len_;
179 std::vector<char> tmp_buf_;
180};
181
182class BlobStreamFrame {
183 public:
184 BlobList blob_list;
185 uint64_t timestamp;
186 void ReadNext(InputFile *fin) {
187 blob_list.clear();
188 if (!fin->ReadNext(&blob_list, &timestamp)) {
189 exit(0);
190 return;
191 }
192 }
193 bool ReadPrev(InputFile *fin) {
194 blob_list.clear();
195 return fin->ReadPrev(&blob_list, &timestamp);
196 }
197};
198
199const char *kHudText =
200 "commands:\n"
201 " SPACE - pause\n"
202 " c - continue to next target\n"
203 " s - single step while paused\n"
204 " k - pause on next target frame\n"
205 " u - change window scaling\n"
206 " a - single step backward\n"
207 " q - quit\n"
208 " h - help\n";
209
210class NetworkForwardingImageStream : public aos::events::EpollWait {
211 public:
212 NetworkForwardingImageStream(ImageFormat fmt, int debug_level,
213 const std::string &fname1,
214 const std::string &fname2)
215 : fmt_(fmt),
216 ifs1_(fname1),
217 ifs2_(fname2),
218 blob_filt_(fmt, 40, 750, 250000),
219 finder_(0.25, 35) {
220 text_overlay_.draw_fn =
221 [this](RenderInterface *render, double /*width*/, double /*height*/) {
222 render->SetSourceRGB(1.0, 1.0, 1.0);
223 if (hud_text) render->Text(20, 20, 0, 0, kHudText);
224 };
225
226 overlays_.push_back(&overlay_);
227 overlays_.push_back(&text_overlay_);
228 view_.view()->SetOverlays(&overlays_);
229
230 if (debug_level > 0) {
231 finder_.EnableOverlay(&overlay_);
232 }
233 if (debug_level > 1) {
234 blob_filt_.EnableOverlay(&overlay_);
235 }
236
237 frame1.ReadNext(&ifs1_);
238 frame2.ReadNext(&ifs2_);
239
240 std::pair<int, int> skip =
241 TickFrame(std::max(frame1.timestamp, frame2.timestamp));
242 printf("Initialzation skipped (%d, %d)\n", skip.first, skip.second);
243
244 ms_event_delta_ = 20;
245 play_forward = true;
246 paused = false;
247 single_step = false;
248 pause_on_next_target = true;
249 continue_to_next_target = false;
250 view_.view()->SetScale(scale_factor);
251 view_.view()->key_press_event = [this](uint32_t keyval) {
252 play_forward = true;
253 switch (keyval) {
254 case GDK_KEY_space:
255 paused = !paused;
256 pause_on_next_target = false;
257 continue_to_next_target = false;
258 break;
259 case GDK_KEY_c:
260 pause_on_next_target = true;
261 continue_to_next_target = true;
262 paused = false;
263 break;
264 case GDK_KEY_s:
265 single_step = true;
266 continue_to_next_target = false;
267 paused = true;
268 break;
269 case GDK_KEY_k:
270 pause_on_next_target = true;
271 continue_to_next_target = false;
272 paused = false;
273 break;
274 case GDK_KEY_u:
275 if (scale_factor == 1.0) {
276 scale_factor = 0.75;
277 view_.view()->SetScale(0.75);
278 } else {
279 scale_factor = 1.0;
280 view_.view()->SetScale(1.0);
281 view_.view()->MoveTo(150, -220);
282 }
283 break;
284 case GDK_KEY_a:
285 play_forward = false;
286 single_step = true;
287 paused = true;
288 break;
289 case GDK_KEY_q:
290 exit(0);
291 case GDK_KEY_h:
292 hud_text = !hud_text;
293 break;
294 default:
295 printf("pressed: %s\n", gdk_keyval_name(keyval));
296 }
297 };
298 }
299
300 double scale_factor = 1.0;
301 bool hud_text = true;
302 bool play_forward;
303 bool paused;
304 bool single_step;
305 bool pause_on_next_target;
306 bool continue_to_next_target;
307
308 std::string distance_text;
309
310 std::pair<int, int> TickFrame(uint64_t time) {
311 timestamp_ += time;
312 return TickToFrame(timestamp_);
313 }
314
315 std::pair<int, int> TickBackFrame(uint64_t time) {
316 timestamp_ -= time;
317 return TickBackToFrame(timestamp_);
318 }
319
320 std::pair<int, int> TickToFrame(uint64_t timestamp) {
321 std::pair<int, int> skip(0, 0);
322 while (frame1.timestamp < timestamp) {
323 frame1.ReadNext(&ifs1_);
324 skip.first++;
325 }
326 while (frame2.timestamp < timestamp) {
327 frame2.ReadNext(&ifs2_);
328 skip.second++;
329 }
330 return skip;
331 }
332
333 std::pair<int, int> TickBackToFrame(uint64_t timestamp) {
334 std::pair<int, int> skip(0, 0);
335 while (frame1.timestamp >= timestamp) {
336 if (!frame1.ReadPrev(&ifs1_)) break;
337 skip.first++;
338 }
339 while (frame2.timestamp >= timestamp) {
340 if (!frame2.ReadPrev(&ifs2_)) break;
341 skip.second++;
342 }
343 frame1.ReadPrev(&ifs1_);
344 frame2.ReadPrev(&ifs2_);
345 return skip;
346 }
347 BlobStreamFrame frame1;
348 BlobStreamFrame frame2;
349 uint64_t timestamp_ = 0;
350
351 Vector<2> GetCenter(const BlobList &blob_list) {
352 std::vector<std::pair<Vector<2>, Vector<2>>> corners =
353 finder_.Find(blob_filt_.FilterBlobs(blob_list));
354
355 if (corners.size() == 1) {
356 Vector<2> center = (corners[0].first + corners[0].second) * (0.5);
357 return center;
358 }
359 return {0, 0};
360 }
361
362 void DrawSuperSpeed() {
363 PixelRef color = {0, 255, 255};
364 // S
Parker Schuh24ee58d2017-03-11 16:13:23 -0800365 overlay_.AddLine(Vector<2>(200, 100), Vector<2>(100, 100), color);
366 overlay_.AddLine(Vector<2>(100, 100), Vector<2>(100, 300), color);
367 overlay_.AddLine(Vector<2>(100, 300), Vector<2>(200, 300), color);
368 overlay_.AddLine(Vector<2>(200, 300), Vector<2>(200, 500), color);
369 overlay_.AddLine(Vector<2>(200, 500), Vector<2>(100, 500), color);
Parker Schuhd7db83d2017-02-08 20:49:15 -0800370 // U
Parker Schuh24ee58d2017-03-11 16:13:23 -0800371 overlay_.AddLine(Vector<2>(250, 100), Vector<2>(250, 500), color);
372 overlay_.AddLine(Vector<2>(250, 500), Vector<2>(350, 500), color);
373 overlay_.AddLine(Vector<2>(350, 500), Vector<2>(350, 100), color);
Parker Schuhd7db83d2017-02-08 20:49:15 -0800374 // P
Parker Schuh24ee58d2017-03-11 16:13:23 -0800375 overlay_.AddLine(Vector<2>(400, 100), Vector<2>(400, 500), color);
376 overlay_.AddLine(Vector<2>(400, 100), Vector<2>(500, 100), color);
377 overlay_.AddLine(Vector<2>(500, 100), Vector<2>(500, 300), color);
378 overlay_.AddLine(Vector<2>(500, 300), Vector<2>(400, 300), color);
Parker Schuhd7db83d2017-02-08 20:49:15 -0800379 // E
Parker Schuh24ee58d2017-03-11 16:13:23 -0800380 overlay_.AddLine(Vector<2>(550, 100), Vector<2>(550, 500), color);
381 overlay_.AddLine(Vector<2>(550, 100), Vector<2>(650, 100), color);
382 overlay_.AddLine(Vector<2>(550, 300), Vector<2>(650, 300), color);
383 overlay_.AddLine(Vector<2>(550, 500), Vector<2>(650, 500), color);
Parker Schuhd7db83d2017-02-08 20:49:15 -0800384 // R
Parker Schuh24ee58d2017-03-11 16:13:23 -0800385 overlay_.AddLine(Vector<2>(700, 100), Vector<2>(700, 500), color);
386 overlay_.AddLine(Vector<2>(700, 100), Vector<2>(800, 100), color);
387 overlay_.AddLine(Vector<2>(800, 100), Vector<2>(800, 300), color);
388 overlay_.AddLine(Vector<2>(800, 300), Vector<2>(700, 300), color);
389 overlay_.AddLine(Vector<2>(700, 350), Vector<2>(800, 500), color);
Parker Schuhd7db83d2017-02-08 20:49:15 -0800390 // S
Parker Schuh24ee58d2017-03-11 16:13:23 -0800391 overlay_.AddLine(Vector<2>(200, 550), Vector<2>(100, 550), color);
392 overlay_.AddLine(Vector<2>(100, 550), Vector<2>(100, 750), color);
393 overlay_.AddLine(Vector<2>(100, 750), Vector<2>(200, 750), color);
394 overlay_.AddLine(Vector<2>(200, 750), Vector<2>(200, 950), color);
395 overlay_.AddLine(Vector<2>(200, 950), Vector<2>(100, 950), color);
Parker Schuhd7db83d2017-02-08 20:49:15 -0800396 // P
Parker Schuh24ee58d2017-03-11 16:13:23 -0800397 overlay_.AddLine(Vector<2>(250, 550), Vector<2>(250, 950), color);
398 overlay_.AddLine(Vector<2>(250, 550), Vector<2>(350, 550), color);
399 overlay_.AddLine(Vector<2>(350, 550), Vector<2>(350, 750), color);
400 overlay_.AddLine(Vector<2>(350, 750), Vector<2>(250, 750), color);
Parker Schuhd7db83d2017-02-08 20:49:15 -0800401 // E
Parker Schuh24ee58d2017-03-11 16:13:23 -0800402 overlay_.AddLine(Vector<2>(400, 550), Vector<2>(400, 950), color);
403 overlay_.AddLine(Vector<2>(400, 550), Vector<2>(500, 550), color);
404 overlay_.AddLine(Vector<2>(400, 750), Vector<2>(500, 750), color);
405 overlay_.AddLine(Vector<2>(400, 950), Vector<2>(500, 950), color);
Parker Schuhd7db83d2017-02-08 20:49:15 -0800406 // E
Parker Schuh24ee58d2017-03-11 16:13:23 -0800407 overlay_.AddLine(Vector<2>(550, 550), Vector<2>(550, 950), color);
408 overlay_.AddLine(Vector<2>(550, 550), Vector<2>(650, 550), color);
409 overlay_.AddLine(Vector<2>(550, 750), Vector<2>(650, 750), color);
410 overlay_.AddLine(Vector<2>(550, 950), Vector<2>(650, 950), color);
Parker Schuhd7db83d2017-02-08 20:49:15 -0800411 // D
Parker Schuh24ee58d2017-03-11 16:13:23 -0800412 overlay_.AddLine(Vector<2>(700, 550), Vector<2>(700, 950), color);
413 overlay_.AddLine(Vector<2>(700, 550), Vector<2>(800, 575), color);
414 overlay_.AddLine(Vector<2>(800, 575), Vector<2>(800, 925), color);
415 overlay_.AddLine(Vector<2>(800, 925), Vector<2>(700, 950), color);
Parker Schuhd7db83d2017-02-08 20:49:15 -0800416 }
417
418 void UpdateNewTime(int new_delta) {
419 if (new_delta != ms_event_delta_) {
420 ms_event_delta_ = new_delta;
421 SetTime(::std::chrono::milliseconds(ms_event_delta_) + aos::monotonic_clock::now());
422 }
423 }
424
425 void Done() override {
426 SetTime(::std::chrono::milliseconds(ms_event_delta_) + aos::monotonic_clock::now());
427 if (paused && !single_step) return;
428 single_step = false;
429 frame_count_++;
430
431 while (true) {
432 overlay_.Reset();
433 view_.SetFormatAndClear(fmt_);
434 std::pair<int, int> skipped(1, 1);
435 // how far we will step to look for the next target
436 int nano_step = 300 * 1e6;
437 if (play_forward && seeking_target_) {
438 skipped = TickFrame(nano_step);
439 } else if (seeking_target_) {
440 skipped = TickBackFrame(nano_step);
441 } else if (play_forward) {
442 frame1.ReadNext(&ifs1_);
443 frame2.ReadNext(&ifs2_);
444 } else {
445 frame1.ReadPrev(&ifs1_);
446 frame2.ReadPrev(&ifs2_);
447 }
448 // printf("skipped (%d, %d)\n", skipped.first, skipped.second);
449
450 std::vector<std::pair<Vector<2>, Vector<2>>> corner1 =
451 finder_.Find(blob_filt_.FilterBlobs(frame1.blob_list));
452 std::vector<std::pair<Vector<2>, Vector<2>>> corner2 =
453 finder_.Find(blob_filt_.FilterBlobs(frame2.blob_list));
454
455 Vector<2> cent1;
456 Vector<2> cent2;
457 SelectTargets(corner1, corner2, &cent1, &cent2);
458
459 /*
460 int target_count_;
461 if (cent1 == Vector<2>(0, 0) && cent2 == Vector<2>(0, 0)) {
462 missed_count_ += std::min(skipped.first, skipped.second);
463 if (missed_count_ > 15) {
464 seeking_target_ = true;
465 DrawSuperSpeed();
466 SetTime(aos::vision::MsTime(1));
467 if (line_break_) {
468 printf("_-_-_-%d_-_-_-_\n", target_count_);
469 target_count_++;
470 line_break_ = false;
471 }
472 if (continue_to_next_target) {
473 continue_to_next_target = false;
474 }
475 continue;
476 }
477 } else {
478 missed_count_ = 0;
479 }
480 */
481
482 if (seeking_target_) {
483 if (play_forward) {
484 // Go back to the last time we didn't see a target and play from there.
485 TickBackFrame(nano_step);
486 seeking_target_ = false;
487 } else if (seeking_target_) {
488 TickFrame(nano_step);
489 seeking_target_ = false;
490 }
491 continue;
492 }
493
494 // comment out to turn off full blob drawing
495 view_.DrawBlobList(frame1.blob_list, {0, 0, 255});
496 view_.DrawSecondBlobList(frame2.blob_list, {0, 255, 0}, {0, 255, 255});
497
498 DrawCross(overlay_, Vector<2>(fmt_.w / 2.0, fmt_.h / 2.0), {255, 0, 0});
499
500 double timeFromEpoch =
501 1e-9 * ((double)frame1.timestamp + (double)frame2.timestamp) / 2;
502 printf("timestamp: %g skew: %g\n", timeFromEpoch,
503 1e-9 * ((double)frame1.timestamp - (double)frame2.timestamp));
504 /*
505 if (cent1 == Vector<2>(0, 0) && cent2 == Vector<2>(0, 0)) {
506 } else {
507 DrawCross(overlay_, cent1, {255, 255, 255});
508 DrawCross(overlay_, cent2, {255, 255, 255});
509 double x = (cent1.x() + cent2.x()) / 2.0;
510 DrawCross(overlay_, Vector<2>(x, fmt_.h / 2.0), {255, 255, 255});
511 SetTime(aos::vision::MsTime(100));
512 if (pause_on_next_target && !continue_to_next_target) {
513 paused = true;
514 pause_on_next_target = false;
515 }
516 line_break_ = true;
517 missed_count_ = 0;
518 }
519 fflush(stdout);
520 */
521 view_.view()->Redraw();
522 break;
523 }
524 }
525
526 void DrawCross(PixelLinesOverlay &overlay, Vector<2> center, PixelRef color) {
Parker Schuh24ee58d2017-03-11 16:13:23 -0800527 overlay.AddLine(Vector<2>(center.x() - 25, center.y()),
Parker Schuhd7db83d2017-02-08 20:49:15 -0800528 Vector<2>(center.x() + 25, center.y()), color);
Parker Schuh24ee58d2017-03-11 16:13:23 -0800529 overlay.AddLine(Vector<2>(center.x(), center.y() - 25),
Parker Schuhd7db83d2017-02-08 20:49:15 -0800530 Vector<2>(center.x(), center.y() + 25), color);
531 }
532
533 void AddTo(aos::events::EpollLoop *loop) {
534 Done();
535 loop->AddWait(this);
536 }
537
538 std::unique_ptr<PixelRef[]> outbuf;
539 ImagePtr ptr;
540
541 BlobStreamViewer view_;
542
543 private:
544 int ms_event_delta_ = 200;
545 public:
546 // basic image size
547 ImageFormat fmt_;
548
549 // where we darw for debugging
550 PixelLinesOverlay overlay_;
551
552 // Where we draw text on the screen.
553 LambdaOverlay text_overlay_;
554 // container for viewer
555 std::vector<OverlayBase *> overlays_;
556
557 InputFile ifs1_;
558 InputFile ifs2_;
559
560 // our blob processing object
561 HistogramBlobFilter blob_filt_;
562
563 // corner finder to align aiming
564 CornerFinder finder_;
565
566 // indicates we have lost a target
567 bool line_break_ = false;
568
569 // indicates we are looking for the next target
570 bool seeking_target_ = false;
571
572 int frame_count_ = 0;
573
574 // count how many frames we miss in a row.
575 int missed_count_ = 16;
576};
577}
578} // namespace y2016::vision
579
580int main(int argc, char *argv[]) {
581 using namespace y2016::vision;
582 aos::events::EpollLoop loop;
583 gtk_init(&argc, &argv);
584
585 if (argc != 3) {
586 printf("Wrong number of arguments. Got (%d) expected 3.\n", argc);
587 printf(
588 " arguments are debug level as {0, 1, 2} and then filename without the "
589 "{_0.dat,_1.dat} suffixes\n");
590 }
591
592 int dbg = std::stoi(argv[1]);
593
594 std::string file(argv[2]);
595 aos::vision::ImageFormat fmt = {640 * 2, 480 * 2};
596
597 printf("file (%s) dbg_lvl (%d)\n", file.c_str(), dbg);
598
599 std::string fname_path = file;
600 NetworkForwardingImageStream strm1(
601 fmt, dbg, fname_path + "_0.dat", fname_path + "_1.dat");
602 fprintf(stderr, "staring main\n");
603 strm1.AddTo(&loop);
604
605 fprintf(stderr, "staring main\n");
606 loop.RunWithGtkMain();
607}