v4lctl_node.cpp
Go to the documentation of this file.
1 /*
2  File: v4lctl_node.cpp
3  Date: 10.04.2016
4  Author: Patrick Feuser
5  Copyrights: 2016 UAV-Concept http://uav-concept.com
6  License: GNU GPLv3
7 
8  This ROS node is a wrapper for the v4lctl command line tool.
9  It provides two services to set or get particular bttv parameter.
10  If a yaml file will be provided a save and restore capability will be enabled.
11  Parameter are then loaded and set automatically in the capture card when starting the node.
12  Changed parameter are stored to a yaml file when the program ends.
13  Additionally a dynamic reconfigure rqt gui is available to manipulate bttv parameter.
14 
15  The below v4lctl list output is based on an Osprey 440 capture card.
16  This node is optimized for this card.
17  Your card may output other options then change this file and v4lctlNodeDyn.cfg to your needs.
18 
19  $ v4lctl list
20  attribute | type | current | default | comment
21  -----------+--------+---------+---------+-------------------------------------
22  norm | choice | PAL-I | NTSC | NTSC NTSC-M NTSC-M-JP NTSC-M-KR PAL PAL-BG PAL-H PAL-I PAL-DK PAL-M PAL-N PAL-Nc PAL-60 SECAM SECAM-B SECAM-G SECAM-H SECAM-DK SECAM-L SECAM-Lc
23  input | choice | Composi | Composi | Composite0 Composite1 Composite2 Composite3
24  bright | int | 32768 | 32768 | range is 0 => 65280
25  contrast | int | 32768 | 27648 | range is 0 => 65408
26  color | int | 32768 | 32768 | range is 0 => 65408
27  hue | int | 32768 | 32768 | range is 0 => 65280
28  mute | bool | on | off |
29  Chroma AGC | bool | off | off |
30  Color Kill | bool | off | off |
31  Comb Filte | bool | off | off |
32  Auto Mute | bool | on | on |
33  Luma Decim | bool | off | off |
34  AGC Crush | bool | on | on |
35  VCR Hack | bool | off | off |
36  Whitecrush | int | 127 | 127 | range is 0 => 255
37  Whitecrush | int | 207 | 207 | range is 0 => 255
38  UV Ratio | int | 51 | 50 | range is 0 => 100
39  Full Luma | bool | off | off |
40  Coring | int | 0 | 0 | range is 0 => 3
41 
42  See also http://linux.die.net/man/1/v4lctl
43 
44  setnorm <norm>
45  Set the TV norm (NTSC/PAL/SECAM).
46  setinput [ <input> | next ]
47  Set the video input (Television/Composite1/...)
48  capture [ on | off | overlay | grabdisplay ]
49  Set capture mode.
50  volume mute on | off
51  mute / unmute audio.
52  volume <arg>
53  color <arg>
54  hue <arg>
55  bright <arg>
56  contrast <arg>
57  Set the parameter to the specified value. <arg> can be one of the following: A percent value ("70%" for example). Some absolute value ("32768"), the valid range is hardware specific. Relative values can be specified too by prefixing with "+=" or "-=" ("+=10%" or "-=2000"). The keywords "inc" and "dec" are accepted to and will increase and decrease the given value in small steps.
58  setattr <name> <value>
59  Set set the value of some attribute (color, contrast, ... can be set this way too).
60  show [ <name> ]
61  Show the value current of some attribute.
62 
63  Samples:
64  $ v4lctl -c /dev/video0 bright 70%
65  $ v4lctl -c /dev/video0 contrast "60%"
66  $ v4lctl -c /dev/video0 color 27648
67  $ v4lctl -c /dev/video0 setattr "Auto Mute" off
68 */
69 #include <ros/ros.h>
70 #include <dynamic_reconfigure/server.h>
71 #include <uavc_v4lctl/v4lctlNodeDynConfig.h>
72 #include <uavc_v4lctl/v4lctlSet.h>
73 #include <uavc_v4lctl/v4lctlGet.h>
74 #include <opencv2/opencv.hpp>
75 #include <boost/algorithm/string/replace.hpp>
76 #include <boost/regex.hpp>
77 #include <sstream>
78 #include <map>
79 
80 #define YAML_OPT_TO_NAME(s) boost::replace_all_copy(boost::replace_all_copy(s,"\"","-")," ","_")
81 #define YAML_NAME_TO_OPT(s) boost::replace_all_copy(boost::replace_all_copy(s,"-","\""),"_"," ")
82 
83 namespace uavc_v4lctl {
84 
86 {
88 
91 
92  v4lctlNodeDynConfig cfg_;
93  dynamic_reconfigure::Server<v4lctlNodeDynConfig> cfg_server_;
94 
95  std::map<std::string, std::string> fs_map_;
96 
97  std::string device_;
98  std::string yaml_;
99 
100 public:
101 
103  {
104  ros::NodeHandle pnh("~");
105 
106  pnh.param<std::string>("device", device_, "/dev/video0");
107  pnh.param<std::string>("yaml", yaml_, "");
108 
109  if (!yaml_.empty())
110  restoreFromYaml();
111 
112  cfg_server_.setCallback(boost::bind(&v4lctlNode::configCb, this, _1, _2));
113 
114  srv_v4lctl_set_ = nh_.advertiseService("v4lctlSet", &v4lctlNode::v4lctlSetCb, this);
115  srv_v4lctl_get_ = nh_.advertiseService("v4lctlGet", &v4lctlNode::v4lctlGetCb, this);
116  }
117 
119  {
120  cv::FileStorage fs;
121 
122  if (!yaml_.empty() && fs.open(yaml_, cv::FileStorage::WRITE))
123  {
124  std::map<std::string, std::string>::iterator it = fs_map_.begin();
125 
126  while (it != fs_map_.end())
127  {
128  std::string key = (*it).first;
129 
130  fs << key << fs_map_[key];
131  it++;
132  }
133  }
134  }
135 
136  std::string v4lctlGet(std::string name)
137  {
138  FILE *pipe;
139  char stdout[128];
140  std::string result;
141  std::stringstream ss;
142 
143  ss << "v4lctl -c " << device_ << " show \"" << name << "\"";
144 
145  if ((pipe=popen(ss.str().c_str(), "r")))
146  {
147  if (fgets(stdout, sizeof(stdout), pipe))
148  result = boost::regex_replace(std::string(stdout), boost::regex("^" + name + ": ([a-zA-Z0-9\\-]+).*"), "$1");
149 
150  ROS_INFO_STREAM("Call '" << ss.str() << "' Result: " << result);
151 
152  pclose(pipe);
153  }
154  else
155  ROS_ERROR_STREAM("Call failed '" << ss.str() << "'");
156 
157  return result;
158  }
159 
160  bool v4lctlSet(std::string name, std::string value)
161  {
162  std::stringstream ss;
163  bool result = false;
164 
165  ss << "v4lctl -c " << device_ << " " << name << " " << value;
166 
167  ROS_INFO_STREAM("Call '" << ss.str() << "'");
168 
169  if ((result=std::system(ss.str().c_str()) > -1))
170  fs_map_[YAML_OPT_TO_NAME(name)] = value;
171 
172  return result;
173  }
174 
176  {
177  cv::FileStorage fs;
178 
179  if (fs.open(yaml_, cv::FileStorage::READ))
180  {
181  cv::FileNode fn = fs.root();
182 
183  for (cv::FileNodeIterator fit = fn.begin(); fit != fn.end(); fit++)
184  {
185  cv::FileNode item = *fit;
186 
187  v4lctlSet(YAML_NAME_TO_OPT(item.name()), (std::string)item);
188  }
189  }
190  }
191 
192  void initConfig(v4lctlNodeDynConfig &config, bool defaults = false)
193  {
194  std::string s;
195 
196 #define V4LCTL_GET_PERCENT(name,default,max) (defaults || (s=v4lctlGet(name)).empty() ? default : (atoi(s.c_str()) * 100 / max))
197 #define V4LCTL_GET_BOOL(name,default) (defaults || (s=v4lctlGet(name)).empty() ? default : boost::regex_match(s, boost::regex("^on$")))
198 #define V4LCTL_GET_INT(name,default) (defaults || (s=v4lctlGet(name)).empty() ? default : atoi(s.c_str()))
199 #define V4LCTL_GET_STRING(name,default) (defaults || (s=v4lctlGet(name)).empty() ? default : s)
200 
201  config.input = V4LCTL_GET_STRING ("input", "Composite0");
202  config.norm = V4LCTL_GET_STRING ("norm", "PAL-I");
203  config.bright = V4LCTL_GET_PERCENT("bright", 50, 65280);
204  config.contrast = V4LCTL_GET_PERCENT("contrast", 40, 65280);
205  config.color = V4LCTL_GET_PERCENT("color", 50, 65280);
206  config.hue = V4LCTL_GET_PERCENT("hue", 50, 65280);
207  config.UV_Ratio = V4LCTL_GET_INT ("UV Ratio", 50);
208  config.Coring = V4LCTL_GET_INT ("Coring", 0);
209  config.Whitecrush_Lower = V4LCTL_GET_PERCENT("Whitecrush Lower", 50, 255);
210  config.Whitecrush_Upper = V4LCTL_GET_PERCENT("Whitecrush Upper", 80, 255);
211  config.mute = V4LCTL_GET_BOOL ("mute", false);
212  config.Chroma_AGC = V4LCTL_GET_BOOL ("Chroma AGC", false);
213  config.Color_Killer = V4LCTL_GET_BOOL ("Color Killer", false);
214  config.Comb_Filter = V4LCTL_GET_BOOL ("Comb Filter", false);
215  config.Auto_Mute = V4LCTL_GET_BOOL ("Auto Mute", true);
216  config.Luma_Decim = V4LCTL_GET_BOOL ("Luma Decimation Filter", false);
217  config.AGC_Crush = V4LCTL_GET_BOOL ("AGC Crush", true);
218  config.VCR_Hack = V4LCTL_GET_BOOL ("VCR Hack", false);
219  config.Full_Luma = V4LCTL_GET_BOOL ("Full Luma Range", false);
220  }
221 
222  void configCb(v4lctlNodeDynConfig &config, int level)
223  {
224  if (level < 0)
225  {
226  initConfig(config);
227  cfg_ = config;
228 
229  ROS_INFO("Reconfigure server initialized");
230 
231  return;
232  }
233 
234  if (config.Set_Defaults)
235  {
236  initConfig(config, true);
237  config.Set_Defaults = false;
238  }
239 
240  if (config.input != cfg_.input)
241  v4lctlSet("setattr input", config.input);
242 
243  if (config.norm != cfg_.norm)
244  v4lctlSet("setnorm", config.norm);
245 
246  if (config.bright != cfg_.bright)
247  v4lctlSet("bright", std::to_string(config.bright)+'%');
248 
249  if (config.contrast != cfg_.contrast)
250  v4lctlSet("contrast", std::to_string(config.contrast)+'%');
251 
252  if (config.color != cfg_.color)
253  v4lctlSet("color", std::to_string(config.color)+'%');
254 
255  if (config.hue != cfg_.hue)
256  v4lctlSet("hue", std::to_string(config.hue)+'%');
257 
258  if (config.UV_Ratio != cfg_.UV_Ratio)
259  v4lctlSet("setattr \"UV Ratio\"", std::to_string(config.UV_Ratio)+'%');
260 
261  if (config.Coring != cfg_.Coring)
262  v4lctlSet("setattr Coring", std::to_string(config.Coring));
263 
264  if (config.Whitecrush_Lower != cfg_.Whitecrush_Lower)
265  v4lctlSet("setattr \"Whitecrush Lower\"", std::to_string(config.Whitecrush_Lower)+'%');
266 
267  if (config.Whitecrush_Upper != cfg_.Whitecrush_Upper)
268  v4lctlSet("setattr \"Whitecrush Upper\"", std::to_string(config.Whitecrush_Upper)+'%');
269 
270  if (config.mute != cfg_.mute)
271  v4lctlSet("setattr mute", config.mute ? "on" : "off");
272 
273  if (config.Chroma_AGC != cfg_.Chroma_AGC)
274  v4lctlSet("setattr \"Chroma AGC\"", config.Chroma_AGC ? "on" : "off");
275 
276  if (config.Color_Killer != cfg_.Color_Killer)
277  v4lctlSet("setattr \"Color Killer\"", config.Color_Killer ? "on" : "off");
278 
279  if (config.Comb_Filter != cfg_.Comb_Filter)
280  v4lctlSet("setattr \"Comb Filter\"", config.Comb_Filter ? "on" : "off");
281 
282  if (config.Auto_Mute != cfg_.Auto_Mute)
283  v4lctlSet("setattr \"Auto Mute\"", config.Auto_Mute ? "on" : "off");
284 
285  if (config.Luma_Decim != cfg_.Luma_Decim)
286  v4lctlSet("setattr \"Luma Decimation Filter\"", config.Luma_Decim ? "on" : "off");
287 
288  if (config.AGC_Crush != cfg_.AGC_Crush)
289  v4lctlSet("setattr \"AGC Crush\"", config.AGC_Crush ? "on" : "off");
290 
291  if (config.VCR_Hack != cfg_.VCR_Hack)
292  v4lctlSet("setattr \"VCR Hack\"", config.VCR_Hack ? "on" : "off");
293 
294  if (config.Full_Luma != cfg_.Full_Luma)
295  v4lctlSet("setattr \"Full Luma Range\"", config.Full_Luma ? "on" : "off");
296 
297  cfg_ = config;
298  }
299 
300  bool v4lctlGetCb(v4lctlGet::Request &req, v4lctlGet::Response &res)
301  {
302  res.result = v4lctlGet(req.name);
303 
304  return true;
305  }
306 
307  bool v4lctlSetCb(v4lctlSet::Request &req, v4lctlSet::Response &res)
308  {
309  return v4lctlSet(req.name, req.value);
310  }
311 };
312 
313 }
314 
315 int main(int argc, char **argv)
316 {
317  ros::init(argc, argv, "v4lctl");
318 
320 
321  ros::spin();
322 
323  return 0;
324 }
dynamic_reconfigure::Server< v4lctlNodeDynConfig > cfg_server_
Definition: v4lctl_node.cpp:93
ros::ServiceServer srv_v4lctl_set_
Definition: v4lctl_node.cpp:90
bool v4lctlSet(std::string name, std::string value)
ros::ServiceServer srv_v4lctl_get_
Definition: v4lctl_node.cpp:89
std::map< std::string, std::string > fs_map_
Definition: v4lctl_node.cpp:95
XmlRpcServer s
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
ros::NodeHandle nh_
Definition: v4lctl_node.cpp:87
#define V4LCTL_GET_BOOL(name, default)
ServiceServer advertiseService(const std::string &service, bool(T::*srv_func)(MReq &, MRes &), T *obj)
#define V4LCTL_GET_PERCENT(name, default, max)
#define YAML_NAME_TO_OPT(s)
Definition: v4lctl_node.cpp:81
std::string v4lctlGet(std::string name)
bool v4lctlSetCb(v4lctlSet::Request &req, v4lctlSet::Response &res)
#define ROS_INFO(...)
bool param(const std::string &param_name, T &param_val, const T &default_val) const
void initConfig(v4lctlNodeDynConfig &config, bool defaults=false)
ROSCPP_DECL void spin()
#define YAML_OPT_TO_NAME(s)
Definition: v4lctl_node.cpp:80
v4lctlNodeDynConfig cfg_
Definition: v4lctl_node.cpp:92
#define ROS_INFO_STREAM(args)
#define V4LCTL_GET_INT(name, default)
bool v4lctlGetCb(v4lctlGet::Request &req, v4lctlGet::Response &res)
int main(int argc, char **argv)
#define ROS_ERROR_STREAM(args)
#define V4LCTL_GET_STRING(name, default)
void configCb(v4lctlNodeDynConfig &config, int level)


uavc_v4lctl
Author(s): Patrick Feuser
autogenerated on Mon Jun 10 2019 15:38:50