2121#include < fcntl.h>
2222#include < unistd.h>
2323
24- const std::array<unsigned int , 5 > axis_ids = {
25- V4L2_CID_PAN_ABSOLUTE, V4L2_CID_TILT_ABSOLUTE, V4L2_CID_ZOOM_ABSOLUTE,
26- V4L2_CID_FOCUS_ABSOLUTE, V4L2_CID_FOCUS_AUTO};
27-
2824class V4L2Control : public PTZControl {
2925private:
3026 int fd;
3127 int query_ctrl (unsigned int i, long *pmin, long *pmax)
3228 {
3329 if (fd == -1 )
3430 return false ;
35- struct v4l2_queryctrl queryctrl;
36- memset (&queryctrl, 0 , sizeof (queryctrl));
37- queryctrl.id = axis_ids[i];
31+ struct v4l2_queryctrl queryctrl = {};
32+ queryctrl.id = i;
3833 if (ioctl (fd, VIDIOC_QUERYCTRL, &queryctrl) == -1 ) {
3934 blog (LOG_ERROR, " VIDIOC_QUERYCTRL failed for axis %d" ,
4035 i);
@@ -48,16 +43,27 @@ class V4L2Control : public PTZControl {
4843 {
4944 if (fd == -1 )
5045 return false ;
51- struct v4l2_control control;
52- memset (&control, 0 , sizeof (control));
53- control.id = axis_ids[i];
46+ struct v4l2_control control = {};
47+ control.id = i;
5448 control.value = value;
5549 if (ioctl (fd, VIDIOC_S_CTRL, &control) == -1 ) {
5650 blog (LOG_ERROR, " Failed to set PTZ %d value" , i);
5751 return false ;
5852 }
5953 return true ;
6054 }
55+ int get_ctrl (unsigned int i)
56+ {
57+ if (fd == -1 )
58+ return 0 ;
59+ struct v4l2_control control = {};
60+ control.id = i;
61+ if (ioctl (fd, VIDIOC_G_CTRL, &control) == -1 ) {
62+ blog (LOG_ERROR, " VIDIOC_G_CTRL failed for axis %d" , i);
63+ return 0 ;
64+ }
65+ return control.value ;
66+ }
6167
6268public:
6369 V4L2Control (const std::string &device)
@@ -69,32 +75,46 @@ class V4L2Control : public PTZControl {
6975 device_path.c_str ());
7076 return ;
7177 }
72- query_ctrl (PTZ_PAN, &min[PTZ_PAN], &max[PTZ_PAN]);
73- query_ctrl (PTZ_TILT, &min[PTZ_TILT], &max[PTZ_TILT]);
74- query_ctrl (PTZ_ZOOM, &min[PTZ_ZOOM], &max[PTZ_ZOOM]);
75- query_ctrl (PTZ_FOCUS, &min[PTZ_FOCUS], &max[PTZ_FOCUS]);
78+ query_ctrl (V4L2_CID_PAN_ABSOLUTE, &min.pan , &max.pan );
79+ query_ctrl (V4L2_CID_TILT_ABSOLUTE, &min.tilt , &max.tilt );
80+ query_ctrl (V4L2_CID_ZOOM_ABSOLUTE, &min.zoom , &max.zoom );
81+ query_ctrl (V4L2_CID_FOCUS_ABSOLUTE, &min.focus , &max.focus );
82+ now_pos.pan =
83+ static_cast <double >(get_ctrl (V4L2_CID_PAN_ABSOLUTE)) /
84+ max.pan ;
85+ now_pos.tilt =
86+ static_cast <double >(get_ctrl (V4L2_CID_TILT_ABSOLUTE)) /
87+ max.tilt ;
88+ now_pos.zoom =
89+ static_cast <double >(get_ctrl (V4L2_CID_ZOOM_ABSOLUTE)) /
90+ max.zoom ;
91+ now_pos.focus =
92+ static_cast <double >(get_ctrl (V4L2_CID_FOCUS_ABSOLUTE)) /
93+ max.focus ;
94+ now_pos.focusAuto = get_ctrl (V4L2_CID_FOCUS_AUTO);
7695 }
7796 bool internal_pan (long value) override
7897 {
79- return set_ctrl (PTZ_PAN , value);
98+ return set_ctrl (V4L2_CID_PAN_ABSOLUTE , value);
8099 }
81100 bool internal_tilt (long value) override
82101 {
83- return set_ctrl (PTZ_TILT , value);
102+ return set_ctrl (V4L2_CID_TILT_ABSOLUTE , value);
84103 }
85104 bool internal_zoom (long value) override
86105 {
87- return set_ctrl (PTZ_ZOOM , value);
106+ return set_ctrl (V4L2_CID_ZOOM_ABSOLUTE , value);
88107 }
89- bool internal_focus (long value) override
108+ bool internal_focus (bool auto_focus, long value) override
90109 {
91- return set_ctrl (PTZ_FOCUS, value);
92- }
93- bool setAutoFocus (bool enabled) override
94- {
95- if (fd == -1 )
96- return false ;
97- return set_ctrl (PTZ_FOCUS_AUTO, enabled ? 1 : 0 );
110+ if (auto_focus) {
111+ return set_ctrl (V4L2_CID_FOCUS_AUTO, 1 );
112+ } else {
113+ if (get_ctrl (V4L2_CID_FOCUS_AUTO) != 0 ) {
114+ set_ctrl (V4L2_CID_FOCUS_AUTO, 0 );
115+ }
116+ return set_ctrl (V4L2_CID_FOCUS_ABSOLUTE, value);
117+ }
98118 }
99119 ~V4L2Control () override
100120 {
@@ -208,31 +228,39 @@ class DirectShowControl : public PTZControl {
208228 }
209229 // blog(LOG_INFO, "Obtained DirectShow filter for device: %s", device_name.c_str());
210230 long step, default_value, flags;
211- hr = cam_control_->GetRange (CameraControl_Pan, &min[PTZ_PAN] ,
212- &max[PTZ_PAN] , &step,
213- &default_value, & flags);
231+ hr = cam_control_->GetRange (CameraControl_Pan, &min. pan ,
232+ &max. pan , &step, &default_value ,
233+ &flags);
214234 if (!FAILED (hr)) {
215235 hr = cam_control_->GetRange (CameraControl_Tilt,
216- &min[PTZ_TILT],
217- &max[PTZ_TILT], &step,
236+ &min.tilt , &max.tilt , &step,
218237 &default_value, &flags);
219238 }
220239 if (!FAILED (hr)) {
221240 hr = cam_control_->GetRange (CameraControl_Zoom,
222- &min[PTZ_ZOOM],
223- &max[PTZ_ZOOM], &step,
241+ &min.zoom , &max.zoom , &step,
224242 &default_value, &flags);
225243 }
226244 if (!FAILED (hr)) {
227245 hr = cam_control_->GetRange (CameraControl_Focus,
228- &min[PTZ_FOCUS] ,
229- &max[PTZ_FOCUS] , &step ,
230- &default_value, & flags);
246+ &min. focus , &max. focus ,
247+ &step , &default_value ,
248+ &flags);
231249 }
232250 if (FAILED (hr)) {
233251 blog (LOG_ERROR, " Failed to get ranges: %ld" , hr);
234252 return ;
235253 }
254+ long pan, tilt, zoom, focus;
255+ cam_control_->Get (CameraControl_Pan, &pan, &flags);
256+ now_pos.pan = static_cast <double >(pan) / max.pan ;
257+ cam_control_->Get (CameraControl_Tilt, &tilt, &flags);
258+ now_pos.tilt = static_cast <double >(tilt) / max.tilt ;
259+ cam_control_->Get (CameraControl_Zoom, &zoom, &flags);
260+ now_pos.zoom = static_cast <double >(zoom) / max.zoom ;
261+ cam_control_->Get (CameraControl_Focus, &focus, &flags);
262+ now_pos.focus = static_cast <double >(focus) / max.focus ;
263+ now_pos.focusAuto = (flags & CameraControl_Flags_Auto) != 0 ;
236264 }
237265 bool internal_pan (long value) override
238266 {
@@ -276,33 +304,14 @@ class DirectShowControl : public PTZControl {
276304 }
277305 return true ;
278306 }
279- bool internal_focus (long value) override
280- {
281- if (!cam_control_)
282- return false ;
283- last_focus = value;
284- HRESULT hr = cam_control_->Set (CameraControl_Focus, value,
285- CameraControl_Flags_Manual);
286- if (FAILED (hr)) {
287- blog (LOG_ERROR,
288- " Failed to set Focus: %ld (mapped value: %ld)" , hr,
289- value);
290- return false ;
291- }
292- return true ;
293- }
294- bool setAutoFocus (bool enabled) override
307+ bool internal_focus (bool auto_focus, long focus) override
295308 {
296309 if (!cam_control_)
297310 return false ;
311+ auto focus_flag = auto_focus ? CameraControl_Flags_Auto
312+ : CameraControl_Flags_Manual;
298313 HRESULT hr;
299- if (!enabled) {
300- hr = cam_control_->Set (CameraControl_Focus, last_focus,
301- CameraControl_Flags_Manual);
302- } else {
303- hr = cam_control_->Set (CameraControl_Focus, 0 ,
304- CameraControl_Flags_Auto);
305- }
314+ hr = cam_control_->Set (CameraControl_Focus, focus, focus_flag);
306315 if (FAILED (hr)) {
307316 blog (LOG_ERROR, " Failed to set AutoFocus: %ld" , hr);
308317 return false ;
@@ -331,9 +340,6 @@ void PTZUSBCam::ptz_tick_callback(void *param, float seconds)
331340PTZUSBCam::PTZUSBCam (OBSData config) : PTZDevice(config)
332341{
333342 set_config (config);
334- pantilt_abs (0 , 0 );
335- zoom_abs (0 );
336- set_autofocus (true );
337343 obs_add_tick_callback (ptz_tick_callback, this );
338344}
339345
@@ -404,25 +410,7 @@ void PTZUSBCam::do_update()
404410 STATUS_FOCUS_SPEED_CHANGED);
405411}
406412
407- void PTZUSBCam::ptz_tick (float seconds)
408- {
409- tick_elapsed += seconds;
410- if (tick_elapsed < 0 .05f ) // Atualiza a cada 50 ms
411- return ;
412- if (pan_speed != 0.0 || tilt_speed != 0.0 ) {
413- pantilt_rel (pan_speed * tick_elapsed,
414- tilt_speed * tick_elapsed);
415- }
416- if (zoom_speed != 0.0 ) {
417- zoom_abs (now_pos.zoom + zoom_speed * tick_elapsed);
418- }
419- if (focus_speed != 0.0 ) {
420- focus_abs (now_pos.focus + focus_speed * tick_elapsed);
421- }
422- tick_elapsed = 0 .0f ; // Reseta após a atualização
423- }
424-
425- void PTZUSBCam::initialize_and_check_ptz_control ()
413+ PTZControl *PTZUSBCam::get_ptz_control ()
426414{
427415 std::string video_device_id = " " ;
428416 OBSSourceAutoRelease src =
@@ -443,7 +431,7 @@ void PTZUSBCam::initialize_and_check_ptz_control()
443431 // already have the device, and it didn't change: nothing to do
444432 if (ptz_control_ != nullptr && ptz_control_->isValid () &&
445433 ptz_control_->getDevicePath () == video_device_id) {
446- return ;
434+ return ptz_control_ ;
447435 }
448436 blog (LOG_INFO, " Switching PTZ USBUVC device from %s to %s" ,
449437 ptz_control_ == nullptr ? " null"
@@ -454,31 +442,61 @@ void PTZUSBCam::initialize_and_check_ptz_control()
454442 ptz_control_ = nullptr ;
455443 }
456444 if (video_device_id.empty ()) {
457- return ;
445+ return nullptr ;
458446 }
459447#ifdef __linux__
460448 ptz_control_ = new V4L2Control (video_device_id);
461449#endif
462450#ifdef _WIN32
463451 ptz_control_ = new DirectShowControl (video_device_id);
464452#endif
453+ if (ptz_control_ == nullptr || !ptz_control_->isValid ()) {
454+ return nullptr ;
455+ }
456+ return ptz_control_;
465457}
466458
467- void PTZUSBCam::pantilt_abs ( double pan, double tilt )
459+ void PTZUSBCam::ptz_tick ( float seconds )
468460{
469- initialize_and_check_ptz_control ();
470- now_pos.pan = std::clamp (pan, -1.0 , 1.0 );
471- now_pos.tilt = std::clamp (tilt, -1.0 , 1.0 );
472-
473- if (ptz_control_ != nullptr && ptz_control_->isValid ()) {
474- ptz_control_->pan (now_pos.pan );
475- ptz_control_->tilt (now_pos.tilt );
461+ tick_elapsed += seconds;
462+ if (tick_elapsed < 0 .03f )
463+ return ;
464+ if (pan_speed != 0.0 || tilt_speed != 0.0 ) {
465+ pantilt_rel (pan_speed * tick_elapsed,
466+ tilt_speed * tick_elapsed);
467+ }
468+ if (zoom_speed != 0.0 ) {
469+ auto ptzctrl = get_ptz_control ();
470+ if (ptzctrl) {
471+ zoom_abs (ptzctrl->getZoom () +
472+ zoom_speed * tick_elapsed);
473+ }
476474 }
475+ if (focus_speed != 0.0 ) {
476+ auto ptzctrl = get_ptz_control ();
477+ if (ptzctrl) {
478+ focus_abs (ptzctrl->getFocus () +
479+ focus_speed * tick_elapsed);
480+ }
481+ }
482+ tick_elapsed = 0 .0f ;
483+ }
484+
485+ void PTZUSBCam::pantilt_abs (double pan, double tilt)
486+ {
487+ auto ptzctrl = get_ptz_control ();
488+ if (!ptzctrl)
489+ return ;
490+ ptzctrl->pan (pan);
491+ ptzctrl->tilt (tilt);
477492}
478493
479494void PTZUSBCam::pantilt_rel (double pan, double tilt)
480495{
481- pantilt_abs (now_pos.pan + pan, now_pos.tilt + tilt);
496+ auto ptzctrl = get_ptz_control ();
497+ if (!ptzctrl)
498+ return ;
499+ pantilt_abs (ptzctrl->getPan () + pan, ptzctrl->getTilt () + tilt);
482500}
483501
484502void PTZUSBCam::pantilt_home ()
@@ -488,30 +506,26 @@ void PTZUSBCam::pantilt_home()
488506
489507void PTZUSBCam::zoom_abs (double pos)
490508{
491- initialize_and_check_ptz_control ();
492- now_pos.zoom = std::clamp (pos, 0.0 , 1.0 );
493- if (ptz_control_ != nullptr && ptz_control_->isValid ()) {
494- ptz_control_->zoom (now_pos.zoom );
495- }
509+ auto ptzctrl = get_ptz_control ();
510+ if (!ptzctrl)
511+ return ;
512+ ptzctrl->zoom (pos);
496513}
497514
498515void PTZUSBCam::focus_abs (double pos)
499516{
500- initialize_and_check_ptz_control ();
501- now_pos.focus = std::clamp (pos, 0.0 , 1.0 );
502- if (ptz_control_ != nullptr && ptz_control_->isValid ()) {
503- ptz_control_->focus (now_pos.focus );
504- }
505- return ;
517+ auto ptzctrl = get_ptz_control ();
518+ if (!ptzctrl)
519+ return ;
520+ ptzctrl->focus (pos);
506521}
507522
508523void PTZUSBCam::set_autofocus (bool enabled)
509524{
510- initialize_and_check_ptz_control ();
511- now_pos.focusAuto = enabled;
512- if (ptz_control_ != nullptr && ptz_control_->isValid ()) {
513- ptz_control_->setAutoFocus (enabled);
514- }
525+ auto ptzctrl = get_ptz_control ();
526+ if (!ptzctrl)
527+ return ;
528+ ptzctrl->setAutoFocus (enabled);
515529}
516530
517531void PTZUSBCam::memory_reset (int i)
@@ -523,15 +537,17 @@ void PTZUSBCam::memory_reset(int i)
523537
524538void PTZUSBCam::memory_set (int i)
525539{
526- presets[i] = now_pos;
540+ auto ptzctrl = get_ptz_control ();
541+ if (!ptzctrl)
542+ return ;
543+ presets[i] = ptzctrl->getPosition ();
527544}
528545
529546void PTZUSBCam::memory_recall (int i)
530547{
531548 if (!presets.contains (i))
532549 return ;
533-
534- now_pos = presets[i];
550+ auto now_pos = presets[i];
535551 pantilt_abs (now_pos.pan , now_pos.tilt );
536552 zoom_abs (now_pos.zoom );
537553 set_autofocus (now_pos.focusAuto );
0 commit comments