佳能 EDSDK 13.11.10 未保存到主机 PC
Canon EDSDK 13.11.10 not saving to host PC
我正在使用 Canons EDSDK 实现远程相机控制应用程序。我的相机是佳能 PowerShot SX 70 HS。到目前为止,一切似乎都正常,除了将拍摄的照片保存到主机 PC 的功能。
我对所需工作流程的理解如下:
- 初始化相机
- 重写对象事件处理程序并传递给
EdsObjectEventHandler
以修改“保存图像行为”
- 拍照
- 关闭流并销毁所有对象。
我已经调整了自己的初始版本并尝试了这些线程中提供的解决方案:
canon EDSDK saving image in my PC
Canon SDK - Downloading image to host PC
下面是代码...
...第一个线程:
#include <iostream>
#include "EDSDK.h"
#include "EDSDKTypes.h"
#include "EDSDKErrors.h"
EdsError getFirstCamera(EdsCameraRef* camera);
EdsError downloadImage(EdsDirectoryItemRef directoryItem);
EdsError EDSCALLBACK handleStateEvent(EdsStateEvent event, EdsUInt32 parameter, EdsVoid* context);
EdsError EDSCALLBACK handleObjectEvent(EdsObjectEvent event, EdsBaseRef object, EdsVoid* context);
EdsError EDSCALLBACK handlePropertyEvent(EdsPropertyEvent event, EdsPropertyID property, EdsUInt32 inParam, EdsVoid* context);
int main(int argc, char** argv)
{
EdsError err;
EdsCameraRef camera = NULL;
bool isSDKLoaded = false;
EdsCapacity capacity = { 0x7FFFFFFF, 0x1000, 1 };
EdsInt32 saveTarget = kEdsSaveTo_Host;
// Initialize SDK
err = EdsInitializeSDK();
if (err == EDS_ERR_OK)
{
isSDKLoaded = true;
}
// Get first camera
if (err == EDS_ERR_OK)
{
err = getFirstCamera(&camera);
}
// Open session with camera
err = EdsOpenSession(camera);
// Set event handler
if (err == EDS_ERR_OK)
err = EdsSetObjectEventHandler(camera, kEdsObjectEvent_All, handleObjectEvent, NULL);
if (err == EDS_ERR_OK)
err = EdsSetPropertyEventHandler(camera, kEdsPropertyEvent_All, handlePropertyEvent, NULL);
if (err == EDS_ERR_OK)
err = EdsSetCameraStateEventHandler(camera, kEdsStateEvent_All, handleStateEvent, NULL);
err = EdsSetPropertyData(camera, kEdsPropID_SaveTo, 0, 4, &saveTarget);
err = EdsSetCapacity(camera, capacity);
///// Take picture
err = EdsSendCommand(camera, kEdsCameraCommand_TakePicture, 0);
////
// Close session with camera
if (err == EDS_ERR_OK)
{
err = EdsCloseSession(camera);
}
// Release camera
if (camera != NULL)
{
EdsRelease(camera);
}
// Terminate SDK
if (isSDKLoaded)
{
EdsTerminateSDK();
}
}
EdsError EDSCALLBACK handleObjectEvent(EdsObjectEvent event, EdsBaseRef object, EdsVoid* context)
{
std::cout << "I'm in the callback-function!!!\n"; // Never shows!
EdsError err = EDS_ERR_OK;
switch (event)
{
case kEdsObjectEvent_DirItemRequestTransfer:
err = downloadImage(object);
break;
default:
break;
}
// Object must be released
if (object) {
err = EdsRelease(object);
}
return err;
}
EdsError EDSCALLBACK handlePropertyEvent(EdsPropertyEvent event, EdsPropertyID property, EdsUInt32 inParam, EdsVoid* context)
{
return EDS_ERR_OK;
}
EdsError EDSCALLBACK handleStateEvent(EdsStateEvent event, EdsUInt32 parameter, EdsVoid* context)
{
return EDS_ERR_OK;
}
EdsError getFirstCamera(EdsCameraRef* camera)
{
EdsError err;
EdsCameraListRef cameraList = NULL;
err = EdsGetCameraList(&cameraList);
err = EdsGetChildAtIndex(cameraList, 0, camera);
return err;
}
EdsError downloadImage(EdsDirectoryItemRef directoryItem)
{
EdsError err = EDS_ERR_OK;
EdsStreamRef stream = NULL;
// Get directory item information
EdsDirectoryItemInfo dirItemInfo;
err = EdsGetDirectoryItemInfo(directoryItem, &dirItemInfo);
// Create file stream for transfer destination
if (err == EDS_ERR_OK)
{
err = EdsCreateFileStream(dirItemInfo.szFileName, kEdsFileCreateDisposition_CreateAlways, kEdsAccess_ReadWrite, &stream);
}
// Download image
if (err == EDS_ERR_OK)
{
err = EdsDownload(directoryItem, dirItemInfo.size, stream);
}
// Issue notification that download is complete
if (err == EDS_ERR_OK)
{
err = EdsDownloadComplete(directoryItem);
}
// Release stream
if (stream != NULL)
{
EdsRelease(stream);
stream = NULL;
}
return err;
}
第二个线程:
#include <iostream>
#include "EDSDK.h"
#include "EDSDKTypes.h"
#include "EDSDKErrors.h"
static EdsError EDSCALLBACK handleObjectEvent(EdsObjectEvent event, EdsBaseRef object, EdsVoid* context)
{
std::cout << "I'm in the callback-function!!!\n"; // NEVER PRINTS!
EdsError err = EDS_ERR_OK;
if (event == kEdsObjectEvent_DirItemRequestTransfer)
{
EdsStreamRef stream = NULL;
EdsDirectoryItemInfo dirItemInfo;
err = EdsGetDirectoryItemInfo(object, &dirItemInfo);
err = EdsCreateFileStream(dirItemInfo.szFileName, kEdsFileCreateDisposition_CreateAlways, kEdsAccess_ReadWrite, &stream);
err = EdsDownload(object, dirItemInfo.size, stream);
err = EdsDownloadComplete(object);
EdsRelease(stream);
stream = NULL;
}
if (object)
EdsRelease(object);
return err;
}
void TakePhoto(EdsCameraRef camera)
{
EdsError err = EDS_ERR_OK;
EdsCameraListRef cameraList = NULL;
EdsUInt32 count = 0;
err = EdsInitializeSDK();
err = EdsGetCameraList(&cameraList);
err = EdsGetChildCount(cameraList, &count);
if (count > 0)
{
err = EdsGetChildAtIndex(cameraList, 0, &camera);
cameraList = NULL;
err = EdsSetObjectEventHandler(camera, kEdsObjectEvent_All, handleObjectEvent, NULL);
err = EdsOpenSession(camera);
err = EdsSendCommand(camera, kEdsCameraCommand_TakePicture, 0);
}
}
void Close(EdsCameraRef camera)
{
EdsError err = EdsCloseSession(camera);
EdsRelease(camera);
EdsTerminateSDK();
}
int main() {
EdsCameraRef camera = NULL;
TakePhoto(camera);
Close(camera);
return 0;
}
但是,如前所述:这些图像在我的主机 PC 上无处可寻。如果我提供 EdsCreateFileStream
的完整路径,这不会改变。将图像保存在二进制文件所在目录中的默认行为(使用 dirItemInfo.szFileName
作为 EdsCreateFileStream
的第一个参数也不起作用。
可能是因为我尝试的最新解决方案是从 2014 年开始的,同时 API 发生了变化。我也在 GitHub 上寻找实现并查看了官方手册,但两者对我来说都非常不透明。
真正让我困惑的是,当我尝试 printf 风格的调试(在 handleObjectEvent
中添加输出时,打印从未出现!这是因为函数的回调性质吗? 我必须承认,我以前没有使用过回调。
下面提供的所有版本都构建并执行。我也可以在这里点击相机,但如前所述:我在磁盘上找不到图像!
是否执行了回调?为什么印刷品永远不会显示?我怎样才能最终修改程序以将图像保存到磁盘?
我能想到它不起作用的两个原因:
这是一个控制台应用程序,因此它没有消息泵。这意味着事件不会“自动”触发。您必须反复调用 EdsGetEvent
,直到收到所需的事件。在您的情况下,理想的点是在发送 TakePicture 命令之后。
发送 TakePicture 命令后,您会立即关闭所有内容,因此没有时间触发事件。 TakePicture 命令 returns 几乎立即执行,不会等到整个 photo-taking 过程完成(不过它会等到对焦完成)。幸运的是,我上面描述的 EdsGetEvent
循环也解决了这个问题。
所以基本上:
err = EdsSendCommand(camera, kEdsCameraCommand_TakePicture, 0);
// eventHasFired is a boolean variable you can
// set to true after you have downloaded the image.
// or use a more sophisticated synchronization approach if necessary
while (!eventHasFired)
{
EdsGetEvent();
// you could add a little pause here to reduce CPU usage
}
if (err == EDS_ERR_OK)
{
err = EdsCloseSession(camera);
}
编辑
在讨论了评论中的一些可能性并查看了 EDSDK 中的 error-codes 后,我们发现相机在第一次发送 TakePicture
时无法自动对焦。在 while-loop 中重复发送命令提供了一个解决方法:
while (err != EDS_ERR_OK)
err = EdsSendCommand(camera, kEdsCameraCommand_TakePicture, 0);
我正在使用 Canons EDSDK 实现远程相机控制应用程序。我的相机是佳能 PowerShot SX 70 HS。到目前为止,一切似乎都正常,除了将拍摄的照片保存到主机 PC 的功能。
我对所需工作流程的理解如下:
- 初始化相机
- 重写对象事件处理程序并传递给
EdsObjectEventHandler
以修改“保存图像行为” - 拍照
- 关闭流并销毁所有对象。
我已经调整了自己的初始版本并尝试了这些线程中提供的解决方案:
canon EDSDK saving image in my PC
Canon SDK - Downloading image to host PC
下面是代码...
...第一个线程:
#include <iostream>
#include "EDSDK.h"
#include "EDSDKTypes.h"
#include "EDSDKErrors.h"
EdsError getFirstCamera(EdsCameraRef* camera);
EdsError downloadImage(EdsDirectoryItemRef directoryItem);
EdsError EDSCALLBACK handleStateEvent(EdsStateEvent event, EdsUInt32 parameter, EdsVoid* context);
EdsError EDSCALLBACK handleObjectEvent(EdsObjectEvent event, EdsBaseRef object, EdsVoid* context);
EdsError EDSCALLBACK handlePropertyEvent(EdsPropertyEvent event, EdsPropertyID property, EdsUInt32 inParam, EdsVoid* context);
int main(int argc, char** argv)
{
EdsError err;
EdsCameraRef camera = NULL;
bool isSDKLoaded = false;
EdsCapacity capacity = { 0x7FFFFFFF, 0x1000, 1 };
EdsInt32 saveTarget = kEdsSaveTo_Host;
// Initialize SDK
err = EdsInitializeSDK();
if (err == EDS_ERR_OK)
{
isSDKLoaded = true;
}
// Get first camera
if (err == EDS_ERR_OK)
{
err = getFirstCamera(&camera);
}
// Open session with camera
err = EdsOpenSession(camera);
// Set event handler
if (err == EDS_ERR_OK)
err = EdsSetObjectEventHandler(camera, kEdsObjectEvent_All, handleObjectEvent, NULL);
if (err == EDS_ERR_OK)
err = EdsSetPropertyEventHandler(camera, kEdsPropertyEvent_All, handlePropertyEvent, NULL);
if (err == EDS_ERR_OK)
err = EdsSetCameraStateEventHandler(camera, kEdsStateEvent_All, handleStateEvent, NULL);
err = EdsSetPropertyData(camera, kEdsPropID_SaveTo, 0, 4, &saveTarget);
err = EdsSetCapacity(camera, capacity);
///// Take picture
err = EdsSendCommand(camera, kEdsCameraCommand_TakePicture, 0);
////
// Close session with camera
if (err == EDS_ERR_OK)
{
err = EdsCloseSession(camera);
}
// Release camera
if (camera != NULL)
{
EdsRelease(camera);
}
// Terminate SDK
if (isSDKLoaded)
{
EdsTerminateSDK();
}
}
EdsError EDSCALLBACK handleObjectEvent(EdsObjectEvent event, EdsBaseRef object, EdsVoid* context)
{
std::cout << "I'm in the callback-function!!!\n"; // Never shows!
EdsError err = EDS_ERR_OK;
switch (event)
{
case kEdsObjectEvent_DirItemRequestTransfer:
err = downloadImage(object);
break;
default:
break;
}
// Object must be released
if (object) {
err = EdsRelease(object);
}
return err;
}
EdsError EDSCALLBACK handlePropertyEvent(EdsPropertyEvent event, EdsPropertyID property, EdsUInt32 inParam, EdsVoid* context)
{
return EDS_ERR_OK;
}
EdsError EDSCALLBACK handleStateEvent(EdsStateEvent event, EdsUInt32 parameter, EdsVoid* context)
{
return EDS_ERR_OK;
}
EdsError getFirstCamera(EdsCameraRef* camera)
{
EdsError err;
EdsCameraListRef cameraList = NULL;
err = EdsGetCameraList(&cameraList);
err = EdsGetChildAtIndex(cameraList, 0, camera);
return err;
}
EdsError downloadImage(EdsDirectoryItemRef directoryItem)
{
EdsError err = EDS_ERR_OK;
EdsStreamRef stream = NULL;
// Get directory item information
EdsDirectoryItemInfo dirItemInfo;
err = EdsGetDirectoryItemInfo(directoryItem, &dirItemInfo);
// Create file stream for transfer destination
if (err == EDS_ERR_OK)
{
err = EdsCreateFileStream(dirItemInfo.szFileName, kEdsFileCreateDisposition_CreateAlways, kEdsAccess_ReadWrite, &stream);
}
// Download image
if (err == EDS_ERR_OK)
{
err = EdsDownload(directoryItem, dirItemInfo.size, stream);
}
// Issue notification that download is complete
if (err == EDS_ERR_OK)
{
err = EdsDownloadComplete(directoryItem);
}
// Release stream
if (stream != NULL)
{
EdsRelease(stream);
stream = NULL;
}
return err;
}
第二个线程:
#include <iostream>
#include "EDSDK.h"
#include "EDSDKTypes.h"
#include "EDSDKErrors.h"
static EdsError EDSCALLBACK handleObjectEvent(EdsObjectEvent event, EdsBaseRef object, EdsVoid* context)
{
std::cout << "I'm in the callback-function!!!\n"; // NEVER PRINTS!
EdsError err = EDS_ERR_OK;
if (event == kEdsObjectEvent_DirItemRequestTransfer)
{
EdsStreamRef stream = NULL;
EdsDirectoryItemInfo dirItemInfo;
err = EdsGetDirectoryItemInfo(object, &dirItemInfo);
err = EdsCreateFileStream(dirItemInfo.szFileName, kEdsFileCreateDisposition_CreateAlways, kEdsAccess_ReadWrite, &stream);
err = EdsDownload(object, dirItemInfo.size, stream);
err = EdsDownloadComplete(object);
EdsRelease(stream);
stream = NULL;
}
if (object)
EdsRelease(object);
return err;
}
void TakePhoto(EdsCameraRef camera)
{
EdsError err = EDS_ERR_OK;
EdsCameraListRef cameraList = NULL;
EdsUInt32 count = 0;
err = EdsInitializeSDK();
err = EdsGetCameraList(&cameraList);
err = EdsGetChildCount(cameraList, &count);
if (count > 0)
{
err = EdsGetChildAtIndex(cameraList, 0, &camera);
cameraList = NULL;
err = EdsSetObjectEventHandler(camera, kEdsObjectEvent_All, handleObjectEvent, NULL);
err = EdsOpenSession(camera);
err = EdsSendCommand(camera, kEdsCameraCommand_TakePicture, 0);
}
}
void Close(EdsCameraRef camera)
{
EdsError err = EdsCloseSession(camera);
EdsRelease(camera);
EdsTerminateSDK();
}
int main() {
EdsCameraRef camera = NULL;
TakePhoto(camera);
Close(camera);
return 0;
}
但是,如前所述:这些图像在我的主机 PC 上无处可寻。如果我提供 EdsCreateFileStream
的完整路径,这不会改变。将图像保存在二进制文件所在目录中的默认行为(使用 dirItemInfo.szFileName
作为 EdsCreateFileStream
的第一个参数也不起作用。
可能是因为我尝试的最新解决方案是从 2014 年开始的,同时 API 发生了变化。我也在 GitHub 上寻找实现并查看了官方手册,但两者对我来说都非常不透明。
真正让我困惑的是,当我尝试 printf 风格的调试(在 handleObjectEvent
中添加输出时,打印从未出现!这是因为函数的回调性质吗? 我必须承认,我以前没有使用过回调。
下面提供的所有版本都构建并执行。我也可以在这里点击相机,但如前所述:我在磁盘上找不到图像!
是否执行了回调?为什么印刷品永远不会显示?我怎样才能最终修改程序以将图像保存到磁盘?
我能想到它不起作用的两个原因:
这是一个控制台应用程序,因此它没有消息泵。这意味着事件不会“自动”触发。您必须反复调用
EdsGetEvent
,直到收到所需的事件。在您的情况下,理想的点是在发送 TakePicture 命令之后。发送 TakePicture 命令后,您会立即关闭所有内容,因此没有时间触发事件。 TakePicture 命令 returns 几乎立即执行,不会等到整个 photo-taking 过程完成(不过它会等到对焦完成)。幸运的是,我上面描述的
EdsGetEvent
循环也解决了这个问题。
所以基本上:
err = EdsSendCommand(camera, kEdsCameraCommand_TakePicture, 0);
// eventHasFired is a boolean variable you can
// set to true after you have downloaded the image.
// or use a more sophisticated synchronization approach if necessary
while (!eventHasFired)
{
EdsGetEvent();
// you could add a little pause here to reduce CPU usage
}
if (err == EDS_ERR_OK)
{
err = EdsCloseSession(camera);
}
编辑
在讨论了评论中的一些可能性并查看了 EDSDK 中的 error-codes 后,我们发现相机在第一次发送 TakePicture
时无法自动对焦。在 while-loop 中重复发送命令提供了一个解决方法:
while (err != EDS_ERR_OK)
err = EdsSendCommand(camera, kEdsCameraCommand_TakePicture, 0);