diff --git a/cmvr-es/devices/camera/hikvision_camera/include/hikvision_camera.h b/cmvr-es/devices/camera/hikvision_camera/include/hikvision_camera.h index dea0cb96..0e544ab0 100644 --- a/cmvr-es/devices/camera/hikvision_camera/include/hikvision_camera.h +++ b/cmvr-es/devices/camera/hikvision_camera/include/hikvision_camera.h @@ -1,6 +1,7 @@ #ifndef CMVR_ES_HIKVISION_CAMERA_H #define CMVR_ES_HIKVISION_CAMERA_H +#include #include #include #include @@ -49,6 +50,7 @@ private: bool login_(); bool startPreview_(); void stopPreview_(); + bool requestKeyFrame_(); void stopRecordingUnlocked_(); void fillIntrinsics_(Rs2Intrinsics& intrinsics) const; void setError_(const std::string& message); @@ -87,6 +89,7 @@ private: std::mutex stream_mtx_; std::vector es_stream_header_; bool has_es_stream_header_ = false; + std::atomic awaiting_key_frame_{false}; int stream_count_ = 0; }; diff --git a/cmvr-es/devices/camera/hikvision_camera/src/hikvision_camera.cpp b/cmvr-es/devices/camera/hikvision_camera/src/hikvision_camera.cpp index d3f0afde..b6255299 100644 --- a/cmvr-es/devices/camera/hikvision_camera/src/hikvision_camera.cpp +++ b/cmvr-es/devices/camera/hikvision_camera/src/hikvision_camera.cpp @@ -334,6 +334,7 @@ bool HikvisionCamera::stop() stopRecordingUnlocked_(); } state_.is_streaming = false; + awaiting_key_frame_.store(false, std::memory_order_release); stream_count_ = 0; resetStreamState_(); stopPreview_(); @@ -462,12 +463,19 @@ bool HikvisionCamera::startStreaming() return false; } - if (stream_count_ == 0 && stream_frame_buffer_) { - stream_frame_buffer_->clear(); + const bool first_stream = stream_count_ == 0; + if (first_stream) { + if (stream_frame_buffer_) { + stream_frame_buffer_->clear(); + } + awaiting_key_frame_.store(true, std::memory_order_release); } state_.is_streaming = true; ++stream_count_; + if (first_stream && !requestKeyFrame_()) { + awaiting_key_frame_.store(false, std::memory_order_release); + } return true; } @@ -479,6 +487,7 @@ void HikvisionCamera::stopStreaming() } if (stream_count_ == 0) { state_.is_streaming = false; + awaiting_key_frame_.store(false, std::memory_order_release); } } @@ -508,6 +517,30 @@ bool HikvisionCamera::controlPtz(PtzCommand command, bool stop, int speed) return true; } +bool HikvisionCamera::requestKeyFrame_() +{ + if (user_id_ < 0) { + CMVR_LOG(WARNING) << "[HikvisionCamera] skip key frame request: camera not logged in"; + return false; + } + + const bool is_sub_stream = stream_type_ == 1; + const BOOL success = is_sub_stream + ? NET_DVR_MakeKeyFrameSub(user_id_, channel_) + : NET_DVR_MakeKeyFrame(user_id_, channel_); + if (!success) { + CMVR_LOG(WARNING) << "[HikvisionCamera] " + << (is_sub_stream ? "NET_DVR_MakeKeyFrameSub" : "NET_DVR_MakeKeyFrame") + << " failed, error_code=" << NET_DVR_GetLastError(); + return false; + } + + CMVR_LOG(INFO) << "[HikvisionCamera] requested key frame" + << ", channel=" << channel_ + << ", stream_type=" << stream_type_; + return true; +} + bool HikvisionCamera::executeJsonCommand(const std::string& request_json, std::string& response_json) { Json::Value root; @@ -605,9 +638,18 @@ void HikvisionCamera::onEsData( return; } + const bool is_key_frame = packet_type == kHikvisionPacketVideoIFrame; + if (awaiting_key_frame_.load(std::memory_order_acquire)) { + if (!is_key_frame) { + return; + } + awaiting_key_frame_.store(false, std::memory_order_release); + CMVR_LOG(INFO) << "[HikvisionCamera] received first key frame after stream start"; + } + pushEncodedFrame_(buffer, buffer_size, - packet_type == kHikvisionPacketVideoIFrame, + is_key_frame, packet_width, packet_height); }