Fawkes API Fawkes Development Version
net.cpp
1
2/***************************************************************************
3 * net.cpp - Camera to access images over the network
4 *
5 * Created: Wed Feb 01 12:24:04 2006
6 * Copyright 2005-2008 Tim Niemueller [www.niemueller.de]
7 *
8 ****************************************************************************/
9
10/* This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version. A runtime exception applies to
14 * this software (see LICENSE.GPL_WRE file mentioned below for details).
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * Read the full text in the LICENSE.GPL_WRE file in the doc directory.
22 */
23
24#include <core/exception.h>
25#include <core/exceptions/software.h>
26#include <fvcams/cam_exceptions.h>
27#include <fvcams/net.h>
28#include <fvutils/compression/jpeg_decompressor.h>
29#include <fvutils/net/fuse_client.h>
30#include <fvutils/net/fuse_image_content.h>
31#include <fvutils/net/fuse_imagelist_content.h>
32#include <fvutils/net/fuse_message.h>
33#include <fvutils/system/camargp.h>
34#include <netinet/in.h>
35
36#include <cstdlib>
37#include <cstring>
38
39using namespace fawkes;
40
41namespace firevision {
42
43/** @class NetworkCamera <fvcams/net.h>
44 * Network camera.
45 * Retrieve images via network (FUSE).
46 * @see FuseClient
47 * @author Tim Niemueller
48 */
49
50/** Constructor.
51 * Allows to initiate a NetworkCamera w/o specifying an image id. This can be
52 * done later with the set_image_id() method.
53 * @param host host to connect to
54 * @param port port to connect to
55 * @param jpeg if true jpeg images will be transferred and automatically be
56 * decompressed, otherwise raw images are transferred
57 */
58NetworkCamera::NetworkCamera(const char *host, unsigned short port, bool jpeg)
59{
60 if (host == NULL) {
61 throw NullPointerException("NetworkCamera: host must not be NULL");
62 }
63 image_id_ = 0;
64 host_ = strdup(host);
65 port_ = port;
66 get_jpeg_ = jpeg;
67
68 connected_ = false;
69 opened_ = false;
70 local_version_ = 0;
71 remote_version_ = 0;
72 decompressor_ = NULL;
73 decompressed_buffer_ = NULL;
74 last_width_ = 0;
75 last_height_ = 0;
76 fuse_image_ = NULL;
77 fuse_message_ = NULL;
78 fuse_imageinfo_ = NULL;
79
80 fusec_ = new FuseClient(host_, port_, this);
81 if (get_jpeg_) {
82 decompressor_ = new JpegImageDecompressor();
83 }
84}
85
86/** Constructor.
87 * @param host host to connect to
88 * @param port port to connect to
89 * @param image_id image ID of image to retrieve
90 * @param jpeg if true jpeg images will be transferred and automatically be
91 * decompressed, otherwise raw images are transferred
92 */
93NetworkCamera::NetworkCamera(const char *host, unsigned short port, const char *image_id, bool jpeg)
94{
95 if (image_id == NULL) {
96 throw NullPointerException("NetworkCamera: image_id must not be NULL");
97 }
98 if (host == NULL) {
99 throw NullPointerException("NetworkCamera: host must not be NULL");
100 }
101 image_id_ = strdup(image_id);
102 host_ = strdup(host);
103 port_ = port;
104 get_jpeg_ = jpeg;
105
106 connected_ = false;
107 opened_ = false;
108 local_version_ = 0;
109 remote_version_ = 0;
110 decompressor_ = NULL;
111 decompressed_buffer_ = NULL;
112 last_width_ = 0;
113 last_height_ = 0;
114 fuse_image_ = NULL;
115 fuse_message_ = NULL;
116 fuse_imageinfo_ = NULL;
117
118 fusec_ = new FuseClient(host_, port_, this);
119 if (get_jpeg_) {
120 decompressor_ = new JpegImageDecompressor();
121 }
122}
123
124/** Constructor.
125 * Initialize with parameters from camera argument parser, supported values are:
126 * - host=HOST, hostname or IP of host to connect to
127 * - port=PORT, port number to connect to
128 * - image=ID, image ID of image to retrieve
129 * - jpeg=<true|false>, if true JPEGs are recieved and decompressed otherwise
130 * raw images will be transferred (raw is the default)
131 * @param cap camera argument parser
132 */
134{
135 if (cap->has("image")) {
136 image_id_ = strdup(cap->get("image").c_str());
137 } else {
138 throw NullPointerException("image parameter must be set");
139 }
140 if (cap->has("host")) {
141 host_ = strdup(cap->get("host").c_str());
142 } else {
143 host_ = strdup("localhost");
144 }
145 if (cap->has("port")) {
146 int i = atoi(cap->get("port").c_str());
147 if ((i < 0) || (i >= 0xFFFF)) {
148 throw IllegalArgumentException("Port must be in the range 0-65535");
149 }
150 port_ = (unsigned int)i;
151 } else {
152 port_ = 2208;
153 }
154
155 get_jpeg_ = (cap->has("jpeg") && (cap->get("jpeg") == "true"));
156
157 connected_ = false;
158 opened_ = false;
159 local_version_ = 0;
160 remote_version_ = 0;
161 decompressor_ = NULL;
162 decompressed_buffer_ = NULL;
163 last_width_ = 0;
164 last_height_ = 0;
165 fuse_image_ = NULL;
166 fuse_message_ = NULL;
167 fuse_imageinfo_ = NULL;
168
169 fusec_ = new FuseClient(host_, port_, this);
170 if (get_jpeg_) {
171 decompressor_ = new JpegImageDecompressor();
172 }
173}
174
175/** Destructor. */
177{
178 close();
179 delete fusec_;
180 free(host_);
181 free(image_id_);
182 if (decompressed_buffer_ != NULL)
183 free(decompressed_buffer_);
184 delete decompressor_;
185}
186
187void
189{
190 if (opened_)
191 return;
192
193 fusec_->connect();
194 fusec_->start();
195 fusec_->wait_greeting();
196
197 if (image_id_) {
198 FUSE_imagedesc_message_t *imagedesc =
200 strncpy(imagedesc->image_id, image_id_, IMAGE_ID_MAX_LENGTH - 1);
201 fusec_->enqueue_and_wait(FUSE_MT_GET_IMAGE_INFO, imagedesc, sizeof(FUSE_imagedesc_message_t));
202
203 if (!fuse_imageinfo_) {
204 throw Exception("Could not receive image info. Image not available?");
205 }
206 }
207
208 opened_ = true;
209}
210
211void
213{
214 started_ = true;
215}
216
217void
219{
220 started_ = false;
221}
222
223void
225{
226}
227
228void
230{
231 if (!connected_) {
232 throw CaptureException("Capture failed, not connected");
233 }
234 if (fuse_image_) {
235 throw CaptureException("You must dispose the buffer before fetching a new image");
236 }
237 if (!image_id_) {
238 throw CaptureException("You must specify an image id");
239 }
240
242 memset(irm, 0, sizeof(FUSE_imagereq_message_t));
243 strncpy(irm->image_id, image_id_, IMAGE_ID_MAX_LENGTH - 1);
244 irm->format = (get_jpeg_ ? FUSE_IF_JPEG : FUSE_IF_RAW);
245 fusec_->enqueue_and_wait(FUSE_MT_GET_IMAGE, irm, sizeof(FUSE_imagereq_message_t));
246
247 if (!connected_) {
248 throw CaptureException("Capture failed, connection died while waiting for image");
249 }
250 if (!fuse_image_) {
251 throw CaptureException("Fetching the image failed, no image received");
252 }
253
254 if (get_jpeg_) {
255 if ((fuse_image_->pixel_width() != last_width_)
256 || (fuse_image_->pixel_height() != last_height_)) {
257 if (decompressed_buffer_ != NULL) {
258 free(decompressed_buffer_);
259 }
260 size_t buffer_size = colorspace_buffer_size(YUV422_PLANAR,
261 fuse_image_->pixel_width(),
262 fuse_image_->pixel_height());
263 decompressed_buffer_ = (unsigned char *)malloc(buffer_size);
264 decompressor_->set_decompressed_buffer(decompressed_buffer_, buffer_size);
265 }
266 decompressor_->set_compressed_buffer(fuse_image_->buffer(), fuse_image_->buffer_size());
267 decompressor_->decompress();
268 }
269}
270
271unsigned char *
273{
274 if (get_jpeg_) {
275 return decompressed_buffer_;
276 } else {
277 if (fuse_image_) {
278 return fuse_image_->buffer();
279 } else {
280 return NULL;
281 }
282 }
283}
284
285unsigned int
287{
288 if (get_jpeg_) {
289 return colorspace_buffer_size(YUV422_PLANAR, pixel_width(), pixel_height());
290 } else {
291 if (!fuse_image_) {
292 return 0;
293 } else {
294 return colorspace_buffer_size((colorspace_t)fuse_image_->colorspace(),
295 fuse_image_->pixel_width(),
296 fuse_image_->pixel_height());
297 }
298 }
299}
300
301void
303{
305 if (started_) {
306 stop();
307 }
308 if (fuse_imageinfo_) {
309 free(fuse_imageinfo_);
310 fuse_imageinfo_ = NULL;
311 }
312 if (opened_) {
313 fusec_->disconnect();
314 fusec_->cancel();
315 fusec_->join();
316 opened_ = false;
317 }
318}
319
320void
322{
323 delete fuse_image_;
324 fuse_image_ = NULL;
325 if (fuse_message_) {
326 fuse_message_->unref();
327 fuse_message_ = NULL;
328 }
329}
330
331unsigned int
333{
334 if (fuse_imageinfo_) {
335 return ntohl(fuse_imageinfo_->width);
336 } else {
337 throw NullPointerException("No valid image info received");
338 }
339}
340
341unsigned int
343{
344 if (fuse_imageinfo_) {
345 return ntohl(fuse_imageinfo_->height);
346 } else {
347 throw NullPointerException("No valid image info received");
348 }
349}
350
353{
354 if (fuse_image_) {
355 return fuse_image_->capture_time();
356 } else {
357 throw NullPointerException("No valid image exists");
358 }
359}
360
361void
363{
364 if (!connected_)
365 return;
367}
368
369bool
371{
372 return connected_;
373}
374
375/** Select the image that is opened.
376 * @param image_id the image id
377 */
378void
379NetworkCamera::set_image_id(const char *image_id)
380{
381 image_id_ = strdup(image_id);
382
383 FUSE_imagedesc_message_t *imagedesc =
385 strncpy(imagedesc->image_id, image_id_, IMAGE_ID_MAX_LENGTH - 1);
386 fusec_->enqueue_and_wait(FUSE_MT_GET_IMAGE_INFO, imagedesc, sizeof(FUSE_imagedesc_message_t));
387
388 if (!fuse_imageinfo_) {
389 throw Exception("Could not received image info. Image not available?");
390 }
391}
392
393void
395{
396 // ignored, has to go away anyway
397}
398
399colorspace_t
401{
402 if (get_jpeg_) {
403 return YUV422_PLANAR;
404 } else {
405 if (fuse_imageinfo_) {
406 return (colorspace_t)ntohs(fuse_imageinfo_->colorspace);
407 } else {
408 return CS_UNKNOWN;
409 }
410 }
411}
412
413/** List the available images.
414 * @return a vector containing information about the available images
415 */
416std::vector<FUSE_imageinfo_t> &
418{
419 image_list_.clear();
420
421 if (!connected_) {
422 throw CaptureException("Capture failed, not connected");
423 }
424
425 fusec_->enqueue_and_wait(FUSE_MT_GET_IMAGE_LIST);
426
427 return image_list_;
428}
429
430void
431NetworkCamera::fuse_invalid_server_version(uint32_t local_version, uint32_t remote_version) noexcept
432{
433 local_version_ = local_version;
434 remote_version_ = remote_version;
435}
436
437void
439{
440 connected_ = true;
441}
442
443void
445{
446 connected_ = false;
447}
448
449void
451{
452 switch (m->type()) {
453 case FUSE_MT_IMAGE:
454 try {
455 fuse_image_ = m->msgc<FuseImageContent>();
456 if (fuse_image_) {
457 fuse_message_ = m;
458 fuse_message_->ref();
459 }
460 } catch (Exception &e) {
461 fuse_image_ = NULL;
462 fuse_message_ = NULL;
463 }
464 break;
465
466 case FUSE_MT_IMAGE_INFO: try { fuse_imageinfo_ = m->msg_copy<FUSE_imageinfo_t>();
467 } catch (Exception &e) {
468 fuse_imageinfo_ = NULL;
469 }
470 break;
471
472 case FUSE_MT_IMAGE_INFO_FAILED: fuse_imageinfo_ = NULL; break;
473
474 case FUSE_MT_GET_IMAGE_FAILED:
475 if (fuse_message_) {
476 fuse_message_->unref();
477 }
478 fuse_message_ = NULL;
479 fuse_image_ = NULL;
480 break;
481
482 case FUSE_MT_IMAGE_LIST:
483 try {
484 FuseImageListContent *fuse_image_list = m->msgc<FuseImageListContent>();
485 if (fuse_image_list) {
486 while (fuse_image_list->has_next()) {
487 FUSE_imageinfo_t *iip = fuse_image_list->next();
489 strncpy(ii.image_id, iip->image_id, IMAGE_ID_MAX_LENGTH);
490 ii.colorspace = ntohs(iip->colorspace);
491 ii.width = ntohl(iip->width);
492 ii.height = ntohl(iip->height);
493 ii.buffer_size = ntohl(iip->buffer_size);
494 image_list_.push_back(ii);
495 }
496 }
497 } catch (Exception &e) {
498 }
499 break;
500
501 default: break;
502 }
503}
504
505} // end namespace firevision
Base class for exceptions in Fawkes.
Definition: exception.h:36
Expected parameter is missing.
Definition: software.h:80
A NULL pointer was supplied where not allowed.
Definition: software.h:32
void unref()
Decrement reference count and conditionally delete this instance.
Definition: refcount.cpp:95
void start(bool wait=true)
Call this method to start the thread.
Definition: thread.cpp:499
void join()
Join the thread.
Definition: thread.cpp:597
void cancel()
Cancel a thread.
Definition: thread.cpp:646
A class for handling time.
Definition: time.h:93
Camera argument parser.
Definition: camargp.h:36
bool has(std::string s) const
Check if an parameter was given.
Definition: camargp.cpp:145
std::string get(std::string s) const
Get the value of the given parameter.
Definition: camargp.cpp:156
Capturing a frame failed.
void wait_greeting()
Wait for greeting message.
void enqueue_and_wait(FuseNetworkMessage *message)
Enqueue message and wait for reply.
void connect()
Connect.
void disconnect()
Disconnect.
size_t buffer_size() const
Get size of buffer.
unsigned int colorspace() const
Get colorspace.
fawkes::Time * capture_time() const
Get capture time.
unsigned char * buffer() const
Image buffer.
unsigned int pixel_height() const
Get image height.
unsigned int pixel_width() const
Get image width.
bool has_next()
Check if another image info is available.
FUSE_imageinfo_t * next()
Get next image info.
FUSE Network Message.
Definition: fuse_message.h:40
virtual void set_decompressed_buffer(unsigned char *buf, unsigned int buf_size)
Set decompressed buffer.
virtual void set_compressed_buffer(unsigned char *buf, unsigned int buf_size)
Set compressed buffer.
Decompressor for JPEG images.
virtual void decompress()
Decompress image.
virtual void open()
Open the camera.
Definition: net.cpp:188
virtual unsigned int pixel_height()
Height of image in pixels.
Definition: net.cpp:342
virtual ~NetworkCamera()
Destructor.
Definition: net.cpp:176
virtual void stop()
Stop image transfer from the camera.
Definition: net.cpp:218
virtual bool ready()
Camera is ready for taking pictures.
Definition: net.cpp:370
virtual std::vector< FUSE_imageinfo_t > & image_list()
List the available images.
Definition: net.cpp:417
virtual colorspace_t colorspace()
Colorspace of returned image.
Definition: net.cpp:400
virtual void fuse_inbound_received(FuseNetworkMessage *m) noexcept
Message received.
Definition: net.cpp:450
virtual void fuse_connection_established() noexcept
Connection has been established.
Definition: net.cpp:438
virtual void set_image_number(unsigned int n)
Set image number to retrieve.
Definition: net.cpp:394
virtual unsigned char * buffer()
Get access to current image buffer.
Definition: net.cpp:272
virtual void print_info()
Print out camera information.
Definition: net.cpp:224
virtual void fuse_connection_died() noexcept
Connection died.
Definition: net.cpp:444
virtual unsigned int buffer_size()
Size of buffer.
Definition: net.cpp:286
virtual void start()
Start image transfer from the camera.
Definition: net.cpp:212
virtual void flush()
Flush image queue.
Definition: net.cpp:362
NetworkCamera(const char *host, unsigned short port, bool jpeg=false)
Constructor.
Definition: net.cpp:58
virtual fawkes::Time * capture_time()
Get the Time of the last successfully captured image.
Definition: net.cpp:352
virtual void close()
Close camera.
Definition: net.cpp:302
virtual unsigned int pixel_width()
Width of image in pixels.
Definition: net.cpp:332
virtual void dispose_buffer()
Dispose current buffer.
Definition: net.cpp:321
virtual void set_image_id(const char *image_id)
Select the image that is opened.
Definition: net.cpp:379
virtual void capture()
Capture an image.
Definition: net.cpp:229
virtual void fuse_invalid_server_version(uint32_t local_version, uint32_t remote_version) noexcept
Invalid version string received.
Definition: net.cpp:431
Fawkes library namespace.
Image description message.
Definition: fuse.h:156
char image_id[IMAGE_ID_MAX_LENGTH]
image ID
Definition: fuse.h:157
Image info message.
Definition: fuse.h:168
uint32_t colorspace
color space
Definition: fuse.h:170
uint32_t height
height in pixels
Definition: fuse.h:173
uint32_t width
width in pixels
Definition: fuse.h:172
char image_id[IMAGE_ID_MAX_LENGTH]
image ID
Definition: fuse.h:169
uint32_t buffer_size
size of following image buffer in bytes
Definition: fuse.h:174
Image request message.
Definition: fuse.h:148
char image_id[IMAGE_ID_MAX_LENGTH]
image ID
Definition: fuse.h:149
uint32_t format
requested image format, see FUSE_image_format_t
Definition: fuse.h:150