Недавно я пытался реализовать демонстрацию экрана с низкой задержкой со скоростью 60 кадров в секунду на C# с помощью библиотеки Sipsorcery. До сих пор я изо всех сил старался увеличить количество кадров, но получал только около 20 кадров в секунду.
Я пытался понять, дело в кодировке или в скриншоте. Я использовал профилировщик использования ЦП Visual Studio и увидел, что в основном это кодировщик. Тем не менее, я переделал функцию создания скриншотов и использовал SharpDX; Я заметил небольшое увеличение производительности, но не около 60 кадров в секунду. Это наводит меня на мысль, что проблема в кодировщике. Возможно, он мог бы использовать FFmpeg или какую-либо кодировку графического процессора. Заранее извините, если я указал неверную информацию, поскольку я относительно новичок в кодировании и декодировании видео.
Вот что я сделал на данный момент:
//Program.cs
using System;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using SIPSorcery.Media;
using SIPSorcery.Net;
using SIPSorceryMedia.Encoders;
using SIPSorceryMedia.FFmpeg;
using WebSocketSharp.Server;
namespace TESTPATTERNSERVER
{
class Program
{
private const int WEBSOCKET_PORT = 8081;
static void Main()
{
Console.WriteLine("WebRTC Get Started");
// Start web socket.
Console.WriteLine("Starting web socket server...");
var webSocketServer = new WebSocketServer(IPAddress.Any, WEBSOCKET_PORT);
webSocketServer.AddWebSocketService("/", (peer) => peer.CreatePeerConnection = () => CreatePeerConnection());
webSocketServer.Start();
Console.WriteLine($"Waiting for web socket connections on {webSocketServer.Address}:{webSocketServer.Port}...");
Console.WriteLine("Press any key exit.");
Console.ReadLine();
}
private static Task CreatePeerConnection()
{
var pc = new RTCPeerConnection(null);
var testPatternSource = new VideoSource(1920, 1080, new VP8VideoEncoder());
var videoEndPoint = new SIPSorceryMedia.FFmpeg.FFmpegVideoEndPoint();
MediaStreamTrack videoTrack = new MediaStreamTrack(videoEndPoint.GetVideoSourceFormats(), MediaStreamStatusEnum.SendOnly);
pc.addTrack(videoTrack);
testPatternSource.OnVideoSourceEncodedSample += pc.SendVideo;
pc.OnVideoFormatsNegotiated += (formats) => testPatternSource.SetVideoSourceFormat(formats.First());
pc.onconnectionstatechange += async (state) =>
{
Console.WriteLine($"Peer connection state change to {state}.");
switch (state)
{
case RTCPeerConnectionState.connected:
await testPatternSource.StartVideo();
break;
case RTCPeerConnectionState.failed:
pc.Close("ice disconnection");
break;
case RTCPeerConnectionState.closed:
await testPatternSource.CloseVideo();
testPatternSource.Dispose();
break;
}
};
return Task.FromResult(pc);
}
}
}
Недавно я пытался реализовать демонстрацию экрана с низкой задержкой со скоростью 60 кадров в секунду на C# с помощью библиотеки Sipsorcery. До сих пор я изо всех сил старался увеличить количество кадров, но получал только около 20 кадров в секунду. Я пытался понять, дело в кодировке или в скриншоте. Я использовал профилировщик использования ЦП Visual Studio и увидел, что в основном это кодировщик. Тем не менее, я переделал функцию создания скриншотов и использовал SharpDX; Я заметил небольшое увеличение производительности, но не около 60 кадров в секунду. Это наводит меня на мысль, что проблема в кодировщике. Возможно, он мог бы использовать FFmpeg или какую-либо кодировку графического процессора. Заранее извините, если я указал неверную информацию, поскольку я относительно новичок в кодировании и декодировании видео. Вот что я сделал на данный момент: [code]//VideoTestPatternSource.cs using System; using System.Collections.Generic; using System.Drawing.Imaging; using System.Drawing; using System.IO; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; using Microsoft.Extensions.Logging; using SIPSorceryMedia.Abstractions; using SharpDX; using SharpDX.Direct3D11; using SharpDX.DXGI; using Device = SharpDX.Direct3D11.Device; using MapFlags = SharpDX.Direct3D11.MapFlags; using System.Runtime.InteropServices;
namespace SIPSorcery.Media { public class VideoSource : IVideoSource, IDisposable { private const int VIDEO_SAMPLING_RATE = 90000; private const int MAXIMUM_FRAMES_PER_SECOND = 20; private const int DEFAULT_FRAMES_PER_SECOND = MAXIMUM_FRAMES_PER_SECOND; // Changed from 30 to 60 private const int MINIMUM_FRAMES_PER_SECOND = MAXIMUM_FRAMES_PER_SECOND - 5; private const int TIMER_DISPOSE_WAIT_MILLISECONDS = 1000; private const int VP8_SUGGESTED_FORMAT_ID = 96; private const int H264_SUGGESTED_FORMAT_ID = 100;
public static readonly List SupportedFormats = new List { new VideoFormat(VideoCodecsEnum.VP8, VP8_SUGGESTED_FORMAT_ID, VIDEO_SAMPLING_RATE), new VideoFormat(VideoCodecsEnum.H264, H264_SUGGESTED_FORMAT_ID, VIDEO_SAMPLING_RATE, "packetization-mode=1") };
public void RestrictFormats(Func filter) => _formatManager.RestrictFormats(filter); public List GetVideoSourceFormats() => _formatManager.GetSourceFormats(); public void SetVideoSourceFormat(VideoFormat videoFormat) => _formatManager.SetSelectedFormat(videoFormat); public List GetVideoSinkFormats() => _formatManager.GetSourceFormats(); public void SetVideoSinkFormat(VideoFormat videoFormat) => _formatManager.SetSelectedFormat(videoFormat);
public void ForceKeyFrame() => _videoEncoder?.ForceKeyFrame(); public bool HasEncodedVideoSubscribers() => OnVideoSourceEncodedSample != null;
public void ExternalVideoSourceRawSample(uint durationMilliseconds, int width, int height, byte[] sample, VideoPixelFormatsEnum pixelFormat) => throw new NotImplementedException("The test pattern video source does not offer any encoding services for external sources.");
public void ExternalVideoSourceRawSampleFaster(uint durationMilliseconds, RawImage rawImage) => throw new NotImplementedException("The test pattern video source does not offer any encoding services for external sources.");
public Task InitialiseVideoSourceDevice() => throw new NotImplementedException("The test pattern video source does not use a device."); public bool IsVideoSourcePaused() => _isPaused;
public void SetFrameRate(int framesPerSecond) { if (framesPerSecond < MINIMUM_FRAMES_PER_SECOND || framesPerSecond > MAXIMUM_FRAMES_PER_SECOND) { MessageBox.Show($"Frames per second not in the allowed range of {MINIMUM_FRAMES_PER_SECOND} to {MAXIMUM_FRAMES_PER_SECOND}, ignoring."); } else { _frameSpacing = 1000 / framesPerSecond;
if (_isStarted) { _sendTestPatternTimer?.Change(0, _frameSpacing); } } }
// Correct pixel inversion (swap R and B channels) for (int i = 0; i < buffer.Length; i += 4) { byte temp = buffer[i]; // Save R buffer[i] = buffer[i + 2]; // Swap R (buffer[i]) with B (buffer[i+2]) buffer[i + 2] = temp; // Swap B with R (saved R) // buffer[i+1] (G) remains unchanged // buffer[i+3] (A) remains unchanged }
public void Dispose() { _isClosed = true; _sendTestPatternTimer?.Dispose(); _videoEncoder?.Dispose();
_screenTexture?.Dispose(); _duplicatedOutput?.Dispose(); _output1?.Dispose(); _device?.Dispose(); _adapter?.Dispose(); _factory?.Dispose(); } } } [/code] Для справки, вот что его загружает: [code]//Program.cs using System; using System.Linq; using System.Net; using System.Threading.Tasks; using SIPSorcery.Media; using SIPSorcery.Net; using SIPSorceryMedia.Encoders; using SIPSorceryMedia.FFmpeg; using WebSocketSharp.Server;
namespace TESTPATTERNSERVER { class Program { private const int WEBSOCKET_PORT = 8081;
static void Main() { Console.WriteLine("WebRTC Get Started");
// Start web socket. Console.WriteLine("Starting web socket server..."); var webSocketServer = new WebSocketServer(IPAddress.Any, WEBSOCKET_PORT); webSocketServer.AddWebSocketService("/", (peer) => peer.CreatePeerConnection = () => CreatePeerConnection()); webSocketServer.Start();
Console.WriteLine($"Waiting for web socket connections on {webSocketServer.Address}:{webSocketServer.Port}...");
Console.WriteLine("Press any key exit."); Console.ReadLine(); }
private static Task CreatePeerConnection() { var pc = new RTCPeerConnection(null);
var testPatternSource = new VideoSource(1920, 1080, new VP8VideoEncoder()); var videoEndPoint = new SIPSorceryMedia.FFmpeg.FFmpegVideoEndPoint();
MediaStreamTrack videoTrack = new MediaStreamTrack(videoEndPoint.GetVideoSourceFormats(), MediaStreamStatusEnum.SendOnly); pc.addTrack(videoTrack);
Я хотел бы создать видео для визуализации небольшого набора данных. Этот набор данных содержит только 10 или 20 кадров данных, и я хочу визуализировать его один кадр в секунду и создать видео .mp4 с помощью FFMpegWriter.
Но когда я устанавливаю...
При использовании приведенного ниже кода он дает мне видео из потока с желаемым количеством кадров и выбранным мной FPS. Однако продолжительность видео становится продолжительностью =(1/fps)*frameCount. Я думаю, что mp4 сжимает видео, чтобы...
При использовании приведенного ниже кода он дает мне видео из потока с желаемым количеством кадров и выбранным мной FPS. Однако продолжительность видео становится продолжительностью =(1/fps)*frameCount. Я думаю, что mp4 сжимает видео, чтобы...
I modified the below code to the code just below it to send frames after 30ms delay to get better FPS but to my surprise they dropped drastically instead of going up, earlier I was receiving 22 fps after modification I got just 2 fps