update hikvision camera
This commit is contained in:
parent
1fc5179344
commit
53f71bb720
@ -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"
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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;
|
||||
};
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
Reference in New Issue
Block a user