簡體   English   中英

佳能 EDSDK 13.11.10 未保存到主機 PC

[英]Canon EDSDK 13.11.10 not saving to host PC

我正在使用佳能 EDSDK 實現遠程相機控制應用程序。 我的相機是佳能 PowerShot SX 70 HS。 到目前為止,除了將拍攝的照片保存到主機 PC 的功能之外,一切似乎都在工作。

我對所需工作流程的理解如下:

  1. 初始化相機
  2. 重寫對象事件處理程序並傳遞給EdsObjectEventHandler以修改“保存圖像行為”
  3. 拍照
  4. 關閉流並銷毀所有對象。

我已經調整了自己的初始版本並嘗試了這些線程中提供的解決方案:

佳能 EDSDK 在我的電腦中保存圖像

佳能 SDK - 將圖像下載到主機 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添加輸出時,打印從未出現!這是因為函數的回調性質嗎?我必須承認,我沒有“以前使用過回調。

下面提供的所有版本構建和執行。 我也可以在這里點擊相機,但如前所述:我在磁盤上找不到圖像!

甚至執行回調嗎? 為什么打印永遠不會顯示呢? 我如何最終修改程序以將圖像保存到磁盤?

我可以想到它不起作用的兩個原因:

  1. 這是一個控制台應用程序,因此它沒有消息泵。 這意味着事件不會“自動”觸發。 您必須反復調用EdsGetEvent ,直到收到所需的事件。 在您的情況下,理想的點是在發送 TakePicture 命令之后。

  2. 發送 TakePicture 命令后,您立即關閉所有內容,以便沒有時間觸發事件。 TakePicture 命令幾乎立即返回,並且不會等到整個拍照過程完成(但它會等到對焦完成)。 幸運的是,這也可以通過我上面描述的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 的錯誤代碼后,我們TakePicture第一次發送TakePicture時相機無法自動對焦。 在 while 循環中重復發送命令提供了一種解決方法:

while (err != EDS_ERR_OK)
    err = EdsSendCommand(camera, kEdsCameraCommand_TakePicture, 0);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM