我正在编写用于通过多播传输MPEG-TS文件的软件。 我有两个关于流的问题 - 比特率控制和每秒数据包的均匀分配。
MPEG-TS具有固定的数据包大小 - 188字节。多亏了我知道我每秒要发送多少个数据包来输入文件的比特率。
因此,对于第一个问题,我使用stopWatch找到了简单但不好的解决方案:
private readonly IPAddress ipAddress;
private readonly int port;
private readonly UdpClient udpClient;
private IPEndPoint endPoint;
private byte[] mpegTsChunk;
private bool disposed = false;
public Server(IPAddress ipAddress, int port, IPAddress localAddress)
{
this.ipAddress = ipAddress;
this.port = port;
udpClient = new UdpClient();
udpClient.JoinMulticastGroup(ipAddress, localAddress);
endPoint = new IPEndPoint(ipAddress, port);
mpegTsChunk = new byte[188];
}
private void SendMpegTsStream(Stream fileStream, int bitRate)
{
int index = 0, packetCounter = 0;
int maxPacketPerSecond = bitRate/(mpegTsChunk.Length*8);
Stopwatch stopWatch = new Stopwatch();
var spin = new SpinWait();
stopWatch.Start();
while (true)
{
while (index < mpegTsChunk.Length)
{
int bytesRead = fileStream.Read(mpegTsChunk, index, mpegTsChunk.Length - index );
if (bytesRead == 0) return;
index += bytesRead;
}
if (index != 0) udpClient.Send(mpegTsChunk, mpegTsChunk.Length, endPoint);
if (index != mpegTsChunk.Length) return;
++packetCounter;
if (packetCounter >= maxPacketPerSecond)
{
/////To fix
while (stopWatch.ElapsedMilliseconds < 1000) { spin.SpinOnce(); }
packetCounter = 0;
stopWatch.Restart();
}
index = 0;
}
}
它有两个问题: - 而(x){}非常重CPU - 这会产生非常不均匀的数据包 即:我有40Mbps的MPEG-TS。我想发送它,使用这种方式,我的程序将尝试在开始时发送尽可能多的数据包,因为它可以创建峰值 - 在这种情况下,它可以很容易地超过100Mbps,如果我有100mbps端口将产生问题。 Wireshark屏幕显示我对第二个问题的意思:
如何在一秒钟内均匀分发数千个数据包?例如,对于10Mbps,每秒要发送6900个数据包 - 并在一秒钟内均匀分配它们。
编辑:
Aboud while(x){} - 我已经添加了SpinOnce()并且CPU下降了很多,但我仍然认为这不是一个好方法。 - 不旋转 - 35-50%的CPU - SpinOnce() - 10-12%(调试时)
EDIT2: 不,这与链接的问题不同。我现在不关心当数据包离开我的计算机时会发生什么 - 现在我希望所有数据包以均匀的方式离开并担心以后接收。关于我的问题的链接问题中的解决方案与我的解决方案类似 - 尽可能多地发送数据包然后在剩下的时间内休眠 - 仍然会导致数据包分布不均匀。
EDIT3 /不完美答案:
过了一段时间我做了这个有效:
private void SendMpegTsStream(Stream fileStream, int bitRate)
{
int index = 0, packetCounter = 0;
var maxPacketPerSecond = (float) bitRate/(mpegTsChunk.Length*8) < 1
? (float) bitRate/(mpegTsChunk.Length*8)
: bitRate/(mpegTsChunk.Length*8);
//To do: adapt speed depending on pc
int timeToSleep = (float) bitRate/(mpegTsChunk.Length*8) < 1 ? 100 : bitRate > 10000000 ? 1 : 10;
var stopWatch = new Stopwatch();
stopWatch.Start();
while (streaming)
{
while (index < mpegTsChunk.Length)
{
int bytesRead = fileStream.Read(mpegTsChunk, index, mpegTsChunk.Length - index);
if (bytesRead == 0) return;
index += bytesRead;
}
if (index != 0) udpClient.Send(mpegTsChunk, mpegTsChunk.Length, endPoint);
if (index != mpegTsChunk.Length) return;
++packetCounter;
index = 0;
while (streaming && packetCounter > stopWatch.ElapsedMilliseconds*maxPacketPerSecond/1000)
{
Thread.Sleep(timeToSleep);
if (packetCounter > 2000000000)
{
packetCounter = 0;
stopWatch.Restart();
}
}
}
}