exremotecam.lua 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473
  1. --[[
  2. @module exremotecam
  3. @summary exremotecam 远程摄像头OSD控制扩展库,提供摄像头OSD文字显示设置和拍照功能。
  4. @version 1.0
  5. @date 2025.12.29
  6. @author 拓毅恒
  7. @usage
  8. 注:在使用exremotecam 扩展库时,需要确保网络连接正常,能够访问到目标摄像头。
  9. 本文件的对外接口有2个:
  10. 1、exremotecam.OSDsetup(Brand, Host, channel, text, X, Y):设置摄像头OSD文字显示
  11. -- 参数说明:
  12. -- Brand: 摄像头品牌,当前仅支持"Dhua"(大华)
  13. -- Host: 摄像头/NVR的IP地址
  14. -- channel: 摄像头通道号
  15. -- text: OSD文本内容,需用竖线分隔,格式如"1111|2222|3333|4444"
  16. -- X: 显示位置的X坐标
  17. -- Y: 显示位置的Y坐标
  18. 2、exremotecam.getphoto(Brand, Host, channel):控制摄像头拍照
  19. -- 参数说明:
  20. -- Brand: 摄像头品牌,当前仅支持"Dhua"(大华)
  21. -- Host: 摄像头/NVR的IP地址
  22. -- channel: 摄像头通道号
  23. -- 返回:若SD卡可用,则图片保存为/sd/1.jpeg
  24. ]]
  25. --------------------------------各品牌摄像头HTTP参数配置--------------------------------
  26. -- 大华参数
  27. local DH_TextAlign = 0 -- 文本对齐方式,0左对齐,3右对齐 默认左对齐
  28. local DH_channel = 0 -- 通道号
  29. -- 大华OSD默认配置参数
  30. local dh_osd_param = {
  31. Host = "192.168.1.108",
  32. url = "/cgi-bin/configManager.cgi?",
  33. GetWidgest = "action=getConfig&name=VideoWidget",
  34. SetWidgest = "action=setConfig&VideoWidget[0].FontColorType=Adapt&VideoWidget[0].CustomTitle[1].PreviewBlend=true&VideoWidget[0].CustomTitle[1].EncodeBlend=true&VideoWidget[0].CustomTitle[1].TextAlign="..DH_TextAlign.."&VideoWidget[0].CustomTitle[1].Text=",
  35. Text = "NULL",
  36. Postion = "&VideoWidget[0].CustomTitle[1].Rect[0]=83&VideoWidget[0].CustomTitle[1].Rect[1]=169&VideoWidget[0].CustomTitle[1].Rect[2]=2666&VideoWidget[0].CustomTitle[1].Rect[3]=607"
  37. }
  38. -- 大华抓图默认配置参数
  39. local DAHUA_MD5Param = {
  40. username = "admin",
  41. password = "Air123456",
  42. realm = "Login to 7720fd71f7dd8d36eaabc67104aa4f38",--值要获取
  43. nonce = "dcd98b7102dd2f0e8b11d0f600bfb0c093", -- 示例nonce值
  44. method = "GET:", -- HTTP方法
  45. qop = "auth",
  46. nc = "00000001",
  47. cnonce = "KeA8e2Cy",
  48. response = "NULL",
  49. url = "/cgi-bin/snapshot.cgi?",
  50. timerul = "/cgi-bin/global.cgi?"
  51. }
  52. --------------------------------各品牌摄像头HTTP参数配置完毕--------------------------------
  53. --[[
  54. 按竖线(|)分割字符串,支持多种返回格式
  55. @api split_string_by_pipe(input_str,return_type)
  56. @string input_str 要分割的字符串,格式如"1111|2222|3333"
  57. @string/number return_type 返回类型,可选值:
  58. "all" - 返回完整拆分数组(默认值)
  59. "count" - 返回元素数量
  60. 整数 - 返回指定索引的元素(索引从1开始)
  61. @return 根据return_type参数不同,返回不同结果:
  62. - "all": table - 包含所有分割元素的数组
  63. - "count": number - 分割后的元素数量
  64. - 整数索引: string - 指定索引的元素,索引越界时返回错误信息
  65. - 无效参数: string - 错误提示信息
  66. @usage:
  67. -- 示例1: 完整数组返回
  68. -- 输入: "OSD行1|OSD行2|OSD行3"
  69. -- 代码: local result = split_string_by_pipe("OSD行1|OSD行2|OSD行3")
  70. -- 输出: {"OSD行1", "OSD行2", "OSD行3"}
  71. -- 示例2: 返回元素数量
  72. -- 输入: "OSD行1|OSD行2|OSD行3"
  73. -- 代码: local count = split_string_by_pipe("OSD行1|OSD行2|OSD行3", "count")
  74. -- 输出: 3
  75. -- 示例3: 返回指定索引元素
  76. -- 输入: "OSD行1|OSD行2|OSD行3"
  77. -- 代码: local second_item = split_string_by_pipe("OSD行1|OSD行2|OSD行3", 2)
  78. -- 输出: "OSD行2"
  79. -- 示例4: 在OSDsetup中的实际应用
  80. -- 代码: OSDsetup("Dhua", "192.168.1.108", 0, "温度|湿度|天气|风向", 0, 2000)
  81. -- 内部处理: split_string_by_pipe("温度|湿度|天气|风向") 得到 {"温度", "湿度", "天气", "风向"}
  82. -- 最终效果: 在大华摄像头OSD上显示这四行文字
  83. ]]
  84. local function split_string_by_pipe(input_str, return_type)
  85. -- 处理默认参数(如果未指定 return_type,默认返回完整数组)
  86. return_type = return_type or "all"
  87. -- 存储拆分后的结果
  88. local split_result = {}
  89. -- 核心拆分逻辑:遍历字符串,按 | 分割
  90. for item in string.gmatch(input_str, "[^|]+") do
  91. table.insert(split_result, item) -- 将匹配到的元素加入数组
  92. end
  93. -- 根据 return_type 处理返回结果
  94. if return_type == "all" then
  95. -- 返回完整拆分数组
  96. return split_result
  97. elseif return_type == "count" then
  98. -- 返回元素数量(#split_result 是 Lua 获取数组长度的方式)
  99. return #split_result
  100. elseif type(return_type) == "number" then
  101. -- 返回指定索引的元素(Lua 数组索引从 1 开始)
  102. if return_type >= 1 and return_type <= #split_result then
  103. return split_result[return_type]
  104. else
  105. -- 处理索引越界
  106. return string.format("索引 %d 越界,当前只有 %d 个元素(索引 1 到 %d)",
  107. return_type, #split_result, #split_result)
  108. end
  109. else
  110. -- 处理无效的 return_type 参数
  111. return "return_type 无效!可选值:'all'、'count' 或整数索引"
  112. end
  113. end
  114. --[[
  115. 解析并验证OSD显示元素,确保不超出最大显示行数
  116. @api ElementJudg(Data, number)
  117. @string Data 竖线分隔的OSD文本内容,格式如"1111|2222|3333"
  118. @number number 最大允许显示的行数
  119. @return table 分割后的所有OSD元素数组
  120. @usage
  121. local osd_elements = ElementJudg("行1|行2|行3|行4", 3)
  122. -- 输出: "超出显示的范围,只能显示3行"
  123. -- 返回: {"行1", "行2", "行3", "行4"}
  124. 注意事项:
  125. 1. 函数会打印所有解析到的元素及其索引
  126. 2. 当元素数量超过最大行数时,会记录警告日志
  127. 3. 无论是否超出限制,都会返回完整的元素数组
  128. ]]
  129. local function ElementJudg(Data,number)
  130. -- 使用split_string_by_pipe函数按竖线分割OSD数据
  131. local all_items = split_string_by_pipe(Data)
  132. -- 遍历并打印所有解析到的OSD元素及其索引
  133. for i, item in ipairs(all_items) do
  134. log.info("元素解析", "索引", i, "值", item)
  135. end
  136. -- 获取OSD元素的总数
  137. local NUM = split_string_by_pipe(Data,"count")
  138. -- 检查元素数量是否超过最大允许行数
  139. if NUM > number then
  140. -- 记录警告日志,提示超出显示范围
  141. log.info("超出显示的范围,只能显示"..number.."行")
  142. end
  143. -- 返回完整的OSD元素数组(无论是否超出限制)
  144. return all_items
  145. end
  146. --[[
  147. URL编码函数,用于将字符串转换为符合URL标准的编码格式
  148. @api urlencode(str)
  149. @string str 需要进行URL编码的字符串
  150. @return string 编码后的URL安全字符串,如果输入为nil则返回空字符串
  151. @usage:
  152. local encoded = urlencode("Hello World!")
  153. -- 输出: "Hello+World%21"
  154. ]]
  155. local function urlencode(str)
  156. -- 检查输入参数是否存在
  157. if (str) then
  158. -- 将换行符转换为CRLF格式,符合HTTP标准
  159. str = string.gsub(str, "\n", "\r\n")
  160. -- 对非字母数字和空格的字符进行%XX编码
  161. str = string.gsub(str, "([^%w ])", function(c) return string.format("%%%02X", string.byte(c)) end)
  162. -- 将空格转换为+号,符合URL编码规范
  163. str = string.gsub(str, " ", "+")
  164. end
  165. -- 返回编码后的字符串或空字符串(如果输入为nil)
  166. return str or ""
  167. end
  168. --[[
  169. 计算Digest认证中的HA1值,用于网络摄像头的身份验证
  170. @api CameraHA1(username,realm,password)
  171. @string username 用户名
  172. @string realm 认证域,由服务器在401响应中提供
  173. @string password 用户密码
  174. @return string 计算得到的HA1值(小写的MD5哈希值)
  175. @usage:
  176. local ha1 = CameraHA1("admin", "realm", "123456")
  177. -- 输出: md5("admin:realm:123456")的小写哈希值
  178. ]]
  179. local function CameraHA1(username,realm,password)
  180. -- 计算HA1值:MD5(用户名:认证域:密码),并转换为小写
  181. -- Digest认证标准要求使用小写的哈希值
  182. local ha1 = string.lower(crypto.md5(username..":"..realm..":"..password))
  183. -- 返回计算得到的HA1值
  184. return ha1
  185. end
  186. --[[
  187. 处理Digest认证,仅在收到401响应时调用
  188. @api handle_digest_auth(Host,url,params,headers,HA2)
  189. @string Host 摄像头的IP地址
  190. @string url 请求的URL路径
  191. @string params 请求参数
  192. @table headers 第一次HTTP请求返回的头部信息
  193. @string HA2 预先计算好的HA2值
  194. @return boolean, table 认证是否成功, 更新后的请求头部
  195. @usage:
  196. local code, headers, body = http.request("GET", "http://192.168.1.100/cgi-bin/test", initial_headers).wait()
  197. if code == 401 then
  198. local success, updated_headers = handle_digest_auth("192.168.1.100", "/cgi-bin/test", "param=value", headers, "ha2_value")
  199. if success then
  200. -- 使用更新后的头部发送第二次请求
  201. end
  202. end
  203. ]]
  204. local function handle_digest_auth(Host, url, params, headers, HA2)
  205. -- 将headers转换为JSON格式以便解析
  206. local str = json.encode(headers)
  207. local Authenticate = json.decode(str)
  208. -- 获取WWW-Authenticate头信息
  209. local www = Authenticate["WWW-Authenticate"]
  210. if not www then
  211. log.info("DigestAuth", "没有找到WWW-Authenticate头信息")
  212. return false, nil
  213. end
  214. log.info("DigestAuth", "获取的鉴权信息:", www)
  215. -- 从鉴权信息中提取所需参数
  216. DAHUA_MD5Param.realm = string.match(www,"realm=\"(.-)\"") -- 提取认证域
  217. DAHUA_MD5Param.nonce = string.match(www,"nonce=\"(.-)\"") -- 提取随机数
  218. if not DAHUA_MD5Param.realm or not DAHUA_MD5Param.nonce then
  219. log.info("DigestAuth", "无法提取realm或nonce参数")
  220. return false, nil
  221. end
  222. -- 计算HA1值(用户名、认证域、密码的MD5哈希)
  223. local HA1 = CameraHA1(DAHUA_MD5Param.username, DAHUA_MD5Param.realm, DAHUA_MD5Param.password)
  224. -- 计算完整的response值(Digest认证的核心)
  225. -- response = MD5(HA1:nonce:nc:cnonce:qop:HA2)
  226. DAHUA_MD5Param.response = string.lower(crypto.md5(HA1..":"..DAHUA_MD5Param.nonce..":"..DAHUA_MD5Param.nc..":"..DAHUA_MD5Param.cnonce..":"..DAHUA_MD5Param.qop..":"..HA2))
  227. -- 构建完整的Authorization头部
  228. local authorization_header = "Digest username=\"" .. DAHUA_MD5Param.username .. "\", realm=\"" .. DAHUA_MD5Param.realm .. "\", nonce=\"" .. DAHUA_MD5Param.nonce .. "\", uri=\"" .. url..params.. "\", qop=" .. DAHUA_MD5Param.qop .. ", nc=" .. DAHUA_MD5Param.nc .. ", cnonce=\"" .. DAHUA_MD5Param.cnonce .. "\", response=\"" .. DAHUA_MD5Param.response.."\""
  229. -- 更新请求头部,添加认证信息
  230. local updated_headers = {['Host']=''..Host, ["Authorization"] = ''..authorization_header, ['Connection']='keep-alive'}
  231. log.info("DigestAuth", "鉴权信息重组完成")
  232. return true, updated_headers
  233. end
  234. --[[
  235. 设置大华(Dahua)摄像头的OSD(屏幕显示)模块
  236. @api DH_set_osd_module(Host,Data,TextAlign,channel,x,y)
  237. @string Host 摄像头的IP地址
  238. @string Data 要显示的OSD文本内容
  239. @number TextAlign OSD文本对齐方式,默认为全局的DH_TextAlign
  240. @number channel 摄像头通道号,默认为全局的DH_channel
  241. @number x OSD显示的X坐标,默认为0
  242. @number y OSD显示的Y坐标,默认为0
  243. @return nil 无返回值,函数通过日志输出执行结果
  244. @usage:
  245. DH_set_osd_module("192.168.1.100", "温度: 25℃", 0, 1, 100, 200)
  246. -- 功能: 在IP为192.168.1.100的摄像头通道1上,坐标(100,200)处显示"温度: 25℃"
  247. ]]
  248. local function DH_set_osd_module(Host,Data,TextAlign,channel,x,y)
  249. -- 设置默认参数值
  250. DH_TextAlign = TextAlign or DH_TextAlign -- 对齐方式 如果没填用默认值左对齐
  251. channel = channel or DH_channel -- 通道号 如果没填用默认值0
  252. x = x or 0 -- x坐标 如果没填用默认值为0
  253. y = y or 0 -- y坐标 如果没填用默认值为0
  254. -- 构建OSD位置参数字符串
  255. dh_osd_param.Postion = "&VideoWidget["..channel.."].CustomTitle[1].Rect[0]="..x.."&VideoWidget["..channel.."].CustomTitle[1].Rect[1]="..y.."&VideoWidget["..channel.."].CustomTitle[1].Rect[2]=0".."&VideoWidget["..channel.."].CustomTitle[1].Rect[3]=0"
  256. -- 构建OSD设置参数字符串
  257. dh_osd_param.SetWidgest = "action=setConfig&VideoWidget["..channel.."].FontColorType=Adapt&VideoWidget["..channel.."].CustomTitle[1].PreviewBlend=true&VideoWidget["..channel.."].CustomTitle[1].EncodeBlend=true&VideoWidget["..channel.."].CustomTitle[1].TextAlign="..DH_TextAlign.."&VideoWidget["..channel.."].CustomTitle[1].Text="
  258. -- 对OSD文本内容进行URL编码,确保特殊字符正确传输
  259. local OsdData = urlencode(Data)
  260. -- 拼接完整的OSD设置参数
  261. local OSDTEXT = dh_osd_param.SetWidgest ..OsdData
  262. ---log.info("打印放置位置",dh_osd_param.Postion)
  263. -- 计算HA2值,用于Digest认证
  264. -- HA2 = MD5(方法:URL路径:请求参数)
  265. local HA2 = string.lower(crypto.md5(DAHUA_MD5Param.method..dh_osd_param.url..OSDTEXT..dh_osd_param.Postion))
  266. -- 构建HTTP请求头部
  267. local Camera_header = {["Accept-Encoding"]="identity",["Host"]=""..Host}
  268. -- 发送第一次HTTP请求,获取鉴权信息
  269. local full_params = OSDTEXT..dh_osd_param.Postion
  270. local full_url = "http://"..Host..dh_osd_param.url..full_params
  271. local code, headers, body = http.request("GET", full_url, Camera_header).wait()
  272. log.info("DHosd", "第一次请求http,code:", code, headers) -- 打印返回的状态码和头部信息
  273. -- 处理HTTP请求返回结果
  274. if code == 401 then -- 401表示需要身份认证
  275. -- 使用Digest认证函数处理认证
  276. local success, updated_headers = handle_digest_auth(Host, dh_osd_param.url, full_params, headers, HA2)
  277. if success then
  278. -- 发送第二次HTTP请求,这次带有完整的认证信息
  279. local code, headers, body = http.request("GET", full_url, updated_headers).wait()
  280. log.info("DHosd", "第二次请求http,code:", code)
  281. else
  282. log.info("DHosd", "Digest认证失败")
  283. return
  284. end
  285. elseif code == -4 then
  286. -- 处理重组错误(参数错误)
  287. log.info("DHosd", "重组错误,请检查参数是否正确")
  288. return -- 退出函数,节省资源
  289. else
  290. -- 处理其他HTTP错误
  291. log.info("DHosd", "HTTP请求错误,code:", code)
  292. return -- 退出函数,节省资源
  293. end
  294. end
  295. --[[
  296. 设置摄像头OSD(屏幕显示)文字功能
  297. @api OSDsetup(Brand,Host,channel,text,X,Y)
  298. @string Brand 摄像头品牌,当前仅支持: "Dhua" - 大华
  299. @string Host 摄像头/NVR的IP地址
  300. @number channel 摄像头通道号(主要用于NVR)
  301. @string text OSD文本内容,需用竖线分隔,格式如"1111|2222|3333|4444",大华最多显示13行
  302. @number X 显示位置的X坐标
  303. @number Y 显示位置的Y坐标
  304. @return 无 无返回值
  305. @usage
  306. -- 大华摄像头OSD测试
  307. OSDsetup("Dhua", "192.168.0.163", 0, "行1|行2|行3", 0, 2000)
  308. -- 多通道NVR示例
  309. OSDsetup("Dhua", "192.168.0.200", 1, "温度: 25℃|湿度: 60%", 100, 50)
  310. ]]
  311. local function OSDsetup(Brand,Host,channel,text,X,Y)
  312. -- 判断摄像头品牌
  313. if Brand == "Dhua" then
  314. log.info("osdsetup","检测到大华摄像头,开始初始化")
  315. -- 解析并验证OSD文本内容,大华摄像头最多支持13行
  316. ElementJudg(text,13)
  317. -- 调用大华摄像头OSD设置函数
  318. -- 参数:IP地址、OSD文本数组、对齐方式、通道号、X坐标、Y坐标
  319. DH_set_osd_module(Host,text,0,channel,X,Y)
  320. -- 以下品牌型号暂不支持,代码已注释
  321. -- elseif Brand == "Hikvision" then
  322. -- log.info("osdsetup","检测到海康摄像头,开始初始化")
  323. -- local all_items = ElementJudg(Text,4)
  324. -- HKOSDBdoyGetFun(Host,channel,all_items[1],all_items[2],all_items[3],all_items[4],X,Y)
  325. -- elseif Brand == "Uniview" then
  326. -- log.info("osdsetup","检测到宇视摄像头,开始初始化")
  327. -- local all_items = ElementJudg(Text,6)
  328. -- EZ_OSDSETFun(Host,channel,all_items[1],all_items[2],all_items[3],all_items[4],all_items[5],all_items[6],X,Y)
  329. -- elseif Brand == "TianDiWeiye" then
  330. -- log.info("osdsetup","检测到天地伟业摄像头,开始初始化")
  331. -- local all_items = ElementJudg(Text,6)
  332. -- -- TDOSDModify(Host,t)
  333. else
  334. -- 处理不支持的品牌
  335. log.info("osdsetup","型号填写错误或暂不支持!!!")
  336. end
  337. end
  338. --[[
  339. 大华摄像头拍照功能,获取指定通道的快照图片
  340. @api DHPicture(Host,channel)
  341. @string Host 摄像头/NVR的IP地址
  342. @number channel 摄像头通道号
  343. @return 无 无返回值,若SD卡可用则图片保存为/sd/1.jpeg
  344. @usage
  345. -- 获取大华摄像头通道0的快照图片
  346. DHPicture("192.168.1.108", 0)
  347. -- 获取大华NVR通道1的快照图片
  348. DHPicture("192.168.0.200", 1)
  349. ]]
  350. local function DHPicture(Host,channel)
  351. log.info("DHPicture","开始执行")
  352. -- 构建拍照请求参数:通道号和图片类型(0表示快照)
  353. local resultStr = "channel="..channel.."&type=0"
  354. -- 计算HA2值:对HTTP方法、URL路径和请求参数进行MD5加密
  355. local HA2 = string.lower(crypto.md5(DAHUA_MD5Param.method..DAHUA_MD5Param.url..resultStr))
  356. -- 准备基础HTTP请求头部
  357. local Camera_header = {["Accept-Encoding"]="identity",["Host"]=""..Host}
  358. -- 发送第一次HTTP请求,主要目的是获取Digest认证信息
  359. local full_url = "http://"..Host..DAHUA_MD5Param.url..resultStr
  360. local code, headers, body = http.request("GET", full_url, Camera_header).wait()
  361. log.info("DHPicture","第一次请求http,code:",code,headers)
  362. -- 获取到鉴权信息
  363. if code ==401 then
  364. -- 使用统一的Digest认证函数处理认证
  365. local success, updated_headers = handle_digest_auth(Host, DAHUA_MD5Param.url, resultStr, headers, HA2)
  366. if success then
  367. Camera_header = updated_headers
  368. log.info("DHPicture","鉴权信息重组完成")
  369. else
  370. log.info("DHPicture", "Digest认证失败")
  371. return
  372. end
  373. end
  374. -- 检查SD卡状态
  375. local can_save_to_sd = false
  376. local data, err = fatfs.getfree("/sd")
  377. if data then
  378. can_save_to_sd = true
  379. log.info("DHPicture", "SD卡可用空间信息:", json.encode(data))
  380. else
  381. log.info("DHPicture", "无法获取SD卡空间信息:", err)
  382. end
  383. -- 根据SD卡状态发送请求
  384. local code, headers, body
  385. if can_save_to_sd then
  386. -- 发送第二次请求(带有完整的认证信息),获取图片并保存到/sd/1.jpeg
  387. code, headers, body = http.request("GET", full_url, Camera_header, nil, {dst = "/sd/1.jpeg"}).wait()
  388. else
  389. -- 发送第二次请求(带有完整的认证信息),不保存图片
  390. code, headers, body = http.request("GET", full_url, Camera_header).wait()
  391. log.info("DHPicture", "没有检测到SD卡,无法保存图片到SD卡中,请确认SD卡状态后重试")
  392. end
  393. log.info("DHPicture","第二次请求http,code:", code, body)
  394. if code == 200 then
  395. log.info("DHPicture","拍照完成")
  396. end
  397. end
  398. --[[
  399. 多品牌摄像头拍照通用接口,根据品牌调用对应厂商的拍照功能
  400. @api getphoto(Brand,Host,channel)
  401. @string Brand 摄像头品牌,当前仅支持: "Dhua" - 大华
  402. @string Host 摄像头/NVR的IP地址
  403. @number channel 摄像头通道号
  404. @return 无 无返回值,若SD卡可用则图片保存为/sd/1.jpeg
  405. @usage
  406. -- 获取大华摄像头通道0的快照图片
  407. getphoto("Dhua", "192.168.1.108", 1)
  408. -- 获取大华NVR通道1的快照图片
  409. getphoto("Dhua", "192.168.0.200", 1)
  410. ]]
  411. local function getphoto(Brand,Host,channel)
  412. -- 判断摄像头品牌
  413. if Brand == "Dhua" then
  414. log.info("getphoto","检测到大华摄像头,开始初始化")
  415. DHPicture(Host,channel)
  416. else
  417. -- 处理不支持的品牌
  418. log.info("getphoto","型号填写错误或暂不支持!!!")
  419. return
  420. end
  421. end
  422. return {
  423. OSDsetup = OSDsetup,
  424. getphoto = getphoto
  425. }