我想使用 aiortc 和 TCPSocketHandling 将视频从 server.py 流式传输到 client.py。 我似乎确实按照 aiortc 示例和文档做了所有事情,但仍然收到以下错误:-
异常=InvalidStateError('RTCIceTransport 已关闭')>
附上client.py和server.py代码
服务器.py
import asyncio
import cv2
from aiortc import MediaStreamTrack, RTCPeerConnection, RTCSessionDescription, RTCIceCandidate
from aiortc.contrib.media import MediaBlackhole, MediaPlayer, MediaRelay
from aiortc.contrib.signaling import TcpSocketSignaling
from av import VideoFrame
class VideoStreamTrack(MediaStreamTrack):
kind = "video"
def __init__(self, video_path):
super().__init__() # Initialize the base class
# self.track = track
self.video_path = video_path
self.cap = cv2.VideoCapture(video_path)
async def recv(self):
# Read frames from the video file and convert them to RTCVideoFrames
ret, img = self.cap.read()
if ret:
# pts, time_base = await self.next_timestamp()
frame = VideoFrame.from_ndarray(img, format="bgr24")
# frame.pts = pts
# frame.time_base = time_base
# await asyncio.sleep(1/30)
return frame
else:
# Video ended, close the connection
self.cap.release()
raise ConnectionError("Video stream ended")
async def serve_video(pc, signaling):
# Create a MediaRelay to relay media tracks between peers
relay = MediaRelay()
# track = MediaStreamTrack()
# Add the video track to the peer connection
video_path = "test.mp4"
video_track = VideoStreamTrack(video_path)
pc.addTrack(relay.subscribe(video_track))
# Create an offer and set it as the local description
offer = await pc.createOffer()
await pc.setLocalDescription(offer)
# Send the offer to the client
await signaling.send(pc.localDescription)
# Wait for the answer from the client
answer = await signaling.receive()
if isinstance(answer, RTCSessionDescription):
await pc.setRemoteDescription(answer)
elif isinstance(answer, RTCIceCandidate):
await pc.addIceCandidate(answer)
# await pc.setRemoteDescription(RTCSessionDescription(answer))
# Start relaying the media between peers
# while True:
# try:
# frame = await video_track.recv()
# await pc.sendVideoFrame(frame)
# except ConnectionError:
# break
# # Cleanup when done
await pc.close()
async def main():
pc = RTCPeerConnection()
# Create a TCP socket signaling instance
signaling = TcpSocketSignaling("127.0.0.1", 8080)
# Connect to the signaling server
await signaling.connect()
# Serve the video
await serve_video(pc, signaling)
# Close the signaling connection
await signaling.close()
if __name__ == "__main__":
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
Client.py:-
import asyncio
import cv2
from aiortc import MediaStreamTrack, RTCPeerConnection, RTCSessionDescription, RTCIceCandidate
from aiortc.contrib.media import MediaBlackhole, MediaPlayer, MediaRelay
from aiortc.contrib.signaling import TcpSocketSignaling
class VideoStreamTrack(MediaStreamTrack):
kind = "video"
def __init__(self, track):
super().__init__() # Initialize the base class
self.track = track
async def recv(self):
# Receive RTCVideoFrames and render them
frame = await self.track.recv()
if frame:
img = frame.to_ndarray(format="bgr24")
cv2.imshow("b", frame)
print("a")
cv2.waitKey(1)
else:
# Video ended, close the connection
raise ConnectionError("Video stream ended")
return frame
async def receive_video(pc, signaling):
# Create a MediaRelay to relay media tracks between peers
# relay = MediaRelay()
offer = await signaling.receive()
@pc.on("iceconnectionstatechange")
async def on_iceconnectionstatechange():
print("ICE connection state is %s" % pc.iceConnectionState)
if pc.iceConnectionState == "failed":
print("Error!!!")
await pc.close()
# pcs.discard(pc)
@pc.on("track")
def on_track(track):
video_track = VideoStreamTrack(track)
if isinstance(offer, RTCSessionDescription):
await pc.setRemoteDescription(offer)
elif isinstance(offer, RTCIceCandidate):
await pc.addIceCandidate(offer)
# await pc.setRemoteDescription(RTCSessionDescription(answer))
# Create a renderer to display the received video
# Add the video track to the peer connection
# pc.addTrack(video_track)
# Create an answer and set it as the local description
await pc.setLocalDescription(await pc.createAnswer())
# Send the answer back to the server
await signaling.send(pc.localDescription)
# Start relaying the media between peers
# while True:
# try:
# await video_track.recv()
# except ConnectionError:
# break
# Cleanup when done
await pc.close()
async def main():
pc = RTCPeerConnection()
# Create a TCP socket signaling instance
signaling = TcpSocketSignaling("127.0.0.1", 8080)
# Connect to the signaling server
await signaling.connect()
# Receive the video
await receive_video(pc, signaling)
# Close the signaling connection
await signaling.close()
if __name__ == "__main__":
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
你找到答案了吗?如果是的话可以分享一下吗?