update hikvision camera

This commit is contained in:
linbo 2026-07-22 15:58:40 +08:00
parent 1fc5179344
commit 53f71bb720
4 changed files with 113 additions and 60 deletions

View File

@ -82,7 +82,7 @@ camera {
cameras {
id: "hikvision_cam"
hikvision {
ip: "192.168.1.64"
ip: "192.168.192.64"
port: 8000
username: "admin"
password: "okwy1688"
@ -101,7 +101,7 @@ camera {
cameras {
id: "hikvision_thermal_cam"
hikvision {
ip: "192.168.1.65"
ip: "192.168.192.65"
port: 8000
username: "admin"
password: "okwy1688"

View File

@ -70,13 +70,13 @@ device_manager {
id: "hikvision_cam"
type: DEVICE_TYPE_CAMERA
config_file: "devices/camera/camera.pb.txt"
enable: false
enable: true
}
devices {
id: "hikvision_thermal_cam"
type: DEVICE_TYPE_CAMERA
config_file: "devices/camera/camera.pb.txt"
enable: false
enable: true
}
devices {

View File

@ -4,6 +4,8 @@
#include <memory>
#include <mutex>
#include <string>
#include <cstdint>
#include <vector>
#include "common/base/ring_buffer.h"
#include "devices/camera/abstract_camera.h"
@ -33,7 +35,11 @@ public:
bool startStreaming() override;
void stopStreaming() override;
void onStandardData(long real_handle, unsigned int data_type, unsigned char* buffer, unsigned int buffer_size);
void onEsData(unsigned int packet_type,
unsigned char* buffer,
unsigned int buffer_size,
unsigned int width,
unsigned int height);
private:
bool initSdk_();
@ -45,7 +51,12 @@ private:
void fillIntrinsics_(Rs2Intrinsics& intrinsics) const;
void setError_(const std::string& message);
std::string sdkError_(const std::string& action) const;
bool isKeyFrame_(const unsigned char* buffer, unsigned int buffer_size) const;
void pushEncodedFrame_(const unsigned char* buffer,
unsigned int buffer_size,
bool is_key_frame,
unsigned int width,
unsigned int height);
void resetStreamState_();
config::HikvisionCameraConfig camera_;
std::string ip_;
@ -71,6 +82,9 @@ private:
std::string current_video_path_;
mutable std::mutex ctrl_mtx_;
std::mutex stream_mtx_;
std::vector<uint8_t> es_stream_header_;
bool has_es_stream_header_ = false;
int stream_count_ = 0;
};

View File

@ -1,9 +1,13 @@
#include "../include/hikvision_camera.h"
#include <atomic>
#include <cstdint>
#include <cstdio>
#include <cstring>
#include <filesystem>
#include <limits.h>
#include <string>
#include <vector>
#if defined(__linux__)
#include <unistd.h>
@ -17,6 +21,13 @@ namespace {
std::mutex g_sdk_mutex;
int g_sdk_ref_count = 0;
bool g_sdk_initialized = false;
std::atomic<int> g_ignored_data_type_log_count{0};
std::atomic<int> g_es_video_log_count{0};
constexpr DWORD kHikvisionPacketFileHeader = 0;
constexpr DWORD kHikvisionPacketVideoIFrame = 1;
constexpr DWORD kHikvisionPacketVideoBFrame = 2;
constexpr DWORD kHikvisionPacketVideoPFrame = 3;
std::string normalizeSdkPath(std::string path)
{
@ -53,14 +64,18 @@ void copyCString(char* dest, size_t dest_size, const std::string& source)
std::snprintf(dest, dest_size, "%s", source.c_str());
}
void CALLBACK hikvisionStandardDataCallback(
LONG real_handle, DWORD data_type, BYTE* buffer, DWORD buffer_size, void* user)
void CALLBACK hikvisionEsRealPlayCallback(
LONG, NET_DVR_PACKET_INFO_EX* packet_info, void* user)
{
auto* camera = static_cast<cmvr::device::HikvisionCamera*>(user);
if (!camera) {
if (!camera || !packet_info) {
return;
}
camera->onStandardData(real_handle, data_type, buffer, buffer_size);
camera->onEsData(packet_info->dwPacketType,
packet_info->pPacketBuffer,
packet_info->dwPacketSize,
packet_info->wWidth,
packet_info->wHeight);
}
} // namespace
@ -117,6 +132,7 @@ bool HikvisionCamera::init()
stream_frame_buffer_ = std::make_shared<SPMCRingBuffer<StreamFrameData>>(buffer_size_);
stream_frame_buffer_->clear();
resetStreamState_();
if (!initSdk_()) {
return false;
@ -167,6 +183,7 @@ bool HikvisionCamera::stop()
}
state_.is_streaming = false;
stream_count_ = 0;
resetStreamState_();
stopPreview_();
if (user_id_ >= 0) {
NET_DVR_Logout(user_id_);
@ -258,13 +275,7 @@ void HikvisionCamera::resumeRecording()
void HikvisionCamera::getEncodedFrame(StreamFrameData& frame_data, size_t& index)
{
if (!stream_frame_buffer_) {
return;
}
auto frame = stream_frame_buffer_->pop(index);
if (frame.has_value()) {
frame_data = frame.value();
}
getLatestEncodedFrame(frame_data, index);
}
bool HikvisionCamera::getLatestEncodedFrame(StreamFrameData& frame_data, size_t& next_index)
@ -299,6 +310,10 @@ bool HikvisionCamera::startStreaming()
return false;
}
if (stream_count_ == 0 && stream_frame_buffer_) {
stream_frame_buffer_->clear();
}
state_.is_streaming = true;
++stream_count_;
return true;
@ -315,28 +330,86 @@ void HikvisionCamera::stopStreaming()
}
}
void HikvisionCamera::onStandardData(
long, unsigned int data_type, unsigned char* buffer, unsigned int buffer_size)
void HikvisionCamera::onEsData(
unsigned int packet_type,
unsigned char* buffer,
unsigned int buffer_size,
unsigned int packet_width,
unsigned int packet_height)
{
if (data_type != NET_DVR_STD_VIDEODATA || !buffer || buffer_size == 0) {
if (!buffer || buffer_size == 0) {
return;
}
if (packet_type == kHikvisionPacketFileHeader) {
std::lock_guard<std::mutex> lock(stream_mtx_);
if (!has_es_stream_header_) {
es_stream_header_.assign(buffer, buffer + buffer_size);
has_es_stream_header_ = true;
CMVR_LOG(INFO) << "[HikvisionCamera] received ES stream header, size=" << buffer_size;
}
return;
}
const bool is_video_packet =
packet_type == kHikvisionPacketVideoIFrame ||
packet_type == kHikvisionPacketVideoBFrame ||
packet_type == kHikvisionPacketVideoPFrame;
if (!is_video_packet) {
const int log_count = g_ignored_data_type_log_count.fetch_add(1);
if (log_count < 10) {
CMVR_LOG(INFO) << "[HikvisionCamera] ignore ES packet_type="
<< packet_type << ", size=" << buffer_size;
}
return;
}
const int video_log_count = g_es_video_log_count.fetch_add(1);
if (video_log_count < 10) {
CMVR_LOG(INFO) << "[HikvisionCamera] ES video packet_type="
<< packet_type << ", size=" << buffer_size;
}
if (!state_.is_streaming || !stream_frame_buffer_) {
return;
}
pushEncodedFrame_(buffer,
buffer_size,
packet_type == kHikvisionPacketVideoIFrame,
packet_width,
packet_height);
}
void HikvisionCamera::pushEncodedFrame_(
const unsigned char* buffer,
unsigned int buffer_size,
bool is_key_frame,
unsigned int packet_width,
unsigned int packet_height)
{
if (!buffer || buffer_size == 0 || !stream_frame_buffer_) {
return;
}
StreamFrameData frame_data;
frame_data.rgbFrame.assign(buffer, buffer + buffer_size);
frame_data.codec = codec_;
frame_data.fps = fps_;
frame_data.width = width_;
frame_data.height = height_;
frame_data.bKey = isKeyFrame_(buffer, buffer_size);
frame_data.width = packet_width > 0 ? static_cast<int>(packet_width) : width_;
frame_data.height = packet_height > 0 ? static_cast<int>(packet_height) : height_;
frame_data.bKey = is_key_frame;
fillIntrinsics_(frame_data.intrinsics);
stream_frame_buffer_->push(frame_data);
}
void HikvisionCamera::resetStreamState_()
{
std::lock_guard<std::mutex> lock(stream_mtx_);
es_stream_header_.clear();
has_es_stream_header_ = false;
}
bool HikvisionCamera::initSdk_()
{
if (sdk_acquired_) {
@ -403,7 +476,7 @@ bool HikvisionCamera::startPreview_()
preview_info.dwStreamType = static_cast<DWORD>(stream_type_);
preview_info.dwLinkMode = static_cast<DWORD>(link_mode_);
preview_info.hPlayWnd = 0;
preview_info.bBlocked = 0;
preview_info.bBlocked = 1;
preview_info.dwDisplayBufNum = 1;
preview_info.byReconnect = 1;
@ -412,9 +485,8 @@ bool HikvisionCamera::startPreview_()
setError_(sdkError_("NET_DVR_RealPlay_V40"));
return false;
}
if (!NET_DVR_SetStandardDataCallBackEx(
real_handle_, hikvisionStandardDataCallback, this)) {
setError_(sdkError_("NET_DVR_SetStandardDataCallBackEx"));
if (!NET_DVR_SetESRealPlayCallBack(real_handle_, hikvisionEsRealPlayCallback, this)) {
setError_(sdkError_("NET_DVR_SetESRealPlayCallBack"));
NET_DVR_StopRealPlay(real_handle_);
real_handle_ = -1;
return false;
@ -453,37 +525,4 @@ std::string HikvisionCamera::sdkError_(const std::string& action) const
return action + " failed, error_code=" + std::to_string(NET_DVR_GetLastError());
}
bool HikvisionCamera::isKeyFrame_(const unsigned char* buffer, unsigned int buffer_size) const
{
if (!buffer || buffer_size < 5) {
return false;
}
for (unsigned int i = 0; i + 5 < buffer_size; ++i) {
unsigned int offset = 0;
if (buffer[i] == 0 && buffer[i + 1] == 0 && buffer[i + 2] == 1) {
offset = i + 3;
} else if (i + 4 < buffer_size && buffer[i] == 0 && buffer[i + 1] == 0 &&
buffer[i + 2] == 0 && buffer[i + 3] == 1) {
offset = i + 4;
} else {
continue;
}
const unsigned char nal = buffer[offset];
if (codec_ == "H265" || codec_ == "h265" || codec_ == "HEVC" || codec_ == "hevc") {
const unsigned char nal_type = (nal >> 1) & 0x3f;
if (nal_type == 19 || nal_type == 20 || nal_type == 32) {
return true;
}
} else {
const unsigned char nal_type = nal & 0x1f;
if (nal_type == 5 || nal_type == 7) {
return true;
}
}
}
return false;
}
} // namespace cmvr::device