c++macosqtedsdk

Canon EDSDK handler isn't called on mac


I'm programming tethering for the canon camera in Qt under Mac OSX and for some reason my handlers for sdk are not called. When I want to shoot with camera it's all goes well but my photo is not downloaded because EdsSetObjectEventHandler is not called.

BUT for some reason when I shoot with camera and after that I restart the application then one photo is downloaded. My opinion is I need to use their event loop, but I don't know how.

My application don't freeze only handler is not called. I can take many photos (but only to camera cache).

Here is my code.

Initialization method

void CameraControl::initEDS()
{
    Q_D(CameraControl);

    // Camera init
    EdsUInt32 count = 0;
    EdsDeviceInfo info;

    EdsError err = EdsInitializeSDK();

    if(err != EDS_ERR_OK)
        qFatal("Error: Could not initialize library!");

    EdsCameraListRef cameraList = NULL;

    if(EdsGetCameraList(&cameraList) != EDS_ERR_OK)
        qFatal("Error: Could not get camera list!");

    if(EdsGetChildCount(cameraList, &count) != EDS_ERR_OK)
        qFatal("Error: Could not get number of cameras!");

    if(EdsGetChildAtIndex(cameraList, 0, &(d->m_camera)) != EDS_ERR_OK)
         qFatal("Error: Could not get camera!");

    if(EdsGetDeviceInfo(d->m_camera, &info) != EDS_ERR_OK)
        qFatal("Error: Could not get camera info!");

    EdsRelease(cameraList);

    // Register handler - this are not called
    if(EdsSetObjectEventHandler(d->m_camera, kEdsObjectEvent_All, handleObjectEvent, (EdsVoid*)this) != EDS_ERR_OK)
    {
        qFatal("Error: can't setup object handler");
    }

    if(info.deviceSubType == 0)
        d->m_isLegacy = true;
    else
        d->m_isLegacy = false;

    // open session
    if(EdsOpenSession(d->m_camera) != EDS_ERR_OK)
        qFatal("Can't open session with camera");

    sleep(1);

    EdsUInt32 saveTo = kEdsSaveTo_Host;
    if(EdsSetPropertyData(d->m_camera, kEdsPropID_SaveTo, 0, sizeof(saveTo), &saveTo) != EDS_ERR_OK)
        qFatal("Error: can't get property for saveTo");

    if(!d->m_isLegacy)
    {
        EdsCapacity capacity = {0x7FFFFFFF, 0x1000, 1};

        if(EdsSetCapacity(d->m_camera, capacity) != EDS_ERR_OK)
        qFatal("Error: can't set capacity");
    }

    // get property camera name
    EdsUInt32 dataSize = 0;
    EdsDataType dataType = kEdsDataType_Unknown;
    EdsChar dataString[EDS_MAX_NAME];

    if(EdsGetPropertySize(d->m_camera, kEdsPropID_ProductName, 0, &dataType, &dataSize) != EDS_ERR_OK)
        qFatal("Can't get property size");

    if(dataType == kEdsDataType_String)
    {
        qDebug() << "property is string";

        if(EdsGetPropertyData(d->m_camera, kEdsPropID_ProductName, 0, dataSize, &dataString) != EDS_ERR_OK)
            qFatal("Can't get product name of camera");
    }

}

Capture method

void CameraControl::capture()
{
    Q_D(CameraControl);

    EdsError err;
    if((err = EdsSendCommand(d->m_camera, kEdsCameraCommand_TakePicture, 0)) != EDS_ERR_OK)
    {
        QString str = QString("Error: can't shoot with camera - code: %1").arg(QString::number(err, 16));

        qDebug() << str;
    }
    else
        qDebug() << "picture taken";
}

Handler method

EdsError EDSCALLBACK handleObjectEvent(EdsUInt32 inEvent, EdsBaseRef inRef, EdsVoid* inContext)
{
    EdsError err = EDS_ERR_OK;
    CameraControl* control = static_cast<CameraControl*>(inContext);

    qDebug() << "object handler called"; // never called

    switch(inEvent)
    {
    case kEdsObjectEvent_DirItemRequestTransfer:
        download(inRef, control); // download photo
    default:
        EdsRelease(inRef);
    }

    return EDS_ERR_OK;
}

Anyone know why this happening? Thank you for your help.


Solution

  • EDIT - RESOLVED

    I found solution for this. When you use EDSDK then you need platform specific event loop runing, but the problem is you need it inside of the main thread, because all usb events go there. So problem araised - you need platform specific event loop but on the same thread you need (in my situation) Qt event loop.

    solution

    You need to run mac event loop time to time to process new events. So I created processEvents() method and this method have CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, false) which process all events in queue.

    Constructor of my object have new timer

    Q_D(CameraControl);
    d->m_timer.setInterval(500);
    d->m_timer.setSingleShot(false);
    connect(&d->m_timer, &QTimer::timeout, this, &CameraControl::processEvents);
    d->m_timer.start();
    

    Timer calling this slot method

    void CameraControl::processEvents()
    {
        CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, false);
    }
    

    I hope this will help someone with the same problem.