takephoto.c 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. #include "takephoto.h"
  2. // 模块名称
  3. static const char MODULE_NAME[] = "TakePhoto";
  4. // 保存照片
  5. static int SavePhoto(HANDLE hCam, MV_FRAME_OUT *pFrame, EImgType imgType, const char *imgFile);
  6. // 拍照回调
  7. typedef struct
  8. {
  9. HANDLE hCam;
  10. EImgType saveImgType;
  11. const char *saveImgFilename;
  12. HANDLE hESig; // 任务结束的通知
  13. int rCode; // 任务结束返回值
  14. } PthotoProcCtx;
  15. static int PhotoProc(unsigned long wParam, unsigned long lParam) // 线程回调函数,执行一次拍照任务
  16. {
  17. PthotoProcCtx *ctx = (PthotoProcCtx *)wParam; MV_FRAME_OUT frame = { 0 };
  18. // 1, 触发一次拍照
  19. int ret = MV_CC_SetCommandValue(ctx->hCam, "TriggerSoftware");
  20. // 2, 等待获取图像
  21. if(MV_OK == ret)
  22. {
  23. memset(&frame, 0, sizeof(MV_FRAME_OUT));
  24. ret = MV_CC_GetImageBuffer(ctx->hCam, &frame, 1000);
  25. }
  26. // 3, 导出图像文件
  27. if(MV_OK == ret)
  28. {
  29. sw_log_debug("[%s] +++GetOneFrame+++, Width[%d], Height[%d], FrameNum[%d], FrameLen[%d], PixelType[0x%08X]", MODULE_NAME, \
  30. frame.stFrameInfo.nWidth, frame.stFrameInfo.nHeight, frame.stFrameInfo.nFrameNum, frame.stFrameInfo.nFrameLen, \
  31. (unsigned int)frame.stFrameInfo.enPixelType);
  32. ret = SavePhoto(ctx->hCam, &frame, ctx->saveImgType, ctx->saveImgFilename);
  33. MV_CC_FreeImageBuffer(ctx->hCam, &frame);
  34. }
  35. // 4, 控制线程退出
  36. switch(ret)
  37. {
  38. case MV_E_NODATA: // 无数据时, 线程继续运行
  39. ret = 1; break;
  40. default: // 成功或发生其他错误,线程结束运行
  41. ctx->rCode = ret; sw_signal_give(ctx->hESig); ret = -1; break;
  42. }
  43. return ret;
  44. }
  45. // 单次执行相机拍照, 并保存到文件, 成功返回: 0值, 失败返回:非0值
  46. // "imgType" - 获取图像类型
  47. // "saveImgFilename" - 保存的文件名
  48. // "timeout" - 等待超时时间, 单位:秒: < 0 表示无超时;
  49. // 无论超时怎么设置, 首次尝试拍照一定会执行
  50. // , 但时间不确定; 拍照成功、超时或发生错误
  51. // 时会自动结束任务(相机持续无数据的时间).
  52. // "pImgMark" - 输出本次拍照图像的水印信息, 可以设置NULL
  53. int TakePhoto(EImgType imgType, const char *saveImgFilename, int timeout, SImgMark *pImgMark)
  54. {
  55. int fd; char runDir[MAX_PATH_CHARS] = { 0 }, lockFile[MAX_PATH_CHARS+32] = { 0 };
  56. int ret; SImgMark imgMark = { 0 }; HANDLE hCam = NULL; PthotoProcCtx ctx = { 0 };
  57. MV_CC_DEVICE_INFO_LIST devList = { 0 }; MV_CC_DEVICE_INFO *pDevInfo = NULL;
  58. // 1, 占用锁定, 避免同时间拍照
  59. xGetSelfRunningInfo(runDir, NULL);
  60. if(runDir[strlen(runDir)-1] == '/') sprintf(lockFile, "%s%s", runDir, "status/");
  61. else sprintf(lockFile, "%s/%s", runDir, "status/");
  62. if(!sw_dir_exists(lockFile)) sw_dir_create(lockFile);
  63. strcat(lockFile, "takephoto.lock");
  64. fd = open(lockFile, O_CREAT | O_RDWR | __O_CLOEXEC, 0666);
  65. if(-1 == fd) { return -1; }
  66. if(-1 == flock(fd, LOCK_EX | LOCK_NB)) { close(fd); return -2; }
  67. // 2, 查找相机, 获取其设备信息
  68. ret = MV_CC_Initialize();
  69. if(MV_OK != ret)
  70. {
  71. sw_log_error("[%s] 相机SDK初始化失败, errCode=0x%x!!", MODULE_NAME, ret);
  72. goto end_p;
  73. }
  74. ret = MV_CC_EnumDevices(MV_USB_DEVICE, &devList); // 目前只枚举USB连接的相机
  75. if(MV_OK != ret)
  76. {
  77. sw_log_error("[%s] USB口枚举相机失败, errCode=0x%x!!", MODULE_NAME, ret);
  78. goto end_p;
  79. }
  80. if(devList.nDeviceNum != 1)
  81. {
  82. ret = -3;
  83. sw_log_error("[%s] USB口相机数量错误, deviceNum=%u!!", MODULE_NAME, devList.nDeviceNum);
  84. goto end_p;
  85. }
  86. pDevInfo = devList.pDeviceInfo[0];
  87. if(!pDevInfo)
  88. {
  89. ret = -4;
  90. sw_log_error("[%s] unexpected internal error, unable to obtain detailed information about the industrial camera!!", MODULE_NAME);
  91. goto end_p;
  92. }
  93. strcpy(imgMark.camModelName, (const char *)pDevInfo->SpecialInfo.stUsb3VInfo.chModelName);
  94. strcpy(imgMark.camSerialNum, (const char *)pDevInfo->SpecialInfo.stUsb3VInfo.chSerialNumber);
  95. // 3, 打开相机, 设置其触发模式
  96. ret = MV_CC_CreateHandleWithoutLog(&hCam, pDevInfo);
  97. if(MV_OK == ret) ret = MV_CC_OpenDevice(hCam, MV_ACCESS_Exclusive, 0);
  98. if(MV_OK == ret) ret = MV_USB_SetTransferWays(hCam, 1); // 设置传输通道个数(RTU硬件资源有限, 需要降低通道数)
  99. if(MV_OK != ret)
  100. {
  101. sw_log_error("[%s] USB口相机打开失败, errCode=0x%x!!", MODULE_NAME, ret);
  102. goto end_p;
  103. }
  104. ret = MV_CC_SetEnumValue(hCam, "TriggerMode", 1); // 允许触发模式
  105. if(MV_OK == ret) ret = MV_CC_SetEnumValue(hCam, "TriggerSource", MV_TRIGGER_SOURCE_SOFTWARE); // 设置软件触发
  106. if(MV_OK != ret)
  107. {
  108. sw_log_error("[%s] USB口相机设置失败, errCode=0x%x!!", MODULE_NAME, ret);
  109. goto end_p;
  110. }
  111. // 4, 开始拍照, 等待完成后输出
  112. ret = MV_CC_StartGrabbing(hCam);
  113. if(MV_OK != ret)
  114. {
  115. sw_log_error("[%s] USB口相机取流失败, errCode=0x%x!!", MODULE_NAME, ret);
  116. goto end_p;
  117. }
  118. ctx.hCam = hCam;
  119. ctx.saveImgType = imgType;
  120. ctx.saveImgFilename = saveImgFilename;
  121. ctx.hESig = sw_signal_create();
  122. if(!ctx.hESig)
  123. {
  124. ret = -5;
  125. sw_log_error("[%s] SIG信号量创建失败!!", MODULE_NAME);
  126. goto end_p;
  127. }
  128. ctx.rCode = MV_OK;
  129. HANDLE hThrd = sw_thrd_create("PhotoProc", THREAD_DEFAULT_PRIORITY, THREAD_DEFAULT_STACK_SIZE, PhotoProc, (unsigned long)&ctx, 0);
  130. if(!hThrd)
  131. {
  132. ret = -6;
  133. sw_signal_destroy(ctx.hESig);
  134. sw_log_error("[%s] 拍照线程-创建失败!!", MODULE_NAME);
  135. goto end_p;
  136. }
  137. sw_thrd_resume(hThrd);
  138. ret = sw_signal_wait(ctx.hESig, timeout*1000); // 阻塞等待拍照任务结束或超时
  139. if(0 == ret) ret = ctx.rCode;
  140. else
  141. {
  142. ret = -7;
  143. sw_log_error("[%s] 拍照过程-等待超时!!", MODULE_NAME);
  144. }
  145. sw_thrd_destroy(hThrd, WAITTHRD_SAFEEXIT_TIMEOUT);
  146. sw_signal_destroy(ctx.hESig);
  147. // 5, 成功拍照, 输出相机的信息
  148. if(MV_OK == ret)
  149. {
  150. MVCC_FLOATVALUE fv = { 0 };
  151. MV_CC_GetFloatValue(hCam, "ExposureTime", &fv);
  152. imgMark.imgExposureTime = fv.fCurValue;
  153. if(pImgMark) memcpy(pImgMark, &imgMark, sizeof(SImgMark));
  154. }
  155. // 6, 任务结束, 释放相关的资源
  156. end_p:
  157. if(hCam)
  158. {
  159. MV_CC_StopGrabbing(hCam);
  160. MV_CC_CloseDevice(hCam);
  161. MV_CC_DestroyHandle(hCam);
  162. }
  163. MV_CC_Finalize();
  164. flock(fd, LOCK_UN);
  165. close(fd);
  166. sw_file_delete(lockFile);
  167. return ret;
  168. }
  169. // 保存照片
  170. static int SavePhoto(HANDLE hCam, MV_FRAME_OUT *pFrame, EImgType imgType, const char *imgFile)
  171. {
  172. MV_SAVE_IMAGE_PARAM_EX3 saveParams = { 0 }; MVCC_INTVALUE_EX iv;
  173. char *filename1 = (char *)imgFile, *filename2 = NULL; int ret; char ext[5];
  174. if(!hCam || !pFrame || !filename1 || strlen(filename1) <= 0) return -8;
  175. switch(imgType)
  176. {
  177. case IMG_TYPE_BMP: // 保存为.bmp格式
  178. imgType = MV_Image_Bmp;
  179. strcpy(ext, ".bmp");
  180. break;
  181. case IMG_TYPE_JPG: // 保存为.jpg格式
  182. imgType = MV_Image_Jpeg;
  183. strcpy(ext, ".jpg");
  184. break;
  185. default: return -9;
  186. }
  187. ret = MV_CC_GetIntValueEx(hCam, "PayloadSize", &iv);
  188. if(MV_OK != ret) return ret;
  189. saveParams.pData = pFrame->pBufAddr;
  190. saveParams.nDataLen = pFrame->stFrameInfo.nFrameLen;
  191. saveParams.enPixelType = pFrame->stFrameInfo.enPixelType;
  192. saveParams.nHeight = pFrame->stFrameInfo.nHeight;
  193. saveParams.nWidth = pFrame->stFrameInfo.nWidth;
  194. saveParams.enImageType = imgType;
  195. saveParams.nJpgQuality = 90; // JPG编码质量(50-99], 其它格式无效, 影响JPG图像文件大小
  196. saveParams.iMethodValue = 1;
  197. if(imgType == IMG_TYPE_JPG) saveParams.nBufferSize = (unsigned int)(iv.nCurValue * 1);
  198. else saveParams.nBufferSize = (unsigned int)(iv.nCurValue * 4);
  199. saveParams.pImageBuffer = (unsigned char *)sw_heap_malloc(saveParams.nBufferSize);
  200. if(!saveParams.pImageBuffer) return -10;
  201. ret = MV_CC_SaveImageEx3(hCam, &saveParams);
  202. if(MV_OK != ret) goto end_p;
  203. if(!xstrcasestr(filename1, "right", ext))
  204. {
  205. filename2 = (char *)sw_heap_malloc(strlen(filename1) +sizeof(ext));
  206. if(filename2) sprintf(filename2, "%s%s", filename1, ext);
  207. else { ret = -11; goto end_p; }
  208. ret = sw_file_update(filename2, "wb", (const char *)saveParams.pImageBuffer, saveParams.nImageLen);
  209. sw_heap_free(filename2);
  210. }
  211. else
  212. {
  213. ret = sw_file_update(filename1, "wb", (const char *)saveParams.pImageBuffer, saveParams.nImageLen);
  214. }
  215. if(ret == saveParams.nImageLen) ret = MV_OK;
  216. else ret = -12;
  217. end_p:
  218. sw_heap_free(saveParams.pImageBuffer);
  219. return ret;
  220. }
  221. // 获取系统当前USBFS内存大小(MB), 成功返回: >=0, 失败返回: -1值
  222. int GetSysUsbfsMemCurrentSize()
  223. {
  224. const char *usbfsFile = "/sys/module/usbcore/parameters/usbfs_memory_mb";
  225. char buf[MAX_LINE_CHARS]; int val = -1;
  226. FILE *fp = fopen(usbfsFile, "r");
  227. if(fp)
  228. {
  229. if(fgets(buf, sizeof(buf), fp)) sscanf(buf, "%d", &val);
  230. fclose(fp);
  231. }
  232. return val;
  233. }
  234. // 设置系统新的USBFS内存大小(MB), 成功返回: 0值, 失败返回: -1值
  235. int SetSysUsbfsMemSize(int val)
  236. {
  237. const char *usbfsFile = "/sys/module/usbcore/parameters/usbfs_memory_mb";
  238. char buf[MAX_LINE_CHARS]; sprintf(buf, "%d\n", val);
  239. if(val >= 0 && sw_file_update(usbfsFile, "w", buf, strlen(buf)) == strlen(buf)) return 0;
  240. else return -1;
  241. }