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);
        }
Exemple #3
0
        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();
        }