Commit 208ed136 authored by nextime's avatar nextime

First version of shmvcam

parent c07480c6
from __future__ import annotations from __future__ import annotations
import cv2 #import cv2
import acapture #import acapture
import argparse
import pyvirtualcam
from pyvirtualcam import PixelFormat
import numpy as np
import time
import asyncio import asyncio
import logging import logging
...@@ -17,6 +23,10 @@ logging.basicConfig(level=logging.DEBUG) ...@@ -17,6 +23,10 @@ logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG) logger.setLevel(logging.DEBUG)
parser = argparse.ArgumentParser()
parser.add_argument("--device", help="VirtualCam path (optional)")
args = parser.parse_args()
class RTMP2SocketController(SimpleRTMPController): class RTMP2SocketController(SimpleRTMPController):
def __init__(self, output_directory: str): def __init__(self, output_directory: str):
...@@ -29,7 +39,8 @@ class RTMP2SocketController(SimpleRTMPController): ...@@ -29,7 +39,8 @@ class RTMP2SocketController(SimpleRTMPController):
session.state = RemoteProcessFLVWriter() session.state = RemoteProcessFLVWriter()
logger.debug(f"output to {prefix}.flv") logger.debug(f"output to {prefix}.flv")
await session.state.initialize( await session.state.initialize(
command=f"ffmpeg -y -i pipe:0 -c:v copy -c:a copy -f flv {prefix}.flv", #command=f"ffmpeg -y -i pipe:0 -c:v copy -c:a copy -f flv {prefix}.flv",
command=f"ffmpeg -hide_banner -y -i pipe:0 -pix_fmt bgr24 -vcodec rawvideo -an -sn -f image2pipe -",
stdout_log=f"{prefix}.stdout.log", stdout_log=f"{prefix}.stdout.log",
stderr_log=f"{prefix}.stderr.log", stderr_log=f"{prefix}.stderr.log",
) )
...@@ -53,12 +64,6 @@ class RTMP2SocketController(SimpleRTMPController): ...@@ -53,12 +64,6 @@ class RTMP2SocketController(SimpleRTMPController):
await super().on_stream_closed(session, exception) await super().on_stream_closed(session, exception)
class OpenCVFLVWriter:
def __init__(self)
self.write = FLVWriter()
async def initialize(self):
class RemoteProcessFLVWriter: class RemoteProcessFLVWriter:
def __init__(self): def __init__(self):
...@@ -74,8 +79,34 @@ class RemoteProcessFLVWriter: ...@@ -74,8 +79,34 @@ class RemoteProcessFLVWriter:
stdout=asyncio.subprocess.PIPE, stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE,
) )
self.stdout = asyncio.create_task(self._read_to_file(stdout_log, self.proc.stdout)) #self.stdout = asyncio.create_task(self._read_to_file(stdout_log, self.proc.stdout))
self.stdout = asyncio.create_task(self._read_to_vcam(self.proc.stdout))
self.stderr = asyncio.create_task(self._read_to_file(stderr_log, self.proc.stderr)) self.stderr = asyncio.create_task(self._read_to_file(stderr_log, self.proc.stderr))
#self.cam = pyvirtualcam.Camera(1920, 1080, 30, fmt=PixelFormat.BGR, device=args.device, print_fps=30)
async def _read_to_vcam(self, stream: StreamReader):
with pyvirtualcam.Camera(1920, 1080, 30, fmt=PixelFormat.BGR, device="/dev/video2", print_fps=30) as cam:
print("AAAAA")
frame=""
while not stream.at_eof():
#data = await stream.read(1920*1080*3)
frame = await stream.readexactly(1920*1080*3)
#if len(frame) == 0:
# frame = data
#else:
# frame = frame + data
#print("collected data: ", len(frame), "bit out of", 1920*1080*3)
if len(frame) >= 1920*1080*3:
#print("sending data")
cam.send(np.fromstring(frame[:1920*1080*3], dtype='uint8').reshape((1080,1920,3,)))
#print("data sent")
cam.sleep_until_next_frame()
#frame=frame[1920*1080*3:]
#time.sleep(.1)
print("else????")
async def _read_to_file(self, filename: str, stream: StreamReader): async def _read_to_file(self, filename: str, stream: StreamReader):
fp = open(filename, "w") fp = open(filename, "w")
......
from __future__ import annotations
#import cv2
#import acapture
import argparse
import pyvirtualcam
from pyvirtualcam import PixelFormat
import numpy as np
import time
import asyncio
import logging
import os
from asyncio import StreamReader
from pyrtmp import StreamClosedException
from pyrtmp.flv import FLVMediaType, FLVWriter
from pyrtmp.rtmp import RTMPProtocol, SimpleRTMPController, SimpleRTMPServer
from pyrtmp.session_manager import SessionManager
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
parser = argparse.ArgumentParser()
parser.add_argument("--device", help="VirtualCam path (optional)")
parser.add_argument("--port", help="Port to listen for RTMP", default=1935, type=int)
args = parser.parse_args()
class RTMP2SocketController(SimpleRTMPController):
def __init__(self, output_directory: str):
self.output_directory = output_directory
super().__init__()
async def on_ns_publish(self, session, message) -> None:
publishing_name = message.publishing_name
prefix = os.path.join(self.output_directory, f"{publishing_name}")
session.state = RemoteProcessFLVWriter()
logger.debug(f"output to {prefix}.flv")
await session.state.initialize(
#command=f"ffmpeg -y -i pipe:0 -c:v copy -c:a copy -f flv {prefix}.flv",
command=f"ffmpeg -hide_banner -y -i pipe:0 -pix_fmt bgr24 -vcodec rawvideo -an -sn -f image2pipe -",
stdout_log=f"{prefix}.stdout.log",
stderr_log=f"{prefix}.stderr.log",
)
session.state.write_header()
await super().on_ns_publish(session, message)
async def on_metadata(self, session, message) -> None:
session.state.write(0, message.to_raw_meta(), FLVMediaType.OBJECT)
await super().on_metadata(session, message)
async def on_video_message(self, session, message) -> None:
session.state.write(message.timestamp, message.payload, FLVMediaType.VIDEO)
await super().on_video_message(session, message)
async def on_audio_message(self, session, message) -> None:
session.state.write(message.timestamp, message.payload, FLVMediaType.AUDIO)
await super().on_audio_message(session, message)
async def on_stream_closed(self, session: SessionManager, exception: StreamClosedException) -> None:
await session.state.close()
await super().on_stream_closed(session, exception)
class RemoteProcessFLVWriter:
def __init__(self):
self.proc = None
self.stdout = None
self.stderr = None
self.writer = FLVWriter()
async def initialize(self, command: str, stdout_log: str, stderr_log: str):
self.proc = await asyncio.create_subprocess_shell(
command,
stdin=asyncio.subprocess.PIPE,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE,
)
self.stdout = asyncio.create_task(self._read_to_vcam(self.proc.stdout))
self.stderr = asyncio.create_task(self._read_to_file(stderr_log, self.proc.stderr))
async def _read_to_vcam(self, stream: StreamReader):
with pyvirtualcam.Camera(1920, 1080, 30, fmt=PixelFormat.BGR, device=args.device, print_fps=30) as cam:
frame=""
while not stream.at_eof():
frame = await stream.readexactly(1920*1080*3)
if len(frame) >= 1920*1080*3:
cam.send(np.fromstring(frame[:1920*1080*3], dtype='uint8').reshape((1080,1920,3,)))
cam.sleep_until_next_frame()
async def _read_to_file(self, filename: str, stream: StreamReader):
fp = open(filename, "w")
while not stream.at_eof():
data = await stream.readline()
fp.write(data.decode())
fp.flush()
fp.close()
def write_header(self):
buffer = self.writer.write_header()
self.proc.stdin.write(buffer)
def write(self, timestamp: int, payload: bytes, media_type: FLVMediaType):
buffer = self.writer.write(timestamp, payload, media_type)
self.proc.stdin.write(buffer)
async def close(self):
await self.proc.stdin.drain()
self.proc.stdin.close()
await self.proc.wait()
class SimpleServer(SimpleRTMPServer):
def __init__(self, output_directory: str):
self.output_directory = output_directory
super().__init__()
async def create(self, host: str, port: int):
loop = asyncio.get_event_loop()
self.server = await loop.create_server(
lambda: RTMPProtocol(controller=RTMP2SocketController(self.output_directory)),
host=host,
port=port,
)
async def main():
current_dir = os.path.dirname(os.path.abspath(__file__))
server = SimpleServer(output_directory=current_dir)
await server.create(host="0.0.0.0", port=args.port)
await server.start()
await server.wait_closed()
if __name__ == "__main__":
asyncio.run(main())
...@@ -27,7 +27,7 @@ with pyvirtualcam.Camera(width, height, fps, fmt=PixelFormat.BGR, ...@@ -27,7 +27,7 @@ with pyvirtualcam.Camera(width, height, fps, fmt=PixelFormat.BGR,
print(f'Virtual cam started: {cam.device} ({cam.width}x{cam.height} @ {cam.fps}fps)') print(f'Virtual cam started: {cam.device} ({cam.width}x{cam.height} @ {cam.fps}fps)')
count = 0 count = 0
while True: while True:
# Restart video on last frame. # Restart video on last frame
if count == length: if count == length:
count = 0 count = 0
video.set(cv2.CAP_PROP_POS_FRAMES, 0) video.set(cv2.CAP_PROP_POS_FRAMES, 0)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment