Refactor project structure

This commit is contained in:
2026-03-28 19:56:39 +11:00
parent 1d267378b2
commit 8a2e721058
511 changed files with 59 additions and 48 deletions

1169
modules/ANSCV/ANSFLV.cpp Normal file

File diff suppressed because it is too large Load Diff

111
modules/ANSCV/ANSFLV.h Normal file
View File

@@ -0,0 +1,111 @@
#ifndef ANSFLV_H
#define ANSFLV_H
#define ANSFLV_API __declspec(dllexport)
#include <iostream>
#include "ANSLicense.h"
#include "LabVIEWHeader/extcode.h"
#include <vector>
#include "sys_inc.h"
#include "http_flv_cln.h"
#include "hqueue.h"
#include "http.h"
#include "http_parse.h"
#include "video_decoder.h"
#include "audio_decoder.h"
#include "http_flv_player.h"
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/opencv.hpp>
namespace ANSCENTER
{
class ANSFLV_API ANSFLVClient
{
protected:
std::unique_ptr<CHttpFlvPlayer> _playerClient = std::make_unique<CHttpFlvPlayer>();
std::string _username;
std::string _password;
std::string _url;
bool _useFullURL;
int _imageRotateDeg = 0;
int _displayWidth = 0; // 0 = no resize (return original resolution)
int _displayHeight = 0;
cv::Mat _pLastFrame;
std::string _lastJpegImage;
int _imageWidth, _imageHeight;
int64_t _pts;
bool _isPlaying;
std::recursive_mutex _mutex;
public:
ANSFLVClient();
~ANSFLVClient() noexcept;
[[nodiscard]] bool Init(std::string licenseKey, std::string url);
[[nodiscard]] bool Init(std::string licenseKey, std::string username, std::string password, std::string url);
[[nodiscard]] bool Setup();
[[nodiscard]] bool Reconnect();
[[nodiscard]] bool Start();
[[nodiscard]] bool IsPaused();
[[nodiscard]] bool IsPlaying();
[[nodiscard]] bool IsRecording();
[[nodiscard]] bool Stop();
[[nodiscard]] bool Pause();
void Destroy();
void EnableAudio(bool status);
void SetAudioVolume(int volume);
bool areImagesIdentical(const cv::Mat& img1, const cv::Mat& img2);
[[nodiscard]] cv::Mat GetImage(int& width, int& height, int64_t& pts);
[[nodiscard]] std::string MatToBinaryData(const cv::Mat& image);
[[nodiscard]] std::string GetJpegImage(int& width, int& height, int64_t& pts);
void SetImageRotate(int mode) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
_imageRotateDeg = mode;
if (mode > 360) _imageRotateDeg = 360;
};
void SetBBox(cv::Rect bbox);
void SetCrop(bool crop);
static void SetMaxHWDecoders(int maxDecoders);
static int AutoConfigureHWDecoders(int maxPerGpuOverride = 0);
void SetHWDecoding(int hwMode, int preferredGpu = -1);
bool IsHWDecodingActive();
int GetHWDecodingGpuIndex();
void SetDisplayResolution(int width, int height); // Set display output size; 0,0 = original (no resize)
void SetImageQuality(int mode); // 0=fast (AI), 1=quality (display)
AVFrame* GetNV12Frame(); // Returns cloned NV12 frame for GPU fast-path (caller must av_frame_free)
AVFrame* GetCudaHWFrame(); // Returns CUDA HW frame (device ptrs) for zero-copy inference
bool IsCudaHWAccel(); // true when decoder uses CUDA (NV12 stays in GPU VRAM)
public:
void CheckLicense();
SPDLogger& _logger = SPDLogger::GetInstance("ANSFLV", false);
bool _licenseValid{ false };
std::string _licenseKey;
//std::once_flag licenseOnceFlag;
};
}
extern "C" __declspec(dllexport) int CreateANSFLVHandle(ANSCENTER::ANSFLVClient * *Handle, const char* licenseKey, const char* username, const char* password, const char* url);
extern "C" __declspec(dllexport) int ReleaseANSFLVHandle(ANSCENTER::ANSFLVClient * *Handle);
extern "C" __declspec(dllexport) int GetFLVImage(ANSCENTER::ANSFLVClient * *Handle, int& width, int& height, int64_t & timeStamp, LStrHandle jpegImage);
extern "C" __declspec(dllexport) int GetFLVStrImage(ANSCENTER::ANSFLVClient * *Handle, int& width, int& height, int64_t & timeStamp, std::string & jpegImage);
extern "C" __declspec(dllexport) int GetFLVCVImage(ANSCENTER::ANSFLVClient** Handle, int& width, int& height, int64_t& timeStamp, cv::Mat** image);
extern "C" __declspec(dllexport) int StartFLV(ANSCENTER::ANSFLVClient * *Handle);
extern "C" __declspec(dllexport) int ReconnectFLV(ANSCENTER::ANSFLVClient * *Handle);
extern "C" __declspec(dllexport) int StopFLV(ANSCENTER::ANSFLVClient * *Handle);
extern "C" __declspec(dllexport) int PauseFLV(ANSCENTER::ANSFLVClient** Handle);
extern "C" __declspec(dllexport) int IsFLVPaused(ANSCENTER::ANSFLVClient * *Handle);
extern "C" __declspec(dllexport) int IsFLVRunning(ANSCENTER::ANSFLVClient * *Handle);
extern "C" __declspec(dllexport) int IsFLVRecording(ANSCENTER::ANSFLVClient * *Handle);
extern "C" __declspec(dllexport) void SetFLVAudioVolume(ANSCENTER::ANSFLVClient * *Handle, int volume);
extern "C" __declspec(dllexport) void EnableFLVAudioVolume(ANSCENTER::ANSFLVClient * *Handle, int status);
extern "C" __declspec(dllexport) void SetFLVImageRotation(ANSCENTER::ANSFLVClient * *Handle, double rotationAngle);
extern "C" __declspec(dllexport) int SetBBoxFLV(ANSCENTER::ANSFLVClient** Handle, int x, int y, int width, int height);
extern "C" __declspec(dllexport) int SetCropFlagFLV(ANSCENTER::ANSFLVClient** Handle, int cropFlag);
extern "C" __declspec(dllexport) void SetFLVMaxHWDecoders(int maxDecoders);
extern "C" __declspec(dllexport) int AutoConfigureFLVHWDecoders(int maxPerGpuOverride);
extern "C" __declspec(dllexport) void SetFLVHWDecoding(ANSCENTER::ANSFLVClient** Handle, int hwMode, int preferredGpu = -1);
extern "C" __declspec(dllexport) int IsFLVHWDecodingActive(ANSCENTER::ANSFLVClient** Handle);
extern "C" __declspec(dllexport) int GetFLVHWDecodingGpuIndex(ANSCENTER::ANSFLVClient** Handle);
extern "C" __declspec(dllexport) void SetFLVImageQuality(ANSCENTER::ANSFLVClient** Handle, int mode);
extern "C" __declspec(dllexport) void SetFLVDisplayResolution(ANSCENTER::ANSFLVClient** Handle, int width, int height);
#endif

View File

@@ -0,0 +1,861 @@
#include "ANSFilePlayer.h"
#include "ANSMatRegistry.h"
#include "ANSGpuFrameOps.h"
#include <memory>
#include <cstdint>
#include <libswscale/swscale.h>
#include <libavutil/imgutils.h>
#include <libavutil/frame.h>
#include "media_codec.h"
static bool ansfileplayerLicenceValid = false;
// Global once_flag to protect license checking
static std::once_flag ansfileplayerLicenseOnceFlag;
namespace ANSCENTER {
#define CHECK_CUDA(call) do { \
cudaError_t err = call; \
if (err != cudaSuccess) { \
std::cout<<"CUDA error: " + std::string(cudaGetErrorString(err)); \
} \
} while (0)
#define CHECK_NVJPEG(call) do { \
nvjpegStatus_t status = call; \
if (status != NVJPEG_STATUS_SUCCESS) { \
std::cout <<"nvJPEG error: " + std::to_string(status); \
} \
} while (0)
ANSFILEPLAYER::ANSFILEPLAYER() {
_url = "";
_imageRotateDeg = 0;
_imageWidth = 0;
_imageHeight = 0;
_pts = 0;
_isPlaying = false;
_lastJpegImage = "";
}
ANSFILEPLAYER::~ANSFILEPLAYER() noexcept {
try {
Destroy();
}
catch (...) {}
}
void ANSFILEPLAYER::Destroy() {
std::lock_guard<std::recursive_mutex> lock(_mutex);
try {
_url = "";
_imageRotateDeg = 0;
_isPlaying = false;
_lastJpegImage = "";
_pLastFrame.release();
if (_playerClient) {
_playerClient->close();
}
}
catch (const std::exception& e) {
_logger.LogError("ANSFILEPLAYER::Destroy. Exception:", e.what(), __FILE__, __LINE__);
}
catch (...) {
_logger.LogError("ANSFILEPLAYER::Destroy.", "Unknown exception", __FILE__, __LINE__);
}
}
void ANSFILEPLAYER::CheckLicense() {
std::lock_guard<std::recursive_mutex> lock(_mutex);
try {
_licenseValid = ANSCENTER::ANSLicenseHelper::LicenseVerification(_licenseKey, 1007, "ANSCV");//Default productId=1005
}
catch (std::exception& e) {
this->_logger.LogFatal("ANSFILEPLAYER::CheckLicense. Error:", e.what(), __FILE__, __LINE__);
}
}
bool ANSFILEPLAYER::Init(std::string licenseKey, std::string url) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
_licenseKey = licenseKey;
CheckLicense();
if (!_licenseValid) {
this->_logger.LogError("ANSFILEPLAYER::Init.", "Invalid license", __FILE__, __LINE__);
return false;
}
//network_init();
//sys_buf_init(200);
//rtsp_parse_buf_init(200);
//http_msg_buf_init(200);
_url = url;
return Setup();
}
void ANSFILEPLAYER::SetBBox(cv::Rect bbox) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
_playerClient->setBbox(bbox);
}
void ANSFILEPLAYER::SetCrop(bool crop) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
_playerClient->setCrop(crop);
}
bool ANSFILEPLAYER::Setup() {
std::lock_guard<std::recursive_mutex> lock(_mutex);
return _playerClient->open(_url);
}
bool ANSFILEPLAYER::Reconnect() {
std::lock_guard<std::recursive_mutex> lock(_mutex);
_playerClient->close();
Setup();
return Start();
}
bool ANSFILEPLAYER::Start() {
std::lock_guard<std::recursive_mutex> lock(_mutex);
_isPlaying = _playerClient->play();
return _isPlaying;
}
bool ANSFILEPLAYER::Stop() {
std::lock_guard<std::recursive_mutex> lock(_mutex);
if (_playerClient->pause()) {
_isPlaying = false;
return true;
}
else {
return false;
}
}
bool ANSFILEPLAYER::IsPaused() {
std::lock_guard<std::recursive_mutex> lock(_mutex);
return _playerClient->isPaused();
}
bool ANSFILEPLAYER::IsPlaying() {
std::lock_guard<std::recursive_mutex> lock(_mutex);
return _playerClient->isPlaying();
}
bool ANSFILEPLAYER::IsRecording() {
std::lock_guard<std::recursive_mutex> lock(_mutex);
return _playerClient->isRecording();
}
std::string ANSFILEPLAYER::GetJpegImage(int& width, int& height, int64_t& pts) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
// If the player is playing, process the frame
if (_isPlaying) {
// Get a new frame from the player client
_lastJpegImage = _playerClient->getJpegImage(width, height, pts);
// Update internal state variables
_pts = pts;
_imageWidth = width;
_imageHeight = height;
// Return the frame
return _lastJpegImage;
}
// If the player is not playing, return the last known frame
else {
width = _imageWidth;
height = _imageHeight;
pts = _pts;
return _lastJpegImage;
}
}
cv::Mat ANSFILEPLAYER::GetImage(int& width, int& height, int64_t& pts) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
if (!_isPlaying) {
width = _imageWidth;
height = _imageHeight;
pts = _pts;
return _pLastFrame;
}
_pLastFrame.release();
int imgW = 0, imgH = 0;
_pLastFrame = _playerClient->getImage(imgW, imgH, pts);
if (_pLastFrame.empty()) {
width = _imageWidth;
height = _imageHeight;
pts = _pts;
return _pLastFrame;
}
cv::Mat result = _pLastFrame;
// Apply rotation if needed
if (_imageRotateDeg >= 1 && _imageRotateDeg != 0) {
cv::Point2f center(imgW / 2.0f, imgH / 2.0f);
cv::Mat rotMat = cv::getRotationMatrix2D(center, _imageRotateDeg, 1.0);
cv::Mat rotated;
cv::warpAffine(result, rotated, rotMat, result.size(),
cv::INTER_CUBIC, cv::BORDER_CONSTANT, cv::Scalar());
result = rotated;
}
// Store full-res 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;
}
_pts = pts;
width = result.cols;
height = result.rows;
_imageWidth = width;
_imageHeight = height;
return result;
}
void ANSFILEPLAYER::SetDisplayResolution(int width, int height) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
_displayWidth = width;
_displayHeight = height;
}
cv::Mat ANSFILEPLAYER::GetInferenceImage() {
std::lock_guard<std::recursive_mutex> lock(_mutex);
return _inferenceImage;
}
void ANSFILEPLAYER::EnableAudio(bool status) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
_playerClient->enableAudio(status);
}
void ANSFILEPLAYER::SetAudioVolume(int volume) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
_playerClient->setVolume(volume);
}
std::string ANSFILEPLAYER::MatToBinaryData(const cv::Mat& image) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
if (!image.empty()) {
if ((image.data != nullptr) && (image.u != nullptr)) {
try {
std::vector<uchar> imageData;
bool success = cv::imencode(".jpg", image, imageData);
if (!success) {
this->_logger.LogError("ANSFILEPLAYER::MatToBinaryData. Error:", "Failed to encode the image.", __FILE__, __LINE__);
return "";
}
std::string binaryData(imageData.begin(), imageData.end());
return binaryData;
}
catch (const std::exception& e) {
this->_logger.LogFatal("ANSFILEPLAYER::MatToBinaryData. Error:", e.what(), __FILE__, __LINE__);
return "";
}
catch (...) {
this->_logger.LogFatal("ANSFILEPLAYER::MatToBinaryData. Error:", "Caught unknown exception!", __FILE__, __LINE__);
return "";
}
}
else return "";
}
else return "";
}
static void VerifyGlobalANSFPLicense(const std::string& licenseKey) {
try {
ansfileplayerLicenceValid = ANSCENTER::ANSLicenseHelper::LicenseVerification(licenseKey, 1007, "ANSCV");//Default productId=1005
if (!ansfileplayerLicenceValid) { // we also support ANSTS license
ansfileplayerLicenceValid = ANSCENTER::ANSLicenseHelper::LicenseVerification(licenseKey, 1003, "ANSVIS");//Default productId=1003 (ANSVIS)
}
if (!ansfileplayerLicenceValid) { // we also support ANSTS license
ansfileplayerLicenceValid = ANSCENTER::ANSLicenseHelper::LicenseVerification(licenseKey, 1008, "ANSTS");//Default productId=1008 (ANSTS)
}
}
catch (std::exception& e) {
ansfileplayerLicenceValid = false;
}
}
}
extern "C" __declspec(dllexport) int CreateANSFilePlayerHandle(ANSCENTER::ANSFILEPLAYER** Handle, const char* licenseKey, const char* url) {
if (!Handle || !licenseKey || !url) return -1;
try {
auto ptr = std::make_unique<ANSCENTER::ANSFILEPLAYER>();
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::ANSFILEPLAYER*>(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 ReleaseANSFilePlayerHandle(ANSCENTER::ANSFILEPLAYER** 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::ANSFILEPLAYER> ptr(*Handle);
*Handle = nullptr;
return 0;
}
catch (...) {
if (Handle) *Handle = nullptr;
return 0;
}
}
extern "C" __declspec(dllexport) int GetFilePlayerStrImage(ANSCENTER::ANSFILEPLAYER** 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 (const std::exception& e) {
std::cerr << "Error getting image data from FilePlayer client: " << e.what() << std::endl;
return -1;
}
catch (...) {
return -1;
}
}
extern "C" __declspec(dllexport) int GetFilePlayerImage(ANSCENTER::ANSFILEPLAYER** 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;
// Resize the jpegImage handle to hold the image data
error = DSSetHandleSize(jpegImage, sizeof(int32) + size * sizeof(uChar));
// Check if resizing the handle was successful
if (error == noErr) {
// Set the size of the image in the handle
(*jpegImage)->cnt = size;
// Use memcpy to copy the data from the std::string to the LStrHandle's str buffer
memcpy((*jpegImage)->str, jpegString.c_str(), size);
// Return success
return 1;
}
else {
// Return failure if there was an error in resizing the handle
std::cerr << "Error resizing jpegImage handle: " << error << std::endl;
return 0;
}
}
else {
// If the JPEG image string is empty, return failure
std::cerr << "No image data retrieved from FilePlayer client." << std::endl;
return 0;
}
}
catch (const std::exception& e) {
std::cerr << "Error getting image data from FilePlayer client: " << e.what() << std::endl;
return -1;
}
catch (...) {
return -1;
}
}
extern "C" __declspec(dllexport) int GetFilePlayerCVImage(ANSCENTER::ANSFILEPLAYER** Handle, int& width, int& height, int64_t& timeStamp, cv::Mat** image) {
if (!Handle || !(*Handle) || !image) {
std::cerr << "Error: Invalid input parameters in GetFilePlayerCVImage." << std::endl;
return -1;
}
try {
cv::Mat img = (*Handle)->GetImage(width, height, timeStamp);
if (img.empty()) {
return 0;
}
anscv_mat_replace(image, std::move(img));
// Attach NV12/CUDA frames to registry for inference zero-copy (same as ANSRTSP/ANSVideoPlayer).
// CFilePlayer inherits getNV12Frame()/getCudaHWFrame() from CVideoPlayer.
int gpuIdx = (*Handle)->_playerClient->getHWDecodingGpuIndex();
AVFrame* cudaHW = (*Handle)->_playerClient->getCudaHWFrame();
if (cudaHW) {
AVFrame* cpuNV12 = (*Handle)->_playerClient->getNV12Frame();
gpu_frame_attach_cuda(*image, cudaHW, gpuIdx, timeStamp, cpuNV12);
} else {
AVFrame* nv12 = (*Handle)->_playerClient->getNV12Frame();
if (nv12) {
gpu_frame_attach(*image, nv12, gpuIdx, timeStamp);
} else {
// CPU-only fallback: attach full-res BGR clone for ANSRTYOLO
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 = 1000; // 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) {
AVFrame* stale = static_cast<AVFrame*>(p);
av_frame_free(&stale);
}
}
}
}
return 1;
}
catch (const cv::Exception& e) {
std::cerr << "OpenCV exception in GetFilePlayerCVImage: " << e.what() << std::endl;
return -2;
}
catch (const std::exception& e) {
std::cerr << "Exception in GetFilePlayerCVImage: " << e.what() << std::endl;
return -2;
}
catch (...) {
std::cerr << "Unknown exception in GetFilePlayerCVImage" << std::endl;
return -2;
}
}
extern "C" __declspec(dllexport) int StartFilePlayer(ANSCENTER::ANSFILEPLAYER** Handle) {
if (Handle == nullptr || *Handle == nullptr) return -1;
try {
bool result = (*Handle)->Start();
if (result) return 1;
else return 0;
}
catch (const std::exception& e) {
std::cerr << "Error starting file player: " << e.what() << std::endl;
return -1;
}
catch (...) {
return -1;
}
}
extern "C" __declspec(dllexport) int ReconnectFilePlayer(ANSCENTER::ANSFILEPLAYER** Handle) {
if (Handle == nullptr || *Handle == nullptr) return -1;
try {
bool result = (*Handle)->Reconnect();
if (result) return 1;
else return 0;
}
catch (const std::exception& e) {
std::cerr << "Error reconnecting file player: " << e.what() << std::endl;
return -1;
}
catch (...) {
return -1;
}
}
extern "C" __declspec(dllexport) int StopFilePlayer(ANSCENTER::ANSFILEPLAYER** Handle) {
if (Handle == nullptr || *Handle == nullptr) return -1;
try {
bool result = (*Handle)->Stop();
if (result) return 1;
else return 0;
}
catch (const std::exception& e) {
std::cerr << "Error stopping file player: " << e.what() << std::endl;
return -1;
}
catch (...) {
return -1;
}
}
extern "C" __declspec(dllexport) int IsFilePlayerPaused(ANSCENTER::ANSFILEPLAYER** Handle) {
if (Handle == nullptr || *Handle == nullptr) return -1;
try {
bool result = (*Handle)->IsPaused();
if (result) return 1;
else return 0;
}
catch (const std::exception& e) {
std::cerr << "Error checking if file player is paused: " << e.what() << std::endl;
return -1;
}
catch (...) {
return -1;
}
}
extern "C" __declspec(dllexport) int IsFilePlayerRunning(ANSCENTER::ANSFILEPLAYER** Handle) {
if (Handle == nullptr || *Handle == nullptr) return -1;
try {
bool result = (*Handle)->IsPlaying();
if (result) return 1;
else return 0;
}
catch (const std::exception& e) {
std::cerr << "Error checking if file player is running: " << e.what() << std::endl;
return -1;
}
catch (...) {
return -1;
}
}
extern "C" __declspec(dllexport) int IsFilePlayerRecording(ANSCENTER::ANSFILEPLAYER** Handle) {
if (Handle == nullptr || *Handle == nullptr) return -1;
try {
bool result = (*Handle)->IsRecording();
if (result) return 1;
else return 0;
}
catch (const std::exception& e) {
std::cerr << "Error checking if file player is recording: " << e.what() << std::endl;
return -1;
}
catch (...) {
return -1;
}
}
extern "C" __declspec(dllexport) void SetFilePlayerAudioVolume(ANSCENTER::ANSFILEPLAYER** Handle, int volume)
{
if (Handle == nullptr || *Handle == nullptr) return;
try {
(*Handle)->SetAudioVolume(volume);
}
catch (...) { }
}
extern "C" __declspec(dllexport) void EnableFilePlayerAudioVolume(ANSCENTER::ANSFILEPLAYER** Handle, int status)
{
if (Handle == nullptr || *Handle == nullptr) return;
try {
bool audioStatus = false;
if (status == 1)audioStatus = true;
(*Handle)->EnableAudio(audioStatus);
}
catch (const std::exception& e) {
std::cerr << "Error enabling audio for file player: " << e.what() << std::endl;
}
catch (...) { }
}
extern "C" __declspec(dllexport) void SetFilePlayerImageRotation(ANSCENTER::ANSFILEPLAYER** Handle, double rotationAngle) {
if (Handle == nullptr || *Handle == nullptr) return;
try {
(*Handle)->SetImageRotate(rotationAngle);
}
catch (...) { }
}
extern "C" __declspec(dllexport) int SetBBoxFilePlayer(ANSCENTER::ANSFILEPLAYER** 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 (const std::exception& e) {
std::cerr << "Error setting bounding box for file player: " << e.what() << std::endl;
return -1;
}
catch (...) {
return -1;
}
}
extern "C" __declspec(dllexport) int SetCropFlagFilePlayer(ANSCENTER::ANSFILEPLAYER** 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 (const std::exception& e) {
std::cerr << "Error setting crop flag for file player: " << e.what() << std::endl;
return -1;
}
catch (...) {
return -1;
}
}
// ============================================================================
// V2 functions: accept uint64_t handleVal by value (LabVIEW-safe)
// ============================================================================
extern "C" __declspec(dllexport) int GetFilePlayerImage_V2(uint64_t handleVal, int& width, int& height, int64_t& timeStamp, LStrHandle jpegImage) {
auto* h = reinterpret_cast<ANSCENTER::ANSFILEPLAYER*>(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 == noErr) {
(*jpegImage)->cnt = size;
memcpy((*jpegImage)->str, jpegString.c_str(), size);
return 1;
}
else {
std::cerr << "Error resizing jpegImage handle: " << error << std::endl;
return 0;
}
}
else {
std::cerr << "No image data retrieved from FilePlayer client." << std::endl;
return 0;
}
}
catch (const std::exception& e) {
std::cerr << "Error getting image data from FilePlayer client: " << e.what() << std::endl;
return -1;
}
catch (...) {
return -1;
}
}
extern "C" __declspec(dllexport) int GetFilePlayerCVImage_V2(uint64_t handleVal, int& width, int& height, int64_t& timeStamp, cv::Mat** image) {
auto* h = reinterpret_cast<ANSCENTER::ANSFILEPLAYER*>(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));
// NV12/CUDA registry attach (same as V1)
int gpuIdx = h->_playerClient->getHWDecodingGpuIndex();
AVFrame* cudaHW = h->_playerClient->getCudaHWFrame();
if (cudaHW) {
AVFrame* cpuNV12 = h->_playerClient->getNV12Frame();
gpu_frame_attach_cuda(*image, cudaHW, gpuIdx, timeStamp, cpuNV12);
} else {
AVFrame* nv12 = h->_playerClient->getNV12Frame();
if (nv12) {
gpu_frame_attach(*image, nv12, gpuIdx, timeStamp);
} else {
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 = 1000;
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) {
AVFrame* stale = static_cast<AVFrame*>(p);
av_frame_free(&stale);
}
}
}
}
return 1;
}
catch (const cv::Exception& e) {
std::cerr << "OpenCV exception in GetFilePlayerCVImage_V2: " << e.what() << std::endl;
return -2;
}
catch (const std::exception& e) {
std::cerr << "Exception in GetFilePlayerCVImage_V2: " << e.what() << std::endl;
return -2;
}
catch (...) {
std::cerr << "Unknown exception in GetFilePlayerCVImage_V2" << std::endl;
return -2;
}
}
extern "C" __declspec(dllexport) int StartFilePlayer_V2(uint64_t handleVal) {
auto* h = reinterpret_cast<ANSCENTER::ANSFILEPLAYER*>(handleVal);
if (!h) return -1;
try {
bool result = h->Start();
if (result) return 1;
else return 0;
}
catch (const std::exception& e) {
std::cerr << "Error starting file player: " << e.what() << std::endl;
return -1;
}
catch (...) {
return -1;
}
}
extern "C" __declspec(dllexport) int ReconnectFilePlayer_V2(uint64_t handleVal) {
auto* h = reinterpret_cast<ANSCENTER::ANSFILEPLAYER*>(handleVal);
if (!h) return -1;
try {
bool result = h->Reconnect();
if (result) return 1;
else return 0;
}
catch (const std::exception& e) {
std::cerr << "Error reconnecting file player: " << e.what() << std::endl;
return -1;
}
catch (...) {
return -1;
}
}
extern "C" __declspec(dllexport) int StopFilePlayer_V2(uint64_t handleVal) {
auto* h = reinterpret_cast<ANSCENTER::ANSFILEPLAYER*>(handleVal);
if (!h) return -1;
try {
bool result = h->Stop();
if (result) return 1;
else return 0;
}
catch (const std::exception& e) {
std::cerr << "Error stopping file player: " << e.what() << std::endl;
return -1;
}
catch (...) {
return -1;
}
}
extern "C" __declspec(dllexport) int IsFilePlayerPaused_V2(uint64_t handleVal) {
auto* h = reinterpret_cast<ANSCENTER::ANSFILEPLAYER*>(handleVal);
if (!h) return -1;
try {
bool result = h->IsPaused();
if (result) return 1;
else return 0;
}
catch (const std::exception& e) {
std::cerr << "Error checking if file player is paused: " << e.what() << std::endl;
return -1;
}
catch (...) {
return -1;
}
}
extern "C" __declspec(dllexport) int IsFilePlayerRunning_V2(uint64_t handleVal) {
auto* h = reinterpret_cast<ANSCENTER::ANSFILEPLAYER*>(handleVal);
if (!h) return -1;
try {
bool result = h->IsPlaying();
if (result) return 1;
else return 0;
}
catch (const std::exception& e) {
std::cerr << "Error checking if file player is running: " << e.what() << std::endl;
return -1;
}
catch (...) {
return -1;
}
}
extern "C" __declspec(dllexport) int IsFilePlayerRecording_V2(uint64_t handleVal) {
auto* h = reinterpret_cast<ANSCENTER::ANSFILEPLAYER*>(handleVal);
if (!h) return -1;
try {
bool result = h->IsRecording();
if (result) return 1;
else return 0;
}
catch (const std::exception& e) {
std::cerr << "Error checking if file player is recording: " << e.what() << std::endl;
return -1;
}
catch (...) {
return -1;
}
}
extern "C" __declspec(dllexport) void SetFilePlayerAudioVolume_V2(uint64_t handleVal, int volume) {
auto* h = reinterpret_cast<ANSCENTER::ANSFILEPLAYER*>(handleVal);
if (!h) return;
try {
h->SetAudioVolume(volume);
}
catch (...) { }
}
extern "C" __declspec(dllexport) void EnableFilePlayerAudioVolume_V2(uint64_t handleVal, int status) {
auto* h = reinterpret_cast<ANSCENTER::ANSFILEPLAYER*>(handleVal);
if (!h) return;
try {
bool audioStatus = false;
if (status == 1) audioStatus = true;
h->EnableAudio(audioStatus);
}
catch (const std::exception& e) {
std::cerr << "Error enabling audio for file player: " << e.what() << std::endl;
}
catch (...) { }
}
extern "C" __declspec(dllexport) void SetFilePlayerImageRotation_V2(uint64_t handleVal, double rotationAngle) {
auto* h = reinterpret_cast<ANSCENTER::ANSFILEPLAYER*>(handleVal);
if (!h) return;
try {
h->SetImageRotate(rotationAngle);
}
catch (...) { }
}
extern "C" __declspec(dllexport) int SetBBoxFilePlayer_V2(uint64_t handleVal, int x, int y, int width, int height) {
auto* h = reinterpret_cast<ANSCENTER::ANSFILEPLAYER*>(handleVal);
if (!h) return -1;
try {
cv::Rect bbox(x, y, width, height);
h->SetBBox(bbox);
return 1;
}
catch (const std::exception& e) {
std::cerr << "Error setting bounding box for file player: " << e.what() << std::endl;
return -1;
}
catch (...) {
return -1;
}
}
extern "C" __declspec(dllexport) int SetCropFlagFilePlayer_V2(uint64_t handleVal, int cropFlag) {
auto* h = reinterpret_cast<ANSCENTER::ANSFILEPLAYER*>(handleVal);
if (!h) return -1;
try {
bool crop = false;
if (cropFlag == 1) crop = true;
h->SetCrop(crop);
return 1;
}
catch (const std::exception& e) {
std::cerr << "Error setting crop flag for file player: " << e.what() << std::endl;
return -1;
}
catch (...) {
return -1;
}
}
extern "C" __declspec(dllexport) void SetFilePlayerDisplayResolution(ANSCENTER::ANSFILEPLAYER** Handle, int width, int height) {
if (Handle == nullptr || *Handle == nullptr) return;
try {
(*Handle)->SetDisplayResolution(width, height);
} catch (...) { }
}

View File

@@ -0,0 +1,117 @@
#ifndef ANSFILEPLAYER_H
#define ANSFILEPLAYER_H
#define ANSFILEPLAYER_API __declspec(dllexport)
#include <iostream>
#include <cstdint>
#include "ANSLicense.h"
#include "LabVIEWHeader/extcode.h"
#include <vector>
#include "sys_inc.h"
#include "rtsp_cln.h"
#include "hqueue.h"
#include "http.h"
#include "http_parse.h"
#include "video_decoder.h"
#include "audio_decoder.h"
#include "file_player.h"
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/opencv.hpp>
#include <thread>
#include <chrono>
#include <atomic>
#include <turbojpeg.h>
namespace ANSCENTER
{
class ANSFILEPLAYER_API ANSFILEPLAYER
{
public:
std::unique_ptr<CFilePlayer> _playerClient = std::make_unique<CFilePlayer>();
protected:
std::string _url;
double _imageRotateDeg = 0;
cv::Mat _pLastFrame;
std::string _lastJpegImage;
int _imageWidth = 0, _imageHeight = 0;
int64_t _pts = 0;
bool _isPlaying = false;
std::recursive_mutex _mutex;
// Display/inference split (same pattern as ANSVideoPlayer)
int _displayWidth = 0;
int _displayHeight = 0;
cv::Mat _inferenceImage; // full-res, no display resize
public:
// Public: accessed by extern "C" GetFilePlayerCVImage for NV12/CUDA registry attachment
cv::Mat _inferenceCloneCurr; // current clone for registry (keeps data alive)
cv::Mat _inferenceClonePrev; // previous clone (keeps data alive until next frame)
ANSFILEPLAYER();
~ANSFILEPLAYER() noexcept;
[[nodiscard]] bool Init(std::string licenseKey, std::string url);
[[nodiscard]] bool Setup();
[[nodiscard]] bool Reconnect();
[[nodiscard]] bool Start();
void SetBBox(cv::Rect bbox);
void SetCrop(bool crop);
[[nodiscard]] bool IsPaused();
[[nodiscard]] bool IsPlaying();
[[nodiscard]] bool IsRecording();
[[nodiscard]] bool Stop();
void Destroy();
void EnableAudio(bool status);
void SetAudioVolume(int volume);
void SetImageRotate(double mode) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
_imageRotateDeg = mode;
if (mode > 360) _imageRotateDeg = 360;
};
void SetDisplayResolution(int width, int height);
[[nodiscard]] cv::Mat GetImage(int& width, int& height, int64_t& pts);
[[nodiscard]] cv::Mat GetInferenceImage();
[[nodiscard]] std::string GetJpegImage(int& width, int& height, int64_t& pts);
[[nodiscard]] std::string GetJpegStringImage(int& width, int& height, int64_t& pts) {
return GetJpegImage(width, height, pts);
}
[[nodiscard]] std::string MatToBinaryData(const cv::Mat& image);
public:
void CheckLicense();
SPDLogger& _logger = SPDLogger::GetInstance("ANSFilePlayer", false);
bool _licenseValid{ false };
std::string _licenseKey;
};
}
extern "C" __declspec(dllexport) int CreateANSFilePlayerHandle(ANSCENTER::ANSFILEPLAYER* *Handle, const char* licenseKey, const char* url);
extern "C" __declspec(dllexport) int ReleaseANSFilePlayerHandle(ANSCENTER::ANSFILEPLAYER* *Handle);
extern "C" __declspec(dllexport) int GetFilePlayerImage(ANSCENTER::ANSFILEPLAYER* *Handle, int& width, int& height, int64_t & timeStamp, LStrHandle jpegImage);
extern "C" __declspec(dllexport) int GetFilePlayerStrImage(ANSCENTER::ANSFILEPLAYER* *Handle, int& width, int& height, int64_t & timeStamp, std::string & jpegImage);
extern "C" __declspec(dllexport) int GetFilePlayerCVImage(ANSCENTER::ANSFILEPLAYER** Handle, int& width, int& height, int64_t& timeStamp, cv::Mat** image);
extern "C" __declspec(dllexport) int StartFilePlayer(ANSCENTER::ANSFILEPLAYER* *Handle);
extern "C" __declspec(dllexport) int ReconnectFilePlayer(ANSCENTER::ANSFILEPLAYER* *Handle);
extern "C" __declspec(dllexport) int StopFilePlayer(ANSCENTER::ANSFILEPLAYER* *Handle);
extern "C" __declspec(dllexport) int IsFilePlayerPaused(ANSCENTER::ANSFILEPLAYER* *Handle);
extern "C" __declspec(dllexport) int IsFilePlayerRunning(ANSCENTER::ANSFILEPLAYER* *Handle);
extern "C" __declspec(dllexport) int IsFilePlayerRecording(ANSCENTER::ANSFILEPLAYER* *Handle);
extern "C" __declspec(dllexport) void SetFilePlayerAudioVolume(ANSCENTER::ANSFILEPLAYER* *Handle, int volume);
extern "C" __declspec(dllexport) void EnableFilePlayerAudioVolume(ANSCENTER::ANSFILEPLAYER* *Handle, int status);
extern "C" __declspec(dllexport) void SetFilePlayerImageRotation(ANSCENTER::ANSFILEPLAYER* *Handle, double rotationAngle);
extern "C" __declspec(dllexport) int SetBBoxFilePlayer(ANSCENTER::ANSFILEPLAYER** Handle, int x, int y, int width, int height);
extern "C" __declspec(dllexport) int SetCropFlagFilePlayer(ANSCENTER::ANSFILEPLAYER** Handle, int cropFlag);
extern "C" __declspec(dllexport) void SetFilePlayerDisplayResolution(ANSCENTER::ANSFILEPLAYER** Handle, int width, int height);
// V2 functions: accept uint64_t handleVal by value (LabVIEW-safe)
extern "C" __declspec(dllexport) int GetFilePlayerImage_V2(uint64_t handleVal, int& width, int& height, int64_t& timeStamp, LStrHandle jpegImage);
extern "C" __declspec(dllexport) int GetFilePlayerCVImage_V2(uint64_t handleVal, int& width, int& height, int64_t& timeStamp, cv::Mat** image);
extern "C" __declspec(dllexport) int StartFilePlayer_V2(uint64_t handleVal);
extern "C" __declspec(dllexport) int ReconnectFilePlayer_V2(uint64_t handleVal);
extern "C" __declspec(dllexport) int StopFilePlayer_V2(uint64_t handleVal);
extern "C" __declspec(dllexport) int IsFilePlayerPaused_V2(uint64_t handleVal);
extern "C" __declspec(dllexport) int IsFilePlayerRunning_V2(uint64_t handleVal);
extern "C" __declspec(dllexport) int IsFilePlayerRecording_V2(uint64_t handleVal);
extern "C" __declspec(dllexport) void SetFilePlayerAudioVolume_V2(uint64_t handleVal, int volume);
extern "C" __declspec(dllexport) void EnableFilePlayerAudioVolume_V2(uint64_t handleVal, int status);
extern "C" __declspec(dllexport) void SetFilePlayerImageRotation_V2(uint64_t handleVal, double rotationAngle);
extern "C" __declspec(dllexport) int SetBBoxFilePlayer_V2(uint64_t handleVal, int x, int y, int width, int height);
extern "C" __declspec(dllexport) int SetCropFlagFilePlayer_V2(uint64_t handleVal, int cropFlag);
#endif

View File

@@ -0,0 +1,762 @@
#include "ANSFilePlayer_CV.h"
#include "ANSMatRegistry.h"
#include <memory>
#include <cstdint>
#include <libswscale/swscale.h>
#include <libavutil/imgutils.h>
#include <libavutil/frame.h>
#include "media_codec.h"
static bool ansfileplayerLicenceValid = false;
// Global once_flag to protect license checking
static std::once_flag ansfileplayerLicenseOnceFlag;
namespace ANSCENTER {
#define CHECK_CUDA(call) do { \
cudaError_t err = call; \
if (err != cudaSuccess) { \
std::cout<<"CUDA error: " + std::string(cudaGetErrorString(err)); \
} \
} while (0)
#define CHECK_NVJPEG(call) do { \
nvjpegStatus_t status = call; \
if (status != NVJPEG_STATUS_SUCCESS) { \
std::cout <<"nvJPEG error: " + std::to_string(status); \
} \
} while (0)
ANSFILEPLAYER_CV::ANSFILEPLAYER_CV() :_stopThread(std::make_shared<std::atomic<bool>>(false))
{
_resWidth = 0;
_resHeight = 0;
m_bPaused = false;
_crop = false;
_isPlaying = false;
_lastJpegImage = "";
_bbox = cv::Rect(0, 0, 0, 0);
_jpegCompressor = nullptr;
_previousPTS = 0;
_totalFrames = 0;
}
ANSFILEPLAYER_CV::~ANSFILEPLAYER_CV() noexcept {
try {
StopTimerThread();
Destroy();
}
catch (...) {}
}
void ANSFILEPLAYER_CV::Destroy() {
std::lock_guard<std::recursive_mutex> lock(_mutex);
try {
_previousImage.release();
_lastJpegImage = "";
_isPlaying = false;
_resWidth = 0;
_resHeight = 0;
_currentFrame = 0;
_previousPTS = 0;
if (cap.isOpened()) {
cap.release();
}
}
catch (const std::exception& e) {
_logger.LogError("ANSFILEPLAYER_CV::Destroy. Exception:", e.what(), __FILE__, __LINE__);
}
catch (...) {
_logger.LogError("ANSFILEPLAYER_CV::Destroy.", "Unknown exception", __FILE__, __LINE__);
}
}
static void VerifyGlobalANSFPLicense(const std::string& licenseKey) {
try {
ansfileplayerLicenceValid = ANSCENTER::ANSLicenseHelper::LicenseVerification(licenseKey, 1007, "ANSCV");//Default productId=1005
if (!ansfileplayerLicenceValid) { // we also support ANSTS license
ansfileplayerLicenceValid = ANSCENTER::ANSLicenseHelper::LicenseVerification(licenseKey, 1003, "ANSVIS");//Default productId=1003 (ANSVIS)
}
if (!ansfileplayerLicenceValid) { // we also support ANSTS license
ansfileplayerLicenceValid = ANSCENTER::ANSLicenseHelper::LicenseVerification(licenseKey, 1008, "ANSTS");//Default productId=1008 (ANSTS)
}
}
catch (std::exception& e) {
ansfileplayerLicenceValid = false;
}
}
void ANSFILEPLAYER_CV::CheckLicense() {
std::lock_guard<std::recursive_mutex> lock(_mutex);
try {
// Check once globally
std::call_once(ansfileplayerLicenseOnceFlag, [this]() {
VerifyGlobalANSFPLicense(_licenseKey);
});
// Update this instance's local license flag
_licenseValid = ansfileplayerLicenceValid;
}
catch (const std::exception& e) {
this->_logger.LogFatal("ANSFILEPLAYER_CV::CheckLicense. Error:", e.what(), __FILE__, __LINE__);
}
}
bool ANSFILEPLAYER_CV::Init(std::string licenseKey, std::string url) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
_licenseKey = licenseKey;
CheckLicense();
if (!_licenseValid) {
_logger.LogError("ANSFILEPLAYER_CV::Init.", "Invalid license", __FILE__, __LINE__);
return false;
}
_url = url;
return Setup();
}
bool ANSFILEPLAYER_CV::Setup() {
std::lock_guard<std::recursive_mutex> lock(_mutex);
_currentFrame = 0;
if (cap.isOpened()) return true;
cap.open(_url, cv::CAP_FFMPEG); // USe FFMPEG for better codec support
if (!cap.isOpened()) {
cap.open(_url, cv::CAP_ANY);
if (!cap.isOpened())return false;
}
try {
_resWidth = static_cast<int>(cap.get(cv::CAP_PROP_FRAME_WIDTH));
_resHeight = static_cast<int>(cap.get(cv::CAP_PROP_FRAME_HEIGHT));
_totalFrames = static_cast<int64_t>(cap.get(cv::CAP_PROP_FRAME_COUNT));
_fps = cap.get(cv::CAP_PROP_FPS);
cap.set(cv::CAP_PROP_POS_FRAMES, _currentFrame);
if (_fps > 0) {
if (_timerThread && _timerThread->joinable()) return true; // Exit if the thread is already running
int interval_ms = static_cast<int>(1000 / _fps);
*_stopThread = false;
_timerThread = std::make_shared<std::thread>(&ANSFILEPLAYER_CV::StartTimer, this, _stopThread, interval_ms);
}
return true;
}
catch (std::exception& e) {
this->_logger.LogError("ANSFILEPLAYER_CV::Setup:", e.what(), __FILE__, __LINE__);
return false;
}
}
void ANSFILEPLAYER_CV::StartTimer(std::shared_ptr<std::atomic<bool>> stopFlag, int interval_ms) {
while (!stopFlag->load()) {
std::unique_lock<std::mutex> lock(_cvMutex);
// Wait for the specified interval or until stopFlag is set
if (_cv.wait_for(lock, std::chrono::milliseconds(interval_ms), [&]() {
return stopFlag->load();
})) {
break; // Exit the loop if stopFlag is true
}
lock.unlock(); // Unlock to avoid deadlocks in further operations
int delayMs = 0;
int actualSleepTime = interval_ms;
{
std::lock_guard<std::recursive_mutex> lock(_mutex);
auto start = std::chrono::system_clock::now();
if (_isPlaying) {
try {
_currentFrame = static_cast<int64_t>(cap.get(cv::CAP_PROP_POS_FRAMES));
// Add check for _stopThread before blocking operations
if (!cap.grab() || _currentFrame >= _totalFrames - 1) {
if (cap.isOpened()) {
cap.release();
cap.open(_url, cv::CAP_FFMPEG); // USe FFMPEG for better codec support
if (!cap.isOpened()) {
cap.open(_url, cv::CAP_ANY);
}
}
if (cap.isOpened()) {
cap.set(cv::CAP_PROP_POS_FRAMES, 0);
_currentFrame = 0;
}
}
}
catch (const std::exception& e) {
this->_logger.LogError("ANSFILEPLAYER_CV::StartTimer. Exception occurred:", e.what(), __FILE__, __LINE__);
}
}
auto end = std::chrono::system_clock::now();
delayMs = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
// Calculate actual sleep time based on any delay introduced
actualSleepTime = interval_ms - delayMs;
if (actualSleepTime < 1) actualSleepTime = 1;
}
std::this_thread::sleep_for(std::chrono::milliseconds(actualSleepTime));
}
}
void ANSFILEPLAYER_CV::StopTimerThread() {
*_stopThread = true; // Signal to stop the thread
_cv.notify_all(); // Notify the condition variable to unblock the thread
if (_timerThread && _timerThread->joinable()) {
_timerThread->join(); // Join the timer thread to ensure cleanup
}
}
bool ANSFILEPLAYER_CV::Reconnect() {
std::lock_guard<std::recursive_mutex> lock(_mutex);
try {
_currentFrame = 0;
if (cap.isOpened()) {
cap.release();
}
Setup();
_isPlaying = cap.isOpened() && cap.grab();
return _isPlaying;
}
catch (const std::exception& e) {
this->_logger.LogError("ANSFILEPLAYER_CV::Reconnect. Exception occurred:", e.what(), __FILE__, __LINE__);
_currentFrame = 0;
return false;
}
}
bool ANSFILEPLAYER_CV::Start() {
std::lock_guard<std::recursive_mutex> lock(_mutex);
try {
if (!cap.isOpened()) {
cap.open(_url, cv::CAP_FFMPEG);
if (!cap.isOpened()) {
cap.open(_url, cv::CAP_ANY);
}
if (!cap.isOpened()) {
this->_logger.LogError("ANSFILEPLAYER_CV::Start. Exception occurred:", "Failed to open video source: ", __FILE__, __LINE__);
return false;
}
try {
if (!cap.set(cv::CAP_PROP_POS_FRAMES, _currentFrame)) {
this->_logger.LogError("ANSFILEPLAYER_CV::Start. Exception occurred:", "Warning: Unable to seek to frame", __FILE__, __LINE__);
}
}
catch (const std::exception& e) {
this->_logger.LogError("ANSFILEPLAYER_CV::Start. Exception occurred:", e.what(), __FILE__, __LINE__);
}
}
_isPlaying = cap.isOpened() && cap.grab();
return _isPlaying;
}
catch (const std::exception& e) {
this->_logger.LogError("ANSFILEPLAYER_CV::Start. Exception occurred:", e.what(), __FILE__, __LINE__);
return false;
}
}
bool ANSFILEPLAYER_CV::Stop() {
std::lock_guard<std::recursive_mutex> lock(_mutex);
try {
if (cap.isOpened()) {
try {
double frame_pos = cap.get(cv::CAP_PROP_POS_FRAMES);
if (frame_pos >= 0) {
_currentFrame = static_cast<int64_t>(frame_pos);
}
else {
_currentFrame = 0;
this->_logger.LogError("ANSFILEPLAYER_CV::Stop. Exception occurred:", "Unable to retrieve current frame position", __FILE__, __LINE__);
}
}
catch (const std::exception& e) {
this->_logger.LogError("ANSFILEPLAYER_CV::Stop. Exception occurred:", e.what(), __FILE__, __LINE__);
_currentFrame = 0;
}
cap.release();
}
_isPlaying = false;
return true;
}
catch (const std::exception& e) {
this->_logger.LogError("ANSFILEPLAYER_CV::Stop. Exception occurred:", e.what(), __FILE__, __LINE__);
return false;
}
}
void ANSFILEPLAYER_CV::SetBBox(cv::Rect bbox) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
_bbox = bbox;
}
void ANSFILEPLAYER_CV::SetCrop(bool crop) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
_crop = crop;
}
bool ANSFILEPLAYER_CV::IsPaused() {
std::lock_guard<std::recursive_mutex> lock(_mutex);
return !cap.isOpened();
}
bool ANSFILEPLAYER_CV::IsPlaying() {
std::lock_guard<std::recursive_mutex> lock(_mutex);
return cap.isOpened();
}
bool ANSFILEPLAYER_CV::IsRecording() {
std::lock_guard<std::recursive_mutex> lock(_mutex);
return false;// do not support recording for webcam
}
cv::Mat ANSFILEPLAYER_CV::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 = std::clamp(_bbox.x, 0, frame.cols - 1);
_bbox.y = std::clamp(_bbox.y, 0, frame.rows - 1);
_bbox.width = std::min(_bbox.width, frame.cols - _bbox.x);
_bbox.height = std::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, minimal quality loss)
cv::warpAffine(result, rotated, rotationMatrix, result.size(),
cv::INTER_LINEAR, cv::BORDER_CONSTANT, cv::Scalar());
result = rotated;
}
}
// Update PTS (presentation timestamp)
if (_previousPTS < INT64_MAX) {
_previousPTS++;
}
else {
_previousPTS = 0;
}
// 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("ANSFILEPLAYER_CV::GetImage. OpenCV exception:", e.what(), __FILE__, __LINE__);
}
catch (const std::exception& e) {
this->_logger.LogError("ANSFILEPLAYER_CV::GetImage. Exception:", e.what(), __FILE__, __LINE__);
}
catch (...) {
this->_logger.LogError("ANSFILEPLAYER_CV::GetImage. Unknown exception", "", __FILE__, __LINE__);
}
return cv::Mat();
}
void ANSFILEPLAYER_CV::EnableAudio(bool status) {
// please support audio enable for webcam
}
void ANSFILEPLAYER_CV::SetAudioVolume(int volume) {
// support audio volumne
}
std::string ANSFILEPLAYER_CV::encodeJpegString(const cv::Mat& img, int quality) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
if (!_isPlaying) return _lastJpegImage;
unsigned char* jpegBuf = nullptr;
tjhandle jpegCompressor = nullptr;
try {
// Initialize TurboJPEG compressor
jpegCompressor = tjInitCompress();
if (!jpegCompressor) {
this->_logger.LogError("Failed to initialize TurboJPEG compressor.", tjGetErrorStr(), __FILE__, __LINE__);
return _lastJpegImage;
}
int maxBufferSize = img.cols * img.rows * 3;
jpegBuf = tjAlloc(maxBufferSize);
if (!jpegBuf) {
this->_logger.LogError("Failed to allocate memory for JPEG buffer.", tjGetErrorStr(), __FILE__, __LINE__);
tjDestroy(jpegCompressor);
return _lastJpegImage;
}
long unsigned int jpegSize = maxBufferSize;
int subsamp = TJSAMP_444;
int pixelFormat = img.channels() == 3 ? TJPF_BGR : TJPF_GRAY;
// Compress the image
if (tjCompress2(jpegCompressor, img.data, img.cols, 0, img.rows, pixelFormat,
&jpegBuf, &jpegSize, subsamp, quality, TJFLAG_FASTDCT) != 0) {
this->_logger.LogError("Compression error:", tjGetErrorStr(), __FILE__, __LINE__);
tjFree(jpegBuf);
tjDestroy(jpegCompressor);
return _lastJpegImage;
}
// Create string from JPEG buffer
std::string jpegString(reinterpret_cast<char*>(jpegBuf), jpegSize);
_lastJpegImage = jpegString;
}
catch (const std::exception& e) {
this->_logger.LogError("Exception occurred:", e.what(), __FILE__, __LINE__);
}
// Cleanup resources
if (jpegBuf) tjFree(jpegBuf);
if (jpegCompressor) tjDestroy(jpegCompressor);
return _lastJpegImage;
}
std::string ANSFILEPLAYER_CV::MatToBinaryData(const cv::Mat& image) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
// Check if the image is empty or has invalid data
if (!_isPlaying) return _lastJpegImage;
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("ANSFILEPLAYER_CV::MatToBinaryData. Exception occurred:", e.what(), __FILE__, __LINE__);
}
catch (...) {
this->_logger.LogFatal("ANSFILEPLAYER_CV::MatToBinaryData.", "Unknown exception occurred.", __FILE__, __LINE__);
}
// Return an empty string in case of failure
return _lastJpegImage;
}
std::string ANSFILEPLAYER_CV::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("ANSFILEPLAYER_CV::GetJpegStringImage. Exception occurred:", e.what(), __FILE__, __LINE__);
return _lastJpegImage;
}
}
}
extern "C" __declspec(dllexport) int CreateANSFileCVPlayerHandle(ANSCENTER::ANSFILEPLAYER_CV** Handle, const char* licenseKey, const char* url) {
if (!Handle || !licenseKey || !url) return -1;
try {
auto ptr = std::make_unique<ANSCENTER::ANSFILEPLAYER_CV>();
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::ANSFILEPLAYER_CV*>(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 ReleaseANSFileCVPlayerHandle(ANSCENTER::ANSFILEPLAYER_CV** Handle) {
if (Handle == nullptr || *Handle == nullptr) return -1;
try {
extern void anscv_unregister_handle(void*);
anscv_unregister_handle(*Handle);
// Destructor calls Destroy() <20> no need to call it explicitly (avoids double-destroy)
std::unique_ptr<ANSCENTER::ANSFILEPLAYER_CV> ptr(*Handle);
*Handle = nullptr;
return 0;
}
catch (...) {
if (Handle) *Handle = nullptr;
return 0;
}
}
extern "C" __declspec(dllexport) int GetFileCVPlayerStrImage(ANSCENTER::ANSFILEPLAYER_CV** 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 (const std::exception& e) {
std::cerr << "Error getting image data from FilePlayer client: " << e.what() << std::endl;
return -1;
}
catch (...) {
return -1;
}
}
extern "C" __declspec(dllexport) int GetFileCVPlayerImage(ANSCENTER::ANSFILEPLAYER_CV** 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;
// Resize the jpegImage handle to hold the image data
error = DSSetHandleSize(jpegImage, sizeof(int32) + size * sizeof(uChar));
// Check if resizing the handle was successful
if (error == noErr) {
// Set the size of the image in the handle
(*jpegImage)->cnt = size;
// Use memcpy to copy the data from the std::string to the LStrHandle's str buffer
memcpy((*jpegImage)->str, jpegString.c_str(), size);
// Return success
return 1;
}
else {
// Return failure if there was an error in resizing the handle
std::cerr << "Error resizing jpegImage handle: " << error << std::endl;
return 0;
}
}
else {
// If the JPEG image string is empty, return failure
std::cerr << "No image data retrieved from FilePlayer client." << std::endl;
return 0;
}
}
catch (const std::exception& e) {
std::cerr << "Error getting image data from FilePlayer client: " << e.what() << std::endl;
return -1;
}
catch (...) {
return -1;
}
}
extern "C" __declspec(dllexport) int GetFileCVPlayerCVImage(ANSCENTER::ANSFILEPLAYER_CV** Handle, int& width, int& height, int64_t& timeStamp, cv::Mat** image) {
if (!Handle || !(*Handle) || !image) {
std::cerr << "Error: Invalid input parameters in GetFilePlayerCVImage." << std::endl;
return -1;
}
try {
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 <20> no global mutex needed
anscv_mat_replace(image, std::move(img));
return 1; // Success
}
catch (const cv::Exception& e) {
std::cerr << "OpenCV exception in GetFilePlayerCVImage: " << e.what() << std::endl;
return -2;
}
catch (const std::exception& e) {
std::cerr << "Exception in GetFilePlayerCVImage: " << e.what() << std::endl;
return -2;
}
catch (...) {
std::cerr << "Unknown exception in GetFilePlayerCVImage" << std::endl;
return -2;
}
}
extern "C" __declspec(dllexport) int StartFileCVPlayer(ANSCENTER::ANSFILEPLAYER_CV** Handle) {
if (Handle == nullptr || *Handle == nullptr) return -1;
try {
bool result = (*Handle)->Start();
if (result) return 1;
else return 0;
}
catch (const std::exception& e) {
std::cerr << "Error starting file player: " << e.what() << std::endl;
return -1;
}
catch (...) {
return -1;
}
}
extern "C" __declspec(dllexport) int ReconnectFileCVPlayer(ANSCENTER::ANSFILEPLAYER_CV** Handle) {
if (Handle == nullptr || *Handle == nullptr) return -1;
try {
bool result = (*Handle)->Reconnect();
if (result) return 1;
else return 0;
}
catch (const std::exception& e) {
std::cerr << "Error reconnecting file player: " << e.what() << std::endl;
return -1;
}
catch (...) {
return -1;
}
}
extern "C" __declspec(dllexport) int StopFileCVPlayer(ANSCENTER::ANSFILEPLAYER_CV** Handle) {
if (Handle == nullptr || *Handle == nullptr) return -1;
try {
bool result = (*Handle)->Stop();
if (result) return 1;
else return 0;
}
catch (const std::exception& e) {
std::cerr << "Error stopping file player: " << e.what() << std::endl;
return -1;
}
catch (...) {
return -1;
}
}
extern "C" __declspec(dllexport) int IsFileCVPlayerPaused(ANSCENTER::ANSFILEPLAYER_CV** Handle) {
if (Handle == nullptr || *Handle == nullptr) return -1;
try {
bool result = (*Handle)->IsPaused();
if (result) return 1;
else return 0;
}
catch (const std::exception& e) {
std::cerr << "Error checking if file player is paused: " << e.what() << std::endl;
return -1;
}
catch (...) {
return -1;
}
}
extern "C" __declspec(dllexport) int IsFileCVPlayerRunning(ANSCENTER::ANSFILEPLAYER_CV** Handle) {
if (Handle == nullptr || *Handle == nullptr) return -1;
try {
bool result = (*Handle)->IsPlaying();
if (result) return 1;
else return 0;
}
catch (const std::exception& e) {
std::cerr << "Error checking if file player is running: " << e.what() << std::endl;
return -1;
}
catch (...) {
return -1;
}
}
extern "C" __declspec(dllexport) int IsFileCVPlayerRecording(ANSCENTER::ANSFILEPLAYER_CV** Handle) {
if (Handle == nullptr || *Handle == nullptr) return -1;
try {
bool result = (*Handle)->IsRecording();
if (result) return 1;
else return 0;
}
catch (const std::exception& e) {
std::cerr << "Error checking if file player is recording: " << e.what() << std::endl;
return -1;
}
catch (...) {
return -1;
}
}
extern "C" __declspec(dllexport) void SetFileCVPlayerAudioVolume(ANSCENTER::ANSFILEPLAYER_CV** Handle, int volume)
{
if (Handle == nullptr || *Handle == nullptr) return;
try {
(*Handle)->SetAudioVolume(volume);
}
catch (...) {}
}
extern "C" __declspec(dllexport) void EnableFileCVPlayerAudioVolume(ANSCENTER::ANSFILEPLAYER_CV** Handle, int status)
{
if (Handle == nullptr || *Handle == nullptr) return;
try {
bool audioStatus = false;
if (status == 1)audioStatus = true;
(*Handle)->EnableAudio(audioStatus);
}
catch (const std::exception& e) {
std::cerr << "Error enabling audio for file player: " << e.what() << std::endl;
}
catch (...) {}
}
extern "C" __declspec(dllexport) void SetFileCVPlayerImageRotation(ANSCENTER::ANSFILEPLAYER_CV** Handle, double rotationAngle) {
if (Handle == nullptr || *Handle == nullptr) return;
try {
(*Handle)->SetImageRotate(rotationAngle);
}
catch (...) {}
}
extern "C" __declspec(dllexport) int SetBBoxFileCVPlayer(ANSCENTER::ANSFILEPLAYER_CV** 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 (const std::exception& e) {
std::cerr << "Error setting bounding box for file player: " << e.what() << std::endl;
return -1;
}
catch (...) {
return -1;
}
}
extern "C" __declspec(dllexport) int SetCropFlagFileCVPlayer(ANSCENTER::ANSFILEPLAYER_CV** 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 (const std::exception& e) {
std::cerr << "Error setting crop flag for file player: " << e.what() << std::endl;
return -1;
}
catch (...) {
return -1;
}
}

View File

@@ -0,0 +1,115 @@
#ifndef ANSFILEPLAYER_H
#define ANSFILEPLAYER_H
#define ANSFILEPLAYER_API __declspec(dllexport)
#include <iostream>
#include <cstdint>
#include "ANSLicense.h"
#include "LabVIEWHeader/extcode.h"
#include <vector>
#include "sys_inc.h"
#include "rtsp_cln.h"
#include "hqueue.h"
#include "http.h"
#include "http_parse.h"
#include "video_decoder.h"
#include "audio_decoder.h"
#include "file_player.h"
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/opencv.hpp>
#include <thread>
#include <chrono>
#include <atomic>
#include <turbojpeg.h>
namespace ANSCENTER
{
class ANSFILEPLAYER_API ANSFILEPLAYER_CV
{
protected:
cv::VideoCapture cap;
int _resWidth;
int _resHeight;
int64_t _totalFrames;
int64_t _currentFrame;
int64_t _previousPTS;
double _fps;
bool _isPlaying;
std::string _lastJpegImage;
//int64_t _previousPTS;
cv::Mat _previousImage;
bool m_bPaused;
int _imageRotateDeg = 0;
std::string _url;
cv::Rect _bbox;
bool _crop;
std::recursive_mutex _mutex;
std::shared_ptr<std::atomic<bool>> _stopThread;
std::shared_ptr<std::thread> _timerThread;
std::mutex _cvMutex;
std::condition_variable _cv;
//EngineType engineType;
//// Initialize nvJPEG structures
//nvjpegHandle_t nv_handle;
//nvjpegEncoderState_t nv_enc_state;
//nvjpegEncoderParams_t nv_enc_params;
//cudaStream_t stream;
tjhandle _jpegCompressor;
public:
ANSFILEPLAYER_CV();
~ANSFILEPLAYER_CV() noexcept;
[[nodiscard]] bool Init(std::string licenseKey, std::string url);
[[nodiscard]] bool Setup();
[[nodiscard]] bool Reconnect();
[[nodiscard]] bool Start();
[[nodiscard]] bool IsPaused();
[[nodiscard]] bool IsPlaying();
[[nodiscard]] bool IsRecording();
void SetBBox(cv::Rect bbox);
void SetCrop(bool crop);
[[nodiscard]] bool Stop();
void Destroy();
void EnableAudio(bool status);
void SetAudioVolume(int volume);
void SetImageRotate(int mode) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
_imageRotateDeg = mode;
if (mode > 360) _imageRotateDeg = 360;
};
[[nodiscard]] cv::Mat GetImage(int& width, int& height, int64_t& pts);
[[nodiscard]] std::string MatToBinaryData(const cv::Mat& image);
[[nodiscard]] std::string GetJpegStringImage(int& width, int& height, int64_t& pts);
public:
void CheckLicense();
SPDLogger& _logger = SPDLogger::GetInstance("ANSFilePlayer_CV", false);
bool _licenseValid{ false };
//std::once_flag licenseOnceFlag;
std::string _licenseKey;
private:
std::string encodeJpegString(const cv::Mat& img, int quality = 80);
//std::string encodeMatToJpegWithNvJPEG(const cv::Mat& inputMat, int quality = 80);
//void uploadPlanarBGRToGPU(const cv::Mat& inputMat, unsigned char** data);
void StartTimer(std::shared_ptr<std::atomic<bool>> stopFlag, int interval_ms);
void StopTimerThread();
};
}
extern "C" __declspec(dllexport) int CreateANSFileCVPlayerHandle(ANSCENTER::ANSFILEPLAYER_CV** Handle, const char* licenseKey, const char* url);
extern "C" __declspec(dllexport) int ReleaseANSFileCVPlayerHandle(ANSCENTER::ANSFILEPLAYER_CV** Handle);
extern "C" __declspec(dllexport) int GetFileCVPlayerImage(ANSCENTER::ANSFILEPLAYER_CV** Handle, int& width, int& height, int64_t& timeStamp, LStrHandle jpegImage);
extern "C" __declspec(dllexport) int GetFileCVPlayerStrImage(ANSCENTER::ANSFILEPLAYER_CV** Handle, int& width, int& height, int64_t& timeStamp, std::string& jpegImage);
extern "C" __declspec(dllexport) int GetFileCVPlayerCVImage(ANSCENTER::ANSFILEPLAYER_CV** Handle, int& width, int& height, int64_t& timeStamp, cv::Mat** image);
extern "C" __declspec(dllexport) int StartFileCVPlayer(ANSCENTER::ANSFILEPLAYER_CV** Handle);
extern "C" __declspec(dllexport) int ReconnectFileCVPlayer(ANSCENTER::ANSFILEPLAYER_CV** Handle);
extern "C" __declspec(dllexport) int StopFileCVPlayer(ANSCENTER::ANSFILEPLAYER_CV** Handle);
extern "C" __declspec(dllexport) int IsFileCVPlayerPaused(ANSCENTER::ANSFILEPLAYER_CV** Handle);
extern "C" __declspec(dllexport) int IsFileCVPlayerRunning(ANSCENTER::ANSFILEPLAYER_CV** Handle);
extern "C" __declspec(dllexport) int IsFileCVPlayerRecording(ANSCENTER::ANSFILEPLAYER_CV** Handle);
extern "C" __declspec(dllexport) void SetFileCVPlayerAudioVolume(ANSCENTER::ANSFILEPLAYER_CV** Handle, int volume);
extern "C" __declspec(dllexport) void EnableFileCVPlayerAudioVolume(ANSCENTER::ANSFILEPLAYER_CV** Handle, int status);
extern "C" __declspec(dllexport) void SetFileCVPlayerImageRotation(ANSCENTER::ANSFILEPLAYER_CV** Handle, double rotationAngle);
extern "C" __declspec(dllexport) int SetBBoxFileCVPlayer(ANSCENTER::ANSFILEPLAYER_CV** Handle, int x, int y, int width, int height);
extern "C" __declspec(dllexport) int SetCropFlagFileCVPlayer(ANSCENTER::ANSFILEPLAYER_CV** Handle, int cropFlag);
#endif

View File

@@ -0,0 +1,212 @@
#pragma once
// ANSGpuFrameOps.h — FFmpeg-aware convenience functions for ANSGpuFrameRegistry.
//
// This header requires FFmpeg headers (libavutil/frame.h) and provides
// typed attach/invalidate/remove operations that handle av_frame_clone/free.
//
// NEW DESIGN: Instead of storing AVFrame* references (which lock NVDEC surfaces),
// we snapshot the CPU NV12 planes into malloc'd buffers and release the AVFrames
// immediately. This prevents decoder surface pool exhaustion when many clones
// hold references to the same frame.
//
// Include this in ANSCV/ANSRTSP (which link FFmpeg). For projects without
// FFmpeg (ANSODEngine), include ANSGpuFrameRegistry.h directly and use
// gpu_frame_lookup() + the GpuFrameData plane pointers.
#include "ANSGpuFrameRegistry.h"
extern "C" {
#include "libavutil/frame.h"
}
#include <cstring>
#include <cstdlib>
namespace anscv_gpu_ops {
namespace detail {
// Snapshot NV12 Y and UV planes from an AVFrame into malloc'd buffers.
// Returns true on success. Caller owns the output buffers.
inline bool snapshotNV12Planes(const AVFrame* nv12,
uint8_t*& outY, int& outYLinesize,
uint8_t*& outUV, int& outUVLinesize,
int& outWidth, int& outHeight) {
if (!nv12 || !nv12->data[0] || !nv12->data[1])
return false;
outWidth = nv12->width;
outHeight = nv12->height;
outYLinesize = nv12->width; // Packed (no alignment padding)
outUVLinesize = nv12->width; // UV interleaved: width bytes per row
size_t yBytes = static_cast<size_t>(outYLinesize) * outHeight;
size_t uvBytes = static_cast<size_t>(outUVLinesize) * (outHeight / 2);
outY = static_cast<uint8_t*>(std::malloc(yBytes));
outUV = static_cast<uint8_t*>(std::malloc(uvBytes));
if (!outY || !outUV) {
std::free(outY);
std::free(outUV);
outY = nullptr;
outUV = nullptr;
return false;
}
// Copy line-by-line (source may have padding via linesize > width)
const int srcYLinesize = nv12->linesize[0];
const int srcUVLinesize = nv12->linesize[1];
for (int row = 0; row < outHeight; ++row) {
std::memcpy(outY + row * outYLinesize,
nv12->data[0] + row * srcYLinesize,
outWidth);
}
for (int row = 0; row < outHeight / 2; ++row) {
std::memcpy(outUV + row * outUVLinesize,
nv12->data[1] + row * srcUVLinesize,
outWidth);
}
return true;
}
} // namespace detail
} // namespace anscv_gpu_ops
// Attach NV12/YUV frame keyed by cv::Mat* pointer.
// Snapshots CPU NV12 planes into owned malloc'd buffers, then releases the AVFrame.
// TAKES OWNERSHIP of nv12 — caller must NOT av_frame_free after this call.
inline void gpu_frame_attach(cv::Mat* mat, AVFrame* nv12, int gpuIdx, int64_t pts) {
if (!mat || !nv12) return;
GpuFrameData data{};
data.gpuIndex = gpuIdx;
data.pts = pts;
data.pixelFormat = nv12->format;
data.width = nv12->width;
data.height = nv12->height;
// Snapshot NV12 planes to owned buffers
bool ok = anscv_gpu_ops::detail::snapshotNV12Planes(
nv12,
data.cpuYPlane, data.cpuYLinesize,
data.cpuUvPlane, data.cpuUvLinesize,
data.width, data.height);
// Keep legacy pointers for backward compat during transition
data.yPlane = data.cpuYPlane;
data.uvPlane = data.cpuUvPlane;
data.yLinesize = data.cpuYLinesize;
data.uvLinesize = data.cpuUvLinesize;
// Store AVFrame for legacy cleanup (will be freed by drain_pending)
data.avframe = nv12;
void* old = ANSGpuFrameRegistry::instance().attach(mat, std::move(data));
if (old) {
AVFrame* oldFrame = static_cast<AVFrame*>(old);
av_frame_free(&oldFrame);
}
// Free stale entries evicted by TTL or previous attach
auto pending = ANSGpuFrameRegistry::instance().drain_pending();
for (void* p : pending) {
AVFrame* stale = static_cast<AVFrame*>(p);
av_frame_free(&stale);
}
}
// Attach CUDA HW frame — keeps CUDA device pointers for zero-copy inference.
// TAKES OWNERSHIP of cudaFrame AND cpuNV12 — caller must NOT av_frame_free after.
//
// Primary path: yPlane/uvPlane point to CUDA device pointers from the cloned
// AVFrame (data[0]/data[1]). The cloned AVFrame keeps the NVDEC surface alive
// until gpu_frame_remove() is called after inference. With 4 cameras each
// holding ~1 surface, this uses 4 of NVDEC's 25-32 surface pool — safe.
//
// Fallback: cpuYPlane/cpuUvPlane hold CPU-side NV12 snapshot for cross-GPU
// inference (when decode GPU != inference GPU, CUDA device ptrs aren't
// accessible from another GPU context).
inline void gpu_frame_attach_cuda(cv::Mat* mat, AVFrame* cudaFrame, int gpuIdx, int64_t pts,
AVFrame* cpuNV12 = nullptr) {
if (!mat || !cudaFrame) return;
GpuFrameData data{};
data.gpuIndex = gpuIdx;
data.pts = pts;
data.width = cudaFrame->width;
data.height = cudaFrame->height;
data.pixelFormat = 23; // AV_PIX_FMT_NV12 — the underlying sw_format
// Primary: CUDA device pointers from NVDEC (zero-copy on same GPU)
data.isCudaDevicePtr = true;
data.yPlane = cudaFrame->data[0]; // CUDA device ptr: Y plane
data.uvPlane = cudaFrame->data[1]; // CUDA device ptr: UV plane
data.yLinesize = cudaFrame->linesize[0];
data.uvLinesize = cudaFrame->linesize[1];
// Fallback: snapshot CPU NV12 for cross-GPU inference
if (cpuNV12) {
anscv_gpu_ops::detail::snapshotNV12Planes(
cpuNV12,
data.cpuYPlane, data.cpuYLinesize,
data.cpuUvPlane, data.cpuUvLinesize,
data.width, data.height);
}
// Store AVFrames for cleanup (cudaFrame keeps NVDEC surface alive)
data.avframe = cudaFrame;
data.cpuAvframe = cpuNV12;
void* old = ANSGpuFrameRegistry::instance().attach(mat, std::move(data));
if (old) {
AVFrame* oldFrame = static_cast<AVFrame*>(old);
av_frame_free(&oldFrame);
}
auto pending = ANSGpuFrameRegistry::instance().drain_pending();
for (void* p : pending) {
AVFrame* stale = static_cast<AVFrame*>(p);
av_frame_free(&stale);
}
}
// Release entry by cv::Mat* and free any returned AVFrames. Safe if not in map (no-op).
inline void gpu_frame_remove(cv::Mat* mat) {
if (!mat) return;
ANSGpuFrameRegistry::instance().release(mat);
// Free any AVFrames that became pending from this release or prior eviction
auto pending = ANSGpuFrameRegistry::instance().drain_pending();
for (void* p : pending) {
AVFrame* stale = static_cast<AVFrame*>(p);
av_frame_free(&stale);
}
// Free any GPU device pointers that became pending
auto gpuPending = gpu_frame_drain_gpu_pending();
// NOTE: cudaFree requires CUDA context — caller must be on a CUDA-capable thread.
// If not, these will leak. In practice, gpu_frame_remove is called from ANSCV
// camera threads which do have CUDA context.
// For safety, we skip cudaFree here and let NV12PreprocessHelper handle it.
// The GPU pointers are tracked in the budget and will be accounted for.
(void)gpuPending;
}
// Alias for remove — used in ANSCV mutating functions to drop stale GPU data.
inline void gpu_frame_invalidate(cv::Mat* mat) {
gpu_frame_remove(mat);
}
// Run TTL eviction + drain pending. Call periodically from camera threads.
inline void gpu_frame_evict_stale() {
ANSGpuFrameRegistry::instance().evictStaleFrames();
auto pending = ANSGpuFrameRegistry::instance().drain_pending();
for (void* p : pending) {
AVFrame* stale = static_cast<AVFrame*>(p);
av_frame_free(&stale);
}
}

View File

@@ -0,0 +1,25 @@
// ANSGpuFrameRegistry.cpp — Process-wide singleton, compiled into ANSCV.dll.
//
// On Windows, header-only singletons (static local in inline function) create
// separate instances in each DLL. Since gpu_frame_attach() runs in ANSCV.dll
// and gpu_frame_lookup() runs in ANSODEngine.dll, we need a single shared
// instance. This file:
// 1. Defines resolveProcessWide() which owns the canonical singleton.
// 2. Exports a C function so other DLLs can find it via GetProcAddress.
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#include <windows.h>
#include "ANSGpuFrameRegistry.h"
// ANSCV.dll owns the process-wide singleton.
ANSGpuFrameRegistry* ANSGpuFrameRegistry::resolveProcessWide() {
static ANSGpuFrameRegistry reg;
return &reg;
}
// Exported so other DLLs (ANSODEngine, etc.) can find this instance at runtime.
extern "C" __declspec(dllexport)
ANSGpuFrameRegistry* ANSGpuFrameRegistry_GetInstance() {
return &ANSGpuFrameRegistry::instance();
}

1175
modules/ANSCV/ANSMJPEG.cpp Normal file

File diff suppressed because it is too large Load Diff

111
modules/ANSCV/ANSMJPEG.h Normal file
View File

@@ -0,0 +1,111 @@
#ifndef ANSMJPEG_H
#define ANSMJPEG_H
#define ANSMJPEG_API __declspec(dllexport)
#include <iostream>
#include "ANSLicense.h"
#include "LabVIEWHeader/extcode.h"
#include <vector>
#include "sys_inc.h"
#include "http_mjpeg_cln.h"
#include "hqueue.h"
#include "http.h"
#include "http_parse.h"
#include "video_decoder.h"
#include "audio_decoder.h"
#include "http_mjpeg_player.h"
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/opencv.hpp>
namespace ANSCENTER
{
class ANSMJPEG_API ANSMJPEGClient
{
protected:
std::unique_ptr<CHttpMjpegPlayer> _playerClient = std::make_unique<CHttpMjpegPlayer>();
std::string _username;
std::string _password;
std::string _url;
bool _useFullURL;
int _imageRotateDeg = 0;
int _displayWidth = 0; // 0 = no resize (return original resolution)
int _displayHeight = 0;
cv::Mat _pLastFrame;
std::string _lastJpegImage;
int _imageWidth, _imageHeight;
int64_t _pts;
bool _isPlaying;
std::recursive_mutex _mutex;
public:
ANSMJPEGClient();
~ANSMJPEGClient() noexcept;
[[nodiscard]] bool Init(std::string licenseKey, std::string url);
[[nodiscard]] bool Init(std::string licenseKey, std::string username, std::string password, std::string url);
[[nodiscard]] bool Setup();
[[nodiscard]] bool Reconnect();
[[nodiscard]] bool Start();
[[nodiscard]] bool Pause();
[[nodiscard]] bool IsPaused();
[[nodiscard]] bool IsPlaying();
[[nodiscard]] bool IsRecording();
[[nodiscard]] bool Stop();
void Destroy();
void EnableAudio(bool status);
void SetAudioVolume(int volume);
bool areImagesIdentical(const cv::Mat& img1, const cv::Mat& img2);
[[nodiscard]] cv::Mat GetImage(int& width, int& height, int64_t& pts);
[[nodiscard]] std::string MatToBinaryData(const cv::Mat& image);
[[nodiscard]] std::string GetJpegImage(int& width, int& height, int64_t& pts);
void SetImageRotate(int mode) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
_imageRotateDeg = mode;
if (mode > 360) _imageRotateDeg = 360;
};
void SetBBox(cv::Rect bbox);
void SetCrop(bool crop);
static void SetMaxHWDecoders(int maxDecoders);
static int AutoConfigureHWDecoders(int maxPerGpuOverride = 0);
void SetHWDecoding(int hwMode, int preferredGpu = -1);
bool IsHWDecodingActive();
int GetHWDecodingGpuIndex();
void SetDisplayResolution(int width, int height); // Set display output size; 0,0 = original (no resize)
void SetImageQuality(int mode); // 0=fast (AI), 1=quality (display)
AVFrame* GetNV12Frame(); // Returns cloned NV12 frame for GPU fast-path (caller must av_frame_free)
AVFrame* GetCudaHWFrame(); // Returns CUDA HW frame (device ptrs) for zero-copy inference
bool IsCudaHWAccel(); // true when decoder uses CUDA (NV12 stays in GPU VRAM)
public:
void CheckLicense();
SPDLogger& _logger = SPDLogger::GetInstance("ANSMJPEG", false);
bool _licenseValid{ false };
std::string _licenseKey;
//std::once_flag licenseOnceFlag;
};
}
extern "C" __declspec(dllexport) int CreateANSMJPEGHandle(ANSCENTER::ANSMJPEGClient * *Handle, const char* licenseKey, const char* username, const char* password, const char* url);
extern "C" __declspec(dllexport) int ReleaseANSMJPEGHandle(ANSCENTER::ANSMJPEGClient * *Handle);
extern "C" __declspec(dllexport) int GetMJPEGImage(ANSCENTER::ANSMJPEGClient * *Handle, int& width, int& height, int64_t & timeStamp, LStrHandle jpegImage);
extern "C" __declspec(dllexport) int GetMJPEGStrImage(ANSCENTER::ANSMJPEGClient * *Handle, int& width, int& height, int64_t & timeStamp, std::string & jpegImage);
extern "C" __declspec(dllexport) int GetMJPEGCVImage(ANSCENTER::ANSMJPEGClient** Handle, int& width, int& height, int64_t& timeStamp, cv::Mat** image);
extern "C" __declspec(dllexport) int StartMJPEG(ANSCENTER::ANSMJPEGClient * *Handle);
extern "C" __declspec(dllexport) int ReconnectMJPEG(ANSCENTER::ANSMJPEGClient * *Handle);
extern "C" __declspec(dllexport) int StopMJPEG(ANSCENTER::ANSMJPEGClient * *Handle);
extern "C" __declspec(dllexport) int PauseMJPEG(ANSCENTER::ANSMJPEGClient** Handle);
extern "C" __declspec(dllexport) int IsMJPEGPaused(ANSCENTER::ANSMJPEGClient * *Handle);
extern "C" __declspec(dllexport) int IsMJPEGRunning(ANSCENTER::ANSMJPEGClient * *Handle);
extern "C" __declspec(dllexport) int IsMJPEGRecording(ANSCENTER::ANSMJPEGClient * *Handle);
extern "C" __declspec(dllexport) void SetMJPEGAudioVolume(ANSCENTER::ANSMJPEGClient * *Handle, int volume);
extern "C" __declspec(dllexport) void EnableMJPEGAudioVolume(ANSCENTER::ANSMJPEGClient * *Handle, int status);
extern "C" __declspec(dllexport) void SetMJPEGImageRotation(ANSCENTER::ANSMJPEGClient * *Handle, double rotationAngle);
extern "C" __declspec(dllexport) int SetBBoxMJPEG(ANSCENTER::ANSMJPEGClient** Handle, int x, int y, int width, int height);
extern "C" __declspec(dllexport) int SetCropFlagMJPEG(ANSCENTER::ANSMJPEGClient** Handle, int cropFlag);
extern "C" __declspec(dllexport) void SetMJPEGMaxHWDecoders(int maxDecoders);
extern "C" __declspec(dllexport) int AutoConfigureMJPEGHWDecoders(int maxPerGpuOverride);
extern "C" __declspec(dllexport) void SetMJPEGHWDecoding(ANSCENTER::ANSMJPEGClient** Handle, int hwMode, int preferredGpu = -1);
extern "C" __declspec(dllexport) int IsMJPEGHWDecodingActive(ANSCENTER::ANSMJPEGClient** Handle);
extern "C" __declspec(dllexport) int GetMJPEGHWDecodingGpuIndex(ANSCENTER::ANSMJPEGClient** Handle);
extern "C" __declspec(dllexport) void SetMJPEGImageQuality(ANSCENTER::ANSMJPEGClient** Handle, int mode);
extern "C" __declspec(dllexport) void SetMJPEGDisplayResolution(ANSCENTER::ANSMJPEGClient** Handle, int width, int height);
#endif

View File

@@ -0,0 +1,116 @@
#pragma once
// ANSMatRegistry.h — Thread-safe cv::Mat* pointer registry.
// Prevents double-free crashes when LabVIEW calls ReleaseImage on a pointer
// that a stream source (RTSP, VideoPlayer, etc.) has already freed and replaced.
//
// Every cv::Mat* allocated through these functions is tracked in a global set.
// Deletion only proceeds if the pointer is still in the set, guaranteeing each
// pointer is freed exactly once regardless of which thread calls delete first.
//
// Usage:
// Allocate: cv::Mat* p = anscv_mat_new(std::move(img));
// Free: anscv_mat_delete(&p); // safe, no-op if already freed
// Swap: anscv_mat_replace(&p, std::move(newImg)); // atomic old-delete + new-alloc
#include <opencv2/core/mat.hpp>
#include <mutex>
#include <unordered_set>
#include "ANSGpuFrameOps.h"
namespace anscv {
namespace detail {
inline std::mutex& registry_mutex() {
static std::mutex m;
return m;
}
inline std::unordered_set<cv::Mat*>& registry() {
static std::unordered_set<cv::Mat*> s;
return s;
}
} // namespace detail
} // namespace anscv
// Allocate a new cv::Mat on the heap and register it.
inline cv::Mat* anscv_mat_new(cv::Mat&& src) {
cv::Mat* p = new cv::Mat(std::move(src));
{
std::lock_guard<std::mutex> lk(anscv::detail::registry_mutex());
anscv::detail::registry().insert(p);
}
return p;
}
inline cv::Mat* anscv_mat_new(const cv::Mat& src) {
cv::Mat* p = new cv::Mat(src);
{
std::lock_guard<std::mutex> lk(anscv::detail::registry_mutex());
anscv::detail::registry().insert(p);
}
return p;
}
// Delete a cv::Mat* only if it is still in the registry.
// Returns true if deleted, false if pointer was null or already freed.
// Thread-safe: the pointer is removed from the registry AND nulled AND deleted
// all inside the lock, so no other thread can race on the same pointer.
inline bool anscv_mat_delete(cv::Mat** pp) {
if (!pp || !(*pp))
return false;
cv::Mat* toDelete = nullptr;
{
std::lock_guard<std::mutex> lk(anscv::detail::registry_mutex());
// Re-check under lock — another thread may have nulled *pp
if (!*pp)
return false;
auto& reg = anscv::detail::registry();
auto it = reg.find(*pp);
if (it == reg.end()) {
// Not in registry — already freed by another thread.
*pp = nullptr;
return false;
}
toDelete = *pp;
reg.erase(it);
*pp = nullptr; // Null the caller's pointer while still under lock
}
// Release GPU frame data (refcount--, frees NV12+GPU cache when refcount=0)
gpu_frame_remove(toDelete);
// Safe to delete outside lock: pointer is removed from registry and
// *pp is nullptr, so no other thread can reach toDelete.
delete toDelete;
return true;
}
// Atomic replace: delete old image (if still registered), allocate new, assign to *pp.
// The old pointer is only deleted if it is in the registry (prevents double-free
// when LabVIEW already freed it via anscv_mat_delete).
inline void anscv_mat_replace(cv::Mat** pp, cv::Mat&& newImg) {
cv::Mat* newPtr = new cv::Mat(std::move(newImg));
cv::Mat* toDelete = nullptr;
{
std::lock_guard<std::mutex> lk(anscv::detail::registry_mutex());
auto& reg = anscv::detail::registry();
if (pp && *pp) {
auto it = reg.find(*pp);
if (it != reg.end()) {
toDelete = *pp;
reg.erase(it);
}
// If not in registry, another thread already freed it — skip delete
}
*pp = newPtr;
reg.insert(newPtr);
}
if (toDelete) {
// Release GPU frame ref for old Mat (safe with refcounting —
// only frees NV12/GPU cache when refcount reaches 0)
gpu_frame_remove(toDelete);
delete toDelete;
}
// Periodically run TTL eviction (piggybacked on camera thread activity)
gpu_frame_evict_stale();
}

5106
modules/ANSCV/ANSOpenCV.cpp Normal file

File diff suppressed because it is too large Load Diff

164
modules/ANSCV/ANSOpenCV.h Normal file
View File

@@ -0,0 +1,164 @@
#ifndef ANSOPENCV_H
#define ANSOPENCV_H
#define ANSOPENCV_API __declspec(dllexport)
#include <iostream>
#include "ANSLicense.h"
#include "LabVIEWHeader/extcode.h"
#include <vector>
#include <opencv2/opencv.hpp>
#define MUTEX_TIMEOUT_MS 45000
namespace fs = std::filesystem;
namespace ANSCENTER
{
std::string CompressJpegToString(const cv::Mat& image, int quality);
struct DetectionObject
{
int classId{ 0 };
int trackId{ 0 };
std::string className{};
float confidence{ 0.0 };
cv::Rect box{};
cv::Mat mask{}; //Json string mask ="point1.x,point1.y,...."
std::vector<float> kps{}; // Pose exsimate keypoint
std::string extraInfo; // More information such as facial recognition
};
class TurboJpegCompressor {
public:
TurboJpegCompressor();
~TurboJpegCompressor() noexcept;
// Delete copy constructor and assignment operator
TurboJpegCompressor(const TurboJpegCompressor&) = delete;
TurboJpegCompressor& operator=(const TurboJpegCompressor&) = delete;
// Your original logic with minimal optimizations
[[nodiscard]] std::string compress(const cv::Mat& image, int quality);
private:
void* _handle = nullptr;
unsigned char* _buffer = nullptr;
unsigned long _bufferSize = 0;
};
/// <summary>
/// // ANSOPENCV class provides various image processing functionalities using OpenCV and ANS Center SDK.
/// </summary>
class ANSOPENCV_API ANSOPENCV
{
public:
[[nodiscard]] bool Init(std::string licenseKey);
void ImageResize(const cv::Mat& inputFrame, int width, int height, cv::Mat& outputFrame);
void ImageResizeWithRatio(const cv::Mat& inputFrame, int width, cv::Mat& outputFrame);
[[nodiscard]] cv::Mat BlurObjects(const cv::Mat& image, const std::vector<cv::Rect>& objects);
[[nodiscard]] cv::Mat BlurBackground(const cv::Mat& image, const std::vector<cv::Rect>& objects);
[[nodiscard]] cv::Mat ToGray(const cv::Mat& image);
[[nodiscard]] cv::Mat ImageDenoise(const cv::Mat& image);
[[nodiscard]] cv::Mat ImageRepair(const cv::Mat& image);
[[nodiscard]] cv::Mat ImageCrop(const cv::Mat& image,const cv::Rect& ROI, int originalImageSize = 0);
[[nodiscard]] cv::Mat ImageResizeV2(const cv::Mat& image, int resizeWidth, int orginalImageSize = 0);
[[nodiscard]] std::string QRDecoder(const cv::Mat& image);
[[nodiscard]] std::string QRDecoderWithBBox(const cv::Mat& image, int maxImageSize, const std::vector<cv::Rect>& bBox);
[[nodiscard]] std::string MatToBase64(const cv::Mat& image);
[[nodiscard]] std::string MatToBinaryData(const cv::Mat& image);
[[nodiscard]] std::vector<cv::Rect> GetBoundingBoxes(std::string strBBoxes);
[[nodiscard]] std::string VectorDetectionToJsonString(const std::vector<DetectionObject>& dets);
[[nodiscard]] std::string PatternMatches(cv::Mat& image, cv::Mat& templateImage, double threshold);
[[nodiscard]] cv::Mat ImageDarkEnhancement(const cv::Mat& img, double brightnessScaleFactor=1.5);
[[nodiscard]] cv::Mat ImageContrastEnhancement(const cv::Mat& img);
[[nodiscard]] cv::Mat ImageWhiteBalance(const cv::Mat& img);
[[nodiscard]] cv::Mat RotateImage(const cv::Mat& image, double angle);
[[nodiscard]] cv::Mat FlipImage(const cv::Mat& image, int flipCode);//flipCode = 0: Vertical flip (around the x-axis). flipCode = 1: Horizontal flip (around the y-axis). flipCode = -1: Both axes, flipping the image horizontally and vertically.
[[nodiscard]] cv::Mat ShiftImage(const cv::Mat& image, int shiftX, int shiftY);
[[nodiscard]] cv::Mat AddGaussianNoise(const cv::Mat& image, double mean, double stddev);
[[nodiscard]] cv::Mat AddSaltAndPepperNoise(const cv::Mat& image, double amount);
[[nodiscard]] cv::Mat AddSpeckleNoise(const cv::Mat& image, double stddev);
static void InitCameraNetwork();
static void DeinitCameraNetwork();
static cv::Mat resizeImageToFit(const cv::Mat& inputImage, int maxWidth, int maxHeight, int& newWidth, int& newHeight);
static bool resizeImage(cv::Mat& inputImage, int resizeWidth, int orginalImageSize=0);
static bool cropImage(cv::Mat& inputImage, const cv::Rect& resizeROI, int originalImageSize=0);
static bool ImagesToMP4(const std::string& imageFolder, const std::string& outputVideoPath, int targetDurationSec);
private:
void CheckLicense();
double CalculateIoU(const cv::Rect& box1, const cv::Rect& box2);
void NonMaximumSuppression(std::vector<DetectionObject>& detectedObjects, double iouThreshold);
std::string EncodeJpegString(const cv::Mat& img, int quality);
SPDLogger& _logger = SPDLogger::GetInstance("ANSCV", false);
std::string _licenseKey;
std::recursive_mutex _mutex;
//std::once_flag licenseOnceFlag; // For one-time license check
bool _licenseValid = false;
public:
};
}
extern "C" __declspec(dllexport) int CreateANSCVHandle(ANSCENTER::ANSOPENCV **Handle, const char* licenseKey);
extern "C" __declspec(dllexport) int ReleaseANSCVHandle(ANSCENTER::ANSOPENCV **Handle);
extern "C" __declspec(dllexport) int ANSCV_ImageResize(ANSCENTER::ANSOPENCV * *Handle,unsigned char* inputImage, unsigned int bufferLength, int width, int height, LStrHandle outputImage);
extern "C" __declspec(dllexport) int ANSCV_ImageResizeWithRatio(ANSCENTER::ANSOPENCV * *Handle, unsigned char* inputImage, unsigned int bufferLength, int width,LStrHandle outputImage);
extern "C" __declspec(dllexport) int ANSCV_ImageToBase64(ANSCENTER::ANSOPENCV * *Handle, unsigned char* inputImage, unsigned int bufferLength, LStrHandle outputImage);
extern "C" __declspec(dllexport) int ANSCV_ImageToGray(ANSCENTER::ANSOPENCV * *Handle, unsigned char* inputImage, unsigned int bufferLength, LStrHandle outputImage);
extern "C" __declspec(dllexport) int ANSCV_ImageDenoise(ANSCENTER::ANSOPENCV * *Handle, unsigned char* inputImage, unsigned int bufferLength, LStrHandle outputImage);
extern "C" __declspec(dllexport) int ANSCV_ImageRepair(ANSCENTER::ANSOPENCV * *Handle, unsigned char* inputImage, unsigned int bufferLength, LStrHandle outputImage);
extern "C" __declspec(dllexport) int ANSCV_ImageAutoWhiteBalance(ANSCENTER::ANSOPENCV * *Handle, unsigned char* inputImage, unsigned int bufferLength, LStrHandle outputImage);
extern "C" __declspec(dllexport) int ANSCV_ImageBrightEnhance(ANSCENTER::ANSOPENCV * *Handle, unsigned char* inputImage, unsigned int bufferLength, double brightnessScaleFactor, LStrHandle outputImage);
extern "C" __declspec(dllexport) int ANSCV_ImageContrastEnhance(ANSCENTER::ANSOPENCV * *Handle, unsigned char* inputImage, unsigned int bufferLength, LStrHandle outputImage);
extern "C" __declspec(dllexport) int ANSCV_ImageCrop(ANSCENTER::ANSOPENCV** Handle, unsigned char* inputImage, unsigned int bufferLength, int x, int y, int width, int height, LStrHandle outputImage);
extern "C" __declspec(dllexport) int ANSCV_GetImageSize(ANSCENTER::ANSOPENCV** Handle, unsigned char* inputImage, unsigned int bufferLength, LStrHandle imageSize);
extern "C" __declspec(dllexport) int ANSCV_GetImageSizeFromImageFile(ANSCENTER::ANSOPENCV** Handle, const char* imageFilePath, LStrHandle imageSize);
extern "C" __declspec(dllexport) int ANSCV_BlurObjects(ANSCENTER::ANSOPENCV * *Handle, unsigned char* inputImage, unsigned int bufferLength, const char* strBboxes, LStrHandle outputImage);
extern "C" __declspec(dllexport) int ANSCV_BlurBackground(ANSCENTER::ANSOPENCV * *Handle, unsigned char* inputImage, unsigned int bufferLength, const char* strBboxes, LStrHandle outputImage);
extern "C" __declspec(dllexport) int ANSCV_QRDecoder(ANSCENTER::ANSOPENCV * *Handle, unsigned char* inputImage, unsigned int bufferLength, LStrHandle detectedQRText);
extern "C" __declspec(dllexport) int ANSCV_QRDecoderCV(ANSCENTER::ANSOPENCV** Handle, const cv::Mat &image, std::string& detectedQRText);
extern "C" __declspec(dllexport) int ANSCV_PatternMatchs(ANSCENTER::ANSOPENCV * *Handle, unsigned char* inputImage, unsigned int bufferLength, const char* templateFilePath, double theshold, LStrHandle detectedMatchedLocations);
extern "C" __declspec(dllexport) int ANSCV_RotateImage(ANSCENTER::ANSOPENCV** Handle, unsigned char* inputImage, unsigned int bufferLength, double angle, LStrHandle outputImage);
extern "C" __declspec(dllexport) int ANSCV_FlipImage(ANSCENTER::ANSOPENCV** Handle, unsigned char* inputImage, unsigned int bufferLength, int flipCode, LStrHandle outputImage);
extern "C" __declspec(dllexport) int ANSCV_ShiftImage(ANSCENTER::ANSOPENCV** Handle, unsigned char* inputImage, unsigned int bufferLength, int shiftX, int shiftY, LStrHandle outputImage);
extern "C" __declspec(dllexport) int ANSCV_AddGaussianNoise(ANSCENTER::ANSOPENCV** Handle, unsigned char* inputImage, unsigned int bufferLength, double mean, double stddev, LStrHandle outputImage);
extern "C" __declspec(dllexport) int ANSCV_AddSaltAndPepperNoise(ANSCENTER::ANSOPENCV** Handle, unsigned char* inputImage, unsigned int bufferLength, double amount, LStrHandle outputImage);
extern "C" __declspec(dllexport) int ANSCV_AddSpeckleNoise(ANSCENTER::ANSOPENCV** Handle, unsigned char* inputImage, unsigned int bufferLength, double stddev, LStrHandle outputImage);
extern "C" __declspec(dllexport) void ANSCV_InitCameraResource();
extern "C" __declspec(dllexport) void ANSCV_FreeCameraResource();
extern "C" __declspec(dllexport) int ANSCV_ResizeImage_Static(unsigned char* inputImage, unsigned int bufferLength, int width,int height, int& newWidth, int&newHeight, LStrHandle outputImage);
// Image reference management functions
extern "C" __declspec(dllexport) int ANSCV_CloneImage_S(cv::Mat **imageIn, cv::Mat** imageOut);
extern "C" __declspec(dllexport) int ANSCV_ReleaseImage_S(cv::Mat** imageIn);
extern "C" __declspec(dllexport) int ANSCV_ReSizeImage_S(cv::Mat** imageIn, int width, int originalImageSize = 0);
extern "C" __declspec(dllexport) int ANSCV_CropImage_S(cv::Mat** imageIn, int x, int y, int width, int height, int originalImageSize=0);
extern "C" __declspec(dllexport) int ANSCV_GetImage_S(cv::Mat** imageIn, int width, int quality, int& newWidth, int& newHeight, LStrHandle outputImage);
extern "C" __declspec(dllexport) int ANSCV_GetImage_CPP(cv::Mat** imageIn, int width, int quality, int& newWidth, int& newHeight, std::string& outputImage);
extern "C" __declspec(dllexport) int ANSCV_GetImageAndRemoveImgRef_S(cv::Mat** imageIn, int width, int quality, int& newWidth, int& newHeight, LStrHandle outputImage);
extern "C" __declspec(dllexport) int ANSCV_GetImageInfo_S(cv::Mat** imageIn, int &width, int& height);
extern "C" __declspec(dllexport) int ANSCV_CreateImageFromJpegString_S(unsigned char* inputImage, unsigned int bufferLength,cv::Mat** image);
extern "C" __declspec(dllexport) int ANSCV_CreateImageFromFile_S(const char* imageFilePath, cv::Mat** image);
// Pre-process image functions
extern "C" __declspec(dllexport) int ANSCV_ImageAutoWhiteBalance_S(cv::Mat** imageIn);
extern "C" __declspec(dllexport) int ANSCV_ImageBrightEnhance_S(cv::Mat** imageIn, double brightnessScaleFactor);
extern "C" __declspec(dllexport) int ANSCV_ImageContrastEnhance_S(cv::Mat** imageIn);
extern "C" __declspec(dllexport) int ANSCV_ImageDenoise_S(cv::Mat** imageIn);
extern "C" __declspec(dllexport) int ANSCV_ImageRepair_S(cv::Mat** imageIn);
extern "C" __declspec(dllexport) int ANSCV_ImageToGray_S(cv::Mat** imageIn);
extern "C" __declspec(dllexport) int ANSCV_ImageRotate_S(cv::Mat** imageIn, double angle);
extern "C" __declspec(dllexport) int ANSCV_ImageFlip_S(cv::Mat** imageIn, int flipCode);
// Post-process image functions
extern "C" __declspec(dllexport) int ANSCV_ImageBlurObjects_S(cv::Mat** imageIn, const char* strBboxes);
extern "C" __declspec(dllexport) int ANSCV_ImageBlurBackground_S(cv::Mat** imageIn, const char* strBboxes);
extern "C" __declspec(dllexport) int ANSCV_ImageQRDecoder_S(cv::Mat** imageIn, int maxImageWidth, const char* strBboxes, LStrHandle detectedQRText);
extern "C" __declspec(dllexport) int ANSCV_ImagePatternMatchs_S(cv::Mat** imageIn, const char* templateFilePath, double theshold, LStrHandle detectedMatchedLocations);
extern "C" __declspec(dllexport) int ANSCV_ImagesToMP4_S(const char* imageFolder, const char* outputVideoPath, int targetDurationSec);
#endif

1198
modules/ANSCV/ANSRTMP.cpp Normal file

File diff suppressed because it is too large Load Diff

110
modules/ANSCV/ANSRTMP.h Normal file
View File

@@ -0,0 +1,110 @@
#ifndef ANSRTMP_H
#define ANSRTMP_H
#define ANSRTMP_API __declspec(dllexport)
#include <iostream>
#include "ANSLicense.h"
#include "LabVIEWHeader/extcode.h"
#include <vector>
#include "sys_inc.h"
#include "rtmp_cln.h"
#include "hqueue.h"
#include "http.h"
#include "http_parse.h"
#include "video_decoder.h"
#include "audio_decoder.h"
#include "rtmp_player.h"
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/opencv.hpp>
namespace ANSCENTER
{
class ANSRTMP_API ANSRTMPClient
{
protected:
std::unique_ptr<CRtmpPlayer> _playerClient = std::make_unique<CRtmpPlayer>();
std::string _username;
std::string _password;
std::string _url;
bool _useFullURL;
int _imageRotateDeg = 0;
int _displayWidth = 0; // 0 = no resize (return original resolution)
int _displayHeight = 0;
cv::Mat _pLastFrame;
std::string _lastJpegImage;
int _imageWidth, _imageHeight;
int64_t _pts;
bool _isPlaying;
std::recursive_mutex _mutex;
public:
ANSRTMPClient();
~ANSRTMPClient() noexcept;
[[nodiscard]] bool Init(std::string licenseKey, std::string url);
[[nodiscard]] bool Init(std::string licenseKey, std::string username, std::string password, std::string url);
[[nodiscard]] bool Setup();
[[nodiscard]] bool Reconnect();
[[nodiscard]] bool Start();
[[nodiscard]] bool IsPaused();
[[nodiscard]] bool IsPlaying();
[[nodiscard]] bool IsRecording();
[[nodiscard]] bool Stop();
[[nodiscard]] bool Pause();
void Destroy();
void EnableAudio(bool status);
void SetAudioVolume(int volume);
bool areImagesIdentical(const cv::Mat& img1, const cv::Mat& img2);
[[nodiscard]] cv::Mat GetImage(int& width, int& height, int64_t& pts);
[[nodiscard]] std::string MatToBinaryData(const cv::Mat& image);
[[nodiscard]] std::string GetJpegImage(int& width, int& height, int64_t& pts);
void SetImageRotate(int mode) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
_imageRotateDeg = mode;
if (mode > 360) _imageRotateDeg = 360;
};
void SetBBox(cv::Rect bbox);
void SetCrop(bool crop);
static void SetMaxHWDecoders(int maxDecoders);
static int AutoConfigureHWDecoders(int maxPerGpuOverride = 0);
void SetHWDecoding(int hwMode, int preferredGpu = -1);
bool IsHWDecodingActive();
int GetHWDecodingGpuIndex();
void SetDisplayResolution(int width, int height); // Set display output size; 0,0 = original (no resize)
void SetImageQuality(int mode); // 0=fast (AI), 1=quality (display)
AVFrame* GetNV12Frame(); // Returns cloned NV12 frame for GPU fast-path (caller must av_frame_free)
AVFrame* GetCudaHWFrame(); // Returns CUDA HW frame (device ptrs) for zero-copy inference
bool IsCudaHWAccel(); // true when decoder uses CUDA (NV12 stays in GPU VRAM)
public:
void CheckLicense();
SPDLogger& _logger = SPDLogger::GetInstance("ANSRTMP", false);
bool _licenseValid{ false };
std::string _licenseKey;
//std::once_flag licenseOnceFlag;
};
}
extern "C" __declspec(dllexport) int CreateANSRTMPHandle(ANSCENTER::ANSRTMPClient * *Handle, const char* licenseKey, const char* username, const char* password, const char* url);
extern "C" __declspec(dllexport) int ReleaseANSRTMPHandle(ANSCENTER::ANSRTMPClient * *Handle);
extern "C" __declspec(dllexport) int GetRTMPImage(ANSCENTER::ANSRTMPClient * *Handle, int& width, int& height, int64_t & timeStamp, LStrHandle jpegImage);
extern "C" __declspec(dllexport) int GetRTMPtrImage(ANSCENTER::ANSRTMPClient * *Handle, int& width, int& height, int64_t & timeStamp, std::string & jpegImage);
extern "C" __declspec(dllexport) int GetRTMPCVImage(ANSCENTER::ANSRTMPClient** Handle, int& width, int& height, int64_t& timeStamp, cv::Mat** image);
extern "C" __declspec(dllexport) int StartRTMP(ANSCENTER::ANSRTMPClient * *Handle);
extern "C" __declspec(dllexport) int ReconnectRTMP(ANSCENTER::ANSRTMPClient * *Handle);
extern "C" __declspec(dllexport) int StopRTMP(ANSCENTER::ANSRTMPClient * *Handle);
extern "C" __declspec(dllexport) int PauseRTMP(ANSCENTER::ANSRTMPClient** Handle);
extern "C" __declspec(dllexport) int IsRTMPPaused(ANSCENTER::ANSRTMPClient * *Handle);
extern "C" __declspec(dllexport) int IsRTMPRunning(ANSCENTER::ANSRTMPClient * *Handle);
extern "C" __declspec(dllexport) int IsRTMPRecording(ANSCENTER::ANSRTMPClient * *Handle);
extern "C" __declspec(dllexport) void SetRTMPAudioVolume(ANSCENTER::ANSRTMPClient * *Handle, int volume);
extern "C" __declspec(dllexport) void EnableRTMPAudioVolume(ANSCENTER::ANSRTMPClient * *Handle, int status);
extern "C" __declspec(dllexport) void SetRTMPImageRotation(ANSCENTER::ANSRTMPClient * *Handle, double rotationAngle);
extern "C" __declspec(dllexport) int SetBBoxRTMP(ANSCENTER::ANSRTMPClient** Handle, int x, int y, int width, int height);
extern "C" __declspec(dllexport) int SetCropFlagRTMP(ANSCENTER::ANSRTMPClient** Handle, int cropFlag);
extern "C" __declspec(dllexport) void SetRTMPMaxHWDecoders(int maxDecoders);
extern "C" __declspec(dllexport) int AutoConfigureRTMPHWDecoders(int maxPerGpuOverride);
extern "C" __declspec(dllexport) void SetRTMPHWDecoding(ANSCENTER::ANSRTMPClient** Handle, int hwMode, int preferredGpu = -1);
extern "C" __declspec(dllexport) int IsRTMPHWDecodingActive(ANSCENTER::ANSRTMPClient** Handle);
extern "C" __declspec(dllexport) int GetRTMPHWDecodingGpuIndex(ANSCENTER::ANSRTMPClient** Handle);
extern "C" __declspec(dllexport) void SetRTMPImageQuality(ANSCENTER::ANSRTMPClient** Handle, int mode);
extern "C" __declspec(dllexport) void SetRTMPDisplayResolution(ANSCENTER::ANSRTMPClient** Handle, int width, int height);
#endif

1512
modules/ANSCV/ANSRTSP.cpp Normal file

File diff suppressed because it is too large Load Diff

111
modules/ANSCV/ANSRTSP.h Normal file
View File

@@ -0,0 +1,111 @@
#ifndef ANSRTSP_H
#define ANSRTSP_H
#define ANSRTSP_API __declspec(dllexport)
#include <iostream>
#include "ANSLicense.h"
#include "LabVIEWHeader/extcode.h"
#include <vector>
#include "sys_inc.h"
#include "rtsp_cln.h"
#include "hqueue.h"
#include "http.h"
#include "http_parse.h"
#include "video_decoder.h"
#include "audio_decoder.h"
#include "rtsp_player.h"
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/opencv.hpp>
namespace ANSCENTER
{
class ANSRTSP_API ANSRTSPClient
{
protected:
std::unique_ptr<CRtspPlayer> _playerClient = std::make_unique<CRtspPlayer>();
std::string _username;
std::string _password;
std::string _url;
bool _useFullURL;
int _imageRotateDeg = 0;
int _displayWidth = 0; // 0 = no resize (return original resolution)
int _displayHeight = 0;
cv::Mat _pLastFrame;
std::string _lastJpegImage;
int _imageWidth,_imageHeight;
int64_t _pts;
bool _isPlaying;
std::recursive_mutex _mutex;
public:
ANSRTSPClient();
~ANSRTSPClient() noexcept;
[[nodiscard]] bool Init(std::string licenseKey, std::string url);
[[nodiscard]] bool Init(std::string licenseKey, std::string username, std::string password, std::string url);
[[nodiscard]] bool Setup();
[[nodiscard]] bool Reconnect();
[[nodiscard]] bool Start();
[[nodiscard]] bool IsPaused();
[[nodiscard]] bool IsPlaying();
[[nodiscard]] bool IsRecording();
[[nodiscard]] bool Stop();
[[nodiscard]] bool Pause();
void Destroy();
void SetBBox(cv::Rect bbox);
void SetCrop(bool crop);
void EnableAudio(bool status);
void SetAudioVolume(int volume);
[[nodiscard]] cv::Mat GetImage(int& width, int& height, int64_t& pts);
[[nodiscard]] std::string MatToBinaryData(const cv::Mat& image);
[[nodiscard]] std::string GetJpegImage(int& width, int& height, int64_t& pts);
bool areImagesIdentical(const cv::Mat& img1, const cv::Mat& img2);
void SetImageRotate(int mode) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
_imageRotateDeg = mode;
if (mode > 360) _imageRotateDeg = 360;
};
static void SetMaxHWDecoders(int maxDecoders);
static int AutoConfigureHWDecoders(int maxPerGpuOverride = 0);
void SetHWDecoding(int hwMode, int preferredGpu = -1);
bool IsHWDecodingActive();
int GetHWDecodingGpuIndex();
void SetDisplayResolution(int width, int height); // Set display output size; 0,0 = original (no resize)
void SetImageQuality(int mode); // 0=fast (AI), 1=quality (display)
AVFrame* GetNV12Frame(); // Returns cloned NV12 frame for GPU fast-path (caller must av_frame_free)
AVFrame* GetCudaHWFrame(); // Returns CUDA HW frame (device ptrs) for zero-copy inference
bool IsCudaHWAccel(); // true when decoder uses CUDA (NV12 stays in GPU VRAM)
public:
void CheckLicense();
SPDLogger& _logger = SPDLogger::GetInstance("ANSRTSP", false);
bool _licenseValid{ false };
std::string _licenseKey;
//std::once_flag licenseOnceFlag;
};
}
extern "C" __declspec(dllexport) int CreateANSRTSPHandle(ANSCENTER::ANSRTSPClient * *Handle, const char* licenseKey, const char* username, const char* password, const char* url);
extern "C" __declspec(dllexport) int ReleaseANSRTSPHandle(ANSCENTER::ANSRTSPClient * *Handle);
extern "C" __declspec(dllexport) int GetRTSPImage(ANSCENTER::ANSRTSPClient **Handle, int &width, int &height, int64_t& timeStamp, LStrHandle jpegImage);
extern "C" __declspec(dllexport) int GetRTSPStrImage(ANSCENTER::ANSRTSPClient * *Handle, int& width, int& height, int64_t & timeStamp, std::string& jpegImage);
extern "C" __declspec(dllexport) int GetRTSPCVImage(ANSCENTER::ANSRTSPClient** Handle, int& width, int& height, int64_t& timeStamp, cv::Mat** image);
extern "C" __declspec(dllexport) int StartRTSP(ANSCENTER::ANSRTSPClient * *Handle);
extern "C" __declspec(dllexport) int ReconnectRTSP(ANSCENTER::ANSRTSPClient * *Handle);
extern "C" __declspec(dllexport) int StopRTSP(ANSCENTER::ANSRTSPClient * *Handle);
extern "C" __declspec(dllexport) int PauseRTSP(ANSCENTER::ANSRTSPClient** Handle);
extern "C" __declspec(dllexport) int IsRTSPPaused(ANSCENTER::ANSRTSPClient * *Handle);
extern "C" __declspec(dllexport) int IsRTSPRunning(ANSCENTER::ANSRTSPClient * *Handle);
extern "C" __declspec(dllexport) int IsRTSPRecording(ANSCENTER::ANSRTSPClient * *Handle);
extern "C" __declspec(dllexport) void SetRTSPAudioVolume(ANSCENTER::ANSRTSPClient * *Handle, int volume);
extern "C" __declspec(dllexport) void EnableRTSPAudioVolume(ANSCENTER::ANSRTSPClient * *Handle, int status);
extern "C" __declspec(dllexport) void SetRTSPImageRotation(ANSCENTER::ANSRTSPClient * *Handle, double rotationAngle);
extern "C" __declspec(dllexport) int SetBBoxRTSP(ANSCENTER::ANSRTSPClient** Handle, int x, int y, int width, int height);
extern "C" __declspec(dllexport) int SetCropFlagRTSP(ANSCENTER::ANSRTSPClient** Handle, int cropFlag);
extern "C" __declspec(dllexport) void SetMaxHWDecoders(int maxDecoders);
extern "C" __declspec(dllexport) int AutoConfigureHWDecoders(int maxPerGpuOverride);
extern "C" __declspec(dllexport) void SetRTSPHWDecoding(ANSCENTER::ANSRTSPClient** Handle, int hwMode, int preferredGpu = -1);
extern "C" __declspec(dllexport) int IsRTSPHWDecodingActive(ANSCENTER::ANSRTSPClient** Handle);
extern "C" __declspec(dllexport) int GetRTSPHWDecodingGpuIndex(ANSCENTER::ANSRTSPClient** Handle);
extern "C" __declspec(dllexport) void SetRTSPImageQuality(ANSCENTER::ANSRTSPClient** Handle, int mode);
extern "C" __declspec(dllexport) void SetRTSPDisplayResolution(ANSCENTER::ANSRTSPClient** Handle, int width, int height);
#endif

1221
modules/ANSCV/ANSSRT.cpp Normal file

File diff suppressed because it is too large Load Diff

110
modules/ANSCV/ANSSRT.h Normal file
View File

@@ -0,0 +1,110 @@
#ifndef ANSSRT_H
#define ANSSRT_H
#define ANSSRT_API __declspec(dllexport)
#include <iostream>
#include "ANSLicense.h"
#include "LabVIEWHeader/extcode.h"
#include <vector>
#include "sys_inc.h"
#include "srt_cln.h"
#include "hqueue.h"
#include "http.h"
#include "http_parse.h"
#include "video_decoder.h"
#include "audio_decoder.h"
#include "srt_player.h"
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/opencv.hpp>
namespace ANSCENTER
{
class ANSSRT_API ANSSRTClient
{
protected:
std::unique_ptr<CSrtPlayer> _playerClient = std::make_unique<CSrtPlayer>();
std::string _username;
std::string _password;
std::string _url;
bool _useFullURL;
int _imageRotateDeg = 0;
int _displayWidth = 0; // 0 = no resize (return original resolution)
int _displayHeight = 0;
cv::Mat _pLastFrame;
std::string _lastJpegImage;
int _imageWidth, _imageHeight;
int64_t _pts;
bool _isPlaying;
std::recursive_mutex _mutex;
public:
ANSSRTClient();
~ANSSRTClient() noexcept;
[[nodiscard]] bool Init(std::string licenseKey, std::string url);
[[nodiscard]] bool Init(std::string licenseKey, std::string username, std::string password, std::string url);
[[nodiscard]] bool Setup();
[[nodiscard]] bool Reconnect();
[[nodiscard]] bool Start();
[[nodiscard]] bool IsPaused();
[[nodiscard]] bool IsPlaying();
[[nodiscard]] bool IsRecording();
[[nodiscard]] bool Stop();
[[nodiscard]] bool Pause();
void Destroy();
void SetBBox(cv::Rect bbox);
void SetCrop(bool crop);
void EnableAudio(bool status);
void SetAudioVolume(int volume);
[[nodiscard]] cv::Mat GetImage(int& width, int& height, int64_t& pts);
[[nodiscard]] std::string MatToBinaryData(const cv::Mat& image);
[[nodiscard]] std::string GetJpegImage(int& width, int& height, int64_t& pts);
bool areImagesIdentical(const cv::Mat& img1, const cv::Mat& img2);
void SetImageRotate(int mode) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
_imageRotateDeg = mode;
if (mode > 360) _imageRotateDeg = 360;
};
static void SetMaxHWDecoders(int maxDecoders);
static int AutoConfigureHWDecoders(int maxPerGpuOverride = 0);
void SetHWDecoding(int hwMode, int preferredGpu = -1);
bool IsHWDecodingActive();
int GetHWDecodingGpuIndex();
void SetDisplayResolution(int width, int height); // Set display output size; 0,0 = original (no resize)
void SetImageQuality(int mode); // 0=fast (AI), 1=quality (display)
AVFrame* GetNV12Frame(); // Returns cloned NV12 frame for GPU fast-path (caller must av_frame_free)
AVFrame* GetCudaHWFrame(); // Returns CUDA HW frame (device ptrs) for zero-copy inference
bool IsCudaHWAccel(); // true when decoder uses CUDA (NV12 stays in GPU VRAM)
public:
void CheckLicense();
SPDLogger& _logger = SPDLogger::GetInstance("ANSSRT", false);
bool _licenseValid{ false };
std::string _licenseKey;
//std::once_flag licenseOnceFlag;
};
}
extern "C" __declspec(dllexport) int CreateANSSRTHandle(ANSCENTER::ANSSRTClient * *Handle, const char* licenseKey, const char* username, const char* password, const char* url);
extern "C" __declspec(dllexport) int ReleaseANSSRTHandle(ANSCENTER::ANSSRTClient * *Handle);
extern "C" __declspec(dllexport) int GetSRTImage(ANSCENTER::ANSSRTClient * *Handle, int& width, int& height, int64_t& timeStamp, LStrHandle jpegImage);
extern "C" __declspec(dllexport) int GetSRTStrImage(ANSCENTER::ANSSRTClient * *Handle, int& width, int& height, int64_t & timeStamp, std::string & jpegImage);
extern "C" __declspec(dllexport) int GetSRTCVImage(ANSCENTER::ANSSRTClient** Handle, int& width, int& height, int64_t& timeStamp, cv::Mat** image);
extern "C" __declspec(dllexport) int StartSRT(ANSCENTER::ANSSRTClient * *Handle);
extern "C" __declspec(dllexport) int ReconnectSRT(ANSCENTER::ANSSRTClient * *Handle);
extern "C" __declspec(dllexport) int StopSRT(ANSCENTER::ANSSRTClient * *Handle);
extern "C" __declspec(dllexport) int PauseSRT(ANSCENTER::ANSSRTClient** Handle);
extern "C" __declspec(dllexport) int IsSRTPaused(ANSCENTER::ANSSRTClient * *Handle);
extern "C" __declspec(dllexport) int IsSRTRunning(ANSCENTER::ANSSRTClient * *Handle);
extern "C" __declspec(dllexport) int IsSRTRecording(ANSCENTER::ANSSRTClient * *Handle);
extern "C" __declspec(dllexport) void SetSRTAudioVolume(ANSCENTER::ANSSRTClient * *Handle, int volume);
extern "C" __declspec(dllexport) void EnableSRTAudioVolume(ANSCENTER::ANSSRTClient * *Handle, int status);
extern "C" __declspec(dllexport) void SetSRTImageRotation(ANSCENTER::ANSSRTClient * *Handle, double rotationAngle);
extern "C" __declspec(dllexport) int SetBBoxSRT(ANSCENTER::ANSSRTClient** Handle, int x, int y, int width, int height);
extern "C" __declspec(dllexport) int SetCropFlagSRT(ANSCENTER::ANSSRTClient** Handle, int cropFlag);
extern "C" __declspec(dllexport) void SetSRTMaxHWDecoders(int maxDecoders);
extern "C" __declspec(dllexport) int AutoConfigureSRTHWDecoders(int maxPerGpuOverride);
extern "C" __declspec(dllexport) void SetSRTHWDecoding(ANSCENTER::ANSSRTClient** Handle, int hwMode, int preferredGpu = -1);
extern "C" __declspec(dllexport) int IsSRTHWDecodingActive(ANSCENTER::ANSSRTClient** Handle);
extern "C" __declspec(dllexport) int GetSRTHWDecodingGpuIndex(ANSCENTER::ANSSRTClient** Handle);
extern "C" __declspec(dllexport) void SetSRTImageQuality(ANSCENTER::ANSSRTClient** Handle, int mode);
extern "C" __declspec(dllexport) void SetSRTDisplayResolution(ANSCENTER::ANSSRTClient** Handle, int width, int height);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,110 @@
#ifndef ANSVIDEOPLAYER_H
#define ANSVIDEOPLAYER_H
#define ANSVIDEOPLAYER_API __declspec(dllexport)
#include <iostream>
#include "ANSLicense.h"
#include "LabVIEWHeader/extcode.h"
#include <vector>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/opencv.hpp>
#include <thread>
#include <chrono>
#include <atomic>
#include <turbojpeg.h>
#include "file_player.h" // CFilePlayer (FFmpeg HW decode: CUDA/D3D11VA/DXVA2)
#include "video_decoder.h" // HW_DECODING_AUTO, HWDecoderPool
namespace ANSCENTER
{
class ANSVIDEOPLAYER_API ANSVIDEOPLAYER
{
protected:
cv::VideoCapture cap;
int _resWidth;
int _resHeight;
int64_t _totalFrames;
int64_t _currentFrame;
int64_t _previousPTS;
double _fps;
bool _isPlaying;
std::string _lastJpegImage;
cv::Mat _previousImage;
bool m_bPaused;
int _imageRotateDeg = 0;
std::string _url;
cv::Rect _bbox;
bool _crop;
std::recursive_mutex _mutex;
std::mutex _cvMutex;
std::condition_variable _cv;
tjhandle _jpegCompressor;
public:
// --- HW decode state (CFilePlayer composition) ---
// Public: accessed by extern "C" GetVideoPlayerCVImage for NV12/CUDA registry attachment
std::unique_ptr<CFilePlayer> _hwPlayer; // HW decode path (nullptr = CV fallback)
bool _hwDecodeActive = false; // true when _hwPlayer init succeeded
int _hwGpuIndex = -1; // GPU index for registry (-1 = CPU only)
bool _hwCudaAccel = false; // true = NVIDIA CUDA zero-copy available
bool _hwEOF = false; // true when video reached end of file
int64_t _hwFrameCount = 0; // frame counter for EOF detection
int64_t _hwLastPts = 0; // last video PTS for EOF wrap detection
ANSVIDEOPLAYER();
~ANSVIDEOPLAYER() noexcept;
[[nodiscard]] bool Init(std::string licenseKey, std::string url);
[[nodiscard]] bool Setup();
[[nodiscard]] bool Reconnect();
[[nodiscard]] bool Start();
[[nodiscard]] bool IsPaused();
[[nodiscard]] bool IsPlaying();
[[nodiscard]] bool IsRecording();
void SetBBox(cv::Rect bbox);
void SetCrop(bool crop);
[[nodiscard]] bool Stop();
void Destroy();
void EnableAudio(bool status);
void SetAudioVolume(int volume);
void SetImageRotate(int mode) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
_imageRotateDeg = mode;
if (mode > 360) _imageRotateDeg = 360;
};
[[nodiscard]] cv::Mat GetImage(int& width, int& height, int64_t& pts);
[[nodiscard]] cv::Mat GetInferenceImage(); // Returns full-res frame for AI inference (no resize/rotation)
[[nodiscard]] std::string MatToBinaryData(const cv::Mat& image);
[[nodiscard]] std::string GetJpegStringImage(int& width, int& height, int64_t& pts);
void SetDisplayResolution(int width, int height); // Set display output size; 0,0 = original (no resize)
public:
void CheckLicense();
SPDLogger& _logger = SPDLogger::GetInstance("ANSVideoPlayer", false);
bool _licenseValid{ false };
//std::once_flag licenseOnceFlag;
std::string _licenseKey;
cv::Mat _inferenceCloneCurr; // Heap-cloned full-res (keeps data alive for registry)
cv::Mat _inferenceClonePrev; // Previous clone (keeps data alive during ANSRTYOLO read)
private:
std::string encodeJpegString(const cv::Mat& img, int quality = 80);
int _displayWidth = 0; // 0 = no resize (return original)
int _displayHeight = 0;
cv::Mat _inferenceImage; // Full-res frame for AI inference
};
}
extern "C" __declspec(dllexport) int CreateANSVideoPlayerHandle(ANSCENTER::ANSVIDEOPLAYER** Handle, const char* licenseKey, const char* url);
extern "C" __declspec(dllexport) int ReleaseANSVideoPlayerHandle(ANSCENTER::ANSVIDEOPLAYER** Handle);
extern "C" __declspec(dllexport) int GetVideoPlayerImage(ANSCENTER::ANSVIDEOPLAYER** Handle, int& width, int& height, int64_t& timeStamp, LStrHandle jpegImage);
extern "C" __declspec(dllexport) int GetVideoPlayerStrImage(ANSCENTER::ANSVIDEOPLAYER** Handle, int& width, int& height, int64_t& timeStamp, std::string& jpegImage);
extern "C" __declspec(dllexport) int GetVideoPlayerCVImage(ANSCENTER::ANSVIDEOPLAYER** Handle, int& width, int& height, int64_t& timeStamp, cv::Mat** image);
extern "C" __declspec(dllexport) int StartVideoPlayer(ANSCENTER::ANSVIDEOPLAYER** Handle);
extern "C" __declspec(dllexport) int ReconnectVideoPlayer(ANSCENTER::ANSVIDEOPLAYER** Handle);
extern "C" __declspec(dllexport) int StopVideoPlayer(ANSCENTER::ANSVIDEOPLAYER** Handle);
extern "C" __declspec(dllexport) int IsVideoPlayerPaused(ANSCENTER::ANSVIDEOPLAYER** Handle);
extern "C" __declspec(dllexport) int IsVidedoPlayerRunning(ANSCENTER::ANSVIDEOPLAYER** Handle);
extern "C" __declspec(dllexport) int IsVideoPlayerRecording(ANSCENTER::ANSVIDEOPLAYER** Handle);
extern "C" __declspec(dllexport) void SetVideoPlayerAudioVolume(ANSCENTER::ANSVIDEOPLAYER** Handle, int volume);
extern "C" __declspec(dllexport) void EnableVideoPlayerAudioVolume(ANSCENTER::ANSVIDEOPLAYER** Handle, int status);
extern "C" __declspec(dllexport) void SetVideoPlayerImageRotation(ANSCENTER::ANSVIDEOPLAYER** Handle, double rotationAngle);
extern "C" __declspec(dllexport) int SetBBoxVideoPlayer(ANSCENTER::ANSVIDEOPLAYER** Handle, int x, int y, int width, int height);
extern "C" __declspec(dllexport) int SetCropFlagVideoPlayer(ANSCENTER::ANSVIDEOPLAYER** Handle, int cropFlag);
extern "C" __declspec(dllexport) void SetVideoPlayerDisplayResolution(ANSCENTER::ANSVIDEOPLAYER** Handle, int width, int height);
#endif

1758
modules/ANSCV/ANSWebcam.cpp Normal file

File diff suppressed because it is too large Load Diff

140
modules/ANSCV/ANSWebcam.h Normal file
View File

@@ -0,0 +1,140 @@
#ifndef ANSWEBCAM_H
#define ANSWEBCAM_H
#define ANSWEBCAM_API __declspec(dllexport)
#include <iostream>
#include "ANSLicense.h"
#include "LabVIEWHeader/extcode.h"
#include <vector>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/opencv.hpp>
#include <dshow.h>
#include <mutex>
#include <nvjpeg.h>
#include <cuda_runtime.h>
#include <turbojpeg.h>
#pragma comment(lib, "strmiids.lib")
#pragma comment(lib, "ole32.lib")
namespace ANSCENTER
{
struct Resolution {
int width;
int height;
Resolution(int w, int h) : width(w), height(h) {}
int getArea() const {
return width * height;
}
bool operator<(const Resolution& other) const {
return getArea() < other.getArea();
}
};
class ANSWEBCAM_API ANSWEBCAMPlayer
{
protected:
// Add this structure definition in the private section
cv::VideoCapture cap;
int _deviceId;
int _resWidth;
int _resHeight;
int _savedResWidth = 0; // Saved resolution for stop/start restore
int _savedResHeight = 0;
bool _enableMaxResolution = false; // false = Full HD default, true = max resolution
int64_t _previousPTS;
cv::Mat _previousImage;
bool m_bPaused;
std::string _lastJpegImage;
bool _isPlaying;
std::vector<std::string> _cameraNames;
int _imageRotateDeg = 0;
std::recursive_mutex _mutex;
cv::Rect _bbox;
bool _crop;
EngineType engineType;
// Initialize nvJPEG structures
nvjpegHandle_t nv_handle;
nvjpegEncoderState_t nv_enc_state;
nvjpegEncoderParams_t nv_enc_params;
cudaStream_t stream;
tjhandle _jpegCompressor;
public:
ANSWEBCAMPlayer();
~ANSWEBCAMPlayer() noexcept;
[[nodiscard]] bool Init(std::string licenseKey, std::string url);
[[nodiscard]] bool Setup();
[[nodiscard]] bool Reconnect();
[[nodiscard]] bool Start();
[[nodiscard]] bool IsPaused();
[[nodiscard]] bool IsPlaying();
[[nodiscard]] bool IsRecording();
[[nodiscard]] bool Stop();
void Destroy();
void EnableAudio(bool status);
void SetAudioVolume(int volume);
[[nodiscard]] cv::Mat GetImage(int& width, int& height, int64_t& pts);
[[nodiscard]] std::string MatToBinaryData(const cv::Mat& image);
[[nodiscard]] std::string GetJpegStringImage(int& width, int& height, int64_t& pts);
[[nodiscard]] static std::string VectorToCommaSeparatedString(const std::vector<std::string>& inputVector);
[[nodiscard]] static std::vector<std::string> ScanWebcamDevices();
[[nodiscard]] static std::string GetSupportedResolutions(int deviceId);
static std::mutex mtx;
void SetImageRotate(int mode) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
_imageRotateDeg = mode;
if (mode > 360) _imageRotateDeg = 360;
};
void SetBBox(cv::Rect bbox);
void SetCrop(bool crop);
void SetDisplayResolution(int width, int height); // Set display output size; 0,0 = original (no resize)
[[nodiscard]] cv::Mat GetInferenceImage(); // Returns full-res frame for AI inference (no resize)
cv::Mat _inferenceCloneCurr; // Heap-cloned full-res (keeps data alive for registry)
cv::Mat _inferenceClonePrev; // Previous clone (keeps data alive during ANSRTYOLO read)
public:
void CheckLicense();
SPDLogger& _logger = SPDLogger::GetInstance("ANSWebcamPlayer", false);
bool _licenseValid{ false };
std::string _licenseKey;
// Resolution management methods
std::vector<Resolution> GetAvailableResolutions(int deviceId);
bool SetBestResolution(int deviceId);
bool SetPreferredResolution(int deviceId);
bool SetResolution(int width, int height);
void SetEnableMaxResolution(bool enable);
std::string GetAvailableResolutionsString(int deviceId);
private:
std::string encodeJpegString(const cv::Mat& img, int quality = 80);
std::string encodeMatToJpegWithNvJPEG(const cv::Mat& inputMat, int quality = 80);
void uploadPlanarBGRToGPU(const cv::Mat& inputMat, unsigned char** data);
int _displayWidth = 0; // 0 = no resize (return original)
int _displayHeight = 0;
cv::Mat _inferenceImage; // Full-res frame for AI inference
};
std::mutex ANSWEBCAMPlayer::mtx; // Definition of the static mutex
}
extern "C" __declspec(dllexport) int CreateANSWebcamPlayerHandle(ANSCENTER::ANSWEBCAMPlayer * *Handle, const char* licenseKey, const char* url);
extern "C" __declspec(dllexport) int CreateANSWebcamPlayerWithMaxResoHandle(ANSCENTER::ANSWEBCAMPlayer * *Handle, const char* licenseKey, const char* url);
extern "C" __declspec(dllexport) int ReleaseANSWebcamPlayerHandle(ANSCENTER::ANSWEBCAMPlayer * *Handle);
extern "C" __declspec(dllexport) int ScanANSWebcamPlayer(LStrHandle cameraNames);
extern "C" __declspec(dllexport) int ScanStrANSWebcamPlayer(std::vector<std::string> &cameraNameList);
extern "C" __declspec(dllexport) int GetWebcamImage(ANSCENTER::ANSWEBCAMPlayer * *Handle, int& width, int& height, int64_t & timeStamp, LStrHandle jpegImage);
extern "C" __declspec(dllexport) int GetWebcamStrImage(ANSCENTER::ANSWEBCAMPlayer * *Handle, int& width, int& height, int64_t & timeStamp, std::string & jpegImage);
extern "C" __declspec(dllexport) int GetWebcamCVImage(ANSCENTER::ANSWEBCAMPlayer** Handle, int& width, int& height, int64_t& timeStamp, cv::Mat** image);
extern "C" __declspec(dllexport) int StartWebcamPlayer(ANSCENTER::ANSWEBCAMPlayer * *Handle);
extern "C" __declspec(dllexport) int ReconnectWebcamPlayer(ANSCENTER::ANSWEBCAMPlayer * *Handle);
extern "C" __declspec(dllexport) int StopWebcamPlayer(ANSCENTER::ANSWEBCAMPlayer * *Handle);
extern "C" __declspec(dllexport) int IsWebcamPlayerPaused(ANSCENTER::ANSWEBCAMPlayer * *Handle);
extern "C" __declspec(dllexport) int IsWebcamPlayerRunning(ANSCENTER::ANSWEBCAMPlayer * *Handle);
extern "C" __declspec(dllexport) int IsWebcamPlayerRecording(ANSCENTER::ANSWEBCAMPlayer * *Handle);
extern "C" __declspec(dllexport) void SetWebcamPlayerAudioVolume(ANSCENTER::ANSWEBCAMPlayer * *Handle, int volume);
extern "C" __declspec(dllexport) void EnableWebcamPlayerAudioVolume(ANSCENTER::ANSWEBCAMPlayer * *Handle, int status);
extern "C" __declspec(dllexport) void SetWebcamImageRotation(ANSCENTER::ANSWEBCAMPlayer * *Handle, double rotationAngle);
extern "C" __declspec(dllexport) int ScanSupportedResolutions(std::string cameraName,std::vector<std::string> cameraNameList, std::string &supportedResolution);
extern "C" __declspec(dllexport) int SetBBoxANSWebcamPlayer(ANSCENTER::ANSWEBCAMPlayer** Handle, int x, int y, int width, int height);
extern "C" __declspec(dllexport) int SetCropFlagANSWebcamPlayer(ANSCENTER::ANSWEBCAMPlayer** Handle, int cropFlag);
extern "C" __declspec(dllexport) void SetWebcamDisplayResolution(ANSCENTER::ANSWEBCAMPlayer** Handle, int width, int height);
#endif

View File

@@ -0,0 +1,121 @@
# ANSCV — Computer Vision / Media DLL (video capture, RTSP, FFmpeg)
file(GLOB ANSCV_HEADERS "*.h")
file(GLOB ANSCV_SOURCES "*.cpp")
# Exclude old VideoPlayer.cpp — superseded by MediaClient/media/video_player.cpp
list(REMOVE_ITEM ANSCV_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/VideoPlayer.cpp")
# MediaClient sources compiled into ANSCV (from original vcxproj)
set(MEDIACLIENT_SOURCES
${CMAKE_SOURCE_DIR}/MediaClient/media/audio_capture.cpp
${CMAKE_SOURCE_DIR}/MediaClient/media/audio_capture_win.cpp
${CMAKE_SOURCE_DIR}/MediaClient/media/audio_decoder.cpp
${CMAKE_SOURCE_DIR}/MediaClient/media/audio_encoder.cpp
${CMAKE_SOURCE_DIR}/MediaClient/media/audio_play.cpp
${CMAKE_SOURCE_DIR}/MediaClient/media/audio_play_win.cpp
${CMAKE_SOURCE_DIR}/MediaClient/media/avcodec_mutex.cpp
${CMAKE_SOURCE_DIR}/MediaClient/media/avi_write.cpp
${CMAKE_SOURCE_DIR}/MediaClient/media/file_player.cpp
${CMAKE_SOURCE_DIR}/MediaClient/media/http_flv_player.cpp
${CMAKE_SOURCE_DIR}/MediaClient/media/http_mjpeg_player.cpp
${CMAKE_SOURCE_DIR}/MediaClient/media/media_codec.cpp
${CMAKE_SOURCE_DIR}/MediaClient/media/media_parse.cpp
${CMAKE_SOURCE_DIR}/MediaClient/media/media_util.cpp
${CMAKE_SOURCE_DIR}/MediaClient/media/rtmp_player.cpp
${CMAKE_SOURCE_DIR}/MediaClient/media/rtsp_player.cpp
${CMAKE_SOURCE_DIR}/MediaClient/media/srt_player.cpp
${CMAKE_SOURCE_DIR}/MediaClient/media/video_decoder.cpp
${CMAKE_SOURCE_DIR}/MediaClient/media/video_player.cpp
${CMAKE_SOURCE_DIR}/MediaClient/rtp/h264_rtp_rx.cpp
${CMAKE_SOURCE_DIR}/MediaClient/rtp/h264_util.cpp
${CMAKE_SOURCE_DIR}/MediaClient/rtp/h265_rtp_rx.cpp
${CMAKE_SOURCE_DIR}/MediaClient/rtp/h265_util.cpp
${CMAKE_SOURCE_DIR}/MediaClient/rtp/mjpeg_rtp_rx.cpp
${CMAKE_SOURCE_DIR}/MediaClient/rtp/mjpeg_tables.cpp
${CMAKE_SOURCE_DIR}/MediaClient/rtp/ts_parser.cpp
${CMAKE_SOURCE_DIR}/MediaClient/rtsp/rtsp_backchannel.cpp
${CMAKE_SOURCE_DIR}/MediaClient/rtsp/rtsp_cln.cpp
)
add_library(ANSCV SHARED ${ANSCV_HEADERS} ${ANSCV_SOURCES} ${MEDIACLIENT_SOURCES})
# MediaClient sources skip precompiled headers (they don't include ANSCV's pch.h)
set_source_files_properties(${MEDIACLIENT_SOURCES} PROPERTIES SKIP_PRECOMPILE_HEADERS ON)
target_include_directories(ANSCV PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}
)
# MediaClient includes (referenced from original ANLS)
target_include_directories(ANSCV PRIVATE
${CMAKE_SOURCE_DIR}/MediaClient
${CMAKE_SOURCE_DIR}/MediaClient/media
${CMAKE_SOURCE_DIR}/MediaClient/rtsp
${CMAKE_SOURCE_DIR}/MediaClient/rtp
${CMAKE_SOURCE_DIR}/MediaClient/http
${CMAKE_SOURCE_DIR}/MediaClient/directx
${CMAKE_SOURCE_DIR}/MediaClient/directx/include
${CMAKE_SOURCE_DIR}/MediaClient/ffmpeg/include
${CMAKE_SOURCE_DIR}/MediaClient/openssl/include
${CMAKE_SOURCE_DIR}/MediaClient/libsrt/include
${CMAKE_SOURCE_DIR}/MediaClient/bm
${CMAKE_SOURCE_DIR}/MediaClient/rtmp
${CMAKE_SOURCE_DIR}/MediaClient/librtmp
${CMAKE_SOURCE_DIR}/MediaClient/srt
${SHARED_INCLUDE_DIR}
)
target_link_libraries(ANSCV
PRIVATE ANSLicensingSystem
PRIVATE labview
PRIVATE spdlog_dep
PRIVATE ANSLibsLoader
PRIVATE opencv
PRIVATE ffmpeg
PRIVATE turbojpeg
PRIVATE zxing
PRIVATE zlib_dep
PRIVATE CUDA::cudart_static
PRIVATE CUDA::cublasLt
PRIVATE CUDA::nvjpeg
)
# Platform-specific libs
if(WIN32)
target_link_directories(ANSCV PRIVATE
${CMAKE_SOURCE_DIR}/MediaClient/directx/lib/x64
${CMAKE_SOURCE_DIR}/MediaClient/openssl/lib/x64
${CMAKE_SOURCE_DIR}/MediaClient/libsrt/lib/x64
)
# Prebuilt MediaClient protocol libraries (built from MediaClient VS project)
target_link_directories(ANSCV PRIVATE "${ANLS_ROOT}/MediaClient/x64/Release")
target_link_libraries(ANSCV PRIVATE
RtspClientLibrary HttpFlvClientLibrary HttpMjpegClientLibrary
RtmpClientLibrary SrtClientLibrary
d3d9 d3dx9 dxva2
libcrypto libssl srt
${WIN_COMMON_LIBS}
)
else()
target_link_libraries(ANSCV PRIVATE ${UNIX_COMMON_LIBS})
endif()
target_compile_definitions(ANSCV PRIVATE
ANSCV_EXPORTS
_USRDLL
HT_STATIC
HTTPS
BACKCHANNEL
METADATA
REPLAY
OVER_HTTP
OVER_WEBSOCKET
NOMINMAX
)
if(WIN32)
target_compile_definitions(ANSCV PRIVATE UNICODE _UNICODE __WINDOWS_OS__)
else()
target_compile_definitions(ANSCV PRIVATE __LINUX_OS__)
endif()
target_precompile_headers(ANSCV PRIVATE pch.h)

File diff suppressed because it is too large Load Diff

199
modules/ANSCV/VideoPlayer.h Normal file
View File

@@ -0,0 +1,199 @@
/***************************************************************************************
*
* IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
*
* By downloading, copying, installing or using the software you agree to this license.
* If you do not agree to this license, do not download, install,
* copy or use the software.
*
* Copyright (C) 2014-2024, Happytimesoft Corporation, all rights reserved.
*
* Redistribution and use in binary forms, with or without modification, are permitted.
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
* language governing permissions and limitations under the License.
*
****************************************************************************************/
#ifndef VIDEO_PLAYER_H
#define VIDEO_PLAYER_H
#include "sys_inc.h"
#include "hqueue.h"
#include "video_decoder.h"
#include "audio_decoder.h"
#include "audio_play.h"
#include "avi_write.h"
#include "media_util.h"
#include <list>
#include <string>
typedef struct
{
uint32 SyncTimestamp;
struct timeval SyncTime;
} HTCLOCK;
typedef std::list<AVFrame*> FRAMELIST;
class CVideoPlayer
{
public:
CVideoPlayer();
virtual ~CVideoPlayer();
virtual BOOL open(std::string fileName);
virtual BOOL play() = 0;
virtual void stop() = 0;
virtual BOOL pause() = 0;
virtual void close();
virtual BOOL seek(int pos) { return FALSE; }
virtual BOOL isPlaying() { return m_bPlaying; }
virtual BOOL isPaused() { return m_bPaused; }
virtual void setVolume(int volume);
virtual void snapshot(int videofmt);
virtual BOOL record(std::string baseName);
virtual void stopRecord();
virtual BOOL isRecording() { return m_bRecording; }
virtual BOOL onRecord() { return FALSE; }
virtual int getVideoClock() { return 1000; }
virtual int getAudioClock() { return 1000; }
virtual void setWindowSize(int size);
virtual int64 getElapse() { return 0; }
virtual int64 getDuration() { return 0; }
virtual int getVideoCodec() { return m_nVideoCodec; }
virtual int getAudioCodec() { return m_nAudioCodec; }
virtual void setAuthInfo(std::string acct, std::string pass) { m_acct = acct; m_pass = pass; }
virtual void setRenderMode(int mode) { m_nRenderMode = mode; }
virtual void setHWDecoding(int mode) { m_nHWDecoding = mode; }
virtual void setRtpMulticast(BOOL flag) {}
virtual void setRtpOverUdp(BOOL flag) {}
#ifdef OVER_HTTP
virtual void setRtspOverHttp(int flag, int port) {}
#endif
#ifdef OVER_WEBSOCKET
virtual void setRtspOverWs(int flag, int port) {}
#endif
#ifdef BACKCHANNEL
virtual int getBCFlag() { return 0; }
virtual void setBCFlag(int flag) {}
virtual int getBCDataFlag() { return 0; }
virtual void setBCDataFlag(int flag) {}
virtual void setAudioDevice(int index) {}
#endif
#ifdef REPLAY
virtual int getReplayFlag() { return 0; }
virtual void setReplayFlag(int flag) {}
virtual void setScale(double scale) {}
virtual void setRateControlFlag(int flag) {}
virtual void setImmediateFlag(int flag) {}
virtual void setFramesFlag(int flag, int interval) {}
virtual void setReplayRange(time_t start, time_t end) {}
#endif
BOOL openVideo(int codec, uint8* extradata = NULL, int extradata_size = 0);
BOOL openVideo(enum AVCodecID codec, uint8* extradata = NULL, int extradata_size = 0);
void closeVideo();
BOOL openAudio(int codec, int samplerate, int channels, int bitpersample = 0);
BOOL openAudio(enum AVCodecID codec, int samplerate, int channels, int bitpersample = 0);
void closeAudio();
void playVideo(uint8* data, int len, uint32 ts, uint16 seq);
void playAudio(uint8* data, int len, uint32 ts, uint16 seq);
void recordVideo(uint8* data, int len, uint32 ts, uint16 seq);
void recordAudio(uint8* data, int len, uint32 ts, uint16 seq);
int getVideoWidth();
int getVideoHeight();
double getFrameRate();
int getSampleRate() { return m_nSampleRate; }
int getChannel() { return m_nChannel; }
void onVideoFrame(AVFrame* frame);
void onAudioFrame(AVFrame* frame);
void audioPlayThread();
void videoPlayThread();
//signals:
// void notify(int);
// void snapshoted(AVFrame*);
protected:
void updateClock(HTCLOCK* clock, uint32 ts, int frequency);
BOOL initFrame(AVFrame*& frame, int width, int height, AVPixelFormat pixfmt);
//BOOL initVideoRender(int width, int height);
BOOL doSnapshot(AVFrame* srcframe);
AVFrame* convertFrame(AVFrame* srcframe, AVFrame* dstframe, BOOL updown);
void recordVideoEx(uint8* data, int len, uint32 ts, uint16 seq);
BOOL recordSwitchCheck();
void recordFileSwitch();
protected:
BOOL m_bVideoInited;
BOOL m_bAudioInited;
CVideoDecoder* m_pVideoDecoder;
CAudioDecoder* m_pAudioDecoder;
//CVideoRender* m_pVideoRender;
CAudioPlay* m_pAudioPlay;
BOOL m_bPlaying;
BOOL m_bPaused;
std::string m_acct;
std::string m_pass;
std::string m_sFileName;
std::string m_sBaseName;
//WId m_nVideoWnd;
int m_size;
BOOL m_bSizeChanged;
int m_nRenderMode;
int m_nHWDecoding;
AVPixelFormat m_nDstVideoFmt;
BOOL m_bUpdown;
BOOL m_bSnapshot;
int m_nSnapVideoFmt;
H26XParamSets m_h26XParamSets;
int m_nVideoCodec;
int m_nAudioCodec;
int m_nSampleRate;
int m_nChannel;
int m_nBitPerSample;
AVFrame* m_pSnapFrame;
AVFrame* m_pRenderFrame;
BOOL m_bRecording;
BOOL m_bNalFlag;
AVICTX* m_pAviCtx;
void* m_pRecordMutex;
HTCLOCK m_audioClock;
void* m_pAudioListMutex;
FRAMELIST m_audioFrameList;
BOOL m_audioPlayFlag;
pthread_t m_audioPlayThread;
HTCLOCK m_videoClock;
void* m_pVideoListMutex;
FRAMELIST m_videoFrameList;
BOOL m_videoPlayFlag;
pthread_t m_videoPlayThread;
uint64 m_nLastAudioPts;
time_t m_lastAudioTS;
};
#endif // end of VIDEO_PLAYER_H

106
modules/ANSCV/dllmain.cpp Normal file
View File

@@ -0,0 +1,106 @@
// dllmain.cpp : Defines the entry point for the DLL application.
#include "pch.h"
#include <mutex>
#include <unordered_map>
#include <iostream>
#include <functional>
// ── Global handle registry for shutdown cleanup ──────────────────────────
// Streaming handle creators register a stop-callback on creation.
// DLL_PROCESS_DETACH invokes all callbacks so threads exit before DLL unmaps.
static std::mutex& shutdownMutex() {
static std::mutex m;
return m;
}
static std::unordered_map<void*, std::function<void()>>& shutdownRegistry() {
static std::unordered_map<void*, std::function<void()>> r;
return r;
}
// Called by Create*Handle functions to register a cleanup callback
extern "C" void anscv_register_handle(void* handle, void(*stopFn)(void*)) {
if (!handle || !stopFn) return;
std::lock_guard<std::mutex> lk(shutdownMutex());
shutdownRegistry()[handle] = [=]() { stopFn(handle); };
}
// Called by Release*Handle functions to unregister (handle properly cleaned up)
extern "C" void anscv_unregister_handle(void* handle) {
if (!handle) return;
std::lock_guard<std::mutex> lk(shutdownMutex());
shutdownRegistry().erase(handle);
}
// Stop all leaked handles
static void stopAllHandles() {
std::unordered_map<void*, std::function<void()>> copy;
{
std::lock_guard<std::mutex> lk(shutdownMutex());
copy.swap(shutdownRegistry());
}
for (auto& [ptr, fn] : copy) {
try { fn(); } catch (...) {}
}
}
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
) noexcept
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
// Pin the DLL so it is never unmapped from the process address space.
// ANSCV creates background threads (RTSP receive, timers) that may
// still be running when LabVIEW's CLR/COM shutdown unloads the DLL.
// If the DLL is unmapped while threads are executing its code, the
// threads crash with an access violation at <Unloaded_ANSCV.dll>.
// Pinning keeps the code pages mapped; the OS kills all threads when
// the process exits, so this is safe and is Microsoft's recommended
// pattern for DLLs that own threads.
{
HMODULE hSelf = nullptr;
GetModuleHandleExW(
GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
GET_MODULE_HANDLE_EX_FLAG_PIN,
reinterpret_cast<LPCWSTR>(&DllMain),
&hSelf);
}
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
// CRITICAL: Do NOT call stopAllHandles() here.
//
// DllMain holds the OS loader lock (LdrpLoaderLock). Destroying
// streaming handles (CRtspPlayer → CVideoPlayer → CWAudioPlay)
// calls dsound!CThread::Terminate which waits for the DirectSound
// admin thread to exit. That thread needs the loader lock to shut
// down → classic deadlock. (Confirmed by crash dump analysis:
// Thread 0 holds LdrpLoaderLock and waits for dsound thread 331,
// which is blocked on LdrpLoaderLock.)
//
// If lpReserved is non-NULL the process is terminating — the OS
// will tear down all threads and reclaim resources; cleanup is
// unnecessary and dangerous. If lpReserved is NULL (dynamic
// FreeLibrary), LabVIEW should have called Release*Handle first.
// Log leaked handles for diagnostics but do NOT stop them here.
if (lpReserved == nullptr) {
// Dynamic unload — warn about leaked handles (non-blocking)
try {
std::lock_guard<std::mutex> lk(shutdownMutex());
if (!shutdownRegistry().empty()) {
std::cerr << "[ANSCV] WARNING: " << shutdownRegistry().size()
<< " streaming handle(s) leaked at DLL unload."
<< " Call Release*Handle before FreeLibrary." << std::endl;
}
} catch (...) {}
}
break;
}
return TRUE;
}

View File

@@ -0,0 +1,7 @@
#pragma once
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#define NOMINMAX // Prevent windows.h from defining min/max macros
// which break std::min / std::max (C2589)
// Windows Header Files
#include <windows.h>

5
modules/ANSCV/pch.cpp Normal file
View File

@@ -0,0 +1,5 @@
// pch.cpp: source file corresponding to the pre-compiled header
#include "pch.h"
// When you are using pre-compiled headers, this source file is necessary for compilation to succeed.

25
modules/ANSCV/pch.h Normal file
View File

@@ -0,0 +1,25 @@
// pch.h: This is a precompiled header file.
// Files listed below are compiled only once, improving build performance for future builds.
// This also affects IntelliSense performance, including code completion and many code browsing features.
// However, files listed here are ALL re-compiled if any one of them is updated between builds.
// Do not add files here that you will be updating frequently as this negates the performance advantage.
#ifndef PCH_H
#define PCH_H
// add headers that you want to pre-compile here
#include "framework.h"
#include <algorithm>
#include <memory>
#include <string>
#include <string_view>
#include <vector>
#include <mutex>
// Legacy code uses bare min/max (without std:: prefix).
// NOMINMAX prevents windows.h from defining min/max macros,
// so pull them in from <algorithm> instead.
using std::min;
using std::max;
#endif //PCH_H