sample code - “Pull out content in ContentsTransferMode”

This sample code is included in SimpleCli.

  1// "pull contents in ContentsTransferMode" sample
  2#include <chrono>
  3#include <cstdint>
  4#include <cstdlib>
  5#include <fstream>
  6#include <future>
  7#include <iostream>
  8#include <mutex>
  9#include <sstream>
 10#include <stdexcept>
 11#include <string>
 12#include <thread>
 13#include <vector>
 14
 15#if !defined(__APPLE__)
 16  #if defined(USE_EXPERIMENTAL_FS) // for jetson
 17    #include <experimental/filesystem>
 18    namespace fs = std::experimental::filesystem;
 19  #else
 20    #include <filesystem>
 21    namespace fs = std::filesystem;
 22  #endif
 23#endif
 24
 25#if defined(__APPLE__) || defined(__linux__)
 26  #include <unistd.h>
 27#endif
 28
 29// macro for multibyte character
 30#if defined(_WIN32) || defined(_WIN64)
 31  using CrString = std::wstring;
 32  #define CRSTR(s) L ## s
 33  #define CrCout std::wcout
 34  #define CrPrintf std::wprintf
 35  #define DELIMITER CRSTR("\\")
 36#else
 37  using CrString = std::string;
 38  #define CRSTR(s) s
 39  #define CrCout std::cout
 40  #define CrPrintf std::printf
 41  #define DELIMITER CRSTR("/")
 42#endif
 43
 44
 45#include "CrDeviceProperty.h"
 46#include "CameraRemote_SDK.h"
 47#include "IDeviceCallback.h"
 48#include "CrDebugString.h"   // use CrDebugString.cpp
 49
 50#define PrintError(msg, err) { fprintf(stderr, "Error in %s(%d):" msg ",%s\n", __FUNCTION__, __LINE__, (err ? CrErrorString(err).c_str():"")); }
 51#define GotoError(msg, err) { PrintError(msg, err); goto Error; }
 52
 53bool  m_connected = false;
 54CrString m_modelId;
 55int64_t  m_device_handle = 0;
 56
 57std::mutex m_eventPromiseMutex;
 58uint32_t m_setDPCode = 0;
 59std::promise<void>* m_eventPromise = nullptr;
 60void setEventPromise(std::promise<void>* dp)
 61{
 62    std::lock_guard<std::mutex> lock(m_eventPromiseMutex);
 63    m_eventPromise = dp;
 64}
 65
 66SCRSDK::CrError _getDeviceProperty(int64_t device_handle, uint32_t code, SCRSDK::CrDeviceProperty* devProp)
 67{
 68    std::int32_t nprop = 0;
 69    SCRSDK::CrDeviceProperty* prop_list = nullptr;
 70    SCRSDK::CrError err = SCRSDK::GetSelectDeviceProperties(device_handle, 1, &code, &prop_list, &nprop);
 71    if(err) GotoError("", err);
 72    if(prop_list && nprop >= 1) {
 73        *devProp = prop_list[0];
 74    }
 75Error:
 76    if(prop_list) SCRSDK::ReleaseDeviceProperties(device_handle, prop_list);
 77    return err;
 78}
 79
 80class DeviceCallback : public SCRSDK::IDeviceCallback
 81{
 82public:
 83    DeviceCallback() {};
 84    ~DeviceCallback() {};
 85
 86    void OnConnected(SCRSDK::DeviceConnectionVersioin version)
 87    {
 88        CrCout << "Connected to " << m_modelId << "\n";
 89        m_connected = true;
 90        std::lock_guard<std::mutex> lock(m_eventPromiseMutex);
 91        if(m_eventPromise) {
 92            m_eventPromise->set_value();
 93            m_eventPromise = nullptr;
 94        }
 95    }
 96
 97    void OnError(CrInt32u error)
 98    {
 99        printf("Connection error:%s\n", CrErrorString(error).c_str());
100        std::lock_guard<std::mutex> lock(m_eventPromiseMutex);
101        if(m_eventPromise) {
102            m_eventPromise->set_exception(std::make_exception_ptr(std::runtime_error("error")));
103            m_eventPromise = nullptr;
104        }
105    }
106
107    void OnDisconnected(CrInt32u error)
108    {
109        CrCout << "Disconnected from " << m_modelId << "\n";
110        m_connected = false;
111        std::lock_guard<std::mutex> lock(m_eventPromiseMutex);
112        if(m_eventPromise) {
113            m_eventPromise->set_value();
114            m_eventPromise = nullptr;
115        }
116    }
117
118    void OnCompleteDownload(CrChar* filename, CrInt32u type )
119    {
120        CrCout << "OnCompleteDownload:" << filename << "\n";
121    }
122
123    void OnNotifyContentsTransfer(CrInt32u notify, SCRSDK::CrContentHandle contentHandle, CrChar* filename)
124    {
125        std::cout << "OnNotifyContentsTransfer(" << CrErrorString(notify) << "):";
126        std::lock_guard<std::mutex> lock(m_eventPromiseMutex);
127        switch(notify) {
128        case SCRSDK::CrNotify_ContentsTransfer_Start:
129            break;
130        case SCRSDK::CrNotify_ContentsTransfer_Complete:
131            CrCout << filename;
132            if(m_eventPromise) {
133                m_eventPromise->set_value();
134                m_eventPromise = nullptr;
135            }
136            break;
137        default:
138            if(m_eventPromise) {
139                m_eventPromise->set_exception(std::make_exception_ptr(std::runtime_error("error")));
140                m_eventPromise = nullptr;
141            }
142            break;
143        }
144        std::cout << "\n";
145    }
146
147    void OnWarning(CrInt32u warning)
148    {
149        if (warning == SCRSDK::CrWarning_Connect_Reconnecting) {
150            CrCout << "Reconnecting to " << m_modelId << "\n";
151            return;
152        }
153        std::cout << "OnWarning:" << CrErrorString(warning) << "\n";
154        switch(warning) {
155        case SCRSDK::CrWarning_ContentsTransferMode_DeviceBusy:
156        case SCRSDK::CrWarning_ContentsTransferMode_StatusError:
157        case SCRSDK::CrWarning_ContentsTransferMode_CanceledFromCamera:
158            if(m_eventPromise) {
159                m_eventPromise->set_exception(std::make_exception_ptr(std::runtime_error("error")));
160                m_eventPromise = nullptr;
161            }
162            break;
163        }
164    }
165
166    void OnWarningExt(CrInt32u warning, CrInt32 param1, CrInt32 param2, CrInt32 param3) {}
167    void OnLvPropertyChanged() {}
168    void OnLvPropertyChangedCodes(CrInt32u num, CrInt32u* codes) {}
169    void OnPropertyChanged() {}
170    void OnPropertyChangedCodes(CrInt32u num, CrInt32u* codes)
171    {
172        for(uint32_t i = 0; i < num; ++i) {
173            std::lock_guard<std::mutex> lock(m_eventPromiseMutex);
174            if(m_setDPCode && m_setDPCode == codes[i]) {
175                std::string name = CrDevicePropertyString((SCRSDK::CrDevicePropertyCode)codes[i]);
176                SCRSDK::CrDeviceProperty devProp;
177                SCRSDK::CrError err = _getDeviceProperty(m_device_handle, codes[i], &devProp);
178                if(err) break;
179                int64_t current = devProp.GetCurrentValue();
180                printf("OnPropertyChangedCodes:%s=%d\n", name.c_str(), (int)current);
181                m_setDPCode = 0;
182                if(m_eventPromise) {
183                    m_eventPromise->set_value();
184                    m_eventPromise = nullptr;
185                }
186            }
187        }
188    }
189};
190
191CrString _getModelId(const SCRSDK::ICrCameraObjectInfo* objInfo)
192{
193    CrString id;
194    if (CrString(objInfo->GetConnectionTypeName()) == CRSTR("IP")) {
195        id = CrString(objInfo->GetMACAddressChar());
196    } else {
197        id = CrString((CrChar*)objInfo->GetId());
198    }
199    return CrString(objInfo->GetModel()).append(CRSTR(" (")).append(id).append(CRSTR(")"));
200}
201
202SCRSDK::CrError _getIdPassword(SCRSDK::ICrCameraObjectInfo* objInfo, std::string& fingerprint, std::string& userId, std::string& userPassword)
203{
204    char fpBuff[128] = {0};
205    CrInt32u fpLen = 0;
206    SCRSDK::CrError err = SCRSDK::GetFingerprint(objInfo, fpBuff, &fpLen);
207    if(err) GotoError("", err);
208    fingerprint = std::string(fpBuff, fpLen);
209
210    std::cout << "fingerprint: " << fingerprint.c_str() << "\n";
211    std::cout << "id:";       std::getline(std::cin, userId);
212    std::cout << "password:"; std::getline(std::cin, userPassword);
213    return 0;
214Error:
215    return err;
216}
217
218SCRSDK::CrError _getThumbnail(int64_t m_device_handle, SCRSDK::CrContentHandle content, CrString path)
219{
220    int result = SCRSDK::CrError_Generic_Unknown;
221    SCRSDK::CrError err = 0;
222    #define  BUF_SIZE 0x28000 // @@@@ temp
223    SCRSDK::CrImageDataBlock image_data;
224    CrInt8u image_buff[BUF_SIZE];
225    SCRSDK::CrFileType fileType = SCRSDK::CrFileType_None;
226
227    image_data.SetSize(BUF_SIZE);
228    image_data.SetData(image_buff);
229
230    err = SCRSDK::GetContentsThumbnailImage(m_device_handle, content, &image_data, &fileType);
231    if(err) GotoError("", err);
232
233    if (image_data.GetSize() <= 0 || fileType == SCRSDK::CrFileType_None)
234        GotoError("", 0);
235
236    {
237        CrString filename = DELIMITER CRSTR("Thumbnail.JPG");
238        if (fileType == SCRSDK::CrFileType_Heif) {
239            filename= DELIMITER CRSTR("Thumbnail.HIF");
240        }
241        filename = path.append(filename);
242        std::ofstream file(filename, std::ios::out | std::ios::binary);
243        if (file.bad()) GotoError("", 0);
244
245        file.write((char*)image_data.GetImageData(), image_data.GetImageSize());
246        file.close();
247        CrCout << "complete:" << filename.data() << "\n";
248    }
249    result = 0;
250Error:
251    return result;
252}
253
254int main(void)
255{
256    int result = -1;
257    SCRSDK::CrError err = SCRSDK::CrError_None;
258    SCRSDK::ICrEnumCameraObjectInfo* enumCameraObjectInfo = nullptr;
259    SCRSDK::ICrCameraObjectInfo* objInfo = nullptr;
260    DeviceCallback deviceCallback;
261
262    SCRSDK::CrMtpFolderInfo* folderList = nullptr;
263    SCRSDK::CrContentHandle* contentsHandleList = nullptr;
264    std::string inputLine;
265
266  #if defined(__APPLE__)
267    #define MAC_MAX_PATH 255
268    char pathBuf[MAC_MAX_PATH] = {0};
269    if(NULL == getcwd(pathBuf, sizeof(pathBuf) - 1)) return 1;
270    CrString path = pathBuf;
271  #else
272    CrString path = fs::current_path().native();
273  #endif
274
275    bool boolRet = SCRSDK::Init();
276    if(!boolRet) GotoError("", 0);
277
278    // enumeration
279    {
280        uint32_t count = 0;
281        uint32_t index = 1;
282
283        err = SCRSDK::EnumCameraObjects(&enumCameraObjectInfo, 3/*timeInSec*/);
284        if(err || !enumCameraObjectInfo) GotoError("no camera", err);
285
286        count = enumCameraObjectInfo->GetCount();
287        if(count >= 2) {
288            for (uint32_t i = 0; i < count; ++i) {
289                auto* info = enumCameraObjectInfo->GetCameraObjectInfo(i);
290                CrCout << '[' << i + 1 << "] " << _getModelId(info) << "\n";
291            }
292
293            std::cout << "select camera:"; std::getline(std::cin, inputLine);
294            try { index = stoi(inputLine); } catch(const std::exception&) { GotoError("", 0); }
295            if(index < 1 || index > count) GotoError("", 0);
296        }
297        objInfo = (SCRSDK::ICrCameraObjectInfo*)enumCameraObjectInfo->GetCameraObjectInfo(index - 1);
298        m_modelId = _getModelId(objInfo);
299    }
300
301    // connect
302    {
303        std::string  fingerprint = "";
304        std::string  userId = "";
305        std::string  userPassword = "";
306        std::promise<void> eventPromise;
307        std::future<void> eventFuture = eventPromise.get_future();
308
309        if (objInfo->GetSSHsupport() == SCRSDK::CrSSHsupport_ON) {
310            err = _getIdPassword(objInfo, fingerprint, userId, userPassword); if(err) goto Error;
311        }
312
313        setEventPromise(&eventPromise);
314        err = SCRSDK::Connect(objInfo, &deviceCallback, &m_device_handle,
315            SCRSDK::CrSdkControlMode_ContentsTransfer,
316            SCRSDK::CrReconnecting_ON,
317            userId.c_str(), userPassword.c_str(), fingerprint.c_str(), (uint32_t)fingerprint.size());
318        if(err) GotoError("", err);
319
320    //  std::future_status status = eventFuture.wait_for(std::chrono::milliseconds(3000));
321    //  if(status != std::future_status::ready) GotoError("timeout",0);
322        try{
323            eventFuture.get();
324        } catch(const std::exception&) GotoError("", 0);
325    }
326
327    // wait contentsTransfer=ON
328    {
329        SCRSDK::CrDeviceProperty devProp;
330        std::promise<void> eventPromise;
331        std::future<void> eventFuture = eventPromise.get_future();
332        {
333            std::lock_guard<std::mutex> lock(m_eventPromiseMutex);
334            m_setDPCode = SCRSDK::CrDeviceProperty_ContentsTransferStatus;
335            m_eventPromise = &eventPromise;
336        }
337
338        try{
339            eventFuture.get();
340        } catch(const std::exception&) GotoError("", 0);
341
342        err = _getDeviceProperty(m_device_handle, SCRSDK::CrDeviceProperty_ContentsTransferStatus, &devProp);
343        if(err) GotoError("", err);
344        if(devProp.GetCurrentValue() != SCRSDK::CrContentsTransfer_ON) GotoError("", 0);
345    }
346
347    // set work directory
348    {
349        CrCout << "path=" << path.data() << "\n";
350        err = SCRSDK::SetSaveInfo(m_device_handle, const_cast<CrChar*>(path.data()), const_cast<CrChar*>(CRSTR("DSC")), -1/*startNo*/);
351        if(err) GotoError("", err);
352    }
353
354    #if defined(__linux__)
355    {
356        // The default value for Linux is 16MB.
357        // The number of divisions is inversely proportional to the "Setting_Key_PartialBuffer" size, and the larger the "Setting_Key_PartialBuffer" size, the fewer accesses between the camera and SDK, improving the processing performance of the SDK and Body.
358        // The number of times the "CrCommandId_CancelContentsTransfer/CrControlCode_CancelContentsTransfer" can be accepted also changes in sync with the number of accesses, so users who want to perform "CrCommandId_CancelContentsTransfer/CrControlCode_CancelContentsTransfer" should not make the "Setting_Key_PartialBuffer" size too large.
359        // 
360        // e.g. 150MB RAW image
361        //        "Setting_Key_PartialBuffer" size 16MB -> 10 divisions
362        //        "Setting_Key_PartialBuffer" size 64MB ->  3 divisions
363        // 
364        // Caution : Do not set a value larger than the USB bulk transfer size.
365
366        CrInt32u bufferSize = 0;
367        err = SCRSDK::GetDeviceSetting(m_device_handle, SCRSDK::Setting_Key_PartialBuffer, &bufferSize);
368        if(err) GotoError("", err);
369        printf("PartialBuffer %d[MB]->", bufferSize); std::getline(std::cin, inputLine);
370        if(inputLine != "") {
371            try { bufferSize = stoi(inputLine); } catch(const std::exception&) { GotoError("", 0); }
372            err = SCRSDK::SetDeviceSetting(m_device_handle, SCRSDK::Setting_Key_PartialBuffer, bufferSize);
373            if(err) GotoError("", err);
374        }
375    }
376    #else
377        // The default value for non-Linux is 2047MB (approximately 2GB).
378        // For content less than 2047MB, "CrCommandId_CancelContentsTransfer/CrControlCode_CancelContentsTransfer" will not be executed (it will be ignored) as it will be obtained in one process.
379        // If you want to be able to cancel the transfer process midway, make the "Setting_Key_PartialBuffer" size smaller than the content size.
380    #endif
381
382    while(1) {
383        int index = 0;
384        SCRSDK::CrFolderHandle folderHandle;
385        SCRSDK::CrContentHandle contentHandle;
386        // select folder
387        {
388            CrInt32u f_nums = 0;
389            err = SCRSDK::GetDateFolderList(m_device_handle, &folderList, &f_nums);
390            if(err) GotoError("", err);
391            if(!folderList || f_nums == 0) GotoError("", 0);
392
393            for (CrInt32u i = 0; i < f_nums; ++i) {
394                CrPrintf(CRSTR(" %d: %s\n"), i+1, folderList[i].folderName);
395            }
396            std::cout << "folder:"; std::getline(std::cin, inputLine);
397            try { index = stoi(inputLine); } catch(const std::exception&) { GotoError("", 0); }
398            if (index < 1 || index > (int)f_nums) GotoError("", 0);
399
400            folderHandle = folderList[index-1].handle;
401            SCRSDK::ReleaseDateFolderList(m_device_handle, folderList);
402            folderList = nullptr;
403        }
404        // select content
405        {
406            SCRSDK::CrMtpContentsInfo contentsDetailInfo;
407            CrInt32u c_nums = 0;
408            err = SCRSDK::GetContentsHandleList(m_device_handle, folderHandle, &contentsHandleList, &c_nums);
409            if(err) GotoError("", err);
410            if(!contentsHandleList || c_nums == 0) GotoError("", 0);
411
412            for (CrInt32u i = 0; i < c_nums; i++) {
413                err = SCRSDK::GetContentsDetailInfo(m_device_handle, contentsHandleList[i], &contentsDetailInfo);
414                if(err) GotoError("", err);
415                CrPrintf(CRSTR(" %d: %s\n"), i+1, contentsDetailInfo.fileName);
416            }
417            std::cout << "content:"; std::getline(std::cin, inputLine);
418            try { index = stoi(inputLine); } catch(const std::exception&) { GotoError("", 0); }
419            if (index < 1 || index > (int)c_nums) GotoError("", 0);
420
421            err = SCRSDK::GetContentsDetailInfo(m_device_handle, contentsHandleList[index-1], &contentsDetailInfo);
422            if(err) GotoError("", err);
423            contentHandle = contentsDetailInfo.handle;
424            SCRSDK::ReleaseContentsHandleList(m_device_handle, contentsHandleList);
425            contentsHandleList = nullptr;
426        }
427        // select type & pull content
428        {
429            std::cout << " 1:Original\n"" 2:2M\n"" 3:Thmbnail\n""type:"; std::getline(std::cin, inputLine);
430            try { index = stoi(inputLine); } catch(const std::exception&) { GotoError("", 0); }
431            if (index < 1 || index > 3) GotoError("", 0);
432
433            if(index == 3) {
434                err = _getThumbnail(m_device_handle, contentHandle, path);
435                if(err) goto Error;
436            } else {
437                std::promise<void> eventPromise;
438                std::future<void> eventFuture = eventPromise.get_future();
439                setEventPromise(&eventPromise);
440                if(index == 1) {
441                    err = SCRSDK::PullContentsFile(m_device_handle, contentHandle, SCRSDK::CrPropertyStillImageTransSize_Original);
442                } else {
443                    // only for .JPG, .ARW, .HIF
444                    err = SCRSDK::PullContentsFile(m_device_handle, contentHandle, SCRSDK::CrPropertyStillImageTransSize_SmallSize);
445                }
446                if(err) GotoError("", err);
447                try{
448                    eventFuture.get();
449                } catch(const std::exception&) GotoError("", 0);
450
451                std::this_thread::sleep_for(std::chrono::milliseconds(100));  // workaround for GetDateFolderList error
452            }
453        }
454    }
455
456    result = 0;
457Error:
458    if(enumCameraObjectInfo) enumCameraObjectInfo->Release();
459
460    if(m_connected) {
461        std::promise<void> eventPromise;
462        std::future<void> eventFuture = eventPromise.get_future();
463        setEventPromise(&eventPromise);
464        SCRSDK::Disconnect(m_device_handle);
465        eventFuture.wait_for(std::chrono::milliseconds(3000));
466    }
467    if(m_device_handle) {
468        if(folderList) SCRSDK::ReleaseDateFolderList(m_device_handle, folderList);
469        if(contentsHandleList) SCRSDK::ReleaseContentsHandleList(m_device_handle, contentsHandleList);
470        SCRSDK::ReleaseDevice(m_device_handle);
471    }
472    SCRSDK::Release();
473
474    return result;
475}