From a0fbeccc190a4a32928f7aa219fb53f11b61ffc7 Mon Sep 17 00:00:00 2001 From: linbo <1034003879@qq.com> Date: Wed, 22 Jul 2026 16:35:20 +0800 Subject: [PATCH] add hikvision camera controlPtz --- cmvr-es/config/devices/camera/camera.pb.txt | 6 +- cmvr-es/devices/camera/abstract_camera.h | 20 +++++ .../include/hikvision_camera.h | 1 + .../hikvision_camera/src/hikvision_camera.cpp | 66 +++++++++++++++ .../grpc/include/grpc_camera_service.h | 1 + .../service/grpc/src/grpc_camera_service.cpp | 81 +++++++++++++++++++ protos/cmvr/api/camera_command.proto | 33 ++++++++ protos/cmvr/api/camera_service.proto | 3 +- 8 files changed, 207 insertions(+), 4 deletions(-) diff --git a/cmvr-es/config/devices/camera/camera.pb.txt b/cmvr-es/config/devices/camera/camera.pb.txt index 54efedd6..fb7f040f 100644 --- a/cmvr-es/config/devices/camera/camera.pb.txt +++ b/cmvr-es/config/devices/camera/camera.pb.txt @@ -108,9 +108,9 @@ camera { channel: 1 stream_type: 0 link_mode: 0 - width: 1920 - height: 1080 - fps: 25 + width: 384 + height: 288 + fps: 50 codec: "H264" camera_mode: CAMERA_MODE_VIDEO stream_mode: STREAM_MODE_RGB diff --git a/cmvr-es/devices/camera/abstract_camera.h b/cmvr-es/devices/camera/abstract_camera.h index 9a9bd728..d18898ad 100644 --- a/cmvr-es/devices/camera/abstract_camera.h +++ b/cmvr-es/devices/camera/abstract_camera.h @@ -36,6 +36,21 @@ namespace cmvr::device { bool bKey; bool depthKey; }; + + enum class PtzCommand { + TiltUp, + TiltDown, + PanLeft, + PanRight, + UpLeft, + UpRight, + DownLeft, + DownRight, + ZoomIn, + ZoomOut, + PanAuto + }; + class AbstractCamera : public AbstractDevice { public: // 录制状态 @@ -64,6 +79,11 @@ namespace cmvr::device { virtual bool startStreaming() {return true;} virtual void stopStreaming() {} + virtual bool controlPtz(PtzCommand command, bool stop, int speed) { + state_.is_error = true; + state_.error_message = "PTZ control unsupported"; + return false; + } virtual Eigen::Vector3f get3DPointFromPixel(int u, int v) {return {0,0,0};} protected: CameraState state_{}; 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 0a2dec95..a4140af4 100644 --- a/cmvr-es/devices/camera/hikvision_camera/include/hikvision_camera.h +++ b/cmvr-es/devices/camera/hikvision_camera/include/hikvision_camera.h @@ -34,6 +34,7 @@ public: bool getLatestEncodedFrame(StreamFrameData& frame_data, size_t& next_index) override; bool startStreaming() override; void stopStreaming() override; + bool controlPtz(PtzCommand command, bool stop, int speed) override; void onEsData(unsigned int packet_type, unsigned char* buffer, 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 6129a2c6..21a39fb9 100644 --- a/cmvr-es/devices/camera/hikvision_camera/src/hikvision_camera.cpp +++ b/cmvr-es/devices/camera/hikvision_camera/src/hikvision_camera.cpp @@ -64,6 +64,46 @@ void copyCString(char* dest, size_t dest_size, const std::string& source) std::snprintf(dest, dest_size, "%s", source.c_str()); } +DWORD toHikvisionPtzCommand(cmvr::device::PtzCommand command) +{ + switch (command) { + case cmvr::device::PtzCommand::TiltUp: + return TILT_UP; + case cmvr::device::PtzCommand::TiltDown: + return TILT_DOWN; + case cmvr::device::PtzCommand::PanLeft: + return PAN_LEFT; + case cmvr::device::PtzCommand::PanRight: + return PAN_RIGHT; + case cmvr::device::PtzCommand::UpLeft: + return UP_LEFT; + case cmvr::device::PtzCommand::UpRight: + return UP_RIGHT; + case cmvr::device::PtzCommand::DownLeft: + return DOWN_LEFT; + case cmvr::device::PtzCommand::DownRight: + return DOWN_RIGHT; + case cmvr::device::PtzCommand::ZoomIn: + return ZOOM_IN; + case cmvr::device::PtzCommand::ZoomOut: + return ZOOM_OUT; + case cmvr::device::PtzCommand::PanAuto: + return PAN_AUTO; + } + return 0; +} + +DWORD normalizePtzSpeed(int speed) +{ + if (speed <= 0) { + return 4; + } + if (speed > 7) { + return 7; + } + return static_cast(speed); +} + void CALLBACK hikvisionEsRealPlayCallback( LONG, NET_DVR_PACKET_INFO_EX* packet_info, void* user) { @@ -330,6 +370,32 @@ void HikvisionCamera::stopStreaming() } } +bool HikvisionCamera::controlPtz(PtzCommand command, bool stop, int speed) +{ + std::lock_guard lock(ctrl_mtx_); + clear_error_(); + + if (!state_.is_opened || user_id_ < 0) { + setError_("camera not opened"); + return false; + } + + const DWORD sdk_command = toHikvisionPtzCommand(command); + if (sdk_command == 0) { + setError_("unsupported PTZ command"); + return false; + } + + const DWORD sdk_stop = stop ? 1 : 0; + const DWORD sdk_speed = normalizePtzSpeed(speed); + if (!NET_DVR_PTZControlWithSpeed_Other(user_id_, channel_, sdk_command, sdk_stop, sdk_speed)) { + setError_(sdkError_("NET_DVR_PTZControlWithSpeed_Other")); + return false; + } + + return true; +} + void HikvisionCamera::onEsData( unsigned int packet_type, unsigned char* buffer, diff --git a/cmvr-es/service/grpc/include/grpc_camera_service.h b/cmvr-es/service/grpc/include/grpc_camera_service.h index d9bc1782..b9be651d 100644 --- a/cmvr-es/service/grpc/include/grpc_camera_service.h +++ b/cmvr-es/service/grpc/include/grpc_camera_service.h @@ -24,6 +24,7 @@ namespace cmvr::service { grpc::Status GetRGBDImages(grpc::ServerContext* context, const api::GetRGBDImagesCommand_Request* request, api::GetRGBDImagesCommand_Feedback* response) override; grpc::Status StartRecording(grpc::ServerContext* context, const api::StartCameraRecordingCommand_Request* request, api::StartCameraRecordingCommand_Feedback* response) override; grpc::Status StopRecording(grpc::ServerContext* context, const api::StopCameraRecordingCommand_Request* request, api::StopCameraRecordingCommand_Feedback* response) override; + grpc::Status ControlPtz(grpc::ServerContext* context, const api::ControlPtzCommand_Request* request, api::ControlPtzCommand_Feedback* response) override; grpc::Status GetDepthImageStream(grpc::ServerContext* context, grpc::ServerReaderWriter* stream) override; grpc::Status GetRGBDImagesStream(grpc::ServerContext* context, grpc::ServerReaderWriter* stream) override; grpc::Status GetRGBImageStream(grpc::ServerContext* context, grpc::ServerReaderWriter* stream) override; diff --git a/cmvr-es/service/grpc/src/grpc_camera_service.cpp b/cmvr-es/service/grpc/src/grpc_camera_service.cpp index 8f15c8a7..7ca3d5a4 100644 --- a/cmvr-es/service/grpc/src/grpc_camera_service.cpp +++ b/cmvr-es/service/grpc/src/grpc_camera_service.cpp @@ -20,6 +20,47 @@ grpc::Status failResponse(ResponseT* response, const std::string& message) { setCurrentTimestamp(response->mutable_header()->mutable_timestamp()); return grpc::Status::OK; } + +bool toPtzCommand(cmvr::api::ControlPtzCommand_Command command, PtzCommand& out) +{ + switch (command) { + case cmvr::api::ControlPtzCommand_Command_TILT_UP: + out = PtzCommand::TiltUp; + return true; + case cmvr::api::ControlPtzCommand_Command_TILT_DOWN: + out = PtzCommand::TiltDown; + return true; + case cmvr::api::ControlPtzCommand_Command_PAN_LEFT: + out = PtzCommand::PanLeft; + return true; + case cmvr::api::ControlPtzCommand_Command_PAN_RIGHT: + out = PtzCommand::PanRight; + return true; + case cmvr::api::ControlPtzCommand_Command_UP_LEFT: + out = PtzCommand::UpLeft; + return true; + case cmvr::api::ControlPtzCommand_Command_UP_RIGHT: + out = PtzCommand::UpRight; + return true; + case cmvr::api::ControlPtzCommand_Command_DOWN_LEFT: + out = PtzCommand::DownLeft; + return true; + case cmvr::api::ControlPtzCommand_Command_DOWN_RIGHT: + out = PtzCommand::DownRight; + return true; + case cmvr::api::ControlPtzCommand_Command_ZOOM_IN: + out = PtzCommand::ZoomIn; + return true; + case cmvr::api::ControlPtzCommand_Command_ZOOM_OUT: + out = PtzCommand::ZoomOut; + return true; + case cmvr::api::ControlPtzCommand_Command_PAN_AUTO: + out = PtzCommand::PanAuto; + return true; + default: + return false; + } +} } gRPCCameraServiceImpl::gRPCCameraServiceImpl(): dmgr_(DeviceManager::getInstance()) {} @@ -331,6 +372,46 @@ grpc::Status gRPCCameraServiceImpl::StopRecording(grpc::ServerContext* context, } } +grpc::Status gRPCCameraServiceImpl::ControlPtz(grpc::ServerContext* context, + const api::ControlPtzCommand_Request* request, api::ControlPtzCommand_Feedback* response) +{ + try { + string dev_id = request->header().device_id(); + CMVR_LOG(INFO) << "[gRPCCameraServiceImpl] (ControlPtz): id=" << dev_id + << ", command=" << request->command() + << ", action=" << request->action() + << ", speed=" << request->speed(); + const auto dev = dmgr_.getDevice(dev_id); + if (!dev) { + return failResponse(response, "Camera device not found: " + dev_id); + } + + PtzCommand command{}; + if (!toPtzCommand(request->command(), command)) { + return failResponse(response, "Invalid PTZ command"); + } + + const bool stop = request->action() == api::ControlPtzCommand_Action_STOP; + if (!dev->controlPtz(command, stop, static_cast(request->speed()))) { + CameraState state{}; + dev->getState(state); + const std::string error_message = + state.error_message.empty() ? "Failed to control PTZ: " + dev_id : state.error_message; + return failResponse(response, error_message); + } + + response->mutable_header()->set_success(true); + setCurrentTimestamp(response->mutable_header()->mutable_timestamp()); + return grpc::Status::OK; + } + catch (exception &e) { + response->mutable_header()->set_success(false); + response->mutable_header()->set_error_message(e.what()); + setCurrentTimestamp(response->mutable_header()->mutable_timestamp()); + return grpc::Status::OK; + } +} + grpc::Status gRPCCameraServiceImpl::GetDepthImageStream(grpc::ServerContext* context , grpc::ServerReaderWriter* stream){ diff --git a/protos/cmvr/api/camera_command.proto b/protos/cmvr/api/camera_command.proto index 03a8f359..487bac96 100644 --- a/protos/cmvr/api/camera_command.proto +++ b/protos/cmvr/api/camera_command.proto @@ -128,6 +128,39 @@ message StopCameraRecordingCommand { } } +message ControlPtzCommand { + enum Command { + COMMAND_UNSPECIFIED = 0; + TILT_UP = 1; + TILT_DOWN = 2; + PAN_LEFT = 3; + PAN_RIGHT = 4; + UP_LEFT = 5; + UP_RIGHT = 6; + DOWN_LEFT = 7; + DOWN_RIGHT = 8; + ZOOM_IN = 9; + ZOOM_OUT = 10; + PAN_AUTO = 11; + } + + enum Action { + START = 0; + STOP = 1; + } + + message Request { + CommandHeader.Request header = 1; + Command command = 2; + Action action = 3; + uint32 speed = 4; + } + + message Feedback { + CommandHeader.Feedback header = 1; + } +} + message GetRGBImageStreamCommand { message Request { CommandHeader.Request header = 1; diff --git a/protos/cmvr/api/camera_service.proto b/protos/cmvr/api/camera_service.proto index cb9b2acd..9ab7d7fa 100644 --- a/protos/cmvr/api/camera_service.proto +++ b/protos/cmvr/api/camera_service.proto @@ -14,8 +14,9 @@ service CameraService { rpc GetRGBDImages(GetRGBDImagesCommand.Request) returns (GetRGBDImagesCommand.Feedback) {} rpc StartRecording(StartCameraRecordingCommand.Request) returns (StartCameraRecordingCommand.Feedback) {} rpc StopRecording(StopCameraRecordingCommand.Request) returns (StopCameraRecordingCommand.Feedback) {} + rpc ControlPtz(ControlPtzCommand.Request) returns (ControlPtzCommand.Feedback) {} rpc GetRGBImageStream(stream GetRGBImageStreamCommand.Request) returns (stream GetRGBImageStreamCommand.Feedback) {} rpc GetDepthImageStream(stream GetDepthImageStreamCommand.Request) returns (stream GetDepthImageStreamCommand.Feedback) {} rpc GetRGBDImagesStream(stream GetRGBDImagesStreamCommand.Request) returns (stream GetRGBDImagesStreamCommand.Feedback) {} -} \ No newline at end of file +}