我正在使用Boost在C ++中开发渐进式下载媒体流服务器。典型配置是运行Android 4.2.2的Android渲染设备,使用库存图库播放器作为媒体播放器,以及在Windows桌面上运行的媒体流服务器。 Android设备通过HTTP URL请求媒体文件,媒体服务器使用渐进式下载流式传输文件。
尝试以20 Mbps的内部比特率流式传输视频文件时,渲染器会一直停顿多次。典型的流媒体体验基本上包括多个步骤:
最合乎逻辑的解释是渲染器遇到“缓冲区欠载”或“缓冲区下溢”
有没有办法解决缓冲区欠载问题,提高媒体流媒体输出率,防止视觉拖延/阻塞?
服务器代码如下所示:
void StreamFile (boost::asio::ip::tcp::socket *socket, const wchar_t *path)
{
. . .
for (long offset=startOffset; offset <= endOffset; offset+=streamingBlockSize)
{
long numBytesToRead = (std::min<long>) (endOffset - offset + 1, streamingBlockSize);
fread (buffer, 1, numBytesToRead, f);
if (RawSocketWrite (socket, buffer, numBytesToRead) == 0)
{
// RawSocketWrite() encountered a serious error, exit
break;
}
}
. . .
}
size_t RawSocketWrite (boost::asio::ip::tcp::socket *socket, const char *data, size_t len)
{
size_t numCharsWritten = 0;
try
{
numCharsWritten = boost::asio::write (socket, boost::asio::buffer (data, len));
}
catch (boost::system::system_error& e)
{
LOG_ERROR (("error", "write() failed in RawSocketWrite (socket %d) %s", socket->native (), e.what()));
numCharsWritten = 0;
}
return numCharsWritten;
}
我正在尝试使用以下文件数据传输39 MB,16秒的视频文件(由MediaInfo提供):
Video information
General
Complete name : TestVideo.mp4
Format : MPEG-4
Format profile : Base Media
Codec ID : isom
File size : 38.6 MiB
Duration : 16s 102ms
Overall bit rate : 20.1 Mbps
Video
ID : 1
Format : AVC
Format/Info : Advanced Video Codec
Format profile : High@L4.0
Format settings, CABAC : Yes
Format settings, ReFrames : 1 frame
Format settings, GOP : M=1, N=61
Codec ID : avc1
Codec ID/Info : Advanced Video Coding
Duration : 15s 701ms
Bit rate : 20.0 Mbps
Width : 1 920 pixels
Height : 1 080 pixels
Display aspect ratio : 16:9
Frame rate mode : Variable
Frame rate : 30.000 fps
Minimum frame rate : 29.732 fps
Maximum frame rate : 30.313 fps
Color space : YUV
Chroma subsampling : 4:2:0
Bit depth : 8 bits
Scan type : Progressive
Bits/(Pixel*Frame) : 0.322
Stream size : 37.5 MiB (97%)
Title : VideoHandle
Language : English
mdhd_Duration : 15701
Audio
ID : 2
Format : AAC
Format/Info : Advanced Audio Codec
Format profile : LC
Codec ID : 40
Duration : 16s 102ms
Source duration : 16s 131ms
Bit rate mode : Constant
Bit rate : 192 Kbps
Nominal bit rate : 96.0 Kbps
Channel(s) : 2 channels
Channel positions : Front: L R
Sampling rate : 48.0 KHz
Compression mode : Lossy
Stream size : 374 KiB (1%)
Source stream size : 375 KiB (1%)
Title : SoundHandle
Language : English
mdhd_Duration : 16102
StreamFile()函数将“streamingBlockSize”字节块紧密循环到输出套接字('streamingBlockSize'通过配置文件设置,并在研究和调试当前缓冲区欠载问题时引入)。 / p>
使用Wireshark跟踪数据包显示以均匀的速度发送1448字节流数据的数据包:
|Time | 192.168.0.197 |
| | | 192.168.0.199 |
|14.420722000| SYN, ACK | |Seq = 0 Ack = 1| |(10243) ------------------> (58358) |
|14.437750000| PSH, ACK - Len: 266 |Seq = 1 Ack = 188| |(10243) ------------------> (58358) |
|14.437924000| ACK - Len: 1448 |Seq = 267 Ack = 188| |(10243) ------------------> (58358) |
|14.437939000| ACK - Len: 1448 |Seq = 1715 Ack = 188| |(10243) ------------------> (58358) |
|14.437950000| ACK - Len: 1448 |Seq = 3163 Ack = 188| |(10243) ------------------> (58358) |
|14.442016000| ACK - Len: 1448 |Seq = 4611 Ack = 188| |(10243) ------------------> (58358) |
|14.444269000| ACK - Len: 1448 |Seq = 6059 Ack = 188| |(10243) ------------------> (58358) |
|14.444293000| ACK - Len: 1448 |Seq = 7507 Ack = 188| |(10243) ------------------> (58358) |
|14.444358000| ACK - Len: 1448 |Seq = 8955 Ack = 188| |(10243) ------------------> (58358) |
|14.444373000| ACK - Len: 1448 |Seq = 10403 Ack = 188| |(10243) ------------------> (58358) |
|14.444389000| ACK - Len: 1448 |Seq = 11851 Ack = 188| |(10243) ------------------> (58358) |
. . .
|72.768739000| ACK - Len: 1448 |Seq = 40488067 Ack = 188| |(10243) ------------------> (58358) |
|72.768766000| ACK - Len: 1448 |Seq = 40489515 Ack = 188| |(10243) ------------------> (58358) |
|72.772484000| ACK - Len: 1448 |Seq = 40490963 Ack = 188| |(10243) ------------------> (58358) |
|72.772521000| PSH, ACK - Len: 895 |Seq = 40492411 Ack = 188| |(10243) ------------------> (58358)
Wireshark通过Statistics&gt; Summary菜单项提供了有关上述数据包的非常有用的摘要信息:
Packets 27997
Between first and last packet 58.352 sec
Avg. packets/sec 479.797
Avg. packet size 1513.586 bytes
Bytes 42375867
Avg. bytes/sec 726213.548
Avg. MBit/sec 5.810
这告诉我们传输39 MB视频需要58.352秒,播放时间为16.102秒,并且渲染器遇到频繁停止。这听起来像缓冲区欠载的经典案例。
此外,Wireshark检测到的平均Mbps速率为5.81 Mbps。根据定义,这永远不能满足需要以20.1 Mbps的比特率渲染视频的渲染器。
在研究这个问题的过程中,我遇到了许多可能导致问题的技术问题,并会感激您的想法。
我已经尝试改变传递给write()函数的字节数(例如,4096,8192,16384),以查看增加数据大小是否可以加快传输速度。它似乎没有什么区别(有关可能的解释,请参阅MTU和MSS的讨论)。
Wireshark显示每个TCP数据包携带1448个视频原始数据。增加MTU或MSS会提高流量吞吐量吗? http://www.stratus.com/blog/openvos/?p=1459在MTU和MSS之间进行了有趣的比较。
有几页讨论套接字设置TCP_NODELAY(参见http://en.wikipedia.org/wiki/Transmission_Control_Protocol)。我的理解是它将改进多文件传输,这通常导致文件的最后字节没有填充输出缓冲区。默认情况下,TCP将等待200 ms以使缓冲区填满。使用TCP_NODELAY将没有延迟。在单个视频文件流媒体情况下,我不希望有任何改进。这是对的吗?
正在使用的网络会导致数据传输速度太慢吗?
最底部的boost :: asio :: write()是一个阻塞写:
try
{
numCharsWritten = boost::asio::write (socket, boost::asio::buffer (data, len));
}
使用阻塞write()和非阻塞write()时是否存在内在延迟?使用非阻塞写入会提高吞吐量吗?
非常感谢您的帮助。
答案 0 :(得分:0)
我试图只给出指针,没有解决方案。
正如你猜想的那样,这个问题涉及多个方面,其中任何一个都可能导致这种情况 - 如何对视频进行编码(它是否有B帧,只有I帧等...),然后是带宽Android设备用来访问此HTTP服务器的网络 - 在此测试期间它是多么拥挤;解码器库和解码器应用程序。不是解决方案,但是,您可以尝试查看相同测试的行为:
1)使用不同的解码器/渲染应用程序
2)在一天中的不同时间运行此测试(当网络负载可能较少时)
3)尝试在不同的操作系统(使用mplayer或其他东西的Linux)或使用Windows媒体播放器的Windows上解码/渲染,只是为了看看它是否可以对Android OS tcp / ip堆栈实现做任何事情。