You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
107 lines
3.2 KiB
Python
107 lines
3.2 KiB
Python
import time
|
|
from av import VideoFrame
|
|
from aiortc import VideoStreamTrack
|
|
import numpy as np
|
|
from aiohttp import web
|
|
import argparse
|
|
import asyncio
|
|
import ssl
|
|
import os
|
|
from aiortc import RTCPeerConnection, RTCSessionDescription
|
|
import cv2
|
|
import json
|
|
import time
|
|
from datetime import datetime
|
|
|
|
ROOT = "./"
|
|
|
|
class WebRTCVideoSink(VideoStreamTrack):
|
|
def __init__(self, vr):
|
|
""" vr - opencv is videocapture. """
|
|
super().__init__() # don't forget this!
|
|
self.counter = 0
|
|
self.vr = vr
|
|
|
|
async def recv(self):
|
|
# time.sleep(1/40)
|
|
ok, frame = self.vr.read()
|
|
pts, time_base = await self.next_timestamp()
|
|
if not ok:
|
|
return None
|
|
else:
|
|
frame = VideoFrame.from_ndarray(frame, format="bgr24")
|
|
frame.pts = pts
|
|
frame.time_base = time_base
|
|
self.counter += 1
|
|
return frame
|
|
|
|
pcs_rgb = dict()
|
|
|
|
async def offer_video(request):
|
|
params = await request.json()
|
|
pc = RTCPeerConnection()
|
|
pcs_rgb[request.remote] = pc
|
|
reader = cv2.VideoCapture("demo.mp4")
|
|
video_track = WebRTCVideoSink(reader)
|
|
pc.addTrack(video_track)
|
|
offer = await pc.createOffer()
|
|
print("Offer:", offer)
|
|
await pc.setLocalDescription(offer)
|
|
return web.Response(
|
|
content_type="application/json",
|
|
text=json.dumps(
|
|
{"sdp": pc.localDescription.sdp, "type": pc.localDescription.type}
|
|
),
|
|
)
|
|
|
|
async def answer_video(request):
|
|
params = await request.json()
|
|
answer = RTCSessionDescription(sdp=params["sdp"], type=params["type"])
|
|
print("Answer:", answer)
|
|
pc = pcs_rgb.get(request.remote, None)
|
|
if not pc is None:
|
|
await pc.setRemoteDescription(answer)
|
|
return web.Response(text="Ok")
|
|
|
|
async def index(request):
|
|
print(f"{datetime.now()}, {request.remote}")
|
|
content = open(os.path.join(ROOT, "index.html"), "r").read()
|
|
return web.Response(content_type="text/html", text=content)
|
|
|
|
async def on_shutdown(app):
|
|
# close peer connections
|
|
coros = [pc.close() for remote, pc in pcs_rgb.items()]
|
|
await asyncio.gather(*coros)
|
|
pcs_rgb.clear()
|
|
|
|
if __name__ == "__main__":
|
|
parser = argparse.ArgumentParser(
|
|
description="WebRTC audio / video / data-channels demo"
|
|
)
|
|
parser.add_argument("--cert-file", help="SSL certificate file (for HTTPS)", default="./certs/cert.pem")
|
|
parser.add_argument("--key-file", help="SSL key file (for HTTPS)", default="./certs/key.pem")
|
|
parser.add_argument(
|
|
"--host", default="0.0.0.0", help="Host for HTTP server (default: 0.0.0.0)"
|
|
)
|
|
parser.add_argument(
|
|
"--port", type=int, default=24000, help="Port for HTTP server (default: 8081)"
|
|
)
|
|
parser.add_argument("--verbose", "-v", action="count")
|
|
args = parser.parse_args()
|
|
|
|
# run event loop
|
|
loop = asyncio.get_event_loop()
|
|
|
|
app = web.Application()
|
|
app.on_shutdown.append(on_shutdown)
|
|
app.router.add_get("/", index)
|
|
app.router.add_post("/offer_video", offer_video)
|
|
app.router.add_post("/answer_video", answer_video)
|
|
|
|
ssl_context = ssl.SSLContext()
|
|
ssl_context.load_cert_chain(args.cert_file, args.key_file)
|
|
|
|
web.run_app(
|
|
app, access_log=None, host=args.host, port=args.port, ssl_context=ssl_context
|
|
)
|