一个用于Windows的MJPEG视频流和虚拟麦克风驱动程序,可以使您的Windows应用程序把《IP摄像头》作为带音频输入的电脑摄像头使用。

IP Camera Bridge 需要Win7 (32位 或 64位) 或以上版本系统才能工作!

1. 安装

下载此工程并解压,双击文件夹 “IPCameraBridge\x86” 下的install.bat安装。如果弹出UAV提示框,请点击“是” 。接下去将会弹出IP Camera Bridge属性对话框,填入你的IP摄像头的信息,单击确定!

IP Camera Bridge同样提供64位版本的二进制文件,同样安装上面的说明安装即可!

从应用程序中选择 IP Camera Bridge Plus 作为视频捕获设备,选择 IP Camera Bridge Audio 作为音频捕获设备即可 例如:

2. 设置

你可以在运行”install.bat”安装时进行设置。也可以通过宿主应用程序的滤镜选项进行设置,如下图所示:

3. 兼容性

经过我的测试,以下应用程序可以与IP Camera Bridge完美工作:

  • AMCap
  • Chrome
  • MPC-HC
  • Media Player Classic
  • PotPlayer
  • KMPlayer
  • TeamViewer 12
  • QQ
  • Mission Planner
  • Python with OpenCV module
  • Skype (desktop version)
  • Adobe Live Flash Encoder
  • GraphEdit
  • GraphEditPlus

其它基于DirectShow的应用程序应该也可以工作 🙂

你还可以同时在多个程序中同时使用!

但是,IP Camera Bridge不能与Modern App协同工作!

4. 作为音频捕获设备(例如,虚拟麦克风)

如果您想使用IP Camera Bridge作为虚拟麦克风,您应该使用以下应用程序的最新版本。 这些应用程序可以通过网络和IP Camera Bridge将他们捕获的音频传输到Windows应用程序。

5. 卸载

关闭所有程序,运行uninstall.bat,并在弹出UAC提示框时点击“是”, IP Camera Bridge将会从磁盘上移除。

很久没写东西了……
最近翻出以前中学时候玩的《口袋怪兽·金》卡带,找出以前玩的黑白GameBoy,插上去,发现十多年前的游戏记录还在,当年跟朋友联机对战,交换过精灵,里面已经收集了245只,现在人老了,虽然手机有模拟器,已经不可能有那时候的激情。于是就想把数据提取出来看能不能到模拟器继续玩。淘宝搜了一下,果然有,叫gbc dump,不仅可以dump记录,连游戏的ROM也行,OK,我这张卡带还是简体中文版,网上还没找到过有简体中文的,刚好把ROM也搞出来……一看价格……208,尼玛,感觉好坑……如下图

这种东西一般都是根据老外的开源项目改的,去bing搜一下gbc dump,果然有类似的东西,用Arduino实现,还要一个SD卡模块用来保存。手头有个树莓派3,加个关键字raspberry一起搜,果然有!github上有个项目就是这个 https://github.com/abrugsch/GBCartSlurp

电路图,程序都有,可以直接把ROM和RAM保存成文件。看电路还是挺简单,用到两块MCP23017把卡带的32个pin转成I2C接到树莓派操作。

搜了一下淘宝,有现成的MCP23017模块卖,GB卡插槽也有,那就很简单了,买了如下两个东西:

插槽的32个pin用杜邦线连上两个I2C模块就ok了,剩下就是跑程序了。不过那32个pin最好做个转接板搞,不然直接焊接会把人搞到放弃,我焊接了一个多小时,主要是电烙铁不好用,期间多次想放弃直接花208元搞一个。



按照电路图连接好之后,像这样,注意看电路图配置一下两个I2C模块的硬件地址,不能一样!

查看安装说明,先启用树莓派的I2C接口,再在树莓派里编译程序,注意需要用到WiringPi,很简单,git一下该项目,make再make install一下就好了。GBCartSlurp程序的编译也很简单,不过这里有个坑,里面写的I2C的两个地址需要修改一下,我在这里耗了两个小时。确认硬件连接OK后打开树莓派,用命令sudo i2cdetect -y 1看一下两个I2C转接板的地址,如图

然后修改源码gbcartslurp.c 405和406行的mcpSetup把0x20和0x21改成上面对应的地址 gcc gbcartslurp.c -std=c99 -lwiringPi编译,没有出错的话会得到a.out可执行文件,直接./a.out运行,按一下4,回车,应该会出来ROM信息

如果没有,或者显示很多?的话,把两个I2C地址对调一下,重新编译运行应该就OK了!

按下1可以把ROM和RAM记录dump出来分别保存成gbc文件和sav文件,导出很慢很慢很慢,一个2MB左右的ROM要超过1个小时才能导出完毕。经过测试可以在模拟器上直接使用!

看到这画面我多激动你知不知道,知不知道……208块居然省下来了!!!!

电脑也可以……如果不能载入记录,需要把后缀名sav改为sa1

成本:i2C板一块12.5,gbc插槽8.00,不算树莓派……手头没有GBA的卡,没做测试,不过需要把5V供电改为3.3V,电路图有标注!

当年是多么有体跟四大天王打了200回……

前一段时间给IP摄像头和USB摄像头加入RTMP推流支持,支持将音视频推送到直播平台做直播。甚至YouTube也能推过去,前提是你要有个好梯子😀就能实现上图的效果,网络状况好的时候好不错,延迟10秒以上。如果是自己搭推流服务器(像nginx-rtmp或者srs)或者使用国内直播云延迟可以控制到1~2秒以内,使用Flash播放器甚至可以降低到1秒。

实现这个的目的是想直播FPV,即通过采集卡把图传接收的画面通过USB摄像头App显示在手机上的同时推送到直播平台😀苦于搬了房子附近没场子飞四轴,就没直播FPV改为家庭监控用了,自己架一个RTMP推流服务器,把旧手机放家里,运行IP摄像头App进行推流,即使家里没有公网IP也能查看家里情况。

IP摄像头和USB摄像头app共用RTMP推流的代码,视频使用H.264编码,音频使用AAC编码,支持根据网络状况自动调整码率,网络状况差时会自动丢帧,以保证延迟。当遇到网络切换或者连接暂时中断时,会自行重连,直到重新连接到推流服务器或者用户自行断开连接。该推流算法自行实现,经过二月份户外4G网络测试效果不错(消耗了近2G流量,刚好二月份移动送流量),即使在户外也能通过4G网络使用IP摄像头或者USB摄像头进行RTMP推流直播。

++++++++++++++++++++++++++++++



IP摄像头 for Mac发布,至此,IP摄像头已经可以在Windows,Android和iOS还有Mac平台上运行了!

IP摄像头 for MacMac版IP摄像头底层使用了和iOS版IP摄像头近乎一致的代码,UI部分因为两者差异全部重写。目前除了不支持OneDrive和rtmp,rtsp协议外其它功能与另外几个平台一致,包括运动检测、FTP上传等,另外如果你外接多个摄像头,还可以在多摄像头之间切换,具体可以前往Mac App Store查看介绍,欢迎使用😀!

前段时间在调试IP摄像头时偶然发现铁通也能刷出独立IP,是183开头的,一开始以为只有铁通网络能够访问,后面发现跟myexternalip.com检测的IP一致,然后IP摄像头居然可以外网访问了,于是写了个python脚本来刷独立IP。

原理很简单,每次路由器重新拨号就能改变IP,然后将路由器的IP跟myexternalip.com检测的外网IP比较,如果一致就是独立IP

我家路由器是水星MD898n(固件:V2.0_140216标准版,以下都是针对此固件,不同版本固件可能不一样),根据Chrome抓包得到每次点击 断线,都会向路由器提交 “[ACT_PPP_DISCONN#2,1,1,0,0,0#0,0,0,0,0,0]0,0\r\n”的指令,点击 连接则提交“[ACT_PPP_CONN#2,1,1,0,0,0#0,0,0,0,0,0]0,0\r\n”,这样就实现路由器重新拨号。路由器登录验证则是base验证,只不过不需要用户名而已。

路由器的IP则可以通过UPnP的方式得到,具体可以参考关于UPnP端口映射的文献。

upnp.py的实现,主要实现get_external_ip()这个函数用于获取路由器IP

import socket
import socket
import re
import urllib2
import httplib
import struct
import time
from xml.dom.minidom import parseString
from urlparse import urlparse
 
xmlLocation = ""
xmlString = ""
 
def _get_external_ip():
	global xmlLocation
	global xmlString
 
	if xmlLocation == "" or xmlString == "":
		ssdpRequest = "M-SEARCH * HTTP/1.1\r\n" + \
						"MX: 3\r\n" + \
						"HOST: 239.255.255.250:1900\r\n" + \
						"MAN: \"ssdp:discover\"\r\n" + \
						"ST: urn:schemas-upnp-org:device:InternetGatewayDevice:1\r\n\r\n"
 
		SSDP_ADDR = "239.255.255.250"
		SSDP_PORT = 1900
 
		sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
		sock.bind(('192.168.1.5', 0))
		sock.settimeout(10)
		sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
		sock.sendto(ssdpRequest, (SSDP_ADDR, SSDP_PORT))
		resp = sock.recv(1024)
 
		lines = resp.splitlines()
		for line in lines:
			params = line.split(':', 1)
			if len(params) == 2 and params[0].strip().lower() == "location":
				xmlLocation = params[1].strip()
				break
		opened = urllib2.urlopen(xmlLocation)
		xmlString = opened.read()
		opened.close()
 
	GetExternalIPAddress = "<?xml version=\"1.0\"?>" + \
								"<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" + \
								"<s:Body>" + \
								"<u:GetExternalIPAddress xmlns:u=\"urn:schemas-upnp-org:service:{0}:1\">" + \
								"</u:GetExternalIPAddress>" + \
								"</s:Body>" + \
								"</s:Envelope>"
 
	router_path = urlparse(xmlLocation)
	dom = parseString(xmlString)
 
	service_types = dom.getElementsByTagName('serviceType')
 
	path = ""
	action = ""
	for service in service_types:
		if service.childNodes[0].data.find('WANIPConnection') > 0:
			path = service.parentNode.getElementsByTagName('controlURL')[0].childNodes[0].data
			action = "urn:schemas-upnp-org:service:WANIPConnection:1#GetExternalIPAddress"
		elif service.childNodes[0].data.find('WANPPPConnection') > 0:
			path = service.parentNode.getElementsByTagName('controlURL')[0].childNodes[0].data
			action = "urn:schemas-upnp-org:service:WANPPPConnection:1#GetExternalIPAddress"
		else:
			continue
 
		conn = httplib.HTTPConnection(router_path.hostname, router_path.port)
		conn.request('POST',
			path,
			GetExternalIPAddress,
			{'SOAPAction': action,
			'Content-Type': 'text/xml; charset="utf-8"'}
		)
		resp = conn.getresponse()
		result = resp.read()
		resp.close()
		conn.close()
		dom = parseString(result)
		external_ip = dom.getElementsByTagName('NewExternalIPAddress')[0].childNodes[0].nodeValue
		if external_ip != "0.0.0.0":
			return external_ip
	return ""
 
def get_external_ip():
	while(1):
		try:
			ip = _get_external_ip()
			if ip != "":
				return ip
		except Exception, e:
			print e
		time.sleep(3)
print get_external_ip()

get_global_ip.py的实现

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import httplib
import urllib
import base64
import time
import re,urllib2
import traceback
import upnp
 
def Get_public_ip(): #获取真实的广域网IP
	try:
		opener = urllib2.urlopen("http://myexternalip.com/raw")
		str = opener.read().strip()
		return str
	except Exception,ex:
		print Exception,":",ex
		return None
 
def _sendhttp(data):
	conn = httplib.HTTPConnection('192.168.1.1') #注意路由器的IP,下同
	conn.putrequest('POST', '/cgi?7')
	conn.putheader("Accept", "*/*")
	conn.putheader("Origin", "http://192.168.1.1")
	conn.putheader("Referer", "http://192.168.1.1/")
	conn.putheader("Content-Type", "text/plain")
	conn.putheader("Content-Length", str(len(data)))
	conn.putheader("Cookie", "Authorization=Basic " + base64.b64encode("123456")) # 123456为路由器登录密码
	conn.endheaders()
	conn.send(data)
 
	return conn.getresponse()
def sendhttp(data):
	httpres = _sendhttp(data)
	while httpres.status != 200:
		print httpres.status
		time.sleep(2)
		httpres = _sendhttp(data)
 
	print httpres.status
	print httpres.reason
	print httpres.read()
 
if __name__ == '__main__':
	try:
		print "Global IP:" + Get_public_ip()
		print "Router IP:" + upnp.get_external_ip()
		print "Refreshing..."
		while(1):
			sendhttp("[ACT_PPP_DISCONN#2,1,1,0,0,0#0,0,0,0,0,0]0,0\r\n") #路由器断线
			time.sleep(2)
			sendhttp("[ACT_PPP_CONN#2,1,1,0,0,0#0,0,0,0,0,0]0,0\r\n") #路由器连接,完成一次重新拨号
			time.sleep(1)
			public_ip = Get_public_ip() #获取实际外网IP
			external_ip = upnp.get_external_ip() #获取路由器IP
			if(public_ip == external_ip): #比较
				print "Global IP:" + public_ip
				print "Refresh OK!"
				break
			else:
				print "Router IP:" + external_ip
				print "Global IP:" + public_ip
				print "Continue refreshing..." #不是独立IP,继续刷
		time.sleep(1000)
	except Exception, e:
		print e
		print traceback.format_exc()
		time.sleep(1000)

将两个文件放置同一个目录,运行get_global_ip.py即可,确保跟路由器处于同一子网,并且路由器没有上级路由器,路由器要开启UPnP,切记!不同的路由器只要改一下拨号部分的代码即可。

当然还有粗暴的方式,把这代码弄到树莓派,再让树莓派控制继电器开关路由器电源,路由器每重启一次就能拨号一次,只是过于粗暴体验不佳……😂😂😂😂

本文地址 http://www.shenyaocn.com/2016/09/using_python_obtain_cmcc_global_ip/