public ImageSharpRenderer(int frameWidth, int frameHeight, VideoTrack videoTrack) { VideoTrack = videoTrack; using (var background = Image.Load <PixelColor>("background-small.jpg")) { background.Mutate(ctx => ctx.Resize(frameWidth, frameHeight)); // Pre-created bouncing ball frames. // ImageSharp is not that fast yet, and our goal is to benchmark webrtc and NvEnc, not ImageSharp. var ballRadius = background.Width / 20f; var ballPath = new EllipsePolygon(0, 0, ballRadius); var ballColor = new PixelColor(255, 255, 128); for (int i = 0; i < FrameCount; ++i) { // ReSharper disable once AccessToDisposedClosure var image = background.Clone(); var a = Math.PI * i / FrameCount; var h = image.Height - ballRadius; var y = image.Height - (float)(Math.Abs(Math.Sin(a) * h)); image.Mutate(ctx => ctx .Fill(GraphicsOptions.Default, ballColor, ballPath.Translate(image.Width / 2f, y))); _videoFrames.Add(image); } } }
public bool SendFrame(TimeSpan elapsedTime, int frameIndex) { var imageFrameIndex = frameIndex % FrameCount; var imageFrame = _videoFrames[imageFrameIndex].Frames[0]; var pixels = MemoryMarshal.Cast <PixelColor, uint>(imageFrame.GetPixelSpan()); var format = PeerConnection.SupportsHardwareTextureEncoding ? VideoFrameFormat.CpuTexture : VideoFrameFormat.Bgra32; VideoTrack.SendVideoFrame(MemoryMarshal.GetReference(pixels), imageFrame.Width * 4, imageFrame.Width, imageFrame.Height, format); return(true); }
private void Run() { try { // For debugging, run everything on this thread. // Should never be done in production. // Note that webrtc callbacks are done on the signaling thread, and must return asap. PeerConnection.Configure(new GlobalOptions { UseWorkerThread = false, UseSignalingThread = false, ForceSoftwareVideoEncoder = true, MinimumLogLevel = System.Diagnostics.TraceLevel.Info, LogToStandardError = false, LogToDebugOutput = false }); PeerConnection.MessageLogged += (message, severity) => { severity.WriteToConsole(message); }; Console.OutputEncoding = Encoding.UTF8; const int frameWidth = 320; const int frameHeight = 180; const int frameRate = 10; using (var senderOutgoingMessages = new ReplaySubject <DataMessage>()) using (var sender = new ObservablePeerConnection(new PeerConnectionOptions { Name = "Sender" })) using (var receiver = new ObservablePeerConnection(new PeerConnectionOptions { Name = "Receiver", CanReceiveVideo = true })) using (var background = Image.Load <Argb32>("background-small.jpg")) using (receiver.ReceivedVideoStream.Buffer(2).Subscribe(SaveFrame)) using (var imageFrame = new Image <Argb32>(frameWidth, frameHeight)) using (var videoTrack = new VideoTrack(sender, VideoEncoderOptions.OptimizedFor(frameWidth, frameHeight, frameRate))) { background.Mutate(ctx => ctx.Resize(frameWidth, frameHeight)); senderOutgoingMessages.OnNext(new DataMessage("data", "Hello")); sender.CreateOffer(); sender.Connect(senderOutgoingMessages, receiver.LocalSessionDescriptionStream, receiver.LocalIceCandidateStream); var receiverOutgoingMessages = receiver .ReceivedDataStream .Where(msg => msg.AsText == "Hello") .Do(msg => Console.WriteLine($"Received message {msg.AsText}")) .Select(msg => new DataMessage(msg.Label, "World")); receiver.Connect(receiverOutgoingMessages, sender.LocalSessionDescriptionStream, sender.LocalIceCandidateStream); sender.AddDataChannel(new DataChannelOptions()); Console.WriteLine("Press any key to exit"); int localFrameIndex = 0; var timeout = TimeSpan.FromMilliseconds(1000.0 / frameRate); //while (!Console.KeyAvailable && PeerConnection.PumpQueuedMessages(timeout)) while (PeerConnection.PumpQueuedMessages(timeout)) { var frame = imageFrame.Frames[0]; var pixels = MemoryMarshal.Cast <Argb32, uint>(frame.GetPixelSpan()); videoTrack.SendVideoFrame(MemoryMarshal.GetReference(pixels), frame.Width * 4, frame.Width, frame.Height, VideoFrameFormat.Argb32); imageFrame.Mutate(ctx => ctx.DrawImage(GraphicsOptions.Default, background).Rotate(localFrameIndex * 10).Crop(frameWidth, frameHeight)); ++localFrameIndex; } sender.RemoveDataChannel("data"); } } catch (Exception ex) { Console.WriteLine($"*** FAILURE: {ex}"); } Console.WriteLine("Press ENTER to exit"); Console.ReadLine(); }