GrabBag/Device/MvsDevice/Src/MvsDevice.cpp
2026-06-08 17:36:13 +08:00

630 lines
20 KiB
C++

#include "MvsDevice.h"
#include "MvsSDKManager.h"
#include "VrError.h"
#include "VrLog.h"
#include <cstring>
#include <chrono>
#include <thread>
namespace
{
constexpr unsigned int kUsbImageNodeNum = 1;
constexpr unsigned int kUsbTransferSize = 0x40000; // 256KB, reduce per-URB DMA pressure on ARM USB2
constexpr unsigned int kUsbTransferWays = 1;
constexpr float kUsbOpenFrameRate = 2.0f;
bool IsUsbDeviceType(unsigned int type)
{
return type == MV_USB_DEVICE || type == MV_VIR_USB_DEVICE;
}
void ApplyConservativeUsbStreamConfig(void* handle, const char* stage)
{
if (!handle) return;
int frameEnableRet = MV_CC_SetBoolValue(handle, "AcquisitionFrameRateEnable", true);
int nodeRet = MV_CC_SetImageNodeNum(handle, kUsbImageNodeNum);
int sizeRet = MV_USB_SetTransferSize(handle, kUsbTransferSize);
int waysRet = MV_USB_SetTransferWays(handle, kUsbTransferWays);
MVCC_FLOATVALUE frameRateValue;
memset(&frameRateValue, 0, sizeof(frameRateValue));
int frameGetRet = MV_CC_GetFloatValue(handle, "AcquisitionFrameRate", &frameRateValue);
unsigned int readSize = 0;
unsigned int readWays = 0;
int getSizeRet = MV_USB_GetTransferSize(handle, &readSize);
int getWaysRet = MV_USB_GetTransferWays(handle, &readWays);
LOG_DEBUG("[MVS] USB stream config(%s) fps=%.1f enableRet=0x%x fpsGetRet=0x%x node=%u ret=0x%x transferSize=0x%x ret=0x%x read=0x%x readRet=0x%x transferWays=%u ret=0x%x read=%u readRet=0x%x\n",
stage ? stage : "",
frameRateValue.fCurValue, frameEnableRet, frameGetRet,
kUsbImageNodeNum, nodeRet,
kUsbTransferSize, sizeRet, readSize, getSizeRet,
kUsbTransferWays, waysRet, readWays, getWaysRet);
}
}
// 工厂
int IMvsDevice::CreateObject(IMvsDevice** ppDevice)
{
if (ppDevice == nullptr)
{
return ERR_CODE(DEV_ARG_INVAILD);
}
try
{
*ppDevice = new CMvsDevice();
return SUCCESS;
}
catch (...)
{
return ERR_CODE(DATA_ERR_MEM);
}
}
CMvsDevice::CMvsDevice() = default;
CMvsDevice::~CMvsDevice()
{
try
{
if (m_bAcquisitioning) StopAcquisition();
if (m_bDeviceOpen) CloseDevice();
if (m_bSDKInitialized) UninitSDK();
}
catch (...) {}
}
int CMvsDevice::InitSDK()
{
if (m_bSDKInitialized) return SUCCESS;
int ret = MvsSDKManager::GetInstance().InitSDK();
if (ret == SUCCESS) m_bSDKInitialized = true;
return ret;
}
int CMvsDevice::UninitSDK()
{
if (!m_bSDKInitialized) return SUCCESS;
int ret = MvsSDKManager::GetInstance().UninitSDK();
if (ret == SUCCESS) m_bSDKInitialized = false;
return ret;
}
int CMvsDevice::GetSDKVersion(std::string& version)
{
unsigned int v = MV_CC_GetSDKVersion();
char buf[64] = {0};
snprintf(buf, sizeof(buf), "MVS %u.%u.%u.%u",
(v >> 24) & 0xFF, (v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF);
version = buf;
return SUCCESS;
}
void CMvsDevice::FillDeviceInfo(const MV_CC_DEVICE_INFO& src, MvsDeviceInfo& dst)
{
if (src.nTLayerType == MV_GIGE_DEVICE
|| src.nTLayerType == MV_VIR_GIGE_DEVICE
|| src.nTLayerType == MV_GENTL_GIGE_DEVICE)
{
const auto& gi = src.SpecialInfo.stGigEInfo;
dst.tlType = EMvsTLType::GigE;
dst.serialNumber = reinterpret_cast<const char*>(gi.chSerialNumber);
dst.modelName = reinterpret_cast<const char*>(gi.chModelName);
dst.manufacturerName = reinterpret_cast<const char*>(gi.chManufacturerName);
dst.deviceVersion = reinterpret_cast<const char*>(gi.chDeviceVersion);
dst.userDefinedName = reinterpret_cast<const char*>(gi.chUserDefinedName);
// IP 拼接
unsigned int ip = gi.nCurrentIp;
char ipBuf[32] = {0};
snprintf(ipBuf, sizeof(ipBuf), "%u.%u.%u.%u",
(ip >> 24) & 0xFF, (ip >> 16) & 0xFF, (ip >> 8) & 0xFF, ip & 0xFF);
dst.ipAddress = ipBuf;
dst.macAddress.clear();
}
else if (src.nTLayerType == MV_USB_DEVICE
|| src.nTLayerType == MV_VIR_USB_DEVICE)
{
const auto& ui = src.SpecialInfo.stUsb3VInfo;
dst.tlType = EMvsTLType::USB3;
dst.serialNumber = reinterpret_cast<const char*>(ui.chSerialNumber);
dst.modelName = reinterpret_cast<const char*>(ui.chModelName);
dst.manufacturerName = reinterpret_cast<const char*>(ui.chManufacturerName);
dst.deviceVersion = reinterpret_cast<const char*>(ui.chDeviceVersion);
dst.userDefinedName = reinterpret_cast<const char*>(ui.chUserDefinedName);
dst.ipAddress.clear();
dst.macAddress.clear();
}
else
{
dst.tlType = EMvsTLType::Other;
}
dst.displayName = dst.userDefinedName.empty()
? (dst.modelName + " (" + dst.serialNumber + ")")
: dst.userDefinedName;
}
int CMvsDevice::EnumerateDevices(std::vector<MvsDeviceInfo>& deviceList, unsigned int tLayerType)
{
if (!m_bSDKInitialized)
{
int r = InitSDK();
if (r != SUCCESS) return r;
}
deviceList.clear();
m_devInfoCache.clear();
unsigned int layer = tLayerType == 0
? (MV_GIGE_DEVICE | MV_USB_DEVICE)
: tLayerType;
MV_CC_DEVICE_INFO_LIST stDeviceList;
memset(&stDeviceList, 0, sizeof(stDeviceList));
int ret = MV_CC_EnumDevices(layer, &stDeviceList);
if (ret != MV_OK)
{
LOG_DEBUG("MV_CC_EnumDevices fail: %x\n", ret);
return ret;
}
for (unsigned int i = 0; i < stDeviceList.nDeviceNum; ++i)
{
MV_CC_DEVICE_INFO* p = stDeviceList.pDeviceInfo[i];
if (!p) continue;
m_devInfoCache.push_back(*p);
MvsDeviceInfo info;
FillDeviceInfo(*p, info);
deviceList.push_back(info);
}
LOG_DEBUG("MVS Enumerated %u devices\n", static_cast<unsigned>(deviceList.size()));
return SUCCESS;
}
int CMvsDevice::OpenDevice(const std::string& serialNumber)
{
std::lock_guard<std::mutex> lk(m_deviceMutex);
if (!m_bSDKInitialized)
{
int r = InitSDK();
if (r != SUCCESS) return r;
}
// 如果缓存为空(外部直接通过 SN 打开),先枚举一次
if (m_devInfoCache.empty())
{
std::vector<MvsDeviceInfo> tmp;
int r = EnumerateDevices(tmp);
if (r != SUCCESS) return r;
}
// 查找匹配的 SN
MV_CC_DEVICE_INFO* pTarget = nullptr;
bool targetIsUsb = false;
for (auto& dev : m_devInfoCache)
{
const char* sn = nullptr;
if (dev.nTLayerType == MV_GIGE_DEVICE
|| dev.nTLayerType == MV_VIR_GIGE_DEVICE
|| dev.nTLayerType == MV_GENTL_GIGE_DEVICE)
{
sn = reinterpret_cast<const char*>(dev.SpecialInfo.stGigEInfo.chSerialNumber);
}
else if (dev.nTLayerType == MV_USB_DEVICE
|| dev.nTLayerType == MV_VIR_USB_DEVICE)
{
sn = reinterpret_cast<const char*>(dev.SpecialInfo.stUsb3VInfo.chSerialNumber);
}
if (sn && serialNumber == sn)
{
pTarget = &dev;
targetIsUsb = IsUsbDeviceType(dev.nTLayerType);
break;
}
}
if (!pTarget) return ERR_CODE(DEV_NOT_FIND);
if (m_bDeviceOpen) CloseDevice();
int ret = MV_CC_CreateHandle(&m_handle, pTarget);
if (ret != MV_OK)
{
LOG_DEBUG("MV_CC_CreateHandle fail: %x\n", ret);
return ret;
}
ret = MV_CC_OpenDevice(m_handle);
if (ret != MV_OK)
{
LOG_DEBUG("MV_CC_OpenDevice fail: %x\n", ret);
MV_CC_DestroyHandle(m_handle);
m_handle = nullptr;
return ret;
}
// GigE 设备建议优化包大小
if (pTarget->nTLayerType == MV_GIGE_DEVICE)
{
int nPacketSize = MV_CC_GetOptimalPacketSize(m_handle);
if (nPacketSize > 0)
{
MV_CC_SetIntValueEx(m_handle, "GevSCPSPacketSize", nPacketSize);
}
}
// USB 设备优化带宽(降低传输负载,避免资源申请失败)
if (pTarget->nTLayerType == MV_USB_DEVICE
|| pTarget->nTLayerType == MV_VIR_USB_DEVICE)
{
// 降低 USB 传输包大小,减少带宽占用
MV_CC_SetIntValueEx(m_handle, "PayloadSize", 0); // 自动计算
// 设置合理的帧率上限(避免带宽不足)
MV_CC_SetBoolValue(m_handle, "AcquisitionFrameRateEnable", true);
MV_CC_SetFloatValue(m_handle, "AcquisitionFrameRate", kUsbOpenFrameRate);
}
// 默认关闭触发模式
MV_CC_SetEnumValue(m_handle, "TriggerMode", MV_TRIGGER_MODE_OFF);
m_currentDeviceIsUsb = targetIsUsb;
if (m_currentDeviceIsUsb) ApplyConservativeUsbStreamConfig(m_handle, "open-final");
FillDeviceInfo(*pTarget, m_currentDeviceInfo);
m_bDeviceOpen = true;
return SUCCESS;
}
int CMvsDevice::OpenDeviceByIndex(unsigned int index)
{
std::vector<MvsDeviceInfo> list;
int r = EnumerateDevices(list);
if (r != SUCCESS) return r;
if (index >= list.size()) return ERR_CODE(DEV_ID_ERR);
return OpenDevice(list[index].serialNumber);
}
int CMvsDevice::CloseDevice()
{
std::lock_guard<std::mutex> lk(m_deviceMutex);
if (m_bAcquisitioning) StopAcquisition();
if (m_handle)
{
MV_CC_CloseDevice(m_handle);
MV_CC_DestroyHandle(m_handle);
m_handle = nullptr;
}
m_bDeviceOpen = false;
m_currentDeviceIsUsb = false;
return SUCCESS;
}
bool CMvsDevice::IsDeviceOpen()
{
return m_bDeviceOpen;
}
int CMvsDevice::GetDeviceInfo(MvsDeviceInfo& info)
{
if (!m_bDeviceOpen) return ERR_CODE(DEV_NO_OPEN);
info = m_currentDeviceInfo;
GetWidth(info.width);
GetHeight(info.height);
return SUCCESS;
}
int CMvsDevice::SetTriggerMode(bool enable)
{
if (!m_handle) return ERR_CODE(DEV_CTRL_ERR);
return MV_CC_SetEnumValue(m_handle, "TriggerMode",
enable ? MV_TRIGGER_MODE_ON : MV_TRIGGER_MODE_OFF);
}
int CMvsDevice::SendSoftTrigger()
{
if (!m_handle) return ERR_CODE(DEV_CTRL_ERR);
return MV_CC_SetCommandValue(m_handle, "TriggerSoftware");
}
int CMvsDevice::StartAcquisition()
{
if (!m_handle) return ERR_CODE(DEV_CTRL_ERR);
if (m_bAcquisitioning) return SUCCESS;
if (m_currentDeviceIsUsb) ApplyConservativeUsbStreamConfig(m_handle, "start");
int ret = MV_CC_StartGrabbing(m_handle);
if (ret == MV_OK)
{
m_bAcquisitioning = true;
}
else
{
LOG_DEBUG("MV_CC_StartGrabbing fail: %x\n", ret);
// 针对资源申请失败,输出详细诊断信息
if (ret == 0x80000006) // MV_E_RESOURCE
{
LOG_ERROR("USB resource allocation failed. Possible causes:\n");
LOG_ERROR(" 1. Insufficient USB bandwidth (try lower resolution/framerate)\n");
LOG_ERROR(" 2. USB controller overload (disconnect other USB devices)\n");
LOG_ERROR(" 3. Insufficient system memory\n");
LOG_ERROR(" 4. USB power supply insufficient\n");
// 尝试读取当前相机参数
MVCC_INTVALUE_EX stParam;
memset(&stParam, 0, sizeof(stParam));
if (MV_CC_GetIntValueEx(m_handle, "Width", &stParam) == MV_OK)
{
LOG_ERROR(" Current Width: %lld\n", stParam.nCurValue);
}
memset(&stParam, 0, sizeof(stParam));
if (MV_CC_GetIntValueEx(m_handle, "Height", &stParam) == MV_OK)
{
LOG_ERROR(" Current Height: %lld\n", stParam.nCurValue);
}
MVCC_FLOATVALUE stFloatParam;
memset(&stFloatParam, 0, sizeof(stFloatParam));
if (MV_CC_GetFloatValue(m_handle, "AcquisitionFrameRate", &stFloatParam) == MV_OK)
{
LOG_ERROR(" Current FrameRate: %.2f\n", stFloatParam.fCurValue);
}
}
}
return ret;
}
int CMvsDevice::StopAcquisition()
{
if (!m_handle) return ERR_CODE(DEV_CTRL_ERR);
if (!m_bAcquisitioning) return SUCCESS;
int ret = MV_CC_StopGrabbing(m_handle);
if (ret == MV_OK) m_bAcquisitioning = false;
else LOG_DEBUG("MV_CC_StopGrabbing fail: %x\n", ret);
return ret;
}
bool CMvsDevice::IsAcquisitioning()
{
return m_bAcquisitioning;
}
int CMvsDevice::CaptureImage(MvsImageData& image, unsigned int timeoutMs)
{
if (!m_handle) return ERR_CODE(DEV_CTRL_ERR);
MV_FRAME_OUT stFrame;
memset(&stFrame, 0, sizeof(stFrame));
int ret = MV_CC_GetImageBuffer(m_handle, &stFrame, timeoutMs);
if (ret != MV_OK)
{
LOG_DEBUG("MV_CC_GetImageBuffer fail: %x\n", ret);
return ret;
}
image.width = stFrame.stFrameInfo.nExtendWidth
? stFrame.stFrameInfo.nExtendWidth
: stFrame.stFrameInfo.nWidth;
image.height = stFrame.stFrameInfo.nExtendHeight
? stFrame.stFrameInfo.nExtendHeight
: stFrame.stFrameInfo.nHeight;
image.dataSize = stFrame.stFrameInfo.nFrameLen;
image.pixelFormat = static_cast<int>(stFrame.stFrameInfo.enPixelType);
image.frameID = stFrame.stFrameInfo.nFrameNum;
image.timestamp = (static_cast<unsigned long long>(stFrame.stFrameInfo.nDevTimeStampHigh) << 32)
| stFrame.stFrameInfo.nDevTimeStampLow;
image.pData = new unsigned char[image.dataSize];
memcpy(image.pData, stFrame.pBufAddr, image.dataSize);
MV_CC_FreeImageBuffer(m_handle, &stFrame);
return SUCCESS;
}
int CMvsDevice::RegisterImageCallback(MvsImageCallback callback)
{
if (!m_handle) return ERR_CODE(DEV_CTRL_ERR);
{
std::lock_guard<std::mutex> lk(m_callbackMutex);
m_imageCallback = std::move(callback);
}
int ret = MV_CC_RegisterImageCallBackEx(m_handle, &CMvsDevice::OnFrameCallback, this);
LOG_DEBUG("[MVS] RegisterImageCallback handle=%p ret=0x%x\n", (void*)m_handle, ret);
return ret;
}
int CMvsDevice::UnregisterImageCallback()
{
if (!m_handle) return SUCCESS;
// MVS 没有显式反注册,使用空回调覆盖
MV_CC_RegisterImageCallBackEx(m_handle, nullptr, nullptr);
std::lock_guard<std::mutex> lk(m_callbackMutex);
m_imageCallback = nullptr;
return SUCCESS;
}
void __stdcall CMvsDevice::OnFrameCallback(unsigned char* pData,
MV_FRAME_OUT_INFO_EX* pFrameInfo,
void* pUser)
{
if (!pData || !pFrameInfo || !pUser) return;
CMvsDevice* self = static_cast<CMvsDevice*>(pUser);
MvsImageCallback cb;
{
std::lock_guard<std::mutex> lk(self->m_callbackMutex);
cb = self->m_imageCallback;
}
if (!cb) return;
MvsImageData img;
img.width = pFrameInfo->nExtendWidth ? pFrameInfo->nExtendWidth : pFrameInfo->nWidth;
img.height = pFrameInfo->nExtendHeight ? pFrameInfo->nExtendHeight : pFrameInfo->nHeight;
img.dataSize = pFrameInfo->nFrameLen;
img.pixelFormat = static_cast<int>(pFrameInfo->enPixelType);
img.frameID = pFrameInfo->nFrameNum;
img.timestamp = (static_cast<unsigned long long>(pFrameInfo->nDevTimeStampHigh) << 32)
| pFrameInfo->nDevTimeStampLow;
// 回调期间 pData 由 SDK 持有,外部不要 delete
img.pData = pData;
try { cb(img); } catch (...) {}
}
int CMvsDevice::GetWidth(unsigned int& width)
{
if (!m_handle) return ERR_CODE(DEV_CTRL_ERR);
MVCC_INTVALUE_EX v; memset(&v, 0, sizeof(v));
int ret = MV_CC_GetIntValueEx(m_handle, "Width", &v);
if (ret == MV_OK) width = static_cast<unsigned int>(v.nCurValue);
return ret;
}
int CMvsDevice::GetHeight(unsigned int& height)
{
if (!m_handle) return ERR_CODE(DEV_CTRL_ERR);
MVCC_INTVALUE_EX v; memset(&v, 0, sizeof(v));
int ret = MV_CC_GetIntValueEx(m_handle, "Height", &v);
if (ret == MV_OK) height = static_cast<unsigned int>(v.nCurValue);
return ret;
}
int CMvsDevice::SetROI(const MvsROI& roi)
{
if (!m_handle) return ERR_CODE(DEV_CTRL_ERR);
int r = 0;
r |= MV_CC_SetIntValueEx(m_handle, "OffsetX", roi.offsetX);
r |= MV_CC_SetIntValueEx(m_handle, "OffsetY", roi.offsetY);
r |= MV_CC_SetIntValueEx(m_handle, "Width", roi.width);
r |= MV_CC_SetIntValueEx(m_handle, "Height", roi.height);
return r == 0 ? SUCCESS : ERR_CODE(DEV_CTRL_ERR);
}
int CMvsDevice::GetROI(MvsROI& roi)
{
if (!m_handle) return ERR_CODE(DEV_CTRL_ERR);
MVCC_INTVALUE_EX v; memset(&v, 0, sizeof(v));
MV_CC_GetIntValueEx(m_handle, "OffsetX", &v); roi.offsetX = (int)v.nCurValue;
memset(&v, 0, sizeof(v));
MV_CC_GetIntValueEx(m_handle, "OffsetY", &v); roi.offsetY = (int)v.nCurValue;
memset(&v, 0, sizeof(v));
MV_CC_GetIntValueEx(m_handle, "Width", &v); roi.width = (int)v.nCurValue;
memset(&v, 0, sizeof(v));
MV_CC_GetIntValueEx(m_handle, "Height", &v); roi.height = (int)v.nCurValue;
return SUCCESS;
}
int CMvsDevice::SetExposureTime(double v)
{ return m_handle ? MV_CC_SetFloatValue(m_handle, "ExposureTime", (float)v) : ERR_CODE(DEV_CTRL_ERR); }
int CMvsDevice::GetExposureTime(double& v)
{
if (!m_handle) return ERR_CODE(DEV_CTRL_ERR);
MVCC_FLOATVALUE fv; memset(&fv, 0, sizeof(fv));
int r = MV_CC_GetFloatValue(m_handle, "ExposureTime", &fv);
if (r == MV_OK) v = fv.fCurValue;
return r;
}
int CMvsDevice::SetGain(double v)
{ return m_handle ? MV_CC_SetFloatValue(m_handle, "Gain", (float)v) : ERR_CODE(DEV_CTRL_ERR); }
int CMvsDevice::GetGain(double& v)
{
if (!m_handle) return ERR_CODE(DEV_CTRL_ERR);
MVCC_FLOATVALUE fv; memset(&fv, 0, sizeof(fv));
int r = MV_CC_GetFloatValue(m_handle, "Gain", &fv);
if (r == MV_OK) v = fv.fCurValue;
return r;
}
int CMvsDevice::SetFrameRate(double v)
{
if (!m_handle) return ERR_CODE(DEV_CTRL_ERR);
MV_CC_SetBoolValue(m_handle, "AcquisitionFrameRateEnable", true);
return MV_CC_SetFloatValue(m_handle, "AcquisitionFrameRate", (float)v);
}
int CMvsDevice::GetFrameRate(double& v)
{
if (!m_handle) return ERR_CODE(DEV_CTRL_ERR);
MVCC_FLOATVALUE fv; memset(&fv, 0, sizeof(fv));
int r = MV_CC_GetFloatValue(m_handle, "AcquisitionFrameRate", &fv);
if (r == MV_OK) v = fv.fCurValue;
return r;
}
int CMvsDevice::SetIntFeature(const std::string& name, int64_t v)
{ return m_handle ? MV_CC_SetIntValueEx(m_handle, name.c_str(), v) : ERR_CODE(DEV_CTRL_ERR); }
int CMvsDevice::GetIntFeature(const std::string& name, int64_t& v)
{
if (!m_handle) return ERR_CODE(DEV_CTRL_ERR);
MVCC_INTVALUE_EX iv; memset(&iv, 0, sizeof(iv));
int r = MV_CC_GetIntValueEx(m_handle, name.c_str(), &iv);
if (r == MV_OK) v = iv.nCurValue;
return r;
}
int CMvsDevice::SetFloatFeature(const std::string& name, double v)
{ return m_handle ? MV_CC_SetFloatValue(m_handle, name.c_str(), (float)v) : ERR_CODE(DEV_CTRL_ERR); }
int CMvsDevice::GetFloatFeature(const std::string& name, double& v)
{
if (!m_handle) return ERR_CODE(DEV_CTRL_ERR);
MVCC_FLOATVALUE fv; memset(&fv, 0, sizeof(fv));
int r = MV_CC_GetFloatValue(m_handle, name.c_str(), &fv);
if (r == MV_OK) v = fv.fCurValue;
return r;
}
int CMvsDevice::SetEnumFeature(const std::string& name, int64_t v)
{ return m_handle ? MV_CC_SetEnumValue(m_handle, name.c_str(), (unsigned int)v) : ERR_CODE(DEV_CTRL_ERR); }
int CMvsDevice::GetEnumFeature(const std::string& name, int64_t& v)
{
if (!m_handle) return ERR_CODE(DEV_CTRL_ERR);
MVCC_ENUMVALUE ev; memset(&ev, 0, sizeof(ev));
int r = MV_CC_GetEnumValue(m_handle, name.c_str(), &ev);
if (r == MV_OK) v = ev.nCurValue;
return r;
}
int CMvsDevice::SetBoolFeature(const std::string& name, bool v)
{ return m_handle ? MV_CC_SetBoolValue(m_handle, name.c_str(), v) : ERR_CODE(DEV_CTRL_ERR); }
int CMvsDevice::GetBoolFeature(const std::string& name, bool& v)
{
if (!m_handle) return ERR_CODE(DEV_CTRL_ERR);
bool bv = false;
int r = MV_CC_GetBoolValue(m_handle, name.c_str(), &bv);
if (r == MV_OK) v = bv;
return r;
}
int CMvsDevice::SetStringFeature(const std::string& name, const std::string& v)
{ return m_handle ? MV_CC_SetStringValue(m_handle, name.c_str(), v.c_str()) : ERR_CODE(DEV_CTRL_ERR); }
int CMvsDevice::GetStringFeature(const std::string& name, std::string& v)
{
if (!m_handle) return ERR_CODE(DEV_CTRL_ERR);
MVCC_STRINGVALUE sv; memset(&sv, 0, sizeof(sv));
int r = MV_CC_GetStringValue(m_handle, name.c_str(), &sv);
if (r == MV_OK) v = sv.chCurValue;
return r;
}
int CMvsDevice::ExecuteCommand(const std::string& name)
{ return m_handle ? MV_CC_SetCommandValue(m_handle, name.c_str()) : ERR_CODE(DEV_CTRL_ERR); }