You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

213 lines
6.9 KiB

import os
import sqlite3
import cv2
import asyncio
import av
from aiohttp import web
from quart import Quart, render_template, request, jsonify,send_from_directory
from aiortc import RTCPeerConnection, RTCSessionDescription, VideoStreamTrack, RTCConfiguration, RTCIceServer
from fractions import Fraction
from .main import main as main_blueprint
#app.config['SECRET_KEY'] = 'mysecret' #密钥 --需要放配置文件
#socketio = SocketIO(app)
'''
************************
功能函数
'''
rtsp_url = 'rtsp://127.0.0.1/live1'
#-------------------基于WEBRTC实现拉流
pcs = set() #创建一个空的集合,去重复且无序
def create_app():
app = Quart(__name__)
# 注册蓝图
app.register_blueprint(main_blueprint)
return app
class VideoTransformTrack(VideoStreamTrack):
kind = "video"
def __init__(self):
super().__init__()
self.cap = cv2.VideoCapture('rtsp://127.0.0.1/live1')
if not self.cap.isOpened():
raise Exception("Unable to open video source")
# Set desired resolution and frame rate
# self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280) # Set width to 1280
# self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720) # Set height to 720
# self.cap.set(cv2.CAP_PROP_FPS, 30) # Set frame rate to 30 FPS
self.frame_rate = int(self.cap.get(cv2.CAP_PROP_FPS)) or 30 # Default to 30 if unable to get FPS
self.time_base = Fraction(1, self.frame_rate)
async def recv(self):
ret, frame = self.cap.read()
if not ret:
raise Exception("Unable to read frame")
# Convert frame to RGB
frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
# Convert to VideoFrame
video_frame = av.VideoFrame.from_ndarray(frame_rgb, format="rgb24")
# Set timestamp
video_frame.pts = int(self.cap.get(cv2.CAP_PROP_POS_FRAMES))
video_frame.time_base = self.time_base
return video_frame
'''
************************
页面路由
'''
@app.route('/')
async def index():
#return await render_template('登录.html')
return await render_template('登录.html')
@app.route('/favicon.ico')
async def favicon():
return await send_from_directory('static', 'favicon.ico')
@app.route('/<html>')
async def get_html(html):
return await render_template(html)
#--------------------webrtc-----------------
async def server(pc, offer):
# 监听 RTC 连接状态
@pc.on("connectionstatechange")
async def on_connectionstatechange():
print("Connection state is %s" % pc.connectionState)
# 当 RTC 连接中断后将连接关闭
if pc.connectionState == "failed":
await pc.close()
pcs.discard(pc)
# 监听客户端发来的视频流
@pc.on("track")
def on_track(track):
print("======= received track: ", track)
if track.kind == "video":
# # 对视频流进行人脸替换
# t = FaceSwapper(track)
# 绑定替换后的视频流
pc.addTrack(track)
# 记录客户端 SDP
await pc.setRemoteDescription(offer)
# 生成本地 SDP
answer = await pc.createAnswer()
# 记录本地 SDP
await pc.setLocalDescription(answer)
@app.route('/offer', methods=['POST'])
async def offer():
#接收客户端的连接请求
params = await request.json
#params = await request.json()
print(params)
#提取客户端发来的SDP,生成服务器端的SDP
offer = RTCSessionDescription(sdp=params["sdp"], type=params["type"])
# Configure ICE servers if necessary
#config = RTCConfiguration([RTCIceServer(urls=['stun:stun.voiparound.com'])])
pc = RTCPeerConnection() #实例化一个rtcp对象
pcs.add(pc) #集合中添加一个对象,若已存在则不添加
print(pc)
@pc.on("datachannel")
def on_datachannel(channel):
@channel.on("message")
def on_message(message):
if isinstance(message, str) and message.startswith("ping"):
channel.send("pong" + message[4:])
#监听RTC连接状态
@pc.on("iconnectionstatechange") #当ice连接状态发生变化时
async def iconnectionstatechange():
if pc.iceConnectionState == "failed":
await pc.close()
pcs.discard(pc) #移除对象
# 添加视频轨道
video_track = VideoTransformTrack()
pc.addTrack(video_track)
print("完成视频轨道的添加")
# 记录客户端 SDP
await pc.setRemoteDescription(offer)
# 生成本地 SDP
answer = await pc.createAnswer()
# 记录本地 SDP
await pc.setLocalDescription(answer)
return jsonify({
"sdp": pc.localDescription.sdp,
"type": pc.localDescription.type
})
@app.route('/shutdown', methods=['POST'])
async def shutdown():
coros = [pc.close() for pc in pcs]
await asyncio.gather(*coros)
pcs.clear()
return 'Server shutting down...'
'''3333
各种配置文件路由
'''
@app.route('/data/<file>')
async def data(file):
return await send_from_directory('static/data',file)
@app.route('/files/<path:subdir>/<file>')
async def files(subdir,file):
return await send_from_directory(os.path.join('static/files', subdir),file)
@app.route('/images/<path:subdir>/<file>')
async def images(subdir,file):
return await send_from_directory(os.path.join('static/images', subdir),file)
@app.route('/resources/<file>')
async def resources(file):
return await send_from_directory('static/resources',file)
@app.route('/resources/<path:subdir>/<file>')
async def resources_dir(subdir,file):
return await send_from_directory(os.path.join('static/resources', subdir),file)
@app.route('/resources/css/<path:subdir>/<file>')
async def resources_css_dir(subdir,file):
return await send_from_directory(os.path.join('static/resources/css', subdir),file)
@app.route('/resources/scripts/<path:subdir>/<file>')
async def resources_scripts_dir(subdir,file):
return await send_from_directory(os.path.join('static/resources/scripts', subdir),file)
'''
后端数据接口
'''
@app.route('/submit', methods=['POST'])
def submit():
if request.method == 'POST':
suggestion = request.form['suggestion']
file = request.files['attachment']
if file:
filename = file.filename
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
# 将意见和附件的文件名保存到数据库
conn = sqlite3.connect(DB_NAME)
cursor = conn.cursor()
cursor.execute('INSERT INTO suggestions (suggestion, attachment_filename) VALUES (?, ?)',
(suggestion, filename))
conn.commit()
conn.close()
return "Thanks for your suggestion and attachment! Data saved to the database."
# 如果没有附件上传的逻辑处理
return "Data saved!"
if __name__ == '__main__':
#app.run(debug=True)
app.run(debug=True, host='0.0.0.0', port=5000)