update hikvision camera
This commit is contained in:
parent
1fc5179344
commit
53f71bb720
@ -82,7 +82,7 @@ camera {
|
|||||||
cameras {
|
cameras {
|
||||||
id: "hikvision_cam"
|
id: "hikvision_cam"
|
||||||
hikvision {
|
hikvision {
|
||||||
ip: "192.168.1.64"
|
ip: "192.168.192.64"
|
||||||
port: 8000
|
port: 8000
|
||||||
username: "admin"
|
username: "admin"
|
||||||
password: "okwy1688"
|
password: "okwy1688"
|
||||||
@ -101,7 +101,7 @@ camera {
|
|||||||
cameras {
|
cameras {
|
||||||
id: "hikvision_thermal_cam"
|
id: "hikvision_thermal_cam"
|
||||||
hikvision {
|
hikvision {
|
||||||
ip: "192.168.1.65"
|
ip: "192.168.192.65"
|
||||||
port: 8000
|
port: 8000
|
||||||
username: "admin"
|
username: "admin"
|
||||||
password: "okwy1688"
|
password: "okwy1688"
|
||||||
|
|||||||
@ -70,13 +70,13 @@ device_manager {
|
|||||||
id: "hikvision_cam"
|
id: "hikvision_cam"
|
||||||
type: DEVICE_TYPE_CAMERA
|
type: DEVICE_TYPE_CAMERA
|
||||||
config_file: "devices/camera/camera.pb.txt"
|
config_file: "devices/camera/camera.pb.txt"
|
||||||
enable: false
|
enable: true
|
||||||
}
|
}
|
||||||
devices {
|
devices {
|
||||||
id: "hikvision_thermal_cam"
|
id: "hikvision_thermal_cam"
|
||||||
type: DEVICE_TYPE_CAMERA
|
type: DEVICE_TYPE_CAMERA
|
||||||
config_file: "devices/camera/camera.pb.txt"
|
config_file: "devices/camera/camera.pb.txt"
|
||||||
enable: false
|
enable: true
|
||||||
}
|
}
|
||||||
|
|
||||||
devices {
|
devices {
|
||||||
|
|||||||
@ -4,6 +4,8 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "common/base/ring_buffer.h"
|
#include "common/base/ring_buffer.h"
|
||||||
#include "devices/camera/abstract_camera.h"
|
#include "devices/camera/abstract_camera.h"
|
||||||
@ -33,7 +35,11 @@ public:
|
|||||||
bool startStreaming() override;
|
bool startStreaming() override;
|
||||||
void stopStreaming() 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:
|
private:
|
||||||
bool initSdk_();
|
bool initSdk_();
|
||||||
@ -45,7 +51,12 @@ private:
|
|||||||
void fillIntrinsics_(Rs2Intrinsics& intrinsics) const;
|
void fillIntrinsics_(Rs2Intrinsics& intrinsics) const;
|
||||||
void setError_(const std::string& message);
|
void setError_(const std::string& message);
|
||||||
std::string sdkError_(const std::string& action) const;
|
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_;
|
config::HikvisionCameraConfig camera_;
|
||||||
std::string ip_;
|
std::string ip_;
|
||||||
@ -71,6 +82,9 @@ private:
|
|||||||
std::string current_video_path_;
|
std::string current_video_path_;
|
||||||
|
|
||||||
mutable std::mutex ctrl_mtx_;
|
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;
|
int stream_count_ = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,9 +1,13 @@
|
|||||||
#include "../include/hikvision_camera.h"
|
#include "../include/hikvision_camera.h"
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
#include <cstdint>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#if defined(__linux__)
|
#if defined(__linux__)
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@ -17,6 +21,13 @@ namespace {
|
|||||||
std::mutex g_sdk_mutex;
|
std::mutex g_sdk_mutex;
|
||||||
int g_sdk_ref_count = 0;
|
int g_sdk_ref_count = 0;
|
||||||
bool g_sdk_initialized = false;
|
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)
|
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());
|
std::snprintf(dest, dest_size, "%s", source.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void CALLBACK hikvisionStandardDataCallback(
|
void CALLBACK hikvisionEsRealPlayCallback(
|
||||||
LONG real_handle, DWORD data_type, BYTE* buffer, DWORD buffer_size, void* user)
|
LONG, NET_DVR_PACKET_INFO_EX* packet_info, void* user)
|
||||||
{
|
{
|
||||||
auto* camera = static_cast<cmvr::device::HikvisionCamera*>(user);
|
auto* camera = static_cast<cmvr::device::HikvisionCamera*>(user);
|
||||||
if (!camera) {
|
if (!camera || !packet_info) {
|
||||||
return;
|
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
|
} // namespace
|
||||||
@ -117,6 +132,7 @@ bool HikvisionCamera::init()
|
|||||||
|
|
||||||
stream_frame_buffer_ = std::make_shared<SPMCRingBuffer<StreamFrameData>>(buffer_size_);
|
stream_frame_buffer_ = std::make_shared<SPMCRingBuffer<StreamFrameData>>(buffer_size_);
|
||||||
stream_frame_buffer_->clear();
|
stream_frame_buffer_->clear();
|
||||||
|
resetStreamState_();
|
||||||
|
|
||||||
if (!initSdk_()) {
|
if (!initSdk_()) {
|
||||||
return false;
|
return false;
|
||||||
@ -167,6 +183,7 @@ bool HikvisionCamera::stop()
|
|||||||
}
|
}
|
||||||
state_.is_streaming = false;
|
state_.is_streaming = false;
|
||||||
stream_count_ = 0;
|
stream_count_ = 0;
|
||||||
|
resetStreamState_();
|
||||||
stopPreview_();
|
stopPreview_();
|
||||||
if (user_id_ >= 0) {
|
if (user_id_ >= 0) {
|
||||||
NET_DVR_Logout(user_id_);
|
NET_DVR_Logout(user_id_);
|
||||||
@ -258,13 +275,7 @@ void HikvisionCamera::resumeRecording()
|
|||||||
|
|
||||||
void HikvisionCamera::getEncodedFrame(StreamFrameData& frame_data, size_t& index)
|
void HikvisionCamera::getEncodedFrame(StreamFrameData& frame_data, size_t& index)
|
||||||
{
|
{
|
||||||
if (!stream_frame_buffer_) {
|
getLatestEncodedFrame(frame_data, index);
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto frame = stream_frame_buffer_->pop(index);
|
|
||||||
if (frame.has_value()) {
|
|
||||||
frame_data = frame.value();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HikvisionCamera::getLatestEncodedFrame(StreamFrameData& frame_data, size_t& next_index)
|
bool HikvisionCamera::getLatestEncodedFrame(StreamFrameData& frame_data, size_t& next_index)
|
||||||
@ -299,6 +310,10 @@ bool HikvisionCamera::startStreaming()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (stream_count_ == 0 && stream_frame_buffer_) {
|
||||||
|
stream_frame_buffer_->clear();
|
||||||
|
}
|
||||||
|
|
||||||
state_.is_streaming = true;
|
state_.is_streaming = true;
|
||||||
++stream_count_;
|
++stream_count_;
|
||||||
return true;
|
return true;
|
||||||
@ -315,28 +330,86 @@ void HikvisionCamera::stopStreaming()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HikvisionCamera::onStandardData(
|
void HikvisionCamera::onEsData(
|
||||||
long, unsigned int data_type, unsigned char* buffer, unsigned int buffer_size)
|
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;
|
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_) {
|
if (!state_.is_streaming || !stream_frame_buffer_) {
|
||||||
return;
|
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;
|
StreamFrameData frame_data;
|
||||||
frame_data.rgbFrame.assign(buffer, buffer + buffer_size);
|
frame_data.rgbFrame.assign(buffer, buffer + buffer_size);
|
||||||
frame_data.codec = codec_;
|
frame_data.codec = codec_;
|
||||||
frame_data.fps = fps_;
|
frame_data.fps = fps_;
|
||||||
frame_data.width = width_;
|
frame_data.width = packet_width > 0 ? static_cast<int>(packet_width) : width_;
|
||||||
frame_data.height = height_;
|
frame_data.height = packet_height > 0 ? static_cast<int>(packet_height) : height_;
|
||||||
frame_data.bKey = isKeyFrame_(buffer, buffer_size);
|
frame_data.bKey = is_key_frame;
|
||||||
fillIntrinsics_(frame_data.intrinsics);
|
fillIntrinsics_(frame_data.intrinsics);
|
||||||
stream_frame_buffer_->push(frame_data);
|
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_()
|
bool HikvisionCamera::initSdk_()
|
||||||
{
|
{
|
||||||
if (sdk_acquired_) {
|
if (sdk_acquired_) {
|
||||||
@ -403,7 +476,7 @@ bool HikvisionCamera::startPreview_()
|
|||||||
preview_info.dwStreamType = static_cast<DWORD>(stream_type_);
|
preview_info.dwStreamType = static_cast<DWORD>(stream_type_);
|
||||||
preview_info.dwLinkMode = static_cast<DWORD>(link_mode_);
|
preview_info.dwLinkMode = static_cast<DWORD>(link_mode_);
|
||||||
preview_info.hPlayWnd = 0;
|
preview_info.hPlayWnd = 0;
|
||||||
preview_info.bBlocked = 0;
|
preview_info.bBlocked = 1;
|
||||||
preview_info.dwDisplayBufNum = 1;
|
preview_info.dwDisplayBufNum = 1;
|
||||||
preview_info.byReconnect = 1;
|
preview_info.byReconnect = 1;
|
||||||
|
|
||||||
@ -412,9 +485,8 @@ bool HikvisionCamera::startPreview_()
|
|||||||
setError_(sdkError_("NET_DVR_RealPlay_V40"));
|
setError_(sdkError_("NET_DVR_RealPlay_V40"));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!NET_DVR_SetStandardDataCallBackEx(
|
if (!NET_DVR_SetESRealPlayCallBack(real_handle_, hikvisionEsRealPlayCallback, this)) {
|
||||||
real_handle_, hikvisionStandardDataCallback, this)) {
|
setError_(sdkError_("NET_DVR_SetESRealPlayCallBack"));
|
||||||
setError_(sdkError_("NET_DVR_SetStandardDataCallBackEx"));
|
|
||||||
NET_DVR_StopRealPlay(real_handle_);
|
NET_DVR_StopRealPlay(real_handle_);
|
||||||
real_handle_ = -1;
|
real_handle_ = -1;
|
||||||
return false;
|
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());
|
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
|
} // namespace cmvr::device
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user