add hikvision camera controlPtz

This commit is contained in:
linbo 2026-07-22 16:35:20 +08:00
parent 53f71bb720
commit a0fbeccc19
8 changed files with 207 additions and 4 deletions

View File

@ -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

View File

@ -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_{};

View File

@ -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,

View File

@ -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<DWORD>(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,

View File

@ -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<cmvr::api::GetDepthImageStreamCommand_Feedback, cmvr::api::GetDepthImageStreamCommand_Request>* stream) override;
grpc::Status GetRGBDImagesStream(grpc::ServerContext* context, grpc::ServerReaderWriter<cmvr::api::GetRGBDImagesStreamCommand_Feedback, cmvr::api::GetRGBDImagesStreamCommand_Request>* stream) override;
grpc::Status GetRGBImageStream(grpc::ServerContext* context, grpc::ServerReaderWriter<cmvr::api::GetRGBImageStreamCommand_Feedback, cmvr::api::GetRGBImageStreamCommand_Request>* stream) override;

View File

@ -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<AbstractCamera>(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<int>(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<cmvr::api::GetDepthImageStreamCommand_Feedback, cmvr::api::GetDepthImageStreamCommand_Request>* stream){

View File

@ -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;

View File

@ -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) {}
}
}