Files
ANSCORE/modules/ANSCV/ANSWebcam.cpp

1759 lines
66 KiB
C++

#include "ANSWEBCAM.h"
#include "ANSMatRegistry.h"
#include "ANSGpuFrameRegistry.h"
#include <cstdint>
#include <memory>
extern "C" {
#include <libavutil/frame.h>
}
// Custom pixel format for BGR full-res Mat entries in ANSGpuFrameRegistry.
static constexpr int ANSCV_PIX_FMT_BGR24 = 1000;
#include <filesystem>
#include <turbojpeg.h>
#include <opencv2/opencv.hpp>
namespace ANSCENTER {
#define CHECK_CUDAWEB(call) do { \
cudaError_t err = call; \
if (err != cudaSuccess) { \
std::cout<<"CUDA error: " + std::string(cudaGetErrorString(err)); \
} \
} while (0)
#define CHECK_NVJPEGWEB(call) do { \
nvjpegStatus_t status = call; \
if (status != NVJPEG_STATUS_SUCCESS) { \
std::cout<<"nvJPEG error: " + std::to_string(status); \
} \
} while (0)
void DeleteMediaType(AM_MEDIA_TYPE* pmt)
{
// allow NULL pointers for coding simplicity
if (pmt == NULL) {
return;
}
if (pmt->cbFormat != 0) {
CoTaskMemFree((PVOID)pmt->pbFormat);
// Strictly unnecessary but tidier
pmt->cbFormat = 0;
pmt->pbFormat = NULL;
}
if (pmt->pUnk != NULL) {
pmt->pUnk->Release();
pmt->pUnk = NULL;
}
}
ANSWEBCAMPlayer::ANSWEBCAMPlayer() {
_deviceId = 0;
_resWidth = 0;
_resHeight = 0;
m_bPaused = false;
_isPlaying = false;
_lastJpegImage = "";
_cameraNames.clear();
_bbox = cv::Rect(0, 0, 0, 0);
_crop = false;
_previousPTS = 0;
_jpegCompressor = nullptr;
}
ANSWEBCAMPlayer::~ANSWEBCAMPlayer() noexcept {
try {
Destroy();
}
catch (...) {}
if (_jpegCompressor) {
tjDestroy(_jpegCompressor);
_jpegCompressor = nullptr;
}
}
void ANSWEBCAMPlayer::Destroy() {
std::lock_guard<std::recursive_mutex> lock(_mutex);
try {
if (cap.isOpened()) {
cap.release();
}
_resWidth = 0;
_resHeight = 0;
_deviceId = 0;
_lastJpegImage = "";
_previousImage.release();
_isPlaying = false;
if (!_cameraNames.empty()) _cameraNames.clear();
}
catch (const std::exception& e) {
_logger.LogError("ANSWEBCAMPlayer::Destroy. Exception:", e.what(), __FILE__, __LINE__);
}
catch (...) {
_logger.LogError("ANSWEBCAMPlayer::Destroy.", "Unknown exception", __FILE__, __LINE__);
}
}
std::vector<Resolution> ANSWEBCAMPlayer::GetAvailableResolutions(int deviceId) {
std::vector<Resolution> resolutions;
try {
cv::VideoCapture testCap(deviceId, cv::CAP_DSHOW);
if (!testCap.isOpened()) {
testCap.open(deviceId, cv::CAP_ANY);
if (!testCap.isOpened()) {
_logger.LogError("ANSWEBCAMPlayer::GetAvailableResolutions", "Unable to open camera", __FILE__, __LINE__);
return resolutions;
}
}
// Common resolutions to test
std::vector<std::pair<int, int>> commonResolutions = {
{3264, 2448},
{3264, 1836},
{2592, 1944},
{2048, 1536},
{1920, 1080},
{1600, 1200},
{1280, 1024},
{1280, 720},
{1024, 768},
{1920, 1080},
{800, 600},
{640, 480}
};
for (const auto& res : commonResolutions) {
testCap.set(cv::CAP_PROP_FRAME_WIDTH, res.first);
testCap.set(cv::CAP_PROP_FRAME_HEIGHT, res.second);
int actualWidth = static_cast<int>(testCap.get(cv::CAP_PROP_FRAME_WIDTH));
int actualHeight = static_cast<int>(testCap.get(cv::CAP_PROP_FRAME_HEIGHT));
// Check if the camera actually supports this resolution
if (actualWidth == res.first && actualHeight == res.second) {
resolutions.emplace_back(actualWidth, actualHeight);
_logger.LogDebug("ANSWEBCAMPlayer::GetAvailableResolutions",
"Supported resolution: " + std::to_string(actualWidth) + "x" + std::to_string(actualHeight),
__FILE__, __LINE__);
}
}
testCap.release();
// Sort resolutions by area (largest first)
std::sort(resolutions.rbegin(), resolutions.rend());
}
catch (const std::exception& e) {
_logger.LogError("ANSWEBCAMPlayer::GetAvailableResolutions", e.what(), __FILE__, __LINE__);
}
return resolutions;
}
void ANSWEBCAMPlayer::SetEnableMaxResolution(bool enable) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
_enableMaxResolution = enable;
}
bool ANSWEBCAMPlayer::SetPreferredResolution(int deviceId) {
// Try Full HD first, then fall back to lower resolutions until one is supported
try {
std::vector<std::pair<int, int>> preferredResolutions = {
{1920, 1080}, // Full HD
{1280, 720}, // HD
{1024, 768}, // XGA
{800, 600}, // SVGA
{640, 480} // VGA
};
for (const auto& res : preferredResolutions) {
cap.set(cv::CAP_PROP_FRAME_WIDTH, res.first);
cap.set(cv::CAP_PROP_FRAME_HEIGHT, res.second);
int actualWidth = static_cast<int>(cap.get(cv::CAP_PROP_FRAME_WIDTH));
int actualHeight = static_cast<int>(cap.get(cv::CAP_PROP_FRAME_HEIGHT));
if (actualWidth == res.first && actualHeight == res.second) {
_resWidth = actualWidth;
_resHeight = actualHeight;
_savedResWidth = _resWidth;
_savedResHeight = _resHeight;
_logger.LogDebug("ANSWEBCAMPlayer::SetPreferredResolution",
"Resolution set to: " + std::to_string(actualWidth) + "x" + std::to_string(actualHeight),
__FILE__, __LINE__);
return true;
}
}
// None of the preferred resolutions worked — use whatever the camera defaults to
_resWidth = static_cast<int>(cap.get(cv::CAP_PROP_FRAME_WIDTH));
_resHeight = static_cast<int>(cap.get(cv::CAP_PROP_FRAME_HEIGHT));
_savedResWidth = _resWidth;
_savedResHeight = _resHeight;
_logger.LogWarn("ANSWEBCAMPlayer::SetPreferredResolution",
"No preferred resolution supported. Using camera default: " + std::to_string(_resWidth) + "x" + std::to_string(_resHeight),
__FILE__, __LINE__);
return false;
}
catch (const std::exception& e) {
_logger.LogError("ANSWEBCAMPlayer::SetPreferredResolution", e.what(), __FILE__, __LINE__);
return false;
}
}
bool ANSWEBCAMPlayer::SetBestResolution(int deviceId) {
try {
std::vector<Resolution> availableResolutions = GetAvailableResolutions(deviceId);
if (availableResolutions.empty()) {
return false;
}
// Use the largest available resolution (first in sorted list)
Resolution bestRes = availableResolutions[0];
_logger.LogDebug("ANSWEBCAMPlayer::SetBestResolution",
"Setting resolution to: " + std::to_string(bestRes.width) + "x" + std::to_string(bestRes.height),
__FILE__, __LINE__);
cap.set(cv::CAP_PROP_FRAME_WIDTH, bestRes.width);
cap.set(cv::CAP_PROP_FRAME_HEIGHT, bestRes.height);
// Verify the resolution was set
int actualWidth = static_cast<int>(cap.get(cv::CAP_PROP_FRAME_WIDTH));
int actualHeight = static_cast<int>(cap.get(cv::CAP_PROP_FRAME_HEIGHT));
_resWidth = actualWidth;
_resHeight = actualHeight;
_savedResWidth = _resWidth;
_savedResHeight = _resHeight;
_logger.LogDebug("ANSWEBCAMPlayer::SetBestResolution",
"Actual resolution set: " + std::to_string(actualWidth) + "x" + std::to_string(actualHeight),
__FILE__, __LINE__);
return (actualWidth == bestRes.width && actualHeight == bestRes.height);
}
catch (const std::exception& e) {
_logger.LogError("ANSWEBCAMPlayer::SetBestResolution", e.what(), __FILE__, __LINE__);
return false;
}
}
bool ANSWEBCAMPlayer::SetResolution(int width, int height) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
try {
if (cap.isOpened()) {
cap.set(cv::CAP_PROP_FRAME_WIDTH, width);
cap.set(cv::CAP_PROP_FRAME_HEIGHT, height);
// Verify the resolution was set
int actualWidth = static_cast<int>(cap.get(cv::CAP_PROP_FRAME_WIDTH));
int actualHeight = static_cast<int>(cap.get(cv::CAP_PROP_FRAME_HEIGHT));
_resWidth = actualWidth;
_resHeight = actualHeight;
_savedResWidth = _resWidth;
_savedResHeight = _resHeight;
if (actualWidth == width && actualHeight == height) {
_logger.LogDebug("ANSWEBCAMPlayer::SetResolution",
"Resolution set successfully: " + std::to_string(width) + "x" + std::to_string(height),
__FILE__, __LINE__);
return true;
}
else {
_logger.LogWarn("ANSWEBCAMPlayer::SetResolution",
"Requested resolution " + std::to_string(width) + "x" + std::to_string(height) +
" not supported. Using: " + std::to_string(actualWidth) + "x" + std::to_string(actualHeight),
__FILE__, __LINE__);
return false;
}
}
// If camera is not opened, just store the values for later use
_resWidth = width;
_resHeight = height;
_savedResWidth = width;
_savedResHeight = height;
return true;
}
catch (const std::exception& e) {
_logger.LogError("ANSWEBCAMPlayer::SetResolution", e.what(), __FILE__, __LINE__);
return false;
}
}
std::string ANSWEBCAMPlayer::GetAvailableResolutionsString(int deviceId) {
std::vector<Resolution> resolutions = GetAvailableResolutions(deviceId);
std::stringstream ss;
for (size_t i = 0; i < resolutions.size(); ++i) {
if (i != 0) ss << ";";
ss << resolutions[i].width << "x" << resolutions[i].height;
}
return ss.str();
}
std::vector<std::string> ANSWEBCAMPlayer::ScanWebcamDevices() {
std::vector<std::string> cameraNames;
std::lock_guard<std::mutex> guard(mtx); // Locks the mutex for the scope of the function
try {
ICreateDevEnum* pDevEnum = nullptr;
IEnumMoniker* pEnum = nullptr;
CoInitialize(nullptr);
HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pDevEnum));
if (SUCCEEDED(hr)) {
hr = pDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEnum, 0);
if (hr == S_OK) {
IMoniker* pMoniker = nullptr;
while (pEnum->Next(1, &pMoniker, nullptr) == S_OK) {
IPropertyBag* pPropBag;
hr = pMoniker->BindToStorage(0, 0, IID_PPV_ARGS(&pPropBag));
if (SUCCEEDED(hr)) {
VARIANT var;
VariantInit(&var);
// Get the description or friendly name.
hr = pPropBag->Read(L"Description", &var, 0);
if (FAILED(hr)) {
hr = pPropBag->Read(L"FriendlyName", &var, 0);
}
if (SUCCEEDED(hr)) {
std::wstring wcameraName(var.bstrVal);
auto s = std::filesystem::path(wcameraName).string();
std::string cameraName = s;
cameraNames.push_back(cameraName);
VariantClear(&var);
}
pPropBag->Release();
}
pMoniker->Release();
}
pEnum->Release();
}
pDevEnum->Release();
}
CoUninitialize();
}
catch (std::exception& e) {
std::cout << "ANSWEBCAMPlayer::ScanWebcamDevices - Exception: " << e.what() << std::endl;
}
return cameraNames;
}
// It does not work
std::string ANSWEBCAMPlayer::GetSupportedResolutions(int deviceId) {
try {
std::vector<std::string> resolutions;
SPDLogger& _logger = SPDLogger::GetInstance("ANSWebcamPlayer", false);
// Initialize COM
HRESULT hr = CoInitialize(NULL);
if (FAILED(hr)) {
// Log error and return
_logger.LogError("ANSWEBCAMPlayer::GetSupportedResolutions:", "Failed to initialize COM.", __FILE__, __LINE__);
return "";
}
// Create the System Device Enumerator.
ICreateDevEnum* pDevEnum;
hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pDevEnum));
if (FAILED(hr)) {
// Log error and return
_logger.LogError("ANSWEBCAMPlayer::GetSupportedResolutions:", "Failed to create System Device Enumerator.", __FILE__, __LINE__);
return "";
}
// Access the specific video capture device
// Create an enumerator for the video capture devices.
IEnumMoniker* pEnum;
pDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEnum, 0);
// Access the specific video capture device
IMoniker* pMoniker;
pEnum->Next(deviceId + 1, &pMoniker, NULL);
IBaseFilter* pCap;
hr = pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&pCap);
if (FAILED(hr) || pCap == NULL) {
// Log error and return
_logger.LogError("ANSWEBCAMPlayer::GetSupportedResolutions:", "Failed to bind to object.", __FILE__, __LINE__);
return "";
}
IAMStreamConfig* pConfig;
hr = pCap->QueryInterface(IID_IAMStreamConfig, (void**)&pConfig);
if (FAILED(hr)) {
// Log error and return
_logger.LogError("ANSWEBCAMPlayer::GetSupportedResolutions:", "Failed to get IAMStreamConfig interface.", __FILE__, __LINE__);
return "";
}
if (FAILED(hr)) {
// Log error and return
_logger.LogError("ANSWEBCAMPlayer::GetSupportedResolutions:", "Failed to get IAMStreamConfig interface.", __FILE__, __LINE__);
return "";
}
int iCount = 0, iSize = 0;
pConfig->GetNumberOfCapabilities(&iCount, &iSize);
// Check the size to make sure we pass in the correct structure.
if (iSize == sizeof(VIDEO_STREAM_CONFIG_CAPS)) {
// Use the video capabilities structure.
for (int iFormat = 0; iFormat < iCount; iFormat++) {
VIDEO_STREAM_CONFIG_CAPS scc;
AM_MEDIA_TYPE* pmtConfig;
HRESULT hr = pConfig->GetStreamCaps(iFormat, &pmtConfig, (BYTE*)&scc);
if (SUCCEEDED(hr)) {
// Check the media type is valid
if (pmtConfig->formattype == FORMAT_VideoInfo) {
// Get the width and height
VIDEOINFOHEADER* videoInfoHeader = reinterpret_cast<VIDEOINFOHEADER*>(pmtConfig->pbFormat);
std::string resolution = std::to_string(videoInfoHeader->bmiHeader.biWidth) + "x" + std::to_string(videoInfoHeader->bmiHeader.biHeight);
resolutions.push_back(resolution);
}
// Delete the media type when done.
DeleteMediaType(pmtConfig);
}
}
}
// Clean up DirectShow objects
pConfig->Release();
pCap->Release();
pMoniker->Release();
pEnum->Release();
pDevEnum->Release();
// Uninitialize COM when done
CoUninitialize();
// Concatenate the resolutions with a semicolon separator
std::stringstream ss;
for (size_t i = 0; i < resolutions.size(); ++i)
{
if (i != 0)
ss << ";";
ss << resolutions[i];
}
return ss.str();
}
catch (std::exception& e) {
std::cout << "ANSWEBCAMPlayer::GetSupportedResolutions - Exception: " << e.what() << std::endl;
return "";
}
}
void ANSWEBCAMPlayer::CheckLicense() {
_licenseValid = true; // No need license for webcam
//try {
// _licenseValid = ANSCENTER::ANSLicenseHelper::LicenseVerification(_licenseKey, 1007, "ANSCV");//Default productId=1005
//}
//catch (std::exception& e) {
// this->_logger.LogFatal("ANSWEBCAMPlayer::CheckLicense. Error:", e.what(), __FILE__, __LINE__);
//}
}
bool ANSWEBCAMPlayer::Init(std::string licenseKey, std::string url) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
_licenseKey = licenseKey;
_resWidth = 0;
_resHeight = 0;
engineType = ANSCENTER::CPU;// ANSLicenseHelper::CheckHardwareInformation();
_jpegCompressor = tjInitCompress();
CheckLicense();
if (!_licenseValid) {
_logger.LogError("ANSWEBCAMPlayer::Init.", "Invalid license", __FILE__, __LINE__);
return false;
}
_deviceId = 0; // Default
_cameraNames = ANSCENTER::ANSWEBCAMPlayer::ScanWebcamDevices();
auto it = std::find(_cameraNames.begin(), _cameraNames.end(), url);
if (it != _cameraNames.end()) {
_deviceId = std::distance(_cameraNames.begin(), it);
// Verify if the device can be opened
cv::VideoCapture cap(_deviceId);
if (!cap.isOpened()) {
_logger.LogError("ANSWEBCAMPlayer::Init.", "Unable to open camera with ID: " + std::to_string(_deviceId), __FILE__, __LINE__);
return false;
}
cap.release(); // Close the camera after testing
return Setup();
}
return false;
}
bool ANSWEBCAMPlayer::Setup() {
_previousPTS = 0;
std::lock_guard<std::recursive_mutex> lock(_mutex);
try {
// Open the camera if not already opened
if (!cap.isOpened()) {
cap.open(_deviceId, cv::CAP_DSHOW);
if (!cap.isOpened()) {
cap.open(_deviceId, cv::CAP_ANY);
if (!cap.isOpened()) {
_logger.LogError("ANSWEBCAMPlayer::Setup", "Unable to open camera", __FILE__, __LINE__);
return false;
}
}
}
// Restore saved resolution if available (stop/start cycle)
if (_savedResWidth > 0 && _savedResHeight > 0) {
cap.set(cv::CAP_PROP_FRAME_WIDTH, _savedResWidth);
cap.set(cv::CAP_PROP_FRAME_HEIGHT, _savedResHeight);
int actualWidth = static_cast<int>(cap.get(cv::CAP_PROP_FRAME_WIDTH));
int actualHeight = static_cast<int>(cap.get(cv::CAP_PROP_FRAME_HEIGHT));
_resWidth = actualWidth;
_resHeight = actualHeight;
if (actualWidth != _savedResWidth || actualHeight != _savedResHeight) {
_logger.LogWarn("ANSWEBCAMPlayer::Setup",
"Could not restore saved resolution " + std::to_string(_savedResWidth) + "x" + std::to_string(_savedResHeight) +
". Using: " + std::to_string(actualWidth) + "x" + std::to_string(actualHeight),
__FILE__, __LINE__);
}
else {
_logger.LogDebug("ANSWEBCAMPlayer::Setup",
"Restored saved resolution: " + std::to_string(actualWidth) + "x" + std::to_string(actualHeight),
__FILE__, __LINE__);
}
}
// If resolution is not set or is default, find and set resolution based on mode
else if ((_resWidth == 0) && (_resHeight == 0)) {
if (_enableMaxResolution) {
// Max resolution mode: pick the highest available resolution
if (!SetBestResolution(_deviceId)) {
_resWidth = static_cast<int>(cap.get(cv::CAP_PROP_FRAME_WIDTH));
_resHeight = static_cast<int>(cap.get(cv::CAP_PROP_FRAME_HEIGHT));
_savedResWidth = _resWidth;
_savedResHeight = _resHeight;
_logger.LogWarn("ANSWEBCAMPlayer::Setup",
"Using default camera resolution: " + std::to_string(_resWidth) + "x" + std::to_string(_resHeight),
__FILE__, __LINE__);
}
}
else {
// Default mode: prefer Full HD, fall back to lower resolutions
if (!SetPreferredResolution(_deviceId)) {
_resWidth = static_cast<int>(cap.get(cv::CAP_PROP_FRAME_WIDTH));
_resHeight = static_cast<int>(cap.get(cv::CAP_PROP_FRAME_HEIGHT));
_savedResWidth = _resWidth;
_savedResHeight = _resHeight;
_logger.LogWarn("ANSWEBCAMPlayer::Setup",
"Using default camera resolution: " + std::to_string(_resWidth) + "x" + std::to_string(_resHeight),
__FILE__, __LINE__);
}
}
}
else {
// User has specified a resolution, try to set it
cap.set(cv::CAP_PROP_FRAME_WIDTH, _resWidth);
cap.set(cv::CAP_PROP_FRAME_HEIGHT, _resHeight);
int actualWidth = static_cast<int>(cap.get(cv::CAP_PROP_FRAME_WIDTH));
int actualHeight = static_cast<int>(cap.get(cv::CAP_PROP_FRAME_HEIGHT));
if (actualWidth != _resWidth || actualHeight != _resHeight) {
_logger.LogWarn("ANSWEBCAMPlayer::Setup",
"Requested resolution " + std::to_string(_resWidth) + "x" + std::to_string(_resHeight) +
" not supported. Using: " + std::to_string(actualWidth) + "x" + std::to_string(actualHeight),
__FILE__, __LINE__);
_resWidth = actualWidth;
_resHeight = actualHeight;
}
_savedResWidth = _resWidth;
_savedResHeight = _resHeight;
}
// Set additional camera properties for better quality
cap.set(cv::CAP_PROP_FPS, 30); // Try to set 30 FPS
cap.set(cv::CAP_PROP_BUFFERSIZE, 1); // Reduce buffer size for lower latency
_logger.LogDebug("ANSWEBCAMPlayer::Setup",
"Camera setup complete. Resolution: " + std::to_string(_resWidth) + "x" + std::to_string(_resHeight),
__FILE__, __LINE__);
return true;
}
catch (std::exception& e) {
this->_logger.LogError("ANSWEBCAMPlayer::Setup:", e.what(), __FILE__, __LINE__);
return false;
}
}
bool ANSWEBCAMPlayer::Reconnect() {
std::lock_guard<std::recursive_mutex> lock(_mutex);
try {
if (cap.isOpened()) {
cap.release();
}
Setup();
_isPlaying = cap.isOpened() && cap.grab();
return _isPlaying;
}
catch (const std::exception& e) {
this->_logger.LogError("ANSWEBCAMPlayer::Reconnect. Exception:", e.what(), __FILE__, __LINE__);
return false;
}
}
bool ANSWEBCAMPlayer::Start() {
std::lock_guard<std::recursive_mutex> lock(_mutex);
try {
if (!cap.isOpened()) {
// Reopen the camera (after Stop released it)
cap.open(_deviceId, cv::CAP_DSHOW);
if (!cap.isOpened()) {
cap.open(_deviceId, cv::CAP_ANY);
if (!cap.isOpened()) {
_logger.LogError("ANSWEBCAMPlayer::Start", "Unable to open camera", __FILE__, __LINE__);
return false;
}
}
}
// Restore saved resolution
if (_savedResWidth > 0 && _savedResHeight > 0) {
cap.set(cv::CAP_PROP_FRAME_WIDTH, _savedResWidth);
cap.set(cv::CAP_PROP_FRAME_HEIGHT, _savedResHeight);
int actualWidth = static_cast<int>(cap.get(cv::CAP_PROP_FRAME_WIDTH));
int actualHeight = static_cast<int>(cap.get(cv::CAP_PROP_FRAME_HEIGHT));
_resWidth = actualWidth;
_resHeight = actualHeight;
_logger.LogDebug("ANSWEBCAMPlayer::Start",
"Restored resolution: " + std::to_string(actualWidth) + "x" + std::to_string(actualHeight),
__FILE__, __LINE__);
}
// Set camera properties
cap.set(cv::CAP_PROP_FPS, 30);
cap.set(cv::CAP_PROP_BUFFERSIZE, 1);
_isPlaying = cap.isOpened() && cap.grab();
return _isPlaying;
}
catch (const std::exception& e) {
this->_logger.LogError("ANSWEBCAMPlayer::Start. Exception:", e.what(), __FILE__, __LINE__);
return false;
}
}
bool ANSWEBCAMPlayer::Stop() {
std::lock_guard<std::recursive_mutex> lock(_mutex);
try {
_isPlaying = false;
// Save current resolution before releasing camera
if (_resWidth > 0 && _resHeight > 0) {
_savedResWidth = _resWidth;
_savedResHeight = _resHeight;
}
// Actually release the camera so the device is freed
if (cap.isOpened()) {
cap.release();
}
_logger.LogDebug("ANSWEBCAMPlayer::Stop",
"Camera stopped. Saved resolution: " + std::to_string(_savedResWidth) + "x" + std::to_string(_savedResHeight),
__FILE__, __LINE__);
return true;
}
catch (const std::exception& e) {
this->_logger.LogError("ANSWEBCAMPlayer::Stop. Exception:", e.what(), __FILE__, __LINE__);
return false;
}
}
void ANSWEBCAMPlayer::SetBBox(cv::Rect bbox) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
_bbox = bbox;
}
void ANSWEBCAMPlayer::SetCrop(bool crop) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
_crop = crop;
}
bool ANSWEBCAMPlayer::IsPaused() {
std::lock_guard<std::recursive_mutex> lock(_mutex);
return !cap.isOpened();
}
bool ANSWEBCAMPlayer::IsPlaying() {
std::lock_guard<std::recursive_mutex> lock(_mutex);
return cap.isOpened();
}
bool ANSWEBCAMPlayer::IsRecording() {
std::lock_guard<std::recursive_mutex> lock(_mutex);
return false;// do not support recording for webcam
}
//cv::Mat ANSWEBCAMPlayer::GetImage(int& width, int& height, int64_t& pts) {
// std::lock_guard<std::recursive_mutex> lock(_mutex);
// if (!_isPlaying) {
// if (!_previousImage.empty()) {
// width = _previousImage.cols;
// height = _previousImage.rows;
// pts = _previousPTS;
// return _previousImage; // Avoid unnecessary cloning
// }
// return cv::Mat();
// }
// cv::Mat frame, result;
// try {
// if (!cap.isOpened()) {
// if (!_previousImage.empty()) {
// width = _previousImage.cols;
// height = _previousImage.rows;
// pts = _previousPTS;
// return _previousImage; // Avoid unnecessary cloning
// }
// return cv::Mat();
// }
// if (!cap.read(frame) || frame.empty()) {
// return cv::Mat();
// }
// if (_crop) {
// // Ensure valid crop region
// _bbox.x = max(0, _bbox.x);
// _bbox.y = max(0, _bbox.y);
// _bbox.width = min(_bbox.width, frame.cols - _bbox.x);
// _bbox.height = min(_bbox.height, frame.rows - _bbox.y);
// cv::Rect roi = _bbox; // Define roi after updating _bbox
// if (roi.width > 0 && roi.height > 0) {
// result = frame(roi);
// }
// else {
// result = frame;
// }
// }
// else {
// result = frame;
// }
// if (_imageRotateDeg > 0) {
// cv::Point2f center(result.cols / 2.0f, result.rows / 2.0f);
// cv::Mat rotationMatrix = cv::getRotationMatrix2D(center, _imageRotateDeg, 1.0);
// cv::warpAffine(result, result, rotationMatrix, result.size(), cv::INTER_CUBIC, cv::BORDER_CONSTANT, cv::Scalar());
// }
// if (_previousPTS < INT64_MAX) {
// _previousPTS++;
// }
// else {
// _previousPTS = 0; // Reset to zero when max is reached
// }
// width = result.cols;
// height = result.rows;
// pts = _previousPTS;
// _previousImage = result; // Store reference instead of clone
// return _previousImage;
// }
// catch (const std::exception& e) {
// this->_logger.LogError("ANSWEBCAMPlayer::GetImage. Exception occurred:", e.what(), __FILE__, __LINE__);
// }
// return cv::Mat();
//}
cv::Mat ANSWEBCAMPlayer::GetImage(int& width, int& height, int64_t& pts) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
if (!_isPlaying) {
if (!_previousImage.empty()) {
width = _previousImage.cols;
height = _previousImage.rows;
pts = _previousPTS;
return _previousImage;
}
return cv::Mat();
}
try {
if (!cap.isOpened()) {
if (!_previousImage.empty()) {
width = _previousImage.cols;
height = _previousImage.rows;
pts = _previousPTS;
return _previousImage;
}
return cv::Mat();
}
cv::Mat frame;
if (!cap.read(frame) || frame.empty()) {
// Return last good frame if available
if (!_previousImage.empty()) {
width = _previousImage.cols;
height = _previousImage.rows;
pts = _previousPTS;
return _previousImage;
}
return cv::Mat();
}
cv::Mat result;
// Apply cropping if enabled
if (_crop) {
// Validate and clamp crop region
_bbox.x = max(0, _bbox.x);
_bbox.y = max(0, _bbox.y);
_bbox.width = min(_bbox.width, frame.cols - _bbox.x);
_bbox.height = min(_bbox.height, frame.rows - _bbox.y);
if (_bbox.width > 0 && _bbox.height > 0) {
// CRITICAL: Clone to avoid dangling reference
result = frame(_bbox).clone();
}
else {
result = frame.clone();
}
}
else {
result = frame.clone();
}
// Apply rotation if specified
if (_imageRotateDeg > 0) {
// Fast path for 90-degree rotations
if (std::abs(_imageRotateDeg - 90.0) < 0.01) {
cv::rotate(result, result, cv::ROTATE_90_CLOCKWISE);
}
else if (std::abs(_imageRotateDeg - 180.0) < 0.01) {
cv::rotate(result, result, cv::ROTATE_180);
}
else if (std::abs(_imageRotateDeg - 270.0) < 0.01) {
cv::rotate(result, result, cv::ROTATE_90_COUNTERCLOCKWISE);
}
else {
// Arbitrary angle rotation
const cv::Point2f center(result.cols / 2.0f, result.rows / 2.0f);
cv::Mat rotationMatrix = cv::getRotationMatrix2D(center, _imageRotateDeg, 1.0);
cv::Mat rotated;
// Use INTER_LINEAR instead of INTER_CUBIC (2-3x faster)
cv::warpAffine(result, rotated, rotationMatrix, result.size(),
cv::INTER_LINEAR, cv::BORDER_CONSTANT, cv::Scalar());
result = rotated;
}
}
// Update PTS
if (_previousPTS < INT64_MAX) {
_previousPTS++;
}
else {
_previousPTS = 0;
}
// Store full-res frame for inference (before display resize)
_inferenceImage = result;
// Resize for display if display resolution is set
if (_displayWidth > 0 && _displayHeight > 0 &&
(result.cols != _displayWidth || result.rows != _displayHeight)) {
cv::Mat displayResult;
cv::resize(result, displayResult, cv::Size(_displayWidth, _displayHeight),
0, 0, cv::INTER_LINEAR);
result = displayResult;
}
// Update cached frame
_previousImage = result;
// Set output parameters
width = result.cols;
height = result.rows;
pts = _previousPTS;
return result;
}
catch (const cv::Exception& e) {
this->_logger.LogError("ANSWEBCAMPlayer::GetImage. OpenCV exception:", e.what(), __FILE__, __LINE__);
}
catch (const std::exception& e) {
this->_logger.LogError("ANSWEBCAMPlayer::GetImage. Exception:", e.what(), __FILE__, __LINE__);
}
catch (...) {
this->_logger.LogError("ANSWEBCAMPlayer::GetImage. Unknown exception", "", __FILE__, __LINE__);
}
return cv::Mat();
}
cv::Mat ANSWEBCAMPlayer::GetInferenceImage() {
std::lock_guard<std::recursive_mutex> lock(_mutex);
return _inferenceImage;
}
void ANSWEBCAMPlayer::SetDisplayResolution(int width, int height) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
_displayWidth = width;
_displayHeight = height;
}
void ANSWEBCAMPlayer::EnableAudio(bool status) {
// please support audio enable for webcam
}
void ANSWEBCAMPlayer::SetAudioVolume(int volume) {
// support audio volumne
}
std::string ANSWEBCAMPlayer::VectorToCommaSeparatedString(const std::vector<std::string>& inputVector) {
std::string result;
for (size_t i = 0; i < inputVector.size(); ++i) {
result += inputVector[i];
if (i < inputVector.size() - 1) {
result += ";";
}
}
return result;
}
void ANSWEBCAMPlayer::uploadPlanarBGRToGPU(const cv::Mat& inputMat, unsigned char** data) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
try {
int width = inputMat.cols;
int height = inputMat.rows;
size_t channelSize = 3 * width * height;
// Allocate GPU memory for each channel
CHECK_CUDAWEB(cudaMalloc(data, channelSize));
// Copy each channel to GPU
CHECK_CUDAWEB(cudaMemcpy(*data, inputMat.data, channelSize, cudaMemcpyHostToDevice));
}
catch (const std::exception& e) {
this->_logger.LogError("ANSWEBCAMPlayer::uploadPlanarBGRToGPU. Exception occurred:", e.what(), __FILE__, __LINE__);
}
}
std::string ANSWEBCAMPlayer::encodeMatToJpegWithNvJPEG(const cv::Mat& inputMat, int quality)
{
std::lock_guard<std::recursive_mutex> lock(_mutex);
try {
// Image dimensions
int width = inputMat.cols;
int height = inputMat.rows;
// Device memory for planar BGR
unsigned char* data = nullptr;
uploadPlanarBGRToGPU(inputMat, &data);
CHECK_NVJPEGWEB(nvjpegEncoderParamsSetSamplingFactors(nv_enc_params, NVJPEG_CSS_444, stream));
// Set JPEG encoding parameters
CHECK_NVJPEGWEB(nvjpegEncoderParamsSetQuality(nv_enc_params, quality, stream));
CHECK_NVJPEGWEB(nvjpegEncoderParamsSetOptimizedHuffman(nv_enc_params, 1, stream));
// Configure nvjpegImage_t for planar BGR
nvjpegImage_t nv_image = {};
nv_image.channel[0] = data;
nv_image.pitch[0] = 3 * width; // Red pitch
// Compress the image using nvJPEG
CHECK_NVJPEGWEB(nvjpegEncodeImage(nv_handle, nv_enc_state, nv_enc_params,
&nv_image, NVJPEG_INPUT_BGRI, width, height, stream));
// Get compressed JPEG size
size_t length;
CHECK_NVJPEGWEB(nvjpegEncodeRetrieveBitstream(nv_handle, nv_enc_state, nullptr, &length, stream));
// Retrieve the JPEG bitstream
std::vector<unsigned char> jpegBuffer(length);
CHECK_NVJPEGWEB(nvjpegEncodeRetrieveBitstream(nv_handle, nv_enc_state, jpegBuffer.data(), &length, stream));
// Synchronize CUDA stream
CHECK_CUDAWEB(cudaStreamSynchronize(stream));
// convert to string
std::string jpegString(reinterpret_cast<char*>(jpegBuffer.data()), length);
// Cleanup
CHECK_CUDAWEB(cudaFree(data));
return jpegString;
}
catch (const std::exception& e) {
this->_logger.LogError("ANSWEBCAMPlayer::encodeMatToJpegWithNvJPEG. Exception occurred:", e.what(), __FILE__, __LINE__);
return _lastJpegImage;
}
}
std::string ANSWEBCAMPlayer::encodeJpegString(const cv::Mat& img, int quality) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
if (!_isPlaying) return _lastJpegImage;
try {
unsigned char* jpegBuf = nullptr;
if (!_jpegCompressor) {
this->_logger.LogError("ANSWEBCAMPlayer::encodeJpegString. Failed to initialize TurboJPEG compressor.", tjGetErrorStr(), __FILE__, __LINE__);
return _lastJpegImage;
}
int maxBufferSize = img.cols * img.rows * 3;
jpegBuf = new unsigned char[maxBufferSize]; // Pre-allocated buffer
long unsigned int jpegSize = maxBufferSize; // Size of the JPEG image (output)
int subsamp = TJSAMP_444; // Chroma subsampling: TJSAMP_444, TJSAMP_422, TJSAMP_420, etc.
int pixelFormat = img.channels() == 3 ? TJPF_BGR : TJPF_GRAY; // Pixel format based on channels
try {
// Compress the image into the pre-allocated buffer
int result = tjCompress2(_jpegCompressor, img.data, img.cols, 0, img.rows, pixelFormat,
&jpegBuf, &jpegSize, subsamp, quality, TJFLAG_FASTDCT);
// Handle compression errors
if (result != 0) {
this->_logger.LogError("ANSWEBCAMPlayer::encodeJpegString. Compression error:", tjGetErrorStr(), __FILE__, __LINE__);
if (jpegBuf) {
tjFree(jpegBuf); // Free the buffer if allocated
}
return _lastJpegImage;
}
// Create a string from the JPEG buffer
std::string jpegString(reinterpret_cast<char*>(jpegBuf), jpegSize);
_lastJpegImage = jpegString;
// Clean up resources
tjFree(jpegBuf);
return jpegString;
}
catch (const std::exception& e) {
this->_logger.LogError("ANSWEBCAMPlayer::encodeJpegString. Exception occurred:", e.what(), __FILE__, __LINE__);
// Clean up resources
if (jpegBuf) {
tjFree(jpegBuf); // Free the buffer if allocated
}
return _lastJpegImage;
}
}
catch (std::exception& e) {
this->_logger.LogError("ANSWEBCAMPlayer::encodeJpegString:", e.what(), __FILE__, __LINE__);
// Clean up resources in case of an exception
}
// Return an empty string in case of failure
return "";
}
std::string ANSWEBCAMPlayer::MatToBinaryData(const cv::Mat& image) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
if (!_isPlaying) return _lastJpegImage;
// Check if the image is empty or has invalid data
if (image.empty() || !image.data || !image.u) {
return _lastJpegImage;
}
try {
// Encode the image to a memory buffer
return encodeJpegString(image, 85);
}
catch (const std::exception& e) {
this->_logger.LogFatal("ANSWEBCAMPlayer::MatToBinaryData. Exception occurred:", e.what(), __FILE__, __LINE__);
}
catch (...) {
this->_logger.LogFatal("ANSWEBCAMPlayer::MatToBinaryData.", "Unknown exception occurred.", __FILE__, __LINE__);
}
// Return an empty string in case of failure
return _lastJpegImage;
}
std::string ANSWEBCAMPlayer::GetJpegStringImage(int& width, int& height, int64_t& pts) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
if (!_isPlaying) return _lastJpegImage;
try {
cv::Mat image = GetImage(width, height, pts);
std::string jpegString = MatToBinaryData(image);
image.release();
return jpegString;
}
catch (const std::exception& e) {
this->_logger.LogError("ANSWEBCAMPlayer::GetJpegStringImage. Exception occurred:", e.what(), __FILE__, __LINE__);
return _lastJpegImage;
}
}
}
extern "C" __declspec(dllexport) int CreateANSWebcamPlayerHandle(ANSCENTER::ANSWEBCAMPlayer * *Handle, const char* licenseKey, const char* url) {
if (!Handle || !licenseKey || !url) return -1;
try {
auto ptr = std::make_unique<ANSCENTER::ANSWEBCAMPlayer>();
bool result = ptr->Init(licenseKey, url);
if (result) {
*Handle = ptr.release();
extern void anscv_unregister_handle(void*);
extern void anscv_register_handle(void*, void(*)(void*));
anscv_register_handle(*Handle, [](void* p) {
auto* h = static_cast<ANSCENTER::ANSWEBCAMPlayer*>(p);
try { h->Stop(); } catch (...) {}
try { h->Destroy(); } catch (...) {}
try { delete h; } catch (...) {}
});
return 1;
}
*Handle = nullptr;
return 0;
}
catch (...) { return 0; }
}
extern "C" __declspec(dllexport) int CreateANSWebcamPlayerWithMaxResoHandle(ANSCENTER::ANSWEBCAMPlayer * *Handle, const char* licenseKey, const char* url) {
if (!Handle || !licenseKey || !url) return -1;
try {
auto ptr = std::make_unique<ANSCENTER::ANSWEBCAMPlayer>();
ptr->SetEnableMaxResolution(true);
bool result = ptr->Init(licenseKey, url);
if (result) {
*Handle = ptr.release();
extern void anscv_unregister_handle(void*);
extern void anscv_register_handle(void*, void(*)(void*));
anscv_register_handle(*Handle, [](void* p) {
auto* h = static_cast<ANSCENTER::ANSWEBCAMPlayer*>(p);
try { h->Stop(); } catch (...) {}
try { h->Destroy(); } catch (...) {}
try { delete h; } catch (...) {}
});
return 1;
}
*Handle = nullptr;
return 0;
}
catch (const std::exception& e) {
std::cerr << "CreateANSWebcamPlayerWithMaxResoHandle - Exception: " << e.what() << std::endl;
if (Handle) *Handle = nullptr;
return 0;
}
catch (...) {
if (Handle) *Handle = nullptr;
return 0;
}
}
extern "C" __declspec(dllexport) int ReleaseANSWebcamPlayerHandle(ANSCENTER::ANSWEBCAMPlayer * *Handle) {
if (Handle == nullptr || *Handle == nullptr) return -1;
try {
extern void anscv_unregister_handle(void*);
anscv_unregister_handle(*Handle);
// Destructor calls Destroy() — no need to call it explicitly (avoids double-destroy)
std::unique_ptr<ANSCENTER::ANSWEBCAMPlayer> ptr(*Handle);
*Handle = nullptr;
return 0;
}
catch (...) {
if (Handle) *Handle = nullptr;
return 0;
}
}
extern "C" __declspec(dllexport) int ScanStrANSWebcamPlayer(std::vector<std::string> &cameraNameList) {
try {
cameraNameList = ANSCENTER::ANSWEBCAMPlayer::ScanWebcamDevices();
int result = 0;
if (cameraNameList.empty()) {
if (cameraNameList.size() > 0) return 1;
}
return result;
}
catch (std::exception& e) {
std::cout << "ScanStrANSWebcamPlayer - Exception: " << e.what() << std::endl;
return 0;
}
}
extern "C" __declspec(dllexport) int ScanANSWebcamPlayer(LStrHandle cameraNames) {
try {
std::vector<std::string> cameraNameList = ANSCENTER::ANSWEBCAMPlayer::ScanWebcamDevices();
std::string st = ANSCENTER::ANSWEBCAMPlayer::VectorToCommaSeparatedString(cameraNameList);
int size = st.length();
if (size > 0) {
MgErr error;
error = DSSetHandleSize(cameraNames, sizeof(int32) + size * sizeof(uChar));
if (error != mFullErr && error != mZoneErr)
{
(*cameraNames)->cnt = size;
memcpy((*cameraNames)->str, st.c_str(), size);
return 1;
}
else return 0;
}
else return 0;
}
catch (std::exception& e) {
std::cout << "ScanANSWebcamPlayer - Exception: " << e.what() << std::endl;
return 0;
}
}
extern "C" __declspec(dllexport) int GetWebcamStrImage(ANSCENTER::ANSWEBCAMPlayer * *Handle, int& width, int& height, int64_t & timeStamp, std::string & jpegImage) {
if (Handle == nullptr || *Handle == nullptr) return -1;
try {
jpegImage = (*Handle)->GetJpegStringImage(width, height, timeStamp);
if (!jpegImage.empty()) return 1;
else return 0;
}
catch (std::exception& e) {
std::cout << "GetWebcamStrImage - Exception: " << e.what() << std::endl;
return -1;
}
catch (...) {
return -1;
}
}
extern "C" __declspec(dllexport) int GetWebcamImage(ANSCENTER::ANSWEBCAMPlayer * *Handle, int& width, int& height, int64_t & timeStamp, LStrHandle jpegImage) {
if (Handle == nullptr || *Handle == nullptr) return -1;
try {
std::string jpegString = (*Handle)->GetJpegStringImage(width, height, timeStamp);
int size = jpegString.length();
if (size > 0) {
MgErr error;
error = DSSetHandleSize(jpegImage, sizeof(int32) + size * sizeof(uChar));
if (error != mFullErr && error != mZoneErr)
{
(*jpegImage)->cnt = size;
memcpy((*jpegImage)->str, jpegString.c_str(), size);
return 1;
}
else return 0;
}
else return 0;
}
catch (std::exception& e) {
std::cout << "GetWebcamImage - Exception: " << e.what() << std::endl;
return -1;
}
catch (...) {
return -1;
}
}
//extern "C" __declspec(dllexport) int GetWebcamCVImage(ANSCENTER::ANSWEBCAMPlayer** Handle, int& width, int& height, int64_t& timeStamp, cv::Mat** image) {
// if (!Handle || !(*Handle) || !image) {
// std::cerr << "Error: Invalid input parameters in GetRTSPCVImage." << std::endl;
// return -1; // Error code for invalid parameters
// }
// try {
// cv::Mat img = (*Handle)->GetImage(width, height, timeStamp);
// std::lock_guard<std::mutex> lock(webcamMutex); // Ensures thread safety
// if (img.empty()) {
// return 0; // No valid image retrieved
// }
// // If an image is already allocated, release it
// if (*image) {
// delete* image;
// *image = nullptr;
// }
//
// // Allocate new image
// *image = new cv::Mat(std::move(img)); // Move constructor avoids deep copy
//
// return 1; // Success
// }
// catch (const std::exception& e) {
// std::cerr << "Exception in GetRTSPCVImage: " << e.what() << std::endl;
// return -2; // Error code for exceptions
// }
// catch (...) {
// std::cerr << "Exception in GetRTSPCVImage: Unknown exception." << std::endl;
// return -2; // Generic error code for exceptions
// }
//}
extern "C" __declspec(dllexport) int GetWebcamCVImage(
ANSCENTER::ANSWEBCAMPlayer** Handle,
int& width,
int& height,
int64_t& timeStamp,
cv::Mat** image)
{
// Validate input parameters
if (!Handle || !*Handle || !image) {
std::cerr << "Error: Invalid input parameters in GetWebcamCVImage" << std::endl;
return -1;
}
try {
// Get image (display-res if SetDisplayResolution was called, otherwise original)
cv::Mat img = (*Handle)->GetImage(width, height, timeStamp);
if (img.empty()) {
return 0; // No valid image retrieved
}
// anscv_mat_replace has its own internal registry_mutex — no global mutex needed
anscv_mat_replace(image, std::move(img));
// Attach full-res BGR frame to ANSGpuFrameRegistry for inference fast-path.
// ANSRTYOLO::DetectObjects will find this via gpu_frame_lookup and use the
// full-res image for inference instead of the display-res input.
cv::Mat infImg = (*Handle)->GetInferenceImage();
if (!infImg.empty() && infImg.data != (*image)->data) {
(*Handle)->_inferenceClonePrev = (*Handle)->_inferenceCloneCurr;
(*Handle)->_inferenceCloneCurr = infImg.clone();
GpuFrameData data{};
data.avframe = nullptr;
data.yPlane = (*Handle)->_inferenceCloneCurr.data;
data.uvPlane = nullptr;
data.yLinesize = static_cast<int>((*Handle)->_inferenceCloneCurr.step[0]);
data.uvLinesize = 0;
data.width = (*Handle)->_inferenceCloneCurr.cols;
data.height = (*Handle)->_inferenceCloneCurr.rows;
data.pixelFormat = ANSCV_PIX_FMT_BGR24;
data.gpuIndex = -1;
data.pts = timeStamp;
data.isCudaDevicePtr = false;
data.cpuAvframe = nullptr;
data.cpuYPlane = nullptr;
data.cpuUvPlane = nullptr;
data.cpuYLinesize = 0;
data.cpuUvLinesize = 0;
ANSGpuFrameRegistry::instance().attach(*image, std::move(data));
auto pending = ANSGpuFrameRegistry::instance().drain_pending();
for (void* p : pending) {
// pending only contains AVFrame* from RTSP/RTMP/SRT/FLV entries (our entries have avframe=nullptr)
auto* stale = static_cast<AVFrame*>(p);
av_frame_free(&stale);
}
}
return 1; // Success
}
catch (const cv::Exception& e) {
std::cerr << "OpenCV exception in GetWebcamCVImage: " << e.what() << std::endl;
return -2;
}
catch (const std::exception& e) {
std::cerr << "Exception in GetWebcamCVImage: " << e.what() << std::endl;
return -2;
}
catch (...) {
std::cerr << "Unknown exception in GetWebcamCVImage" << std::endl;
return -2;
}
}
extern "C" __declspec(dllexport) int StartWebcamPlayer(ANSCENTER::ANSWEBCAMPlayer * *Handle) {
if (Handle == nullptr || *Handle == nullptr) return -1;
try {
bool result = (*Handle)->Start();
if (result) return 1;
else return 0;
}
catch (std::exception& e) {
std::cout << "StartWebcamPlayer - Exception: " << e.what() << std::endl;
return -1;
}
catch (...) {
return -1;
}
}
extern "C" __declspec(dllexport) int ReconnectWebcamPlayer(ANSCENTER::ANSWEBCAMPlayer * *Handle) {
if (Handle == nullptr || *Handle == nullptr) return -1;
try {
bool result = (*Handle)->Reconnect();
if (result) return 1;
else return 0;
}
catch (std::exception& e) {
std::cout << "ReconnectWebcamPlayer - Exception: " << e.what() << std::endl;
return -1;
}
catch (...) {
return -1;
}
}
extern "C" __declspec(dllexport) int StopWebcamPlayer(ANSCENTER::ANSWEBCAMPlayer * *Handle) {
if (Handle == nullptr || *Handle == nullptr) return -1;
try {
bool result = (*Handle)->Stop();
if (result) return 1;
else return 0;
}
catch (std::exception& e) {
std::cout << "StopWebcamPlayer - Exception: " << e.what() << std::endl;
return -1;
}
catch (...) {
return -1;
}
}
extern "C" __declspec(dllexport) int IsWebcamPlayerPaused(ANSCENTER::ANSWEBCAMPlayer * *Handle) {
if (Handle == nullptr || *Handle == nullptr) return -1;
try {
bool result = (*Handle)->IsPaused();
if (result) return 1;
else return 0;
}
catch (std::exception& e) {
std::cout << "IsWebcamPlayerPaused - Exception: " << e.what() << std::endl;
return -1;
}
catch (...) {
return -1;
}
}
extern "C" __declspec(dllexport) int IsWebcamPlayerRunning(ANSCENTER::ANSWEBCAMPlayer * *Handle) {
if (Handle == nullptr || *Handle == nullptr) return -1;
try {
bool result = (*Handle)->IsPlaying();
if (result) return 1;
else return 0;
}
catch (std::exception& e) {
std::cout << "IsWebcamPlayerRunning - Exception: " << e.what() << std::endl;
return -1;
}
catch (...) {
return -1;
}
}
extern "C" __declspec(dllexport) int IsWebcamPlayerRecording(ANSCENTER::ANSWEBCAMPlayer * *Handle) {
if (Handle == nullptr || *Handle == nullptr) return -1;
try {
bool result = (*Handle)->IsRecording();
if (result) return 1;
else return 0;
}
catch (std::exception& e) {
std::cout << "IsWebcamPlayerRecording - Exception: " << e.what() << std::endl;
return -1;
}
catch (...) {
return -1;
}
}
extern "C" __declspec(dllexport) void SetWebcamPlayerAudioVolume(ANSCENTER::ANSWEBCAMPlayer * *Handle, int volume)
{
if (Handle == nullptr || *Handle == nullptr) return;
try {
(*Handle)->SetAudioVolume(volume);
}
catch (...) { }
}
extern "C" __declspec(dllexport) void EnableWebcamPlayerAudioVolume(ANSCENTER::ANSWEBCAMPlayer * *Handle, int status)
{
if (Handle == nullptr || *Handle == nullptr) return;
try {
bool audioStatus = false;
if (status == 1)audioStatus = true;
(*Handle)->EnableAudio(audioStatus);
}
catch (std::exception& e) {
std::cout << "EnableWebcamPlayerAudioVolume - Exception: " << e.what() << std::endl;
}
catch (...) { }
}
extern "C" __declspec(dllexport) void SetWebcamImageRotation(ANSCENTER::ANSWEBCAMPlayer * *Handle, double rotationAngle) {
if (Handle == nullptr || *Handle == nullptr) return;
try {
(*Handle)->SetImageRotate(rotationAngle);
}
catch (...) { }
}
extern "C" __declspec(dllexport) int ScanSupportedResolutions(std::string cameraName, std::vector<std::string> cameraNameList, std::string & supportedResolution) {
try {
for (size_t i = 0; i < cameraNameList.size(); ++i) {
if (cameraNameList.at(i) == cameraName) {
supportedResolution = ANSCENTER::ANSWEBCAMPlayer::GetSupportedResolutions(i);
if (!supportedResolution.empty()) return 1;
else return 0;
}
}
return 0;
}
catch (std::exception& e) {
std::cout << "ScanSupportedResolutions - Exception: " << e.what() << std::endl;
return 0;
}
catch (...) { return 0; }
}
extern "C" __declspec(dllexport) int SetBBoxANSWebcamPlayer(ANSCENTER::ANSWEBCAMPlayer** Handle, int x, int y, int width, int height) {
if (Handle == nullptr || *Handle == nullptr) return -1;
try {
cv::Rect bbox(x, y, width, height);
(*Handle)->SetBBox(bbox);
return 1;
}
catch (std::exception& e) {
std::cout << "SetBBoxANSWebcamPlayer - Exception: " << e.what() << std::endl;
return -1;
}
catch (...) {
return -1;
}
}
extern "C" __declspec(dllexport) int SetCropFlagANSWebcamPlayer(ANSCENTER::ANSWEBCAMPlayer** Handle, int cropFlag) {
if (Handle == nullptr || *Handle == nullptr) return -1;
try {
bool crop = false;
if (cropFlag == 1)crop = true;
(*Handle)->SetCrop(crop);
return 1;
}
catch (std::exception& e) {
std::cout << "SetCropFlagANSWebcamPlayer - Exception: " << e.what() << std::endl;
return -1;
}
catch (...) {
return -1;
}
}
extern "C" __declspec(dllexport) void SetWebcamDisplayResolution(ANSCENTER::ANSWEBCAMPlayer** Handle, int width, int height) {
if (Handle == nullptr || *Handle == nullptr) return;
try {
(*Handle)->SetDisplayResolution(width, height);
} catch (...) { }
}
// ============================================================================
// V2 entry points — accept uint64_t handle by value (LabVIEW safe)
// ============================================================================
extern "C" __declspec(dllexport) int GetWebcamImage_V2(uint64_t handleVal, int& width, int& height, int64_t& timeStamp, LStrHandle jpegImage) {
auto* h = reinterpret_cast<ANSCENTER::ANSWEBCAMPlayer*>(handleVal);
if (!h) return -1;
try {
std::string jpegString = h->GetJpegStringImage(width, height, timeStamp);
int size = jpegString.length();
if (size > 0) {
MgErr error;
error = DSSetHandleSize(jpegImage, sizeof(int32) + size * sizeof(uChar));
if (error != mFullErr && error != mZoneErr)
{
(*jpegImage)->cnt = size;
memcpy((*jpegImage)->str, jpegString.c_str(), size);
return 1;
}
else return 0;
}
else return 0;
}
catch (std::exception& e) {
std::cout << "GetWebcamImage_V2 - Exception: " << e.what() << std::endl;
return -1;
}
catch (...) {
return -1;
}
}
extern "C" __declspec(dllexport) int GetWebcamCVImage_V2(
uint64_t handleVal,
int& width,
int& height,
int64_t& timeStamp,
cv::Mat** image)
{
auto* h = reinterpret_cast<ANSCENTER::ANSWEBCAMPlayer*>(handleVal);
if (!h || !image) return -1;
try {
cv::Mat img = h->GetImage(width, height, timeStamp);
if (img.empty()) {
return 0;
}
anscv_mat_replace(image, std::move(img));
// Attach full-res BGR frame to ANSGpuFrameRegistry for inference fast-path
cv::Mat infImg = h->GetInferenceImage();
if (!infImg.empty() && infImg.data != (*image)->data) {
h->_inferenceClonePrev = h->_inferenceCloneCurr;
h->_inferenceCloneCurr = infImg.clone();
GpuFrameData data{};
data.avframe = nullptr;
data.yPlane = h->_inferenceCloneCurr.data;
data.uvPlane = nullptr;
data.yLinesize = static_cast<int>(h->_inferenceCloneCurr.step[0]);
data.uvLinesize = 0;
data.width = h->_inferenceCloneCurr.cols;
data.height = h->_inferenceCloneCurr.rows;
data.pixelFormat = ANSCV_PIX_FMT_BGR24;
data.gpuIndex = -1;
data.pts = timeStamp;
data.isCudaDevicePtr = false;
data.cpuAvframe = nullptr;
data.cpuYPlane = nullptr;
data.cpuUvPlane = nullptr;
data.cpuYLinesize = 0;
data.cpuUvLinesize = 0;
ANSGpuFrameRegistry::instance().attach(*image, std::move(data));
auto pending = ANSGpuFrameRegistry::instance().drain_pending();
for (void* p : pending) {
auto* stale = static_cast<AVFrame*>(p);
av_frame_free(&stale);
}
}
return 1;
}
catch (const cv::Exception& e) {
std::cerr << "OpenCV exception in GetWebcamCVImage_V2: " << e.what() << std::endl;
return -2;
}
catch (const std::exception& e) {
std::cerr << "Exception in GetWebcamCVImage_V2: " << e.what() << std::endl;
return -2;
}
catch (...) {
std::cerr << "Unknown exception in GetWebcamCVImage_V2" << std::endl;
return -2;
}
}
extern "C" __declspec(dllexport) int StartWebcamPlayer_V2(uint64_t handleVal) {
auto* h = reinterpret_cast<ANSCENTER::ANSWEBCAMPlayer*>(handleVal);
if (!h) return -1;
try {
bool result = h->Start();
if (result) return 1;
else return 0;
}
catch (std::exception& e) {
std::cout << "StartWebcamPlayer_V2 - Exception: " << e.what() << std::endl;
return -1;
}
catch (...) {
return -1;
}
}
extern "C" __declspec(dllexport) int ReconnectWebcamPlayer_V2(uint64_t handleVal) {
auto* h = reinterpret_cast<ANSCENTER::ANSWEBCAMPlayer*>(handleVal);
if (!h) return -1;
try {
bool result = h->Reconnect();
if (result) return 1;
else return 0;
}
catch (std::exception& e) {
std::cout << "ReconnectWebcamPlayer_V2 - Exception: " << e.what() << std::endl;
return -1;
}
catch (...) {
return -1;
}
}
extern "C" __declspec(dllexport) int StopWebcamPlayer_V2(uint64_t handleVal) {
auto* h = reinterpret_cast<ANSCENTER::ANSWEBCAMPlayer*>(handleVal);
if (!h) return -1;
try {
bool result = h->Stop();
if (result) return 1;
else return 0;
}
catch (std::exception& e) {
std::cout << "StopWebcamPlayer_V2 - Exception: " << e.what() << std::endl;
return -1;
}
catch (...) {
return -1;
}
}
extern "C" __declspec(dllexport) int IsWebcamPlayerPaused_V2(uint64_t handleVal) {
auto* h = reinterpret_cast<ANSCENTER::ANSWEBCAMPlayer*>(handleVal);
if (!h) return -1;
try {
bool result = h->IsPaused();
if (result) return 1;
else return 0;
}
catch (std::exception& e) {
std::cout << "IsWebcamPlayerPaused_V2 - Exception: " << e.what() << std::endl;
return -1;
}
catch (...) {
return -1;
}
}
extern "C" __declspec(dllexport) int IsWebcamPlayerRunning_V2(uint64_t handleVal) {
auto* h = reinterpret_cast<ANSCENTER::ANSWEBCAMPlayer*>(handleVal);
if (!h) return -1;
try {
bool result = h->IsPlaying();
if (result) return 1;
else return 0;
}
catch (std::exception& e) {
std::cout << "IsWebcamPlayerRunning_V2 - Exception: " << e.what() << std::endl;
return -1;
}
catch (...) {
return -1;
}
}
extern "C" __declspec(dllexport) int IsWebcamPlayerRecording_V2(uint64_t handleVal) {
auto* h = reinterpret_cast<ANSCENTER::ANSWEBCAMPlayer*>(handleVal);
if (!h) return -1;
try {
bool result = h->IsRecording();
if (result) return 1;
else return 0;
}
catch (std::exception& e) {
std::cout << "IsWebcamPlayerRecording_V2 - Exception: " << e.what() << std::endl;
return -1;
}
catch (...) {
return -1;
}
}
extern "C" __declspec(dllexport) void SetWebcamPlayerAudioVolume_V2(uint64_t handleVal, int volume)
{
auto* h = reinterpret_cast<ANSCENTER::ANSWEBCAMPlayer*>(handleVal);
if (!h) return;
try {
h->SetAudioVolume(volume);
}
catch (...) { }
}
extern "C" __declspec(dllexport) void EnableWebcamPlayerAudioVolume_V2(uint64_t handleVal, int status)
{
auto* h = reinterpret_cast<ANSCENTER::ANSWEBCAMPlayer*>(handleVal);
if (!h) return;
try {
bool audioStatus = false;
if (status == 1) audioStatus = true;
h->EnableAudio(audioStatus);
}
catch (std::exception& e) {
std::cout << "EnableWebcamPlayerAudioVolume_V2 - Exception: " << e.what() << std::endl;
}
catch (...) { }
}
extern "C" __declspec(dllexport) void SetWebcamImageRotation_V2(uint64_t handleVal, double rotationAngle) {
auto* h = reinterpret_cast<ANSCENTER::ANSWEBCAMPlayer*>(handleVal);
if (!h) return;
try {
h->SetImageRotate(rotationAngle);
}
catch (...) { }
}
extern "C" __declspec(dllexport) int SetBBoxANSWebcamPlayer_V2(uint64_t handleVal, int x, int y, int width, int height) {
auto* h = reinterpret_cast<ANSCENTER::ANSWEBCAMPlayer*>(handleVal);
if (!h) return -1;
try {
cv::Rect bbox(x, y, width, height);
h->SetBBox(bbox);
return 1;
}
catch (std::exception& e) {
std::cout << "SetBBoxANSWebcamPlayer_V2 - Exception: " << e.what() << std::endl;
return -1;
}
catch (...) {
return -1;
}
}
extern "C" __declspec(dllexport) int SetCropFlagANSWebcamPlayer_V2(uint64_t handleVal, int cropFlag) {
auto* h = reinterpret_cast<ANSCENTER::ANSWEBCAMPlayer*>(handleVal);
if (!h) return -1;
try {
bool crop = false;
if (cropFlag == 1) crop = true;
h->SetCrop(crop);
return 1;
}
catch (std::exception& e) {
std::cout << "SetCropFlagANSWebcamPlayer_V2 - Exception: " << e.what() << std::endl;
return -1;
}
catch (...) {
return -1;
}
}