Revision: 8651
http://playerstage.svn.sourceforge.net/playerstage/?rev=8651&view=rev
Author: thjc
Date: 2010-05-03 17:59:33 +0000 (Mon, 03 May 2010)
Log Message:
-----------
Applied patch 2960235: New drivers for surveillance systems
Modified Paths:
--------------
code/player/trunk/server/drivers/camera/CMakeLists.txt
Added Paths:
-----------
code/player/trunk/server/drivers/camera/imgcmp/
code/player/trunk/server/drivers/camera/imgcmp/CMakeLists.txt
code/player/trunk/server/drivers/camera/imgcmp/imgcmp.cc
code/player/trunk/server/drivers/camera/imgsave/
code/player/trunk/server/drivers/camera/imgsave/CMakeLists.txt
code/player/trunk/server/drivers/camera/imgsave/imgsave.cc
code/player/trunk/server/drivers/camera/imgsave/videofont.h
Modified: code/player/trunk/server/drivers/camera/CMakeLists.txt
===================================================================
--- code/player/trunk/server/drivers/camera/CMakeLists.txt 2010-05-03
17:55:28 UTC (rev 8650)
+++ code/player/trunk/server/drivers/camera/CMakeLists.txt 2010-05-03
17:59:33 UTC (rev 8651)
@@ -6,6 +6,8 @@
ADD_SUBDIRECTORY (cvcam)
ADD_SUBDIRECTORY (gstreamer)
ADD_SUBDIRECTORY (imageseq)
+ADD_SUBDIRECTORY (imgcmp)
+ADD_SUBDIRECTORY (imgsave)
ADD_SUBDIRECTORY (sphere)
ADD_SUBDIRECTORY (uvc)
ADD_SUBDIRECTORY (yarp)
Added: code/player/trunk/server/drivers/camera/imgcmp/CMakeLists.txt
===================================================================
--- code/player/trunk/server/drivers/camera/imgcmp/CMakeLists.txt
(rev 0)
+++ code/player/trunk/server/drivers/camera/imgcmp/CMakeLists.txt
2010-05-03 17:59:33 UTC (rev 8651)
@@ -0,0 +1,7 @@
+PLAYERDRIVER_OPTION (imgcmp build_imgcmp ON)
+IF (HAVE_JPEG)
+ PLAYERDRIVER_REQUIRE_HEADER (imgcmp build_imgcmp jpeglib.h stdio.h)
+ PLAYERDRIVER_ADD_DRIVER (imgcmp build_imgcmp LINKFLAGS "-ljpeg" SOURCES
imgcmp.cc)
+ELSE (HAVE_JPEG)
+ PLAYERDRIVER_ADD_DRIVER (imgcmp build_imgcmp SOURCES imgcmp.cc)
+ENDIF (HAVE_JPEG)
Added: code/player/trunk/server/drivers/camera/imgcmp/imgcmp.cc
===================================================================
--- code/player/trunk/server/drivers/camera/imgcmp/imgcmp.cc
(rev 0)
+++ code/player/trunk/server/drivers/camera/imgcmp/imgcmp.cc 2010-05-03
17:59:33 UTC (rev 8651)
@@ -0,0 +1,627 @@
+/*
+ * Player - One Hell of a Robot Server
+ * Copyright (C) 2000 Brian Gerkey et al.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+/** @ingroup drivers */
+/** @{ */
+/** @defgroup driver_imgcmp imgcmp
+ * @brief image comparing driver
+
+The imgcmp driver compares current image frame with previous one in order to
detect
+any changes on it. Frames that not differ will have the same timestamp.
+
+...@par Compile-time dependencies
+
+- none
+
+...@par Provides
+
+- @ref interface_camera (key "output" - regular image output)
+- @ref interface_dio (to signal change detection)
+- (optional) @ref interface_camera (key "diff" - differences map)
+
+Any command sent to provided dio interface forces positive compare result.
+
+...@par Requires
+
+- @ref interface_camera
+- (optionally) @ref interface_dio (to signal change detection by sending dio
commands)
+
+...@par Configuration requests
+
+- none
+
+...@par Configuration file options
+
+- see properties section
+
+...@par Properties
+
+- skip_lines (integer)
+ - Default: 0
+ - During computations, skip n lines from the top
+ (as usually there's nothing interesting in first few lines)
+- sleep_nsec (integer)
+ - Default: 10000
+ - timespec value for additional nanosleep()
+- max_lum_dist (integer)
+ - Default: 0
+ - Allowed values: 0 - 255
+ - Maximal luminance distance between two pixels in old and new images; if
luminance distance
+ computed for two pixels (old and new) is greater than max_lum_dist, these
pixels differ.
+- max_diff_pixels (integer)
+ - Default: 0
+ - Allowed value: 0 - 100
+ - Percents of pixels that differ (see above) to consider that two images
+ (old and new) are different.
+- idle_publish_interval (double)
+ - Default: 0.5
+ - Image publish interval (in seconds) whenever differences were not detected.
+- keep_buffer (integer)
+ - Default: 1
+ - If set to non-zero, buffer with previous image is kept until change is
detected.
+ Otherwise, only two last frames will be compared. Set this property to
zero for noisy
+ camera image and bad light.
+
+...@par Example
+
+...@verbatim
+driver
+(
+ name "imgcmp"
+ requires ["camera:1"]
+ provides ["output:::camera:0" "dio:0"]
+ skip_lines 16
+ max_lum_dist 128
+ max_diff_pixels 50
+ keep_buffer 0
+)
+...@endverbatim
+
+...@author Paul Osmialowski
+
+*/
+/** @} */
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <time.h>
+#include <pthread.h>
+#include <math.h>
+#include <libplayercore/playercore.h>
+#include <config.h>
+#if HAVE_JPEG
+ #include <libplayerjpeg/playerjpeg.h>
+#endif
+
+#define QUEUE_LEN 1
+
+class ImgCmp : public ThreadedDriver
+{
+ public: ImgCmp(ConfigFile * cf, int section);
+ public: virtual ~ImgCmp();
+
+ public: virtual int MainSetup();
+ public: virtual void MainQuit();
+
+ // This method will be invoked on each incoming message
+ public: virtual int ProcessMessage(QueuePointer & resp_queue,
+ player_msghdr * hdr,
+ void * data);
+
+ private: virtual void Main();
+
+ // Input camera device
+ private: player_devaddr_t camera_provided_addr, dio_provided_addr,
diff_provided_addr, camera_id, dio_id;
+ private: Device * camera;
+ private: Device * dio;
+ private: struct
+ {
+ unsigned char * buffer;
+ size_t bufsize;
+ } buffers[2];
+ private: int currentbuffer;
+ private: int use_dio;
+ private: int publish_diffs;
+ private: int forced;
+ private: double lastTStamp;
+ private: double lastPublish;
+ private: IntProperty skip_lines;
+ private: IntProperty sleep_nsec;
+ private: IntProperty max_lum_dist;
+ private: IntProperty max_diff_pixels;
+ private: DoubleProperty idle_publish_interval;
+ private: IntProperty keep_buffer;
+};
+
+Driver * ImgCmp_Init(ConfigFile * cf, int section)
+{
+ return reinterpret_cast<Driver *>(new ImgCmp(cf, section));
+}
+
+void imgcmp_Register(DriverTable *table)
+{
+ table->AddDriver("imgcmp", ImgCmp_Init);
+}
+
+ImgCmp::ImgCmp(ConfigFile * cf, int section)
+ : ThreadedDriver(cf, section, true, QUEUE_LEN),
+ skip_lines("skip_lines", 0, false),
+ sleep_nsec("sleep_nsec", 10000, false),
+ max_lum_dist("max_lum_dist", 0, false),
+ max_diff_pixels("max_diff_pixels", 0, false),
+ idle_publish_interval("idle_publish_interval", 0.5, false),
+ keep_buffer("keep_buffer", 1, false)
+{
+ memset(&(this->camera_provided_addr), 0, sizeof(player_devaddr_t));
+ memset(&(this->dio_provided_addr), 0, sizeof(player_devaddr_t));
+ memset(&(this->diff_provided_addr), 0, sizeof(player_devaddr_t));
+ memset(&(this->camera_id), 0, sizeof(player_devaddr_t));
+ memset(&(this->dio_id), 0, sizeof(player_devaddr_t));
+ this->camera = NULL;
+ this->dio = NULL;
+ memset(this->buffers, 0, sizeof this->buffers);
+ this->buffers[0].buffer = NULL;
+ this->buffers[0].bufsize = 0;
+ this->buffers[1].buffer = NULL;
+ this->buffers[1].bufsize = 0;
+ this->currentbuffer = 0;
+ this->use_dio = 0;
+ this->publish_diffs = 0;
+ this->forced = 0;
+ this->lastTStamp = 0.0;
+ this->lastPublish = 0.0;
+ if (cf->ReadDeviceAddr(&(this->camera_provided_addr), section, "provides",
PLAYER_CAMERA_CODE, -1, "output"))
+ {
+ this->SetError(-1);
+ return;
+ }
+ if (this->AddInterface(this->camera_provided_addr))
+ {
+ this->SetError(-1);
+ return;
+ }
+ if (cf->ReadDeviceAddr(&(this->dio_provided_addr), section, "provides",
PLAYER_DIO_CODE, -1, NULL))
+ {
+ this->SetError(-1);
+ return;
+ }
+ if (this->AddInterface(this->dio_provided_addr))
+ {
+ this->SetError(-1);
+ return;
+ }
+ if (cf->ReadDeviceAddr(&(this->diff_provided_addr), section, "provides",
PLAYER_CAMERA_CODE, -1, "diff"))
+ {
+ this->publish_diffs = 0;
+ } else
+ {
+ if (this->AddInterface(this->diff_provided_addr))
+ {
+ this->SetError(-1);
+ return;
+ }
+ this->publish_diffs = !0;
+ }
+ if (cf->ReadDeviceAddr(&(this->camera_id), section, "requires",
PLAYER_CAMERA_CODE, -1, NULL) != 0)
+ {
+ this->SetError(-1);
+ return;
+ }
+ if (cf->ReadDeviceAddr(&(this->dio_id), section, "requires",
PLAYER_DIO_CODE, -1, NULL) != 0)
+ {
+ this->use_dio = 0;
+ } else
+ {
+ this->use_dio = !0;
+ }
+ if (!(this->RegisterProperty("skip_lines", &(this->skip_lines), cf,
section)))
+ {
+ this->SetError(-1);
+ return;
+ }
+ if (this->skip_lines.GetValue() < 0)
+ {
+ this->SetError(-1);
+ return;
+ }
+ if (!(this->RegisterProperty("sleep_nsec", &(this->sleep_nsec), cf,
section)))
+ {
+ this->SetError(-1);
+ return;
+ }
+ if (this->sleep_nsec.GetValue() < 0)
+ {
+ this->SetError(-1);
+ return;
+ }
+ if (!(this->RegisterProperty("max_lum_dist", &(this->max_lum_dist), cf,
section)))
+ {
+ this->SetError(-1);
+ return;
+ }
+ if ((this->max_lum_dist.GetValue() < 0) || (this->max_lum_dist.GetValue() >
255))
+ {
+ this->SetError(-1);
+ return;
+ }
+ if (!(this->RegisterProperty("max_diff_pixels", &(this->max_diff_pixels),
cf, section)))
+ {
+ this->SetError(-1);
+ return;
+ }
+ if ((this->max_diff_pixels.GetValue() < 0) ||
(this->max_diff_pixels.GetValue() > 255))
+ {
+ this->SetError(-1);
+ return;
+ }
+ if (!(this->RegisterProperty("idle_publish_interval",
&(this->idle_publish_interval), cf, section)))
+ {
+ this->SetError(-1);
+ return;
+ }
+ if (this->idle_publish_interval.GetValue() < 0.0)
+ {
+ this->SetError(-1);
+ return;
+ }
+ if (!(this->RegisterProperty("keep_buffer", &(this->keep_buffer), cf,
section)))
+ {
+ this->SetError(-1);
+ return;
+ }
+}
+
+ImgCmp::~ImgCmp()
+{
+ if (this->buffers[0].buffer) free(this->buffers[0].buffer);
+ this->buffers[0].buffer = NULL;
+ if (this->buffers[1].buffer) free(this->buffers[1].buffer);
+ this->buffers[1].buffer = NULL;
+}
+
+int ImgCmp::MainSetup()
+{
+ if (Device::MatchDeviceAddress(this->camera_id, this->camera_provided_addr))
+ {
+ PLAYER_ERROR("attempt to subscribe to self");
+ return -1;
+ }
+ if (this->use_dio)
+ {
+ if (Device::MatchDeviceAddress(this->dio_id, this->dio_provided_addr))
+ {
+ PLAYER_ERROR("attempt to subscribe to self");
+ return -1;
+ }
+ }
+ if (this->publish_diffs)
+ {
+ if (Device::MatchDeviceAddress(this->camera_id, this->diff_provided_addr))
+ {
+ PLAYER_ERROR("attempt to subscribe to self");
+ return -1;
+ }
+ }
+ this->camera = deviceTable->GetDevice(this->camera_id);
+ if (!this->camera)
+ {
+ PLAYER_ERROR("unable to locate suitable camera device");
+ return -1;
+ }
+ if (this->camera->Subscribe(this->InQueue) != 0)
+ {
+ PLAYER_ERROR("unable to subscribe to camera device");
+ this->camera = NULL;
+ return -1;
+ }
+ if (this->use_dio)
+ {
+ this->dio = deviceTable->GetDevice(this->dio_id);
+ if (!this->dio)
+ {
+ PLAYER_ERROR("unable to locate suitable dio device");
+ if (this->camera) this->camera->Unsubscribe(this->InQueue);
+ this->camera = NULL;
+ return -1;
+ }
+ if (this->dio->Subscribe(this->InQueue) != 0)
+ {
+ PLAYER_ERROR("unable to subscribe to dio device");
+ if (this->camera) this->camera->Unsubscribe(this->InQueue);
+ this->camera = NULL;
+ this->dio = NULL;
+ return -1;
+ }
+ }
+ return 0;
+}
+
+void ImgCmp::MainQuit()
+{
+ if (this->camera) this->camera->Unsubscribe(this->InQueue);
+ this->camera = NULL;
+ if (this->use_dio)
+ {
+ if (this->dio) this->dio->Unsubscribe(this->InQueue);
+ this->dio = NULL;
+ }
+}
+
+void ImgCmp::Main()
+{
+ struct timespec tspec;
+
+ for (;;)
+ {
+ this->InQueue->Wait();
+ pthread_testcancel();
+ this->ProcessMessages();
+ pthread_testcancel();
+ tspec.tv_sec = 0;
+ tspec.tv_nsec = this->sleep_nsec.GetValue();
+ if (tspec.tv_nsec > 0)
+ {
+ nanosleep(&tspec, NULL);
+ pthread_testcancel();
+ }
+ }
+}
+
+int ImgCmp::ProcessMessage(QueuePointer & resp_queue, player_msghdr * hdr,
void * data)
+{
+ player_camera_data_t * output = NULL;
+ int i, j;
+ size_t new_size;
+ unsigned char * ptr, * ptr1, * ptr2;
+ player_camera_data_t * rawdata;
+ int diff, diffs;
+ int nextbuffer = ((this->currentbuffer) ? 0 : 1);
+ double lum, lum1;
+ int skip_lines = this->skip_lines.GetValue();
+ int differ;
+ player_dio_data_t dio_data;
+ player_dio_cmd_t dio_cmd;
+ double t;
+ int d;
+
+ assert(hdr);
+ if (Message::MatchMessage(hdr, PLAYER_MSGTYPE_DATA, -1, this->dio_id))
+ {
+ assert(data);
+ return 0;
+ }
+ if (Message::MatchMessage(hdr, PLAYER_MSGTYPE_CMD, -1,
this->dio_provided_addr))
+ {
+ assert(data);
+ this->forced = !0;
+ return 0;
+ }
+ if (Message::MatchMessage(hdr, PLAYER_MSGTYPE_DATA,
PLAYER_CAMERA_DATA_STATE, this->camera_id))
+ {
+ assert(data);
+ rawdata = reinterpret_cast<player_camera_data_t *>(data);
+ if ((static_cast<int>(rawdata->width) <= 0) ||
(static_cast<int>(rawdata->height) <= 0))
+ {
+ return -1;
+ } else
+ {
+ new_size = rawdata->width * rawdata->height * 3;
+ if ((this->buffers[this->currentbuffer].bufsize) != new_size)
+ {
+ if (this->buffers[this->currentbuffer].buffer)
free(this->buffers[this->currentbuffer].buffer);
+ this->buffers[this->currentbuffer].buffer = NULL;
+ this->buffers[this->currentbuffer].bufsize = 0;
+ }
+ if (!(this->buffers[this->currentbuffer].buffer))
+ {
+ this->buffers[this->currentbuffer].bufsize = 0;
+ this->buffers[this->currentbuffer].buffer = reinterpret_cast<unsigned
char *>(malloc(new_size));
+ if (!(this->buffers[this->currentbuffer].buffer))
+ {
+ PLAYER_ERROR("Out of memory");
+ return -1;
+ }
+ this->buffers[this->currentbuffer].bufsize = new_size;
+ }
+ switch (rawdata->compression)
+ {
+ case PLAYER_CAMERA_COMPRESS_RAW:
+ switch (rawdata->bpp)
+ {
+ case 8:
+ ptr = this->buffers[this->currentbuffer].buffer;
+ ptr1 = reinterpret_cast<unsigned char *>(rawdata->image);
+ for (i = 0; i < static_cast<int>(rawdata->height); i++)
+ {
+ for (j = 0; j < static_cast<int>(rawdata->width); j++)
+ {
+ ptr[0] = *ptr1;
+ ptr[1] = *ptr1;
+ ptr[2] = *ptr1;
+ ptr += 3; ptr1++;
+ }
+ }
+ break;
+ case 24:
+ memcpy(this->buffers[this->currentbuffer].buffer, rawdata->image,
this->buffers[this->currentbuffer].bufsize);
+ break;
+ case 32:
+ ptr = this->buffers[this->currentbuffer].buffer;
+ ptr1 = reinterpret_cast<unsigned char *>(rawdata->image);
+ for (i = 0; i < static_cast<int>(rawdata->height); i++)
+ {
+ for (j = 0; j < static_cast<int>(rawdata->width); j++)
+ {
+ ptr[0] = ptr1[0];
+ ptr[1] = ptr1[1];
+ ptr[2] = ptr1[2];
+ ptr += 3; ptr1 += 4;
+ }
+ }
+ break;
+ default:
+ PLAYER_WARN("unsupported image depth (not good)");
+ return -1;
+ }
+ break;
+#if HAVE_JPEG
+ case PLAYER_CAMERA_COMPRESS_JPEG:
+ jpeg_decompress(this->buffers[this->currentbuffer].buffer,
this->buffers[this->currentbuffer].bufsize, rawdata->image,
rawdata->image_count);
+ break;
+#endif
+ default:
+ PLAYER_WARN("unsupported compression scheme (not good)");
+ return -1;
+ }
+ assert(skip_lines >= 0);
+ assert(skip_lines < static_cast<int>(rawdata->height));
+ assert(this->buffers[this->currentbuffer].buffer);
+ if ((this->buffers[nextbuffer].buffer) &&
((this->buffers[this->currentbuffer].bufsize) ==
(this->buffers[nextbuffer].bufsize)))
+ {
+ if (this->forced)
+ {
+ this->forced = 0;
+ differ = !0;
+ } else
+ {
+ if (this->publish_diffs)
+ {
+ output = reinterpret_cast<player_camera_data_t
*>(malloc(sizeof(player_camera_data_t)));
+ if (!output)
+ {
+ PLAYER_ERROR("Out of memory");
+ return -1;
+ }
+ memset(output, 0, sizeof(player_camera_data_t));
+ output->bpp = 8;
+ output->compression = PLAYER_CAMERA_COMPRESS_RAW;
+ output->format = PLAYER_CAMERA_FORMAT_MONO8;
+ output->fdiv = rawdata->fdiv;
+ output->width = rawdata->width;
+ output->height = rawdata->height;
+ output->image_count = ((rawdata->width) * (rawdata->height));
+ output->image = reinterpret_cast<uint8_t
*>(malloc(output->image_count));
+ if (!(output->image))
+ {
+ free(output);
+ PLAYER_ERROR("Out of memory");
+ return -1;
+ }
+ memset(output->image, 0, output->image_count);
+ ptr2 = output->image + (skip_lines * (rawdata->width));
+ } else ptr2 = NULL;
+ ptr = (this->buffers[this->currentbuffer].buffer) + (skip_lines *
(rawdata->width) * 3);
+ assert(ptr);
+ ptr1 = this->buffers[nextbuffer].buffer + (skip_lines *
(rawdata->width) * 3);
+ assert(ptr1);
+ diffs = 0;
+ differ = 0;
+ d = this->max_lum_dist.GetValue();
+ for (i = skip_lines; i < static_cast<int>(rawdata->height); i++)
+ {
+ for (j = 0; j < static_cast<int>(rawdata->width); j++)
+ {
+ lum = (0.299 * static_cast<double>(ptr[0])) + (0.587 *
static_cast<double>(ptr[1])) + (0.114 * static_cast<double>(ptr[2]));
+ lum1 = (0.299 * static_cast<double>(ptr1[0])) + (0.587 *
static_cast<double>(ptr1[1])) + (0.114 * static_cast<double>(ptr1[2]));
+ diff = static_cast<int>(fabs(lum - lum1));
+ assert(diff >= 0);
+ if (diff > 255)
+ {
+ PLAYER_WARN("difference too big");
+ diff = 255;
+ }
+ if (diff > d)
+ {
+ diffs++;
+ diff = 255;
+ }
+ if (this->publish_diffs)
+ {
+ assert(ptr2);
+ *ptr2 = static_cast<unsigned char>(diff);
+ ptr2++;
+ }
+ ptr += 3; ptr1 += 3;
+ }
+ }
+ if (this->publish_diffs)
+ {
+ this->Publish(this->diff_provided_addr, PLAYER_MSGTYPE_DATA,
PLAYER_CAMERA_DATA_STATE, reinterpret_cast<void *>(output), 0,
&(hdr->timestamp), false); // copy = false
+ // I assume that Publish() (with copy = false) freed those output
data!
+ output = NULL;
+ }
+ diffs = (static_cast<int>((static_cast<double>(diffs) /
static_cast<double>((rawdata->width) * (rawdata->height))) * 100.0));
+ differ = (diffs > (this->max_diff_pixels.GetValue()));
+ }
+ memset(&dio_data, 0, sizeof dio_data);
+ dio_data.count = 1;
+ dio_data.bits = differ ? 1 : 0;
+ this->Publish(this->dio_provided_addr, PLAYER_MSGTYPE_DATA,
PLAYER_DIO_DATA_VALUES, reinterpret_cast<void *>(&dio_data), 0,
&(hdr->timestamp), true); // copy = true
+ if (this->use_dio)
+ {
+ memset(&dio_cmd, 0, sizeof dio_cmd);
+ dio_cmd.count = 1;
+ dio_cmd.digout = differ ? 1 : 0;
+ this->dio->PutMsg(this->InQueue, PLAYER_MSGTYPE_CMD,
PLAYER_DIO_CMD_VALUES, reinterpret_cast<void *>(&dio_cmd), 0,
&(hdr->timestamp));
+ }
+ GlobalTime->GetTimeDouble(&t);
+ if ((differ) || (fabs(t - (this->lastPublish)) >
(this->idle_publish_interval.GetValue())))
+ {
+ output = reinterpret_cast<player_camera_data_t
*>(malloc(sizeof(player_camera_data_t)));
+ if (!output)
+ {
+ PLAYER_ERROR("Out of memory");
+ return -1;
+ }
+ memset(output, 0, sizeof(player_camera_data_t));
+ output->bpp = 24;
+ output->compression = PLAYER_CAMERA_COMPRESS_RAW;
+ output->format = PLAYER_CAMERA_FORMAT_RGB888;
+ output->fdiv = rawdata->fdiv;
+ output->width = rawdata->width;
+ output->height = rawdata->height;
+ output->image_count = this->buffers[this->currentbuffer].bufsize;
+ output->image = reinterpret_cast<uint8_t
*>(malloc(output->image_count));
+ if (!(output->image))
+ {
+ free(output);
+ PLAYER_ERROR("Out of memory");
+ return -1;
+ }
+ memcpy(output->image, this->buffers[this->currentbuffer].buffer,
output->image_count);
+ if (differ) this->lastTStamp = hdr->timestamp;
+ this->Publish(this->camera_provided_addr, PLAYER_MSGTYPE_DATA,
PLAYER_CAMERA_DATA_STATE, reinterpret_cast<void *>(output), 0,
&(this->lastTStamp), false); // copy = false
+ // I assume that Publish() (with copy = false) freed those output
data!
+ output = NULL;
+ this->lastPublish = t;
+ }
+ if ((differ) || (!(this->keep_buffer.GetValue()))) this->currentbuffer
= nextbuffer;
+ } else
+ {
+ this->lastTStamp = hdr->timestamp;
+ this->currentbuffer = nextbuffer;
+ }
+ }
+ return 0;
+ }
+ return -1;
+}
Added: code/player/trunk/server/drivers/camera/imgsave/CMakeLists.txt
===================================================================
--- code/player/trunk/server/drivers/camera/imgsave/CMakeLists.txt
(rev 0)
+++ code/player/trunk/server/drivers/camera/imgsave/CMakeLists.txt
2010-05-03 17:59:33 UTC (rev 8651)
@@ -0,0 +1,8 @@
+PLAYERDRIVER_OPTION (imgsave build_imgsave ON)
+PLAYERDRIVER_REJECT_OS (imgsave build_imgsave PLAYER_OS_WIN)
+IF (HAVE_JPEG)
+ PLAYERDRIVER_REQUIRE_HEADER (imgsave build_imgsave jpeglib.h stdio.h)
+ PLAYERDRIVER_ADD_DRIVER (imgsave build_imgsave LINKFLAGS "-ljpeg" SOURCES
imgsave.cc)
+ELSE (HAVE_JPEG)
+ PLAYERDRIVER_ADD_DRIVER (imgsave build_imgsave SOURCES imgsave.cc)
+ENDIF (HAVE_JPEG)
Added: code/player/trunk/server/drivers/camera/imgsave/imgsave.cc
===================================================================
--- code/player/trunk/server/drivers/camera/imgsave/imgsave.cc
(rev 0)
+++ code/player/trunk/server/drivers/camera/imgsave/imgsave.cc 2010-05-03
17:59:33 UTC (rev 8651)
@@ -0,0 +1,571 @@
+/*
+ * Player - One Hell of a Robot Server
+ * Copyright (C) 2000 Brian Gerkey et al.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+/** @ingroup drivers */
+/** @{ */
+/** @defgroup driver_imgsave imgsave
+ * @brief image storage dispatcher
+
+The imgsave driver stores received images into a directory tree in which paths
form
+such a pattern: key/date/hour, where key is the given key name of camera
device.
+By default images are written in human readable format called xyRGB (where
each line
+is formed by five integers: x, y, R, G, B of a pixel), alternatively, JPEG
compressed
+files can be stored. When desired, this driver can inprint image informations
at the
+top of stored and published images (key, date, time, number of current image
in given
+second). This driver publishes all images that are stored (if needed, JPEG
compressed).
+
+...@par Compile-time dependencies
+
+- none
+
+...@par Provides
+
+- @ref interface_camera
+
+...@par Requires
+
+- @ref interface_camera
+
+...@par Configuration requests
+
+- none
+
+...@par Configuration file options
+
+- key (string)
+ - Default: "Unnamed"
+ - The name of camera device (any name you like for it)
+- jpeg (integer)
+ - Default: 0
+ - If set to 1, images that are stored and published are JPEG compressed
+- jpeg_quality (float)
+ - Default: 0.8
+ - JPEG quality
+- print (integer)
+ - Default: 0
+ - If set to 1, images are decorated at the top with status info
+ (key, date, time, number of current image in given second)
+- sleep_nsec (integer)
+ - Default: 10000
+ - timespec value for additional nanosleep()
+
+...@par Properties
+
+- none
+
+...@par Example
+
+...@verbatim
+driver
+(
+ name "imgsave"
+ requires ["camera:0"]
+ provides ["camera:10"]
+ key "vault"
+ jpeg 1
+ print 1
+)
+...@endverbatim
+
+...@author Paul Osmialowski
+
+*/
+/** @} */
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <time.h>
+#include <pthread.h>
+#include <math.h>
+#include <libplayercore/playercore.h>
+#include <config.h>
+#if HAVE_JPEG
+ #include <libplayerjpeg/playerjpeg.h>
+#endif
+#include "videofont.h"
+
+#define QUEUE_LEN 1
+#define MAX_KEY_LEN 15
+#define MAX_STAMP_LEN 255
+#define EPS 0.00001
+
+class ImgSave : public ThreadedDriver
+{
+ public: ImgSave(ConfigFile * cf, int section);
+ public: virtual ~ImgSave();
+
+ public: virtual int MainSetup();
+ public: virtual void MainQuit();
+
+ // This method will be invoked on each incoming message
+ public: virtual int ProcessMessage(QueuePointer & resp_queue,
+ player_msghdr * hdr,
+ void * data);
+
+ private: virtual void Main();
+
+ // Input camera device
+ private: player_devaddr_t camera_provided_addr, camera_id;
+ private: Device * camera;
+ private: char key[MAX_KEY_LEN + 1];
+ private: int jpeg;
+ private: double jpeg_quality;
+ private: int print;
+ private: int sleep_nsec;
+ private: unsigned char * font;
+ private: char stamp[MAX_STAMP_LEN + 1];
+ private: time_t last_time;
+ private: int last_num;
+ private: double tstamp;
+ private: static void txtwrite(int x, int y, unsigned char forecolor,
unsigned char backcolor, const char * msg, const unsigned char * _fnt, unsigned
char * img, size_t imgwidth, size_t imgheight);
+};
+
+Driver * ImgSave_Init(ConfigFile * cf, int section)
+{
+ return reinterpret_cast<Driver *>(new ImgSave(cf, section));
+}
+
+void imgsave_Register(DriverTable *table)
+{
+ table->AddDriver("imgsave", ImgSave_Init);
+}
+
+ImgSave::ImgSave(ConfigFile * cf, int section)
+ : ThreadedDriver(cf, section, true, QUEUE_LEN)
+{
+ static const unsigned char _fnt[] = VIDEOFONT; /* static: I don't want huge
array to stick on local stack */
+ const char * _key;
+ int i;
+
+ memset(&(this->camera_provided_addr), 0, sizeof(player_devaddr_t));
+ memset(&(this->camera_id), 0, sizeof(player_devaddr_t));
+ this->camera = NULL;
+ this->key[0] = '\0';
+ this->jpeg = 0;
+ this->jpeg_quality = 0.0;
+ this->print = 0;
+ this->sleep_nsec = 0;
+ this->font = NULL;
+ this->stamp[0] = '\0';
+ this->last_time = 0;
+ this->last_num = 0;
+ this->tstamp = 0;
+ if (cf->ReadDeviceAddr(&(this->camera_provided_addr), section, "provides",
PLAYER_CAMERA_CODE, -1, NULL))
+ {
+ this->SetError(-1);
+ return;
+ }
+ if (this->AddInterface(this->camera_provided_addr))
+ {
+ this->SetError(-1);
+ return;
+ }
+ if (cf->ReadDeviceAddr(&(this->camera_id), section, "requires",
PLAYER_CAMERA_CODE, -1, NULL) != 0)
+ {
+ this->SetError(-1);
+ return;
+ }
+ _key = cf->ReadString(section, "key", "Unnamed");
+ if (!_key)
+ {
+ this->SetError(-1);
+ return;
+ }
+ if (!((strlen(_key) > 0) && (strlen(_key) <= MAX_KEY_LEN)))
+ {
+ this->SetError(-1);
+ return;
+ }
+ for (i = 0; i < MAX_KEY_LEN; i++)
+ {
+ if (!(_key[i])) break;
+ this->key[i] = (((_key[i] >= '0') && (_key[i] <= '9')) \
+ || ((_key[i] >= 'A') && (_key[i] <= 'Z')) \
+ || ((_key[i] >= 'a') && (_key[i] <= 'z')) \
+ || (_key[i] == '.') \
+ || (_key[i] == '-')) \
+ ? _key[i] : '_';
+ }
+ if (!i)
+ {
+ this->SetError(-1);
+ return;
+ }
+ this->key[i] = '\0';
+ this->jpeg = cf->ReadInt(section, "jpeg", 0);
+ this->jpeg_quality = cf->ReadFloat(section, "jpeg_quality", 0.8);
+ if (((this->jpeg_quality) < EPS) || ((this->jpeg_quality) > 1.0))
+ {
+ this->SetError(-1);
+ return;
+ }
+ this->print = cf->ReadInt(section, "print", 0);
+ this->sleep_nsec = cf->ReadInt(section, "sleep_nsec", 10000);
+ if ((this->sleep_nsec) < 0)
+ {
+ this->SetError(-1);
+ return;
+ }
+ if (this->print)
+ {
+ this->font = reinterpret_cast<unsigned char *>(malloc(sizeof _fnt));
+ if (!(this->font))
+ {
+ this->SetError(-1);
+ return;
+ }
+ for (i = 0; i < static_cast<int>(sizeof _fnt); i++) this->font[i] =
_fnt[i];
+ }
+}
+
+ImgSave::~ImgSave()
+{
+ if (this->font) free(this->font);
+ this->font = NULL;
+}
+
+int ImgSave::MainSetup()
+{
+ if (Device::MatchDeviceAddress(this->camera_id, this->camera_provided_addr))
+ {
+ PLAYER_ERROR("attempt to subscribe to self");
+ return -1;
+ }
+ this->camera = deviceTable->GetDevice(this->camera_id);
+ if (!this->camera)
+ {
+ PLAYER_ERROR("unable to locate suitable camera device");
+ return -1;
+ }
+ if (this->camera->Subscribe(this->InQueue) != 0)
+ {
+ PLAYER_ERROR("unable to subscribe to camera device");
+ this->camera = NULL;
+ return -1;
+ }
+ return 0;
+}
+
+void ImgSave::MainQuit()
+{
+ if (this->camera) this->camera->Unsubscribe(this->InQueue);
+ this->camera = NULL;
+}
+
+void ImgSave::Main()
+{
+ struct timespec tspec;
+
+ snprintf(this->stamp, sizeof this->stamp, "**Start**");
+ this->last_time = time(NULL);
+ this->last_num = 0;
+ for (;;)
+ {
+ this->InQueue->Wait();
+ pthread_testcancel();
+ this->ProcessMessages();
+ pthread_testcancel();
+ tspec.tv_sec = 0;
+ tspec.tv_nsec = this->sleep_nsec;
+ if (tspec.tv_nsec > 0)
+ {
+ nanosleep(&tspec, NULL);
+ pthread_testcancel();
+ }
+ }
+}
+
+int ImgSave::ProcessMessage(QueuePointer & resp_queue, player_msghdr * hdr,
void * data)
+{
+ player_camera_data_t * output;
+ int i, j;
+ int save = 0;
+ size_t jpegsize = 0;
+ size_t bufsize = 0;
+ unsigned char * buffer = NULL;
+ unsigned char * jbuffer = NULL;
+ unsigned char * ptr, * ptr1;
+ player_camera_data_t * rawdata;
+ char dname[MAX_STAMP_LEN + 1];
+ char fname[MAX_STAMP_LEN + 1];
+ char cmd[MAX_STAMP_LEN + 1];
+ FILE * f;
+ struct tm t;
+ time_t tt = time(NULL);
+
+ assert(hdr);
+ if (Message::MatchMessage(hdr, PLAYER_MSGTYPE_DATA,
PLAYER_CAMERA_DATA_STATE, this->camera_id))
+ {
+ assert(data);
+ rawdata = reinterpret_cast<player_camera_data_t *>(data);
+ if ((static_cast<int>(rawdata->width) <= 0) ||
(static_cast<int>(rawdata->height) <= 0))
+ {
+ return -1;
+ } else
+ {
+ bufsize = rawdata->width * rawdata->height * 3;
+ buffer = reinterpret_cast<unsigned char *>(malloc(bufsize));
+ if (!buffer)
+ {
+ PLAYER_ERROR("Out of memory");
+ return -1;
+ }
+ if (this->jpeg)
+ {
+ jbuffer = reinterpret_cast<unsigned char *>(malloc(bufsize));
+ if (!jbuffer)
+ {
+ PLAYER_ERROR("Out of memory");
+ if (buffer) free(buffer);
+ buffer = NULL;
+ return -1;
+ }
+ } else jbuffer = NULL;
+ switch (rawdata->compression)
+ {
+ case PLAYER_CAMERA_COMPRESS_RAW:
+ switch (rawdata->bpp)
+ {
+ case 8:
+ ptr = buffer;
+ ptr1 = reinterpret_cast<unsigned char *>(rawdata->image);
+ assert(ptr);
+ assert(ptr1);
+ for (i = 0; i < static_cast<int>(rawdata->height); i++)
+ {
+ for (j = 0; j < static_cast<int>(rawdata->width); j++)
+ {
+ ptr[0] = *ptr1;
+ ptr[1] = *ptr1;
+ ptr[2] = *ptr1;
+ ptr += 3; ptr1++;
+ }
+ }
+ break;
+ case 24:
+ assert(buffer);
+ assert(rawdata->image);
+ memcpy(buffer, rawdata->image, bufsize);
+ break;
+ case 32:
+ ptr = buffer;
+ ptr1 = reinterpret_cast<unsigned char *>(rawdata->image);
+ assert(ptr);
+ assert(ptr1);
+ for (i = 0; i < static_cast<int>(rawdata->height); i++)
+ {
+ for (j = 0; j < static_cast<int>(rawdata->width); j++)
+ {
+ ptr[0] = ptr1[0];
+ ptr[1] = ptr1[1];
+ ptr[2] = ptr1[2];
+ ptr += 3; ptr1 += 4;
+ }
+ }
+ break;
+ default:
+ PLAYER_WARN("unsupported image depth (not good)");
+ if (buffer) free(buffer);
+ buffer = NULL;
+ if (jbuffer) free(jbuffer);
+ jbuffer = NULL;
+ return -1;
+ }
+ break;
+#if HAVE_JPEG
+ case PLAYER_CAMERA_COMPRESS_JPEG:
+ if ((this->jpeg) && (!(this->print)))
+ {
+ assert(jbuffer);
+ assert(rawdata->image);
+ jpegsize = rawdata->image_count;
+ memcpy(jbuffer, rawdata->image, jpegsize);
+ } else
+ {
+ assert(buffer);
+ assert(rawdata->image);
+ jpeg_decompress(buffer, bufsize, rawdata->image,
rawdata->image_count);
+ }
+ break;
+#endif
+ default:
+ PLAYER_WARN("unsupported compression scheme (not good)");
+ if (buffer) free(buffer);
+ buffer = NULL;
+ if (jbuffer) free(jbuffer);
+ jbuffer = NULL;
+ return -1;
+ }
+ if (this->print)
+ {
+ assert(buffer);
+ txtwrite(0, 8, 255, 0, this->stamp, this->font, buffer,
rawdata->width, rawdata->height);
+ }
+ save = ((this->tstamp) != (hdr->timestamp)) ? (!0) : 0;
+ if (save)
+ {
+ assert((localtime_r(&tt, &t)) == (&t));
+ if (tt != (this->last_time))
+ {
+ this->last_time = tt;
+ this->last_num = 0;
+ }
+ snprintf(dname, sizeof dname, "%s/%d.%.2d.%.2d/%.2d", this->key,
(t.tm_year) + 1900, (t.tm_mon) + 1, t.tm_mday, t.tm_hour);
+ snprintf(fname, sizeof fname, "%s/%.2d.%.2d.%.2d-%.2d.%s", dname,
t.tm_hour, t.tm_min, t.tm_sec, this->last_num, (this->jpeg) ? "jpg" : "txt");
+ snprintf(this->stamp, sizeof this->stamp, "%s %d.%.2d.%.2d
%.2d:%.2d:%.2d-%.2d", this->key, (t.tm_year) + 1900, (t.tm_mon) + 1, t.tm_mday,
t.tm_hour, t.tm_min, t.tm_sec, this->last_num);
+ this->last_num++;
+ }
+ if (this->print)
+ {
+ assert(buffer);
+ txtwrite(0, 0, 0, 255, this->stamp, this->font, buffer,
rawdata->width, rawdata->height);
+ }
+ if (this->jpeg)
+ {
+ assert(jbuffer);
+ if ((this->print) || ((rawdata->compression) ==
PLAYER_CAMERA_COMPRESS_RAW))
+ {
+ assert(buffer);
+#if HAVE_JPEG
+ jpegsize = jpeg_compress(reinterpret_cast<char *>(jbuffer),
reinterpret_cast<char *>(buffer), rawdata->width, rawdata->height, bufsize,
static_cast<int>((this->jpeg_quality) * 100.0));
+#else
+ PLAYER_ERROR("No JPEG compression supported");
+ if (buffer) free(buffer);
+ buffer = NULL;
+ if (jbuffer) free(jbuffer);
+ jbuffer = NULL;
+ return -1;
+#endif
+ } else
+ {
+ assert((rawdata->compression) == PLAYER_CAMERA_COMPRESS_JPEG);
+ }
+ free(buffer);
+ buffer = NULL;
+ assert(jpegsize > 0);
+ } else
+ {
+ assert(buffer);
+ assert(!jbuffer);
+ }
+ if (save)
+ {
+ f = fopen(fname, (this->jpeg) ? "wb" : "w");
+ if (!f)
+ {
+ snprintf(cmd, sizeof cmd, "mkdir -p %s", dname);
+ system(cmd);
+ f = fopen(fname, (this->jpeg) ? "wb" : "w");
+ }
+ if (!f)
+ {
+ PLAYER_ERROR1("Cannot open file in order to write [%s]", fname);
+ } else
+ {
+ if (this->jpeg)
+ {
+ assert(jbuffer);
+ assert(jpegsize > 0);
+ fwrite(jbuffer, jpegsize, 1, f);
+ } else
+ {
+ assert(buffer);
+ ptr1 = buffer;
+ for (i = 0; i < static_cast<int>(rawdata->height); i++)
+ {
+ for (j = 0; j < static_cast<int>(rawdata->width); j++)
+ {
+ fprintf(f, "%d %d %u %u %u\n", j, i, ptr1[0], ptr1[1],
ptr1[2]);
+ ptr1 += 3;
+ }
+ }
+ }
+ fclose(f);
+ }
+ }
+ output = reinterpret_cast<player_camera_data_t
*>(malloc(sizeof(player_camera_data_t)));
+ if (!output)
+ {
+ PLAYER_ERROR("Out of memory");
+ if (buffer) free(buffer);
+ buffer = NULL;
+ if (jbuffer) free(jbuffer);
+ jbuffer = NULL;
+ return -1;
+ }
+ memset(output, 0, sizeof(player_camera_data_t));
+ output->bpp = 24;
+ output->compression = (this->jpeg) ? PLAYER_CAMERA_COMPRESS_JPEG :
PLAYER_CAMERA_COMPRESS_RAW;
+ output->format = PLAYER_CAMERA_FORMAT_RGB888;
+ output->fdiv = rawdata->fdiv;
+ output->width = rawdata->width;
+ output->height = rawdata->height;
+ output->image_count = (this->jpeg) ? jpegsize : bufsize;
+ output->image = (this->jpeg) ? jbuffer : buffer;
+ assert(output->image);
+ this->tstamp = hdr->timestamp;
+ this->Publish(this->camera_provided_addr, PLAYER_MSGTYPE_DATA,
PLAYER_CAMERA_DATA_STATE, reinterpret_cast<void *>(output), 0, &(this->tstamp),
false); // copy = false
+ // I assume that Publish() (with copy = false) freed those output data!
+ output = NULL;
+ }
+ return 0;
+ }
+ return -1;
+}
+
+void ImgSave::txtwrite(int x, int y, unsigned char forecolor, unsigned char
backcolor, const char * msg, const unsigned char * _fnt, unsigned char * img,
size_t imgwidth, size_t imgheight)
+{
+ int i, l, c, xi;
+ const unsigned char * lettershape;
+ size_t linewidth = imgwidth * 3;
+ unsigned char * line;
+ unsigned char * col;
+ unsigned char color;
+
+ assert(msg);
+ assert(_fnt);
+ assert(img);
+ for (i = 0; msg[i]; i++) if ((msg[i]) > ' ')
+ {
+ lettershape = _fnt + (msg[i] * 8);
+ xi = x + (i * 8);
+ assert(lettershape);
+ for (l = 0; l < 8; l++)
+ {
+ if ((y + l) >= static_cast<int>(imgheight)) break;
+ line = img + ((y + l) * linewidth);
+ assert(line);
+ for (c = 0; c < 8; c++)
+ {
+ if ((xi + c) >= static_cast<int>(imgwidth)) break;
+ col = line + ((xi + c) * 3);
+ assert(col);
+ color = (((lettershape[l]) << c) & 128) ? forecolor : backcolor;
+ col[0] = color;
+ col[1] = color;
+ col[2] = color;
+ }
+ }
+ }
+}
+
Added: code/player/trunk/server/drivers/camera/imgsave/videofont.h
===================================================================
--- code/player/trunk/server/drivers/camera/imgsave/videofont.h
(rev 0)
+++ code/player/trunk/server/drivers/camera/imgsave/videofont.h 2010-05-03
17:59:33 UTC (rev 8651)
@@ -0,0 +1,264 @@
+#ifndef __VIDEOFONT_H
+#define __VIDEOFONT_H
+
+#define VIDEOFONT \
+{ \
+ 0, 0, 0, 0, 0, 0, 0, 0, \
+ 126, 129, 165, 129, 189, 153, 129, 126, \
+ 126, 255, 219, 255, 195, 231, 255, 126, \
+ 108, 254, 254, 254, 124, 56, 16, 0, \
+ 16, 56, 124, 254, 124, 56, 16, 0, \
+ 56, 124, 56, 254, 254, 124, 56, 124, \
+ 16, 16, 56, 124, 254, 124, 56, 124, \
+ 0, 0, 24, 60, 60, 24, 0, 0, \
+ 255, 255, 231, 195, 195, 231, 255, 255, \
+ 0, 60, 102, 66, 66, 102, 60, 0, \
+ 255, 195, 153, 189, 189, 153, 195, 255, \
+ 15, 7, 15, 125, 204, 204, 204, 120, \
+ 60, 102, 102, 102, 60, 24, 126, 24, \
+ 63, 51, 63, 48, 48, 112, 240, 224, \
+ 127, 99, 127, 99, 99, 103, 230, 192, \
+ 153, 90, 60, 231, 231, 60, 90, 153, \
+ 128, 224, 248, 254, 248, 224, 128, 0, \
+ 2, 14, 62, 254, 62, 14, 2, 0, \
+ 24, 60, 126, 24, 24, 126, 60, 24, \
+ 102, 102, 102, 102, 102, 0, 102, 0, \
+ 127, 219, 219, 123, 27, 27, 27, 0, \
+ 62, 99, 56, 108, 108, 56, 204, 120, \
+ 0, 0, 0, 0, 126, 126, 126, 0, \
+ 24, 60, 126, 24, 126, 60, 24, 255, \
+ 24, 60, 126, 24, 24, 24, 24, 0, \
+ 24, 24, 24, 24, 126, 60, 24, 0, \
+ 0, 24, 12, 254, 12, 24, 0, 0, \
+ 0, 48, 96, 254, 96, 48, 0, 0, \
+ 0, 0, 192, 192, 192, 254, 0, 0, \
+ 0, 36, 102, 255, 102, 36, 0, 0, \
+ 0, 24, 60, 126, 255, 255, 0, 0, \
+ 0, 255, 255, 126, 60, 24, 0, 0, \
+ 0, 0, 0, 0, 0, 0, 0, 0, \
+ 48, 120, 120, 48, 48, 0, 48, 0, \
+ 108, 108, 108, 0, 0, 0, 0, 0, \
+ 108, 108, 254, 108, 254, 108, 108, 0, \
+ 48, 124, 192, 120, 12, 248, 48, 0, \
+ 0, 198, 204, 24, 48, 102, 198, 0, \
+ 56, 108, 56, 118, 220, 204, 118, 0, \
+ 96, 96, 192, 0, 0, 0, 0, 0, \
+ 24, 48, 96, 96, 96, 48, 24, 0, \
+ 96, 48, 24, 24, 24, 48, 96, 0, \
+ 0, 102, 60, 255, 60, 102, 0, 0, \
+ 0, 48, 48, 252, 48, 48, 0, 0, \
+ 0, 0, 0, 0, 0, 48, 48, 96, \
+ 0, 0, 0, 252, 0, 0, 0, 0, \
+ 0, 0, 0, 0, 0, 48, 48, 0, \
+ 6, 12, 24, 48, 96, 192, 128, 0, \
+ 124, 198, 206, 222, 246, 230, 124, 0, \
+ 48, 112, 48, 48, 48, 48, 252, 0, \
+ 120, 204, 12, 56, 96, 204, 252, 0, \
+ 120, 204, 12, 56, 12, 204, 120, 0, \
+ 28, 60, 108, 204, 254, 12, 30, 0, \
+ 252, 192, 248, 12, 12, 204, 120, 0, \
+ 56, 96, 192, 248, 204, 204, 120, 0, \
+ 252, 204, 12, 24, 48, 48, 48, 0, \
+ 120, 204, 204, 120, 204, 204, 120, 0, \
+ 120, 204, 204, 124, 12, 24, 112, 0, \
+ 0, 48, 48, 0, 0, 48, 48, 0, \
+ 0, 48, 48, 0, 0, 48, 48, 96, \
+ 24, 48, 96, 192, 96, 48, 24, 0, \
+ 0, 0, 252, 0, 0, 252, 0, 0, \
+ 96, 48, 24, 12, 24, 48, 96, 0, \
+ 120, 204, 12, 24, 48, 0, 48, 0, \
+ 124, 198, 222, 222, 222, 192, 120, 0, \
+ 48, 120, 204, 204, 252, 204, 204, 0, \
+ 252, 102, 102, 124, 102, 102, 252, 0, \
+ 60, 102, 192, 192, 192, 102, 60, 0, \
+ 248, 108, 102, 102, 102, 108, 248, 0, \
+ 254, 98, 104, 120, 104, 98, 254, 0, \
+ 254, 98, 104, 120, 104, 96, 240, 0, \
+ 60, 102, 192, 192, 206, 102, 62, 0, \
+ 204, 204, 204, 252, 204, 204, 204, 0, \
+ 120, 48, 48, 48, 48, 48, 120, 0, \
+ 30, 12, 12, 12, 204, 204, 120, 0, \
+ 230, 102, 108, 120, 108, 102, 230, 0, \
+ 240, 96, 96, 96, 98, 102, 254, 0, \
+ 198, 238, 254, 254, 214, 198, 198, 0, \
+ 198, 230, 246, 222, 206, 198, 198, 0, \
+ 56, 108, 198, 198, 198, 108, 56, 0, \
+ 252, 102, 102, 124, 96, 96, 240, 0, \
+ 120, 204, 204, 204, 220, 120, 28, 0, \
+ 252, 102, 102, 124, 108, 102, 230, 0, \
+ 120, 204, 224, 112, 28, 204, 120, 0, \
+ 252, 180, 48, 48, 48, 48, 120, 0, \
+ 204, 204, 204, 204, 204, 204, 252, 0, \
+ 204, 204, 204, 204, 204, 120, 48, 0, \
+ 198, 198, 198, 214, 254, 238, 198, 0, \
+ 198, 198, 108, 56, 56, 108, 198, 0, \
+ 204, 204, 204, 120, 48, 48, 120, 0, \
+ 254, 198, 140, 24, 50, 102, 254, 0, \
+ 120, 96, 96, 96, 96, 96, 120, 0, \
+ 192, 96, 48, 24, 12, 6, 2, 0, \
+ 120, 24, 24, 24, 24, 24, 120, 0, \
+ 16, 56, 108, 198, 0, 0, 0, 0, \
+ 0, 0, 0, 0, 0, 0, 0, 255, \
+ 48, 48, 24, 0, 0, 0, 0, 0, \
+ 0, 0, 120, 12, 124, 204, 118, 0, \
+ 224, 96, 96, 124, 102, 102, 220, 0, \
+ 0, 0, 120, 204, 192, 204, 120, 0, \
+ 28, 12, 12, 124, 204, 204, 118, 0, \
+ 0, 0, 120, 204, 252, 192, 120, 0, \
+ 56, 108, 96, 240, 96, 96, 240, 0, \
+ 0, 0, 118, 204, 204, 124, 12, 248, \
+ 224, 96, 108, 118, 102, 102, 230, 0, \
+ 48, 0, 112, 48, 48, 48, 120, 0, \
+ 12, 0, 12, 12, 12, 204, 204, 120, \
+ 224, 96, 102, 108, 120, 108, 230, 0, \
+ 112, 48, 48, 48, 48, 48, 120, 0, \
+ 0, 0, 204, 254, 254, 214, 198, 0, \
+ 0, 0, 248, 204, 204, 204, 204, 0, \
+ 0, 0, 120, 204, 204, 204, 120, 0, \
+ 0, 0, 220, 102, 102, 124, 96, 240, \
+ 0, 0, 118, 204, 204, 124, 12, 30, \
+ 0, 0, 220, 118, 102, 96, 240, 0, \
+ 0, 0, 124, 192, 120, 12, 248, 0, \
+ 16, 48, 124, 48, 48, 52, 24, 0, \
+ 0, 0, 204, 204, 204, 204, 118, 0, \
+ 0, 0, 204, 204, 204, 120, 48, 0, \
+ 0, 0, 198, 214, 254, 254, 108, 0, \
+ 0, 0, 198, 108, 56, 108, 198, 0, \
+ 0, 0, 204, 204, 204, 124, 12, 248, \
+ 0, 0, 252, 152, 48, 100, 252, 0, \
+ 28, 48, 48, 224, 48, 48, 28, 0, \
+ 24, 24, 24, 0, 24, 24, 24, 0, \
+ 224, 48, 48, 28, 48, 48, 224, 0, \
+ 118, 220, 0, 0, 0, 0, 0, 0, \
+ 0, 16, 56, 108, 198, 198, 254, 0, \
+ 30, 54, 102, 102, 126, 102, 102, 0, \
+ 124, 96, 96, 124, 102, 102, 124, 0, \
+ 124, 102, 102, 124, 102, 102, 124, 0, \
+ 126, 96, 96, 96, 96, 96, 96, 0, \
+ 56, 108, 108, 108, 108, 108, 254, 198, \
+ 126, 96, 96, 124, 96, 96, 126, 0, \
+ 219, 219, 126, 60, 126, 219, 219, 0, \
+ 60, 102, 6, 28, 6, 102, 60, 0, \
+ 102, 102, 110, 126, 118, 102, 102, 0, \
+ 60, 102, 110, 126, 118, 102, 102, 0, \
+ 102, 108, 120, 112, 120, 108, 102, 0, \
+ 30, 54, 102, 102, 102, 102, 102, 0, \
+ 198, 238, 254, 254, 214, 198, 198, 0, \
+ 102, 102, 102, 126, 102, 102, 102, 0, \
+ 60, 102, 102, 102, 102, 102, 60, 0, \
+ 126, 102, 102, 102, 102, 102, 102, 0, \
+ 124, 102, 102, 102, 124, 96, 96, 0, \
+ 60, 102, 96, 96, 96, 102, 60, 0, \
+ 126, 24, 24, 24, 24, 24, 24, 0, \
+ 102, 102, 102, 62, 6, 102, 60, 0, \
+ 126, 219, 219, 219, 126, 24, 24, 0, \
+ 102, 102, 60, 24, 60, 102, 102, 0, \
+ 102, 102, 102, 102, 102, 102, 127, 3, \
+ 102, 102, 102, 62, 6, 6, 6, 0, \
+ 219, 219, 219, 219, 219, 219, 255, 0, \
+ 219, 219, 219, 219, 219, 219, 255, 3, \
+ 224, 96, 96, 124, 102, 102, 124, 0, \
+ 198, 198, 198, 246, 222, 222, 246, 0, \
+ 96, 96, 96, 124, 102, 102, 124, 0, \
+ 120, 140, 6, 62, 6, 140, 120, 0, \
+ 206, 219, 219, 251, 219, 219, 206, 0, \
+ 62, 102, 102, 102, 62, 54, 102, 0, \
+ 0, 0, 120, 12, 124, 204, 118, 0, \
+ 0, 60, 96, 60, 102, 102, 60, 0, \
+ 0, 124, 102, 124, 102, 102, 124, 0, \
+ 0, 0, 126, 96, 96, 96, 96, 0, \
+ 0, 0, 60, 108, 108, 108, 254, 198, \
+ 0, 0, 60, 102, 126, 96, 60, 0, \
+ 0, 0, 219, 126, 60, 126, 219, 0, \
+ 0, 0, 60, 102, 12, 102, 60, 0, \
+ 0, 0, 102, 110, 126, 118, 102, 0, \
+ 0, 24, 102, 110, 126, 118, 102, 0, \
+ 0, 0, 102, 108, 120, 108, 102, 0, \
+ 0, 0, 30, 54, 102, 102, 102, 0, \
+ 0, 0, 198, 254, 254, 214, 198, 0, \
+ 0, 0, 102, 102, 126, 102, 102, 0, \
+ 0, 0, 60, 102, 102, 102, 60, 0, \
+ 0, 0, 126, 102, 102, 102, 102, 0, \
+ 17, 68, 17, 68, 17, 68, 17, 68, \
+ 85, 170, 85, 170, 85, 170, 85, 170, \
+ 221, 119, 221, 119, 221, 119, 221, 119, \
+ 24, 24, 24, 24, 24, 24, 24, 24, \
+ 24, 24, 24, 248, 24, 24, 24, 24, \
+ 24, 248, 24, 248, 24, 24, 24, 24, \
+ 54, 54, 54, 246, 54, 54, 54, 54, \
+ 0, 0, 0, 254, 54, 54, 54, 54, \
+ 0, 248, 24, 248, 24, 24, 24, 24, \
+ 54, 246, 6, 246, 54, 54, 54, 54, \
+ 54, 54, 54, 54, 54, 54, 54, 54, \
+ 0, 254, 6, 246, 54, 54, 54, 54, \
+ 54, 246, 6, 254, 0, 0, 0, 0, \
+ 54, 54, 54, 254, 0, 0, 0, 0, \
+ 24, 248, 24, 248, 0, 0, 0, 0, \
+ 0, 0, 0, 248, 24, 24, 24, 24, \
+ 24, 24, 24, 31, 0, 0, 0, 0, \
+ 24, 24, 24, 255, 0, 0, 0, 0, \
+ 0, 0, 0, 255, 24, 24, 24, 24, \
+ 24, 24, 24, 31, 24, 24, 24, 24, \
+ 0, 0, 0, 255, 0, 0, 0, 0, \
+ 24, 24, 24, 255, 24, 24, 24, 24, \
+ 24, 31, 24, 31, 24, 24, 24, 24, \
+ 54, 54, 54, 55, 54, 54, 54, 54, \
+ 54, 55, 48, 63, 0, 0, 0, 0, \
+ 0, 63, 48, 55, 54, 54, 54, 54, \
+ 54, 247, 0, 255, 0, 0, 0, 0, \
+ 0, 255, 0, 247, 54, 54, 54, 54, \
+ 54, 55, 48, 55, 54, 54, 54, 54, \
+ 0, 255, 0, 255, 0, 0, 0, 0, \
+ 54, 247, 0, 247, 54, 54, 54, 54, \
+ 24, 255, 0, 255, 0, 0, 0, 0, \
+ 54, 54, 54, 255, 0, 0, 0, 0, \
+ 0, 255, 0, 255, 24, 24, 24, 24, \
+ 0, 0, 0, 255, 54, 54, 54, 54, \
+ 54, 54, 54, 63, 0, 0, 0, 0, \
+ 24, 31, 24, 31, 0, 0, 0, 0, \
+ 0, 31, 24, 31, 24, 24, 24, 24, \
+ 0, 0, 0, 63, 54, 54, 54, 54, \
+ 54, 54, 54, 255, 54, 54, 54, 54, \
+ 24, 255, 24, 255, 24, 24, 24, 24, \
+ 24, 24, 24, 248, 0, 0, 0, 0, \
+ 0, 0, 0, 31, 24, 24, 24, 24, \
+ 255, 255, 255, 255, 255, 255, 255, 255, \
+ 0, 0, 0, 255, 255, 255, 255, 255, \
+ 240, 240, 240, 240, 240, 240, 240, 240, \
+ 15, 15, 15, 15, 15, 15, 15, 15, \
+ 255, 255, 255, 0, 0, 0, 0, 0, \
+ 0, 0, 124, 102, 102, 124, 96, 0, \
+ 0, 0, 60, 102, 96, 102, 60, 0, \
+ 0, 0, 126, 24, 24, 24, 24, 0, \
+ 0, 0, 102, 102, 62, 6, 60, 0, \
+ 0, 0, 126, 219, 219, 126, 24, 0, \
+ 0, 0, 102, 60, 24, 60, 102, 0, \
+ 0, 0, 102, 102, 102, 102, 127, 3, \
+ 0, 0, 102, 102, 62, 6, 6, 0, \
+ 0, 0, 219, 219, 219, 219, 255, 0, \
+ 0, 0, 219, 219, 219, 219, 255, 3, \
+ 0, 0, 224, 96, 124, 102, 124, 0, \
+ 0, 0, 198, 198, 246, 222, 246, 0, \
+ 0, 0, 96, 96, 124, 102, 124, 0, \
+ 0, 0, 124, 6, 62, 6, 124, 0, \
+ 0, 0, 206, 219, 251, 219, 206, 0, \
+ 0, 0, 62, 102, 62, 54, 102, 0, \
+ 0, 0, 254, 0, 254, 0, 254, 0, \
+ 16, 16, 124, 16, 16, 0, 124, 0, \
+ 0, 48, 24, 12, 6, 12, 24, 48, \
+ 0, 12, 24, 48, 96, 48, 24, 12, \
+ 14, 27, 27, 24, 24, 24, 24, 24, \
+ 24, 24, 24, 24, 24, 216, 216, 112, \
+ 0, 24, 24, 0, 126, 0, 24, 24, \
+ 0, 118, 220, 0, 118, 220, 0, 0, \
+ 0, 56, 108, 108, 56, 0, 0, 0, \
+ 0, 0, 0, 0, 24, 0, 0, 0, \
+ 0, 0, 0, 56, 56, 0, 0, 0, \
+ 15, 12, 12, 12, 236, 108, 60, 28, \
+ 216, 108, 108, 108, 108, 0, 0, 0, \
+ 48, 72, 16, 32, 120, 0, 0, 0, \
+ 0, 0, 124, 124, 124, 124, 0, 0, \
+ 0, 0, 0, 0, 0, 66, 126, 0 \
+}
+
+#endif
This was sent by the SourceForge.net collaborative development platform, the
world's largest Open Source development site.
------------------------------------------------------------------------------
_______________________________________________
Playerstage-commit mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/playerstage-commit