gpt4 book ai didi

sockets - 文件流遇到缓冲区欠载/下溢?

转载 作者:可可西里 更新时间:2023-11-01 02:34:45 25 4
gpt4 key购买 nike

背景

我正在使用 Boost 用 C++ 开发渐进式下载媒体流服务器。典型的配置是运行 Android 4.2.2 的 Android 渲染设备,使用库存图库播放器作为媒体播放器,以及在 Windows 桌面上运行的媒体流服务器。 Android 设备通过 HTTP URL 请求媒体文件,媒体服务器使用渐进式下载流式传输文件。

问题

当尝试以 20 Mbps 的内部比特率流式传输视频文件时,渲染器始终停顿多次。典型的流媒体体验基本上由多次出现的步骤组成:

  • 平滑渲染 3-5 秒
  • 视频停顿 5-10 秒
  • 转到步骤 1

  • 最合乎逻辑的解释是渲染器遇到了“buffer underrun”或“buffer underflow”

    问题

    有没有办法解决缓冲区欠载问题, boost 流媒体输出速率,防止视觉卡顿/阻塞?

    技术信息

    服务器代码如下所示:
    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”字节 block 流式传输到输出套接字(“streamingBlockSize”通过配置文件设置,在研究和调试当前缓冲区欠载问题时引入)。

    使用 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>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() 的缓冲区大小

    我尝试改变传递给 write() 函数的字节数(例如 4096、8192、16384),以查看增加数据大小是否可以加快传输速度。它似乎没有什么区别(有关可能的解释,请参阅 MTU 和 MSS 的讨论)。

    增加以太网 MTU(最大传输单元)和/或 TCP MSS(最大段大小)

    Wireshark 显示每个 TCP 数据包携带 1448 个视频原始数据。增加 MTU 或 MSS 会 boost 流传输吞吐量吗? http://www.stratus.com/blog/openvos/?p=1459 MTU 和 MSS 之间有一个有趣的比较。

    TCP_NODELAY

    有几页讨论了套接字设置 TCP_NODELAY(参见 http://en.wikipedia.org/wiki/Transmission_Control_Protocol)。我的理解是它会改进多文件传输,这通常会导致文件的最后一个字节没有填充输出缓冲区。默认情况下,TCP 将等待 200 毫秒让缓冲区填满。使用 TCP_NODELAY 不会有延迟。在单个视频文件流的情况下,我不希望有改进。这个对吗?

    网络负载可变性

    正在使用的网络是否会导致数据流过慢?

    boost::asio::write() 是阻塞写入——非阻塞写入会有帮助吗?

    最底部的 boost::asio::write() 是一个阻塞写入:
    try
    {
    numCharsWritten = boost::asio::write (socket, boost::asio::buffer (data, len));
    }

    与非阻塞 write() 相比,使用阻塞 write() 时是否可能存在固有延迟?使用非阻塞写入会 boost 吞吐量吗?

    非常感谢您的帮助。

    最佳答案

    我试图只给出指示,没有解决方案。

    正如您所猜想的那样,这个问题涉及多个方面,其中任何一个都可能导致这种情况 - 视频是如何编码的(是否有 B 帧,只有 I 帧等...),然后是网络带宽和 android设备用于访问此 HTTP 服务器 - 在此测试期间它有多拥挤;解码器库和解码器应用程序。不是解决方案,但是,您可以尝试查看相同测试的行为:

    1)使用不同的解码器/渲染应用程序

    2) 在一天中的不同时间运行此测试(当网络负载可能较小时)

    3)尝试在不同的操作系统(Linux 使用 mplayer 或其他东西)或使用 Windows 媒体播放器的 Windows 上解码/渲染,看看它是否与 Android 操作系统 tcp/ip 堆栈实现有关。

    关于sockets - 文件流遇到缓冲区欠载/下溢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16791022/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com