Revision: 8844
http://playerstage.svn.sourceforge.net/playerstage/?rev=8844&view=rev
Author: jpgr87
Date: 2010-08-06 14:51:55 +0000 (Fri, 06 Aug 2010)
Log Message:
-----------
Applied patch #3040302: Canon Powershot driver and other fixes
Modified Paths:
--------------
code/player/trunk/server/drivers/camera/CMakeLists.txt
code/player/trunk/server/drivers/camera/compress/cameracompress.cc
Added Paths:
-----------
code/player/trunk/server/drivers/camera/powershot/
code/player/trunk/server/drivers/camera/powershot/CMakeLists.txt
code/player/trunk/server/drivers/camera/powershot/powershot.cc
Modified: code/player/trunk/server/drivers/camera/CMakeLists.txt
===================================================================
--- code/player/trunk/server/drivers/camera/CMakeLists.txt 2010-07-30
23:20:33 UTC (rev 8843)
+++ code/player/trunk/server/drivers/camera/CMakeLists.txt 2010-08-06
14:51:55 UTC (rev 8844)
@@ -9,6 +9,7 @@
ADD_SUBDIRECTORY (imageseq)
ADD_SUBDIRECTORY (imgcmp)
ADD_SUBDIRECTORY (imgsave)
+ADD_SUBDIRECTORY (powershot)
ADD_SUBDIRECTORY (sphere)
ADD_SUBDIRECTORY (uvc)
ADD_SUBDIRECTORY (yarp)
Modified: code/player/trunk/server/drivers/camera/compress/cameracompress.cc
===================================================================
--- code/player/trunk/server/drivers/camera/compress/cameracompress.cc
2010-07-30 23:20:33 UTC (rev 8843)
+++ code/player/trunk/server/drivers/camera/compress/cameracompress.cc
2010-08-06 14:51:55 UTC (rev 8844)
@@ -97,6 +97,7 @@
#include <stddef.h>
#include <stdlib.h> // for atoi(3)
#include <math.h>
+#include <assert.h>
#include <libplayercore/playercore.h>
#include <libplayerjpeg/playerjpeg.h>
@@ -230,6 +231,7 @@
void * data)
{
player_msghdr_t newhdr;
+ player_camera_data_t camdata, * rqdata;
Message * msg;
assert(hdr);
@@ -244,6 +246,60 @@
// don't delete anything here! this->imgdata.image is required and is
deleted somewhere else
}
return 0;
+ } else if (Message::MatchMessage(hdr, PLAYER_MSGTYPE_REQ,
PLAYER_CAMERA_REQ_GET_IMAGE, this->device_addr))
+ {
+ hdr->addr = this->camera_id;
+ msg = this->camera->Request(this->InQueue, hdr->type, hdr->subtype, data,
0, NULL, true); // threaded = true
+ if (!msg)
+ {
+ PLAYER_WARN("failed to forward request");
+ return -1;
+ }
+ if (!(msg->GetDataSize() > 0))
+ {
+ PLAYER_WARN("Wrong size of request reply");
+ delete msg;
+ return -1;
+ }
+ rqdata = reinterpret_cast<player_camera_data_t *>(msg->GetPayload());
+ if (!rqdata)
+ {
+ PLAYER_WARN("No image data from forwarded request");
+ delete msg;
+ return -1;
+ }
+ if (!((rqdata->width > 0) && (rqdata->height > 0) && (rqdata->bpp > 0) &&
(rqdata->image_count > 0) && (rqdata->image)))
+ {
+ newhdr = *(msg->GetHeader());
+ newhdr.addr = this->device_addr;
+ this->Publish(resp_queue, &newhdr, reinterpret_cast<void *>(rqdata),
true); // copy = true, do not dispose published data as we're disposing whole
source message in the next line
+ delete msg;
+ return 0;
+ }
+ camdata = *rqdata;
+ camdata.image = NULL;
+ assert((camdata.width > 0) && (camdata.height > 0) && (camdata.bpp > 0) &&
(camdata.image_count > 0));
+ camdata.image = reinterpret_cast<uint8_t *>(malloc(camdata.image_count));
+ if (!(camdata.image))
+ {
+ PLAYER_ERROR("Out of memory");
+ delete msg;
+ return -1;
+ }
+ assert((camdata.image_count) == (rqdata->image_count));
+ memcpy(camdata.image, rqdata->image, camdata.image_count);
+ if (this->ProcessImage(camdata))
+ {
+ free(camdata.image);
+ delete msg;
+ return -1;
+ }
+ free(camdata.image);
+ newhdr = *(msg->GetHeader());
+ newhdr.addr = this->device_addr;
+ this->Publish(resp_queue, &newhdr, reinterpret_cast<void
*>(&(this->imgdata)), true); // copy = true
+ delete msg;
+ return 0;
} else if (Message::MatchMessage(hdr, PLAYER_MSGTYPE_REQ, -1,
this->device_addr))
{
hdr->addr = this->camera_id;
Added: code/player/trunk/server/drivers/camera/powershot/CMakeLists.txt
===================================================================
--- code/player/trunk/server/drivers/camera/powershot/CMakeLists.txt
(rev 0)
+++ code/player/trunk/server/drivers/camera/powershot/CMakeLists.txt
2010-08-06 14:51:55 UTC (rev 8844)
@@ -0,0 +1,14 @@
+PLAYERDRIVER_OPTION (powershot build_powershot ON)
+PLAYERDRIVER_REJECT_OS (powershot build_powershot PLAYER_OS_WIN)
+PLAYERDRIVER_REQUIRE_HEADER (powershot build_powershot libptp2/ptp.h)
+PLAYERDRIVER_REQUIRE_PKG (powershot build_powershot libexif libexif_includeDirs
+ libexif_libDirs libexif_linkLibs libexif_linkFlags libexif_cFlags)
+PLAYERDRIVER_REQUIRE_PKG (powershot build_powershot libusb libusb_includeDirs
+ libusb_libDirs libusb_linkLibs libusb_linkFlags libusb_cFlags)
+PLAYERDRIVER_ADD_DRIVER (powershot build_powershot
+ INCLUDEDIRS ${libexif_includeDirs} ${libusb_includeDirs}
+ LIBDIRS ${libexif_libDirs} ${libusb_libDirs}
+ LINKLIBS ${libexif_linkLibs} ${libusb_linkLibs}
+ LINKFLAGS ${libexif_linkFlags} ${libusb_linkFlags} -lptp2
+ CFLAGS ${libexif_cFlags} ${libusb_cFlags}
+ SOURCES powershot.cc)
Added: code/player/trunk/server/drivers/camera/powershot/powershot.cc
===================================================================
--- code/player/trunk/server/drivers/camera/powershot/powershot.cc
(rev 0)
+++ code/player/trunk/server/drivers/camera/powershot/powershot.cc
2010-08-06 14:51:55 UTC (rev 8844)
@@ -0,0 +1,1557 @@
+/*
+ * 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
+ *
+ */
+///////////////////////////////////////////////////////////////////////////
+//
+// Desc: Canon Powershot digicam capture driver
+// Author: Paul Osmialowski
+// Date: 24 Jul 2010
+//
+///////////////////////////////////////////////////////////////////////////
+
+/** @ingroup drivers */
+/** @{ */
+/** @defgroup driver_powershot powershot
+ * @brief Canon Powershot digicam capture driver
+
+The powershot driver captures images from various Canon Powershot digicams.
+Based on Capture tool http://capture.sourceforge.net (GNU GPL v2).
+
+...@par Compile-time dependencies
+
+- libusb
+- libptp2
+- libexif
+
+...@par Provides
+
+- @ref interface_camera
+
+...@par Requires
+
+- none
+
+...@par Configuration requests
+
+- none
+
+...@par Configuration file options
+
+- repeat (integer)
+ - Default: 0
+ - If set to 1, keep on publishing any previously captured frame
+
+- sleep_nsec (integer)
+ - Default: 10000000 (=10ms which gives max 100 fps)
+ - timespec value for nanosleep() (used when repeat = 1)
+
+- init_commands (string tuple)
+ - Default: NONE
+ - See list of commands accepted by capture tool by Petr Danecek
+ http://capture.sourceforge.net
+
+- live_view (integer)
+ - Default: 0
+ - If set to 1, live view will be published (better framerate, worse quality)
+
+...@par Properties
+
+- live_width (integer)
+ - Default: 320
+ - Image width when live_view is set to 1 (set this when 320 does not fit
live image width)
+
+- live_height (integer)
+ - Default: 240
+ - Image height when live_view is set to 1 (set this when 240 does not fit
live image height)
+
+...@par Example
+
+...@verbatim
+driver
+(
+ name "powershot"
+ provides ["camera:0"]
+ init_commands ["flash on" "size small"]
+)
+...@endverbatim
+
+...@author Paul Osmialowski, Petr Danecek
+
+*/
+/** @} */
+
+#include <time.h>
+#include <stddef.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#if HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#include <assert.h>
+#include <string.h>
+#include <pthread.h>
+#include <usb.h>
+#include <libplayercore/playercore.h>
+#include <libexif/exif-byte-order.h>
+#include <libexif/exif-data-type.h>
+#include <libexif/exif-ifd.h>
+#include <libexif/exif-tag.h>
+#include <libexif/exif-loader.h>
+#include <libexif/exif-data.h>
+#include <libexif/exif-content.h>
+#include <libexif/exif-entry.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <libptp2/ptp.h>
+
+#ifdef __cplusplus
+}
+#endif
+
+#define IS_JPEG(ptr) ((((ptr)[0]) == 0xff) && (((ptr)[1]) == 0xd8))
+
+#define MAX_BULK_SIZE 131072
+#define MAX_SMALLREAD_SIZE 256
+
+class Powershot : public ThreadedDriver
+{
+public:
+ Powershot(ConfigFile * cf, int section);
+
+ virtual ~Powershot();
+
+ virtual int ProcessMessage(QueuePointer & resp_queue,
+ player_msghdr * hdr,
+ void * data);
+
+private:
+ virtual void Main();
+
+ player_devaddr_t camera_addr;
+ player_camera_data_t imgData;
+ int needs_frame;
+ int repeat;
+ int sleep_nsec;
+ int live_view;
+ IntProperty live_width;
+ IntProperty live_height;
+ struct ptp_usb_t
+ {
+ usb_dev_handle * handle;
+ int inep;
+ int outep;
+ int intep;
+ };
+ struct settings_t
+ {
+ struct usb_device * dev;
+ PTPParams params;
+ struct Powershot::ptp_usb_t ptp_usb;
+ } settings;
+ int started;
+ struct allowed_t
+ {
+ int code;
+ char string[40];
+ };
+ static struct allowed_t zoom_vals[];
+ static struct allowed_t flash_vals[];
+ static struct allowed_t macro_vals[];
+ static struct allowed_t aperture_vals[];
+ static struct allowed_t shutter_vals[];
+ static struct allowed_t tvav_vals[];
+ static struct allowed_t focuspoint_vals[];
+ static struct allowed_t exposure_compensation_vals[];
+ static struct allowed_t iso_speed_vals[];
+ static struct allowed_t white_balance_vals[];
+ static struct allowed_t photo_effect_vals[];
+ static struct allowed_t light_metering_vals[];
+ static struct allowed_t qual_vals[];
+ static struct allowed_t size_vals[];
+ static struct allowed_t focus_vals[];
+ static struct cmd_t
+ {
+ char command[40];
+ int ptpcode;
+ int (* handler)(struct Powershot::settings_t *, struct Powershot::cmd_t *,
char *);
+ struct Powershot::allowed_t * params;
+ } cmds[];
+ static struct usb_device * find_device(int busn, int devn);
+ static void find_endpoints(struct Powershot::settings_t * settings);
+ static int ptp_usb_init(struct Powershot::settings_t * settings);
+ static void ptp_usb_close(struct Powershot::settings_t * settings);
+ static int magic_code(struct Powershot::settings_t * settings);
+ static int usb_checkevent_wait(struct Powershot::settings_t * settings);
+ static int ptp_checkevent(struct Powershot::settings_t * settings,
PTPUSBEventContainer * fill_event);
+ static short ptp_write_func(unsigned char * bytes, unsigned int size, void *
data);
+ static short ptp_read_func(unsigned char * bytes, unsigned int size, void *
data);
+ static short ptp_check_int_func(unsigned char * bytes, unsigned int size,
void * data);
+ static short ptp_check_int_fast_func(unsigned char * bytes, unsigned int
size, void * data);
+ static int set_prop8(struct Powershot::settings_t * settings, uint16_t prop,
uint8_t val);
+ static int set_prop16(struct Powershot::settings_t * settings, uint16_t
prop, uint16_t val);
+ static int get_prop16(struct Powershot::settings_t * settings, uint16_t
prop, uint16_t * val);
+ static int get_prop32(struct Powershot::settings_t * settings, uint16_t
prop, uint32_t * val);
+ static void do_nothing(void * data, const char * format, va_list args);
+ static char * getarg(char * line, int * n);
+ static int cmdcmp(char * cmd1, char * cmd2);
+ static int exec_cmd(struct Powershot::settings_t * settings, char * arg);
+ static int value_ok(struct Powershot::allowed_t * all, char * value);
+ static int prop16_handler(struct Powershot::settings_t * settings, struct
Powershot::cmd_t * cmd, char * args);
+ static int prop8_handler(struct Powershot::settings_t * settings, struct
Powershot::cmd_t * cmd, char * args);
+ static int focuslock_handler(struct Powershot::settings_t * settings, struct
Powershot::cmd_t * cmd, char * args);
+ static int lock_focus(struct Powershot::settings_t * settings);
+ static int unlock_focus(struct Powershot::settings_t * settings);
+ static int getchanges(struct Powershot::settings_t * settings);
+ static int image_size_from_exif(player_camera_data_t * camData);
+};
+
+struct Powershot::allowed_t Powershot::exposure_compensation_vals[] =
+{
+ { 0xff, "factory default" },
+ { 8 , "+2" },
+ { 11, "+1 2/3" },
+ { 13, "+1 1/3" },
+ { 16, "+1" },
+ { 19, "+2/3" },
+ { 21, "+1/3" },
+ { 24, "0" },
+ { 27, "-1/3" },
+ { 29, "-2/3" },
+ { 32, "-1" },
+ { 35, "-1 1/3" },
+ { 37, "-1 2/3" },
+ { 40, "-2" },
+ { 0 , "" }
+};
+
+struct Powershot::allowed_t Powershot::iso_speed_vals[] =
+{
+ { 0xffff, "factory default" },
+ { 0x0040, "50" },
+ { 0x0048, "100" },
+ { 0x0050, "200" },
+ { 0x0058, "400" },
+ { 0x0000, "Auto" },
+ { 0, "" }
+};
+
+struct Powershot::allowed_t Powershot::white_balance_vals[] =
+{
+ { 0, "Auto" },
+ { 1, "Daylight" },
+ { 2, "Cloudy" },
+ { 3, "Tungsten" },
+ { 4, "Fluorescent" },
+ { 7, "Fluorescent H" },
+ { 6, "Custom" },
+ { 0, "" }
+};
+
+struct Powershot::allowed_t Powershot::photo_effect_vals[] =
+{
+ { 0, "off" },
+ { 1, "Vivid" },
+ { 2, "Neutral" },
+ { 3, "Low sharpening" },
+ { 4, "Sepia" },
+ { 5, "Black & white" },
+ { 0, "" }
+};
+
+struct Powershot::allowed_t Powershot::light_metering_vals[] =
+{
+ { 0, "center weighted(?)" },
+ { 1, "spot" },
+ { 3, "integral(?)" },
+ { 0, "" }
+};
+
+struct Powershot::allowed_t Powershot::zoom_vals[] =
+{
+ { 0, "0" },
+ { 1, "1" },
+ { 2, "2" },
+ { 3, "3" },
+ { 4, "4" },
+ { 5, "5" },
+ { 6, "6" },
+ { 7, "7" },
+ { 8, "8" },
+ { 9, "9" },
+ { 10, "10" },
+ { 11, "11" },
+ { 12, "12" },
+ { 13, "13" },
+ { 14, "14" },
+ { 15, "15" },
+ { 0, "" }
+};
+
+struct Powershot::allowed_t Powershot::focus_vals[] =
+{
+ { 0, "unlock" },
+ { 1, "lock" },
+ { 0, "" }
+};
+
+struct Powershot::allowed_t Powershot::flash_vals[] =
+{
+ { 0, "off" },
+ { 1, "auto" },
+ { 2, "on" },
+ { 5, "auto red eye" },
+ { 6, "on red eye" },
+ { 0, "" }
+};
+
+struct Powershot::allowed_t Powershot::tvav_vals[] =
+{
+ { 1, "program" },
+ { 2, "shutter priority" },
+ { 3, "aperture priority" },
+ { 4, "manual" },
+ { 0 , "" }
+};
+
+struct Powershot::allowed_t Powershot::focuspoint_vals[] =
+{
+ { 0x3003, "center" },
+ { 0x3001, "auto" },
+ { 0, "" }
+};
+
+struct Powershot::allowed_t Powershot::macro_vals[] =
+{
+ { 1, "off" },
+ { 3, "on" },
+ { 0, "" }
+};
+
+struct Powershot::allowed_t Powershot::shutter_vals[] =
+{
+ { 0 , "auto" },
+ { 0x0018, "15\"" },
+ { 0x001b, "13\"" },
+ { 0x001d, "10\"" },
+ { 0x0020, "8\"" },
+ { 0x0023, "6\"" },
+ { 0x0025, "5\"" },
+ { 0x0028, "4\"" },
+ { 0x002b, "3\"2" },
+ { 0x002d, "2\"5" },
+ { 0x0030, "2\"" },
+ { 0x0033, "1\"6" },
+ { 0x0035, "1\"3" },
+ { 0x0038, "1\"" },
+ { 0x003b, "0\"8" },
+ { 0x003d, "0\"6" },
+ { 0x0040, "0\"5" },
+ { 0x0043, "0\"4" },
+ { 0x0045, "0\"3" },
+ { 0x0048, "1/4" },
+ { 0x004b, "1/5" },
+ { 0x004d, "1/6" },
+ { 0x0050, "1/8" },
+ { 0x0053, "1/10" },
+ { 0x0055, "1/13" },
+ { 0x0058, "1/15" },
+ { 0x005b, "1/20" },
+ { 0x005d, "1/25" },
+ { 0x0060, "1/30" },
+ { 0x0063, "1/40" },
+ { 0x0065, "1/50" },
+ { 0x0068, "1/60" },
+ { 0x006b, "1/80" },
+ { 0x006d, "1/100" },
+ { 0x0070, "1/125" },
+ { 0x0073, "1/160" },
+ { 0x0075, "1/200" },
+ { 0x0078, "1/250" },
+ { 0x007b, "1/320" },
+ { 0x007d, "1/400" },
+ { 0x0080, "1/500" },
+ { 0x0083, "1/640" },
+ { 0x0085, "1/800" },
+ { 0x0088, "1/1000" },
+ { 0x008b, "1/1250" },
+ { 0x008d, "1/1600" },
+ { 0x0090, "1/2000" },
+ { 0, "" }
+};
+
+struct Powershot::allowed_t Powershot::aperture_vals[] =
+{
+ { 0xffff, "auto" },
+ { 0x0018, "2.0" }, /* Added on request for G5 */
+ { 0x001B, "2.2" }, /* Added on request for G5 */
+ { 0x001D, "2.5" }, /* Added on request for G5 */
+ { 0x0020, "2.8" },
+ { 0x0023, "3.2" },
+ { 0x0025, "3.5" },
+ { 0x0028, "4.0" },
+ { 0x002b, "4.5" },
+ { 0x0030, "5.6" },
+ { 0x0033, "6.3" },
+ { 0x0035, "7.1" },
+ { 0x0038, "8.0" },
+ { 0x002d, "5" },
+ { 0 , "" }
+};
+
+struct Powershot::allowed_t Powershot::qual_vals[] =
+{
+ { 5, "superfine" },
+ { 3, "fine" },
+ { 2, "normal" },
+ { 0 , "" }
+};
+
+struct Powershot::allowed_t Powershot::size_vals[] =
+{
+ { 0, "large" },
+ { 1, "medium1" },
+ { 3, "medium2" },
+ { 7, "medium3" },
+ { 2, "small" },
+ { 0 , "" }
+};
+
+struct Powershot::cmd_t Powershot::cmds[] =
+{
+ { "zoom", PTP_DPC_CANON_Zoom, Powershot::prop16_handler,
Powershot::zoom_vals },
+ { "flash", PTP_DPC_CANON_FlashMode, Powershot::prop8_handler,
Powershot::flash_vals },
+ { "macro", PTP_DPC_CANON_MacroMode, Powershot::prop8_handler,
Powershot::macro_vals },
+ { "aperture", PTP_DPC_CANON_Aperture, Powershot::prop16_handler,
Powershot::aperture_vals },
+ { "shutter", PTP_DPC_CANON_ShutterSpeed, Powershot::prop16_handler,
Powershot::shutter_vals },
+ { "tv/av", PTP_DPC_CANON_TvAvSetting, Powershot::prop8_handler,
Powershot::tvav_vals },
+ { "focuspoint", PTP_DPC_CANON_FocusingPoint, Powershot::prop16_handler,
Powershot::focuspoint_vals },
+ { "ecomp", PTP_DPC_CANON_ExpCompensation, Powershot::prop8_handler,
Powershot::exposure_compensation_vals },
+ { "iso", PTP_DPC_CANON_ISOSpeed, Powershot::prop16_handler,
Powershot::iso_speed_vals },
+ { "white", PTP_DPC_CANON_WhiteBalance, Powershot::prop8_handler,
Powershot::white_balance_vals },
+ { "effect", PTP_DPC_CANON_PhotoEffect, Powershot::prop16_handler,
Powershot::photo_effect_vals },
+ { "metering", PTP_DPC_CANON_MeteringMode, Powershot::prop8_handler,
Powershot::light_metering_vals },
+ { "qual", PTP_DPC_CANON_ImageQuality, Powershot::prop8_handler,
Powershot::qual_vals },
+ { "size", PTP_DPC_CANON_ImageSize, Powershot::prop8_handler,
Powershot::size_vals },
+ { "focus", 0, Powershot::focuslock_handler, Powershot::focus_vals },
+ { "", 0, NULL, NULL }
+};
+
+Powershot::Powershot(ConfigFile * cf, int section)
+ : ThreadedDriver(cf, section, true, PLAYER_MSGQUEUE_DEFAULT_MAXLEN),
+ live_width("live_width", 320, false),
+ live_height("live_height", 240, false)
+{
+ int i, stat, opts;
+ struct timespec ts;
+ char cmd[80];
+ const char * str;
+
+ assert(PTP_RC_OK != 0); // logical assumptions verification
+ this->RegisterProperty("live_width", &(this->live_width), cf, section);
+ if ((this->live_width.GetValue()) <= 0)
+ {
+ PLAYER_ERROR("invalid live_widht value");
+ this->SetError(-1);
+ return;
+ }
+ this->RegisterProperty("live_height", &(this->live_height), cf, section);
+ if ((this->live_height.GetValue()) <= 0)
+ {
+ PLAYER_ERROR("invalid live_height value");
+ this->SetError(-1);
+ return;
+ }
+ memset(&(this->camera_addr), 0, sizeof(player_devaddr_t));
+ memset(&(this->imgData), 0, sizeof this->imgData);
+ memset(&(this->settings), 0, sizeof this->settings);
+ this->imgData.image_count = 0;
+ this->imgData.image = NULL;
+ this->needs_frame = 0;
+ this->repeat = 0;
+ this->sleep_nsec = 0;
+ this->live_view = 0;
+ this->started = 0;
+ if (cf->ReadDeviceAddr(&(this->camera_addr), section, "provides",
PLAYER_CAMERA_CODE, -1, NULL))
+ {
+ this->SetError(-1);
+ return;
+ }
+ if (this->AddInterface(this->camera_addr))
+ {
+ this->SetError(-1);
+ return;
+ }
+ this->repeat = cf->ReadInt(section, "repeat", 0);
+ this->sleep_nsec = cf->ReadInt(section, "sleep_nsec", 10000000);
+ if ((this->sleep_nsec) < 0)
+ {
+ PLAYER_ERROR("Invalid sleep_nsec value");
+ this->SetError(-1);
+ return;
+ }
+ this->live_view = cf->ReadInt(section, "live_view", 0);
+ if (this->live_view) this->repeat = 0;
+ for (i = 0; i < 5; i++)
+ {
+ if (i)
+ {
+ ts.tv_sec = 1;
+ ts.tv_nsec = 0;
+ nanosleep(&ts, NULL);
+ }
+ this->settings.dev = Powershot::find_device(0, 0);
+ if (!(this->settings.dev)) continue;
+ Powershot::find_endpoints(&(this->settings));
+ if (!(Powershot::ptp_usb_init(&(this->settings))))
+ {
+ PLAYER_WARN("could not init ptp_usb");
+ }
+ ts.tv_sec = 1;
+ ts.tv_nsec = 0;
+ nanosleep(&ts, NULL);
+ if ((ptp_opensession(&(this->settings.params), 1)) != PTP_RC_OK)
+ {
+ PLAYER_WARN("could not open session");
+ Powershot::ptp_usb_close(&(this->settings));
+ continue;
+ }
+ break;
+ }
+ if (Powershot::magic_code(&(this->settings)) != PTP_RC_OK)
+ {
+ PLAYER_ERROR("No magic can be done");
+ stat = Powershot::usb_checkevent_wait(&(this->settings));
+ Powershot::ptp_checkevent(&(this->settings), NULL);
+ Powershot::ptp_checkevent(&(this->settings), NULL);
+ if (stat != PTP_RC_OK) Powershot::usb_checkevent_wait(&(this->settings));
+ ptp_closesession(&(this->settings.params));
+ Powershot::ptp_usb_close(&(this->settings));
+ this->SetError(-1);
+ return;
+ }
+ if (ptp_canon_startshootingmode(&(this->settings.params)) != PTP_RC_OK)
+ {
+ PLAYER_ERROR("Cannot start shooting mode");
+ stat = Powershot::usb_checkevent_wait(&(this->settings));
+ Powershot::ptp_checkevent(&(this->settings), NULL);
+ Powershot::ptp_checkevent(&(this->settings), NULL);
+ if (stat != PTP_RC_OK) Powershot::usb_checkevent_wait(&(this->settings));
+ ptp_closesession(&(this->settings.params));
+ Powershot::ptp_usb_close(&(this->settings));
+ this->SetError(-1);
+ return;
+ }
+ Powershot::usb_checkevent_wait(&(this->settings));
+ Powershot::ptp_checkevent(&(this->settings), NULL);
+ if (Powershot::set_prop16(&(this->settings), PTP_DPC_CANON_D029, 3) !=
PTP_RC_OK)
+ {
+ PLAYER_ERROR("Cannot set PTP_DPC_CANON_D029");
+ if (ptp_canon_endshootingmode(&(this->settings.params)) != PTP_RC_OK)
PLAYER_ERROR("endshootingmode cannot be done");
+ stat = Powershot::usb_checkevent_wait(&(this->settings));
+ Powershot::ptp_checkevent(&(this->settings), NULL);
+ Powershot::ptp_checkevent(&(this->settings), NULL);
+ if (stat != PTP_RC_OK) Powershot::usb_checkevent_wait(&(this->settings));
+ ptp_closesession(&(this->settings.params));
+ Powershot::ptp_usb_close(&(this->settings));
+ this->SetError(-1);
+ return;
+ }
+ this->started = !0;
+ opts = cf->GetTupleCount(section, "init_commands");
+ for (i = 0; i < opts; i++)
+ {
+ str = cf->ReadTupleString(section, "init_commands", i, NULL);
+ if (!str)
+ {
+ PLAYER_ERROR("NULL init command");
+ if (ptp_canon_endshootingmode(&(this->settings.params)) != PTP_RC_OK)
PLAYER_ERROR("endshootingmode cannot be done");
+ stat = Powershot::usb_checkevent_wait(&(this->settings));
+ Powershot::ptp_checkevent(&(this->settings), NULL);
+ Powershot::ptp_checkevent(&(this->settings), NULL);
+ if (stat != PTP_RC_OK) Powershot::usb_checkevent_wait(&(this->settings));
+ ptp_closesession(&(this->settings.params));
+ Powershot::ptp_usb_close(&(this->settings));
+ this->started = 0;
+ this->SetError(-1);
+ return;
+ }
+ snprintf(cmd, sizeof cmd, "%s", str);
+ if (Powershot::exec_cmd(&(this->settings), cmd) != PTP_RC_OK)
+ {
+ PLAYER_ERROR1("Cannot execute command [%s]", cmd);
+ if (ptp_canon_endshootingmode(&(this->settings.params)) != PTP_RC_OK)
PLAYER_ERROR("endshootingmode cannot be done");
+ stat = Powershot::usb_checkevent_wait(&(this->settings));
+ Powershot::ptp_checkevent(&(this->settings), NULL);
+ Powershot::ptp_checkevent(&(this->settings), NULL);
+ if (stat != PTP_RC_OK) Powershot::usb_checkevent_wait(&(this->settings));
+ ptp_closesession(&(this->settings.params));
+ Powershot::ptp_usb_close(&(this->settings));
+ this->started = 0;
+ this->SetError(-1);
+ return;
+ }
+ }
+ if (this->live_view)
+ {
+ if (ptp_canon_reflectchanges(&(this->settings.params), 7) != PTP_RC_OK)
+ {
+ PLAYER_ERROR("Cannot reflect changes");
+ if (ptp_canon_endshootingmode(&(this->settings.params)) != PTP_RC_OK)
PLAYER_ERROR("endshootingmode cannot be done");
+ stat = Powershot::usb_checkevent_wait(&(this->settings));
+ Powershot::ptp_checkevent(&(this->settings), NULL);
+ Powershot::ptp_checkevent(&(this->settings), NULL);
+ if (stat != PTP_RC_OK) Powershot::usb_checkevent_wait(&(this->settings));
+ ptp_closesession(&(this->settings.params));
+ Powershot::ptp_usb_close(&(this->settings));
+ this->started = 0;
+ this->SetError(-1);
+ return;
+ }
+ if (Powershot::getchanges(&(this->settings)) != PTP_RC_OK)
+ {
+ PLAYER_ERROR("Cannot get changes");
+ if (ptp_canon_endshootingmode(&(this->settings.params)) != PTP_RC_OK)
PLAYER_ERROR("endshootingmode cannot be done");
+ stat = Powershot::usb_checkevent_wait(&(this->settings));
+ Powershot::ptp_checkevent(&(this->settings), NULL);
+ Powershot::ptp_checkevent(&(this->settings), NULL);
+ if (stat != PTP_RC_OK) Powershot::usb_checkevent_wait(&(this->settings));
+ ptp_closesession(&(this->settings.params));
+ Powershot::ptp_usb_close(&(this->settings));
+ this->started = 0;
+ this->SetError(-1);
+ return;
+ }
+ ptp_canon_viewfinderon(&(this->settings.params));
+ }
+}
+
+Powershot::~Powershot()
+{
+ int stat;
+
+ if (this->imgData.image) free(this->imgData.image);
+ this->imgData.image_count = 0;
+ this->imgData.image = NULL;
+ if (this->started)
+ {
+ if (this->live_view) ptp_canon_viewfinderoff(&(this->settings.params));
+ if (ptp_canon_endshootingmode(&(this->settings.params)) != PTP_RC_OK)
PLAYER_ERROR("endshootingmode cannot be done");
+ stat = Powershot::usb_checkevent_wait(&(this->settings));
+ Powershot::ptp_checkevent(&(this->settings), NULL);
+ Powershot::ptp_checkevent(&(this->settings), NULL);
+ if (stat != PTP_RC_OK) Powershot::usb_checkevent_wait(&(this->settings));
+ ptp_closesession(&(this->settings.params));
+ Powershot::ptp_usb_close(&(this->settings));
+ this->started = 0;
+ }
+}
+
+void Powershot::do_nothing(void * data, const char * format, va_list args) { }
+
+struct usb_device * Powershot::find_device(int busn, int devn)
+{
+ struct usb_bus * bus;
+ struct usb_device * dev;
+ int curbusn, curdevn;
+
+ usb_init();
+ usb_find_busses();
+ usb_find_devices();
+ for (bus = usb_get_busses(); bus; bus = bus->next)
+ {
+ for (dev = bus->devices; dev; dev = dev->next)
+ {
+ assert(dev);
+ assert(dev->config);
+ assert(dev->config->interface);
+ assert(dev->config->interface->altsetting);
+ if ((dev->config->interface->altsetting->bInterfaceClass) ==
USB_CLASS_PTP)
+ {
+ if ((dev->descriptor.bDeviceClass) != USB_CLASS_HUB)
+ {
+ curbusn = strtol(bus->dirname, NULL, 10);
+ curdevn = strtol(dev->filename, NULL, 10);
+ if (!devn)
+ {
+ if (!busn) return dev;
+ if (curbusn == busn) return dev;
+ } else
+ {
+ if ((!busn) && (curdevn == devn)) return dev;
+ if ((curbusn == busn) && (curdevn == devn)) return dev;
+ }
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+void Powershot::find_endpoints(struct Powershot::settings_t * settings)
+{
+ int i, n;
+ struct usb_endpoint_descriptor * ep;
+
+ assert(settings);
+ assert(settings->dev);
+ assert(settings->dev->config);
+ assert(settings->dev->config->interface);
+ assert(settings->dev->config->interface->altsetting);
+ ep = settings->dev->config->interface->altsetting->endpoint;
+ n = settings->dev->config->interface->altsetting->bNumEndpoints;
+
+ for (i = 0; i < n; i++)
+ {
+ if (ep[i].bmAttributes == USB_ENDPOINT_TYPE_BULK)
+ {
+ if (((ep[i].bEndpointAddress) & USB_ENDPOINT_DIR_MASK) ==
USB_ENDPOINT_DIR_MASK)
+ settings->ptp_usb.inep = ep[i].bEndpointAddress;
+ if (((ep[i].bEndpointAddress) & USB_ENDPOINT_DIR_MASK) == 0)
settings->ptp_usb.outep = ep[i].bEndpointAddress;
+ } else
+ {
+ if ((ep[i].bmAttributes) == USB_ENDPOINT_TYPE_INTERRUPT)
+ {
+ if (((ep[i].bEndpointAddress) & USB_ENDPOINT_DIR_MASK) ==
USB_ENDPOINT_DIR_MASK) settings->ptp_usb.intep = ep[i].bEndpointAddress;
+ }
+ }
+ }
+}
+
+int Powershot::ptp_usb_init(struct Powershot::settings_t * settings)
+{
+ usb_dev_handle * device_handle;
+
+ assert(settings);
+ settings->params.write_func = Powershot::ptp_write_func;
+ settings->params.read_func = Powershot::ptp_read_func;
+ settings->params.check_int_func = Powershot::ptp_check_int_func;
+ settings->params.check_int_fast_func = Powershot::ptp_check_int_fast_func;
+ settings->params.error_func = Powershot::do_nothing;
+ settings->params.debug_func = Powershot::do_nothing;
+ settings->params.sendreq_func = ptp_usb_sendreq;
+ settings->params.senddata_func = ptp_usb_senddata;
+ settings->params.getresp_func = ptp_usb_getresp;
+ settings->params.getdata_func = ptp_usb_getdata;
+ settings->params.data = &(settings->ptp_usb);
+ settings->params.transaction_id = 0;
+ settings->params.byteorder = PTP_DL_LE;
+ device_handle = usb_open(settings->dev);
+ if (device_handle)
+ {
+ settings->ptp_usb.handle = device_handle;
+ assert(settings->dev);
+ assert(settings->dev->config);
+ assert(settings->dev->config->interface);
+ assert(settings->dev->config->interface->altsetting);
+ usb_claim_interface(device_handle,
settings->dev->config->interface->altsetting->bInterfaceNumber);
+ return !0;
+ }
+ return 0;
+}
+
+int Powershot::magic_code(struct Powershot::settings_t * settings)
+{
+ uint32_t ui32;
+ uint16_t ui16;
+ int stat;
+
+ assert(settings);
+ Powershot::get_prop16(settings, 0xd045, &ui16);
+ stat = Powershot::set_prop16(settings, 0xd045, 1);
+ if (stat != PTP_RC_OK) return stat;
+ stat = Powershot::get_prop32(settings, 0xd02e, &ui32);
+ if (stat != PTP_RC_OK) return stat;
+ stat = get_prop32(settings,0xd02f, &ui32);
+ if (stat != PTP_RC_OK) return stat;
+ stat = ptp_getdeviceinfo(&(settings->params),
&(settings->params.deviceinfo));
+ if (stat != PTP_RC_OK) return stat;
+ stat = ptp_getdeviceinfo(&(settings->params),
&(settings->params.deviceinfo));
+ if (stat != PTP_RC_OK) return stat;
+ stat = get_prop32(settings, 0xd02e, &ui32);
+ if (stat != PTP_RC_OK) return stat;
+ stat = get_prop32(settings, 0xd02f, &ui32);
+ if (stat != PTP_RC_OK) return stat;
+ stat = ptp_getdeviceinfo(&(settings->params),
&(settings->params.deviceinfo));
+ if (stat != PTP_RC_OK) return stat;
+ stat = get_prop16(settings, 0xd045, &ui16);
+ if (stat != PTP_RC_OK) return stat;
+ stat = set_prop16(settings, 0xd045, 4);
+ if (stat != PTP_RC_OK) return stat;
+ return PTP_RC_OK;
+}
+
+int Powershot::usb_checkevent_wait(struct Powershot::settings_t * settings)
+{
+ int stat;
+ PTPContainer evc;
+
+ assert(settings);
+ stat = ptp_usb_event_wait(&(settings->params), &evc);
+ return stat;
+}
+
+int Powershot::ptp_checkevent(struct Powershot::settings_t * settings,
PTPUSBEventContainer * fill_event)
+{
+ int isevent;
+ PTPUSBEventContainer event;
+ PTPUSBEventContainer * ev = (fill_event) ? fill_event : &event;
+
+ assert(settings);
+ assert(ev);
+ if (ptp_canon_checkevent(&(settings->params), ev, &isevent) != PTP_RC_OK)
return 0;
+ if (!isevent) return 0;
+ if (! ev->code && ev->type == PTP_USB_CONTAINER_UNDEFINED) return 0;
+ return 1;
+}
+
+void Powershot::ptp_usb_close(struct Powershot::settings_t * settings)
+{
+ assert(settings);
+ assert(settings->dev);
+ assert(settings->dev->config);
+ assert(settings->dev->config->interface);
+ assert(settings->dev->config->interface->altsetting);
+ usb_release_interface(settings->ptp_usb.handle,
settings->dev->config->interface->altsetting->bInterfaceNumber);
+}
+
+short Powershot::ptp_write_func(unsigned char * bytes, unsigned int size, void
* data)
+{
+ int result;
+ struct Powershot::ptp_usb_t * ptp_usb;
+
+ assert(bytes);
+ assert(size > 0);
+ assert(data);
+ ptp_usb = reinterpret_cast<struct Powershot::ptp_usb_t *>(data);
+ assert(ptp_usb);
+ result = usb_bulk_write(ptp_usb->handle, ptp_usb->outep,
reinterpret_cast<char *>(bytes), size, MAX_BULK_SIZE);
+ if (result >= 0) return PTP_RC_OK;
+ return PTP_ERROR_IO;
+}
+
+short Powershot::ptp_read_func(unsigned char * bytes, unsigned int size, void
* data)
+{
+ int result;
+ struct Powershot::ptp_usb_t * ptp_usb;
+
+ assert(bytes);
+ assert(size > 0);
+ assert(data);
+ ptp_usb = reinterpret_cast<struct Powershot::ptp_usb_t *>(data);
+ assert(ptp_usb);
+ result = usb_bulk_read(ptp_usb->handle, ptp_usb->inep, reinterpret_cast<char
*>(bytes), size, MAX_BULK_SIZE);
+ if (!result) result = usb_bulk_read(ptp_usb->handle, ptp_usb->inep,
reinterpret_cast<char *>(bytes), size, MAX_BULK_SIZE);
+ if (result >= 0) return PTP_RC_OK;
+ return PTP_ERROR_IO;
+}
+
+short Powershot::ptp_check_int_func(unsigned char * bytes, unsigned int size,
void * data)
+{
+ int count = 100;
+ int result = 0;
+ struct Powershot::ptp_usb_t * ptp_usb;
+
+ assert(bytes);
+ assert(size > 0);
+ assert(data);
+ ptp_usb = reinterpret_cast<struct Powershot::ptp_usb_t *>(data);
+ assert(ptp_usb);
+ while (!result && count)
+ {
+ result = usb_bulk_read(ptp_usb->handle, ptp_usb->intep,
reinterpret_cast<char *>(bytes), size, MAX_SMALLREAD_SIZE);
+ count--;
+ }
+ if (result >= 0)
+ {
+ do
+ {
+ bytes += result;
+ size -= result;
+ if (size > 0) result = usb_bulk_read(ptp_usb->handle, ptp_usb->intep,
reinterpret_cast<char *>(bytes), size, MAX_SMALLREAD_SIZE);
+ } while ((result > 0) && (size > 0));
+ return PTP_RC_OK;
+ }
+ return PTP_ERROR_IO;
+}
+
+short Powershot::ptp_check_int_fast_func(unsigned char * bytes, unsigned int
size, void * data)
+{
+ int result;
+ struct Powershot::ptp_usb_t * ptp_usb;
+
+ assert(bytes);
+ assert(size > 0);
+ assert(data);
+ ptp_usb = reinterpret_cast<struct Powershot::ptp_usb_t *>(data);
+ assert(ptp_usb);
+ result = usb_bulk_read(ptp_usb->handle, ptp_usb->intep,
reinterpret_cast<char *>(bytes), size, MAX_SMALLREAD_SIZE);
+ if (!result) result = usb_bulk_read(ptp_usb->handle, ptp_usb->intep,
reinterpret_cast<char *>(bytes), size, MAX_SMALLREAD_SIZE);
+ if (result >= 0)
+ {
+ do
+ {
+ bytes += result;
+ size -= result;
+ if (size > 0) result = usb_bulk_read(ptp_usb->handle, ptp_usb->intep,
reinterpret_cast<char *>(bytes), size, MAX_SMALLREAD_SIZE);
+ } while ((result > 0) && (size > 0));
+ return PTP_RC_OK;
+ }
+ return PTP_ERROR_IO;
+}
+
+int Powershot::set_prop8(struct Powershot::settings_t * settings, uint16_t
prop, uint8_t val)
+{
+ return ptp_setdevicepropvalue(&(settings->params), prop, &val,
PTP_DTC_UINT8);
+}
+
+int Powershot::set_prop16(struct Powershot::settings_t * settings, uint16_t
prop, uint16_t val)
+{
+ return ptp_setdevicepropvalue(&(settings->params), prop, &val,
PTP_DTC_UINT16);
+}
+
+int Powershot::get_prop16(struct Powershot::settings_t * settings, uint16_t
prop, uint16_t * val)
+{
+ uint16_t * p = NULL;
+
+ uint32_t stat = ptp_getdevicepropvalue(&(settings->params), prop,
reinterpret_cast<void **>(&p), PTP_DTC_UINT16);
+ if (p && *p)
+ {
+ *val = *p;
+ free(p);
+ }
+ return stat;
+}
+
+int Powershot::get_prop32(struct Powershot::settings_t * settings, uint16_t
prop, uint32_t * val)
+{
+ uint32_t * p = NULL;
+
+ uint32_t stat = ptp_getdevicepropvalue(&(settings->params), prop,
reinterpret_cast<void **>(&p), PTP_DTC_UINT32);
+ if (p && *p)
+ {
+ *val = *p;
+ free(p);
+ }
+ return stat;
+}
+
+char * Powershot::getarg(char * line, int * n)
+{
+ char * p = line;
+ char * s;
+
+ assert(line);
+ while (p && *p && ((*p) == ' ')) p++;
+ if (! p || ! *p) return NULL;
+ s = p;
+ while (p && *p && !((*p) == ' ')) p++;
+ if (p == s) return NULL;
+ if (n) (*n) = (p - s);
+ return s;
+}
+
+int Powershot::cmdcmp(char * cmd1, char * cmd2)
+{
+ int n1, n2;
+ char * arg1 = Powershot::getarg(cmd1, &n1);
+ char * arg2 = Powershot::getarg(cmd2, &n2);
+
+ if (n1 != n2) return 1;
+ if (!arg1) return 1;
+ if (!arg2) return 1;
+ assert(arg2);
+ return strncasecmp(arg1, arg2, n1);
+}
+
+int Powershot::exec_cmd(struct Powershot::settings_t * settings, char * arg)
+{
+ int n;
+ struct Powershot::cmd_t * c;
+
+ assert(settings);
+ arg = Powershot::getarg(arg, &n);
+ if (!arg) return 0;
+ c = Powershot::cmds;
+ while (c->command[0])
+ {
+ if (!(Powershot::cmdcmp(arg, c->command)))
+ {
+ if (c->handler)
+ {
+ arg = Powershot::getarg(arg + n, &n);
+ return c->handler(settings, c, arg);
+ } else
+ {
+ PLAYER_ERROR1("Powershot configuration command cannot be executed
[%s]", arg);
+ return 0;
+ }
+ }
+ c++;
+ assert(c);
+ }
+ PLAYER_ERROR1("Powershot configuration command cannot be understood [%s]",
arg);
+ return 0;
+}
+
+int Powershot::value_ok(struct Powershot::allowed_t * all, char * value)
+{
+ int n;
+
+ assert(value);
+ value = getarg(value, &n);
+ if (!value) return -1;
+ while (all && (all->string[0]))
+ {
+ if (!strcasecmp(value, all->string)) return all->code;
+ all++;
+ }
+ return -1;
+}
+
+int Powershot::prop16_handler(struct Powershot::settings_t * settings, struct
Powershot::cmd_t * cmd, char * args)
+{
+ int prop;
+ uint16_t value;
+ PTPDevicePropDesc dpd;
+
+ assert(settings);
+ assert(cmd);
+ assert(args);
+ memset(&dpd, 0, sizeof dpd);
+ if (!(Powershot::getarg(args, NULL)))
+ {
+ if (ptp_getdevicepropdesc(&(settings->params), cmd->ptpcode, &dpd) !=
PTP_RC_OK) return 0;
+ ptp_free_devicepropdesc(&dpd);
+ return PTP_RC_OK;
+ }
+ prop = Powershot::value_ok(cmd->params, args);
+ if (prop == -1)
+ {
+ PLAYER_ERROR1("bad parameter \"%s\"", args);
+ return 0;
+ }
+ value = prop;
+ if (ptp_getdevicepropdesc(&(settings->params),cmd->ptpcode,&dpd) !=
PTP_RC_OK) return 0;
+ ptp_free_devicepropdesc(&dpd);
+ if (ptp_setdevicepropvalue(&(settings->params), cmd->ptpcode, &value,
dpd.DataType) != PTP_RC_OK) return 0;
+ if (ptp_getdevicepropdesc(&(settings->params), cmd->ptpcode, &dpd) !=
PTP_RC_OK) return 0;
+ if (value != (*(reinterpret_cast<uint16_t *>(dpd.CurrentValue))))
+ {
+ ptp_free_devicepropdesc(&dpd);
+ return 0;
+ }
+ ptp_free_devicepropdesc(&dpd);
+ return PTP_RC_OK;
+}
+
+int Powershot::prop8_handler(struct Powershot::settings_t * settings, struct
Powershot::cmd_t * cmd, char * args)
+{
+ int prop;
+ PTPDevicePropDesc dpd;
+
+ assert(settings);
+ assert(cmd);
+ assert(args);
+ memset(&dpd, 0, sizeof dpd);
+ if (!(Powershot::getarg(args, NULL)))
+ {
+ if (ptp_getdevicepropdesc(&(settings->params), cmd->ptpcode, &dpd) !=
PTP_RC_OK) return 0;
+ ptp_free_devicepropdesc(&dpd);
+ return PTP_RC_OK;
+ }
+ prop = Powershot::value_ok(cmd->params, args);
+ if (prop == -1)
+ {
+ PLAYER_ERROR1("bad parameter \"%s\"", args);
+ return 0;
+ }
+ if (Powershot::set_prop8(settings, cmd->ptpcode, prop) != PTP_RC_OK) return
0;
+ return PTP_RC_OK;
+}
+
+int Powershot::focuslock_handler(struct Powershot::settings_t * settings,
struct Powershot::cmd_t * cmd, char * args)
+{
+ int lock;
+
+ assert(settings);
+ assert(cmd);
+ assert(args);
+ lock = Powershot::value_ok(cmd->params, args);
+ if (lock == -1)
+ {
+ PLAYER_ERROR1("bad parameter \"%s\"", args);
+ return 0;
+ }
+ if (lock) Powershot::lock_focus(settings); else
Powershot::unlock_focus(settings);
+ return PTP_RC_OK;
+}
+
+int Powershot::lock_focus(struct Powershot::settings_t * settings)
+{
+ int stat;
+
+ assert(settings);
+ stat = ptp_canon_focuslock(&(settings->params));
+ if (stat != PTP_RC_OK) return stat;
+ stat = Powershot::getchanges(settings);
+ if (stat != PTP_RC_OK) return stat;
+ return PTP_RC_OK;
+}
+
+int Powershot::unlock_focus(struct Powershot::settings_t * settings)
+{
+ int stat;
+
+ assert(settings);
+ stat = ptp_canon_focusunlock(&(settings->params));
+ if (stat != PTP_RC_OK) return stat;
+ stat = Powershot::getchanges(settings);
+ if (stat != PTP_RC_OK) return stat;
+ return PTP_RC_OK;
+}
+
+int Powershot::getchanges(struct Powershot::settings_t * settings)
+{
+ uint16_t * props = NULL;
+ uint32_t propnum;
+ int stat;
+
+ assert(settings);
+ stat = ptp_canon_getchanges(&(settings->params), &props, &propnum);
+ if (stat != PTP_RC_OK) return stat;
+ if (props) free(props);
+ return PTP_RC_OK;
+}
+
+int Powershot::image_size_from_exif(player_camera_data_t * camData)
+{
+ ExifLoader * el;
+ ExifData * ed;
+ ExifEntry * ee;
+ struct timespec ts;
+ int i;
+
+ el = exif_loader_new();
+ if (!el)
+ {
+ PLAYER_ERROR("cannot create new EXIF loader");
+ return -1;
+ }
+ for (i = 0; i < 100; i++)
+ {
+ if (!(exif_loader_write(el, camData->image, camData->image_count))) break;
+ ts.tv_sec = 0;
+ ts.tv_nsec = 1000000;
+ nanosleep(&ts, NULL);
+ }
+ if (i == 100)
+ {
+ PLAYER_ERROR("Cannot read EXIF data");
+ exif_loader_unref(el);
+ return -1;
+ }
+ ed = exif_loader_get_data(el);
+ if (!ed)
+ {
+ PLAYER_ERROR("NULL EXIF data");
+ exif_loader_unref(el);
+ return -1;
+ }
+ if (exif_data_get_byte_order(ed) != EXIF_BYTE_ORDER_INTEL)
exif_data_set_byte_order(ed, EXIF_BYTE_ORDER_INTEL);
+ if (exif_data_get_byte_order(ed) != EXIF_BYTE_ORDER_INTEL)
+ {
+ PLAYER_ERROR("invalid EXIF data byte order");
+ exif_data_unref(ed);
+ exif_loader_unref(el);
+ return -1;
+ }
+ ee = exif_data_get_entry(ed, exif_tag_from_name("PixelXDimension"));
+ if (!ee)
+ {
+ PLAYER_ERROR("cannot get PixelXDimension EXIF entry");
+ exif_data_unref(ed);
+ exif_loader_unref(el);
+ return -1;
+ }
+ if (strcmp(exif_format_get_name(ee->format), "Short") ||
(exif_format_get_size(ee->format) != 2))
+ {
+ PLAYER_ERROR("cannot handle this kind of EXIF data");
+ exif_data_unref(ed);
+ exif_loader_unref(el);
+ return -1;
+ }
+ if (exif_format_get_size(ee->format) != ee->size)
+ {
+ PLAYER_ERROR("EXIF inconsistency");
+ exif_data_unref(ed);
+ exif_loader_unref(el);
+ return -1;
+ }
+ camData->width = ((ee->data[1]) * 256) + (ee->data[0]); // Intel endiannes
handled this way should also fit to big-endian machines
+ ee = exif_data_get_entry(ed, exif_tag_from_name("PixelYDimension"));
+ if (!ee)
+ {
+ PLAYER_ERROR("cannot get PixelYDimension EXIF entry");
+ exif_data_unref(ed);
+ exif_loader_unref(el);
+ return -1;
+ }
+ if (strcmp(exif_format_get_name(ee->format), "Short") ||
(exif_format_get_size(ee->format) != 2))
+ {
+ PLAYER_ERROR("cannot handle this kind of EXIF data");
+ exif_data_unref(ed);
+ exif_loader_unref(el);
+ return -1;
+ }
+ if (exif_format_get_size(ee->format) != ee->size)
+ {
+ PLAYER_ERROR("EXIF inconsistency");
+ exif_data_unref(ed);
+ exif_loader_unref(el);
+ return -1;
+ }
+ camData->height = ((ee->data[1]) * 256) + (ee->data[0]); // Intel endiannes
handled this way should also fit to big-endian machines
+ exif_data_unref(ed);
+ exif_loader_unref(el);
+ PLAYER_WARN2("JPEG size %u x %u", camData->width, camData->height);
+ return 0;
+}
+
+void Powershot::Main()
+{
+ char * image;
+ uint8_t * img;
+ int has_frame = 0;
+ int stat;
+ int nblocks, tail;
+ unsigned int readnum;
+ double frame_stamp = 0.0;
+ int i, j;
+ struct timespec ts;
+ PTPUSBEventContainer event;
+ uint32_t handle, size, dummy, pos;
+
+ for (;;)
+ {
+ if (((this->repeat) && has_frame) || (this->live_view))
+ {
+ if ((this->sleep_nsec) > 0)
+ {
+ ts.tv_sec = 0;
+ ts.tv_nsec = this->sleep_nsec;
+ nanosleep(&ts, NULL);
+ }
+ } else this->InQueue->Wait();
+ pthread_testcancel();
+ ProcessMessages();
+ if (this->live_view)
+ {
+ this->imgData.width = this->live_width.GetValue();
+ this->imgData.height = this->live_height.GetValue();
+ this->imgData.bpp = 24;
+ this->imgData.format = PLAYER_CAMERA_FORMAT_RGB888;
+ this->imgData.compression = PLAYER_CAMERA_COMPRESS_JPEG;
+ this->imgData.fdiv = 0;
+ if (this->imgData.image) free(this->imgData.image);
+ this->imgData.image_count = 0;
+ this->imgData.image = NULL;
+ ptp_canon_getviewfinderimage(&(this->settings.params),
reinterpret_cast<char **>(&(this->imgData.image)),
&(this->imgData.image_count));
+ if (!((this->imgData.image) && (this->imgData.image_count > 0)))
+ {
+ if (this->imgData.image) free(this->imgData.image);
+ this->imgData.image_count = 0;
+ continue;
+ }
+ if (!(IS_JPEG(this->imgData.image)))
+ {
+ PLAYER_ERROR("not a JPEG image");
+ free(this->imgData.image);
+ this->imgData.image_count = 0;
+ this->imgData.image = NULL;
+ continue;
+ }
+ assert(this->imgData.image);
+ this->Publish(this->camera_addr,
+ PLAYER_MSGTYPE_DATA, PLAYER_CAMERA_DATA_STATE,
+ reinterpret_cast<void *>(&(this->imgData)), 0, NULL,
true); // copy = true
+ if (this->imgData.image) free(imgData.image);
+ this->imgData.image_count = 0;
+ this->imgData.image = NULL;
+ continue;
+ } else if (this->needs_frame)
+ {
+ this->needs_frame = 0;
+ if (ptp_canon_initiatecaptureinmemory(&(this->settings.params)) !=
PTP_RC_OK)
+ {
+ PLAYER_ERROR("cannot capture frame
(ptp_canon_initiatecaptureinmemory)");
+ continue;
+ }
+ stat = Powershot::usb_checkevent_wait(&(this->settings));
+ handle = 0;
+ for (i = 0; i < 50; i++)
+ {
+ if (i)
+ {
+ ts.tv_sec = 0;
+ ts.tv_nsec = 50000000;
+ nanosleep(&ts, NULL);
+ }
+ if (!(Powershot::ptp_checkevent(&(this->settings), &event))) continue;
+ if ((event.type != PTP_USB_CONTAINER_EVENT) || (event.code !=
PTP_EC_CANON_RequestObjectTransfer)) continue;
+ handle = event.param1;
+ Powershot::ptp_checkevent(&(this->settings), NULL);
+ Powershot::ptp_checkevent(&(this->settings), NULL);
+ break;
+ }
+ if (stat != PTP_RC_OK) stat = usb_checkevent_wait(&(this->settings));
+ if (!(i < 50))
+ {
+ PLAYER_ERROR("capture timed out");
+ continue;
+ }
+ size = 0;
+ dummy = 0;
+ stat = ptp_canon_getobjectsize(&(this->settings.params), handle, 0,
&size, &dummy);
+ if (stat != PTP_RC_OK)
+ {
+ ts.tv_sec = 0;
+ ts.tv_nsec = 50000000;
+ nanosleep(&ts, NULL);
+ stat = ptp_canon_getobjectsize(&(this->settings.params), handle, 0,
&size, &dummy);
+ if (stat != PTP_RC_OK)
+ {
+ PLAYER_ERROR("cannot get image size");
+ continue;
+ }
+ }
+ if (!(size > 0))
+ {
+ PLAYER_ERROR("invalid image size");
+ continue;
+ }
+ this->imgData.width = 0;
+ this->imgData.height = 0;
+ this->imgData.bpp = 24;
+ this->imgData.format = PLAYER_CAMERA_FORMAT_RGB888;
+ this->imgData.compression = PLAYER_CAMERA_COMPRESS_JPEG;
+ this->imgData.fdiv = 0;
+ if ((this->imgData.image_count) != size)
+ {
+ if (this->imgData.image) free(this->imgData.image);
+ this->imgData.image_count = 0;
+ this->imgData.image = NULL;
+ }
+ if (!(this->imgData.image))
+ {
+ assert(!(this->imgData.image_count));
+ this->imgData.image_count = size;
+ this->imgData.image = reinterpret_cast<uint8_t
*>(malloc(this->imgData.image_count));
+ if (!(this->imgData.image))
+ {
+ this->imgData.image_count = 0;
+ PLAYER_ERROR("Out of memory");
+ continue;
+ }
+ }
+ assert(this->imgData.image);
+ assert((this->imgData.image_count) == size);
+ nblocks = size / 5000;
+ tail = size % 5000;
+ img = this->imgData.image;
+ image = NULL;
+ for (i = 0; i < nblocks; i++)
+ {
+ pos = (!i) ? 0 : ((!tail && i == nblocks - 1) ? 2 : 1);
+ for (j = 0; j < 10; j++)
+ {
+ image = NULL;
+ if (ptp_canon_getpartialobject(&(this->settings.params), handle, i *
5000, 5000, pos, &image, &readnum) == PTP_RC_OK) break;
+ }
+ if (j == 10)
+ {
+ if (image) free(image);
+ image = NULL;
+ break;
+ }
+ if (!image) break;
+ if (readnum != 5000)
+ {
+ PLAYER_ERROR("wrong chunk size");
+ free(image);
+ image = NULL;
+ break;
+ }
+ assert(img);
+ memcpy(img, image, readnum);
+ img += readnum;
+ free(image);
+ image = NULL;
+ }
+ assert(!image);
+ if (i != nblocks)
+ {
+ PLAYER_ERROR("cannot get image (ptp_canon_getpartialobject)");
+ free(this->imgData.image);
+ this->imgData.image_count = 0;
+ this->imgData.image = NULL;
+ continue;
+ }
+ if (tail)
+ {
+ pos = (nblocks) ? 3 : 1;
+ image = NULL;
+ if (ptp_canon_getpartialobject(&(this->settings.params), handle,
nblocks * 5000, 5000, pos, &image, &readnum) != PTP_RC_OK)
+ {
+ if (image) free(image);
+ image = NULL;
+ PLAYER_ERROR("cannot get image tail (ptp_canon_getpartialobject)");
+ free(this->imgData.image);
+ this->imgData.image_count = 0;
+ this->imgData.image = NULL;
+ continue;
+ }
+ if (!image)
+ {
+ PLAYER_ERROR("cannot get image tail (NULL image)");
+ free(this->imgData.image);
+ this->imgData.image_count = 0;
+ this->imgData.image = NULL;
+ continue;
+ }
+ if ((readnum < 1) || (readnum > 5000))
+ {
+ PLAYER_ERROR("cannot get image tail (wrong chunk size)");
+ free(image);
+ image = NULL;
+ free(this->imgData.image);
+ this->imgData.image_count = 0;
+ this->imgData.image = NULL;
+ continue;
+ }
+ assert(img);
+ memcpy(img, image, readnum);
+ free(image);
+ image = NULL;
+ }
+ assert(!image);
+ if (!(IS_JPEG(this->imgData.image)))
+ {
+ PLAYER_ERROR("not a JPEG image");
+ free(this->imgData.image);
+ this->imgData.image_count = 0;
+ this->imgData.image = NULL;
+ continue;
+ }
+ if (Powershot::image_size_from_exif(&(this->imgData)))
+ {
+ free(this->imgData.image);
+ this->imgData.image_count = 0;
+ this->imgData.image = NULL;
+ continue;
+ }
+ has_frame = !0;
+ GlobalTime->GetTimeDouble(&frame_stamp);
+ }
+ if (has_frame)
+ {
+ if ((!(this->imgData.width > 0)) || (!(this->imgData.height > 0)))
+ {
+ PLAYER_ERROR("zero sized image");
+ if (this->imgData.image) free(imgData.image);
+ this->imgData.image_count = 0;
+ this->imgData.image = NULL;
+ has_frame = 0;
+ continue;
+ }
+ assert(this->imgData.image);
+ this->Publish(this->camera_addr,
+ PLAYER_MSGTYPE_DATA, PLAYER_CAMERA_DATA_STATE,
+ reinterpret_cast<void *>(&(this->imgData)), 0,
&frame_stamp, true); // copy = true
+ }
+ if (!(this->repeat)) has_frame = 0;
+ }
+}
+
+int Powershot::ProcessMessage(QueuePointer & resp_queue, player_msghdr * hdr,
void * data)
+{
+ player_camera_data_t img;
+
+ assert(hdr);
+ if (Message::MatchMessage(hdr, PLAYER_MSGTYPE_REQ,
PLAYER_CAMERA_REQ_GET_IMAGE, this->camera_addr))
+ {
+ memset(&img, 0, sizeof img);
+ if (this->live_view)
+ {
+ img.width = this->live_width.GetValue();
+ img.height = this->live_height.GetValue();
+ img.bpp = 24;
+ img.format = PLAYER_CAMERA_FORMAT_RGB888;
+ img.compression = PLAYER_CAMERA_COMPRESS_JPEG;
+ img.fdiv = 0;
+ img.image_count = 0;
+ img.image = NULL;
+ ptp_canon_getviewfinderimage(&(this->settings.params),
reinterpret_cast<char **>(&(img.image)), &(img.image_count));
+ if (!((img.image) && (img.image_count > 0)))
+ {
+ if (img.image) free(img.image);
+ return -1;
+ }
+ if (!(IS_JPEG(img.image)))
+ {
+ PLAYER_ERROR("not a JPEG image");
+ free(img.image);
+ return -1;
+ }
+ assert(img.image);
+ } else
+ {
+ img.width = 0;
+ img.height = 0;
+ img.bpp = 24;
+ img.format = PLAYER_CAMERA_FORMAT_RGB888;
+ img.compression = PLAYER_CAMERA_COMPRESS_RAW;
+ img.fdiv = 0;
+ img.image_count = 0;
+ img.image = NULL;
+ this->needs_frame = !0;
+ }
+ this->Publish(this->camera_addr,
+ resp_queue,
+ PLAYER_MSGTYPE_RESP_ACK,
+ PLAYER_CAMERA_REQ_GET_IMAGE,
+ reinterpret_cast<void *>(&img));
+ if (img.image) free(img.image);
+ return 0;
+ }
+ return -1;
+}
+
+Driver * Powershot_Init(ConfigFile * cf, int section)
+{
+ return (Driver *)(new Powershot(cf, section));
+}
+
+void powershot_Register(DriverTable * table)
+{
+ table->AddDriver("powershot", Powershot_Init);
+}
This was sent by the SourceForge.net collaborative development platform, the
world's largest Open Source development site.
------------------------------------------------------------------------------
This SF.net email is sponsored by
Make an app they can't live without
Enter the BlackBerry Developer Challenge
http://p.sf.net/sfu/RIM-dev2dev
_______________________________________________
Playerstage-commit mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/playerstage-commit