在多媒体应用中,针对Client端的带宽情况,Server端对Video Data要进行不同的处理,当Client带宽比较差时,需要在Server端对不同的视频帧进行是丢弃处理,如在低带宽条件下,对于非关键帧,为了更好的用户体验性和播放的平滑性,可对其进行丢弃,而关键帧,则一般不给予丢弃。下面结合代码,详细分析下Red5是如何根据Client端的带宽进行丢包处理的。
Red5的Video Data丢包处理的代码集中在其PlayEngine 的 PushMessage方法,代码如下:
if (body instanceof VideoData) {
IVideoStreamCodec videoCodec = null;
if (msgIn instanceof IBroadcastScope) {
IBroadcastStream stream = (IBroadcastStream) ((IBroadcastScope) msgIn)
.getAttribute(IBroadcastScope.STREAM_ATTRIBUTE);
if (stream != null && stream.getCodecInfo() != null) {
videoCodec = stream.getCodecInfo().getVideoCodec();
}
}
//dont try to drop frames if video codec is null - related to SN-77
if (videoCodec != null && videoCodec.canDropFrames()) {
if (playlistSubscriberStream.state == State.PAUSED) {
// The subscriber paused the video
log.debug("Dropping packet because we are paused");
videoFrameDropper.dropPacket(rtmpMessage);
return;
}
// Only check for frame dropping if the codec supports it
long pendingVideos = pendingVideoMessages();
if (!videoFrameDropper.canSendPacket(rtmpMessage, pendingVideos)) {
// Drop frame as it depends on other frames that were dropped before.
log.debug("Dropping packet because frame dropper says we cant send it");
return;
}
if (!receiveVideo) {
// The client disabled video or the app doesn't have enough bandwidth
// allowed for this stream.
log.debug("Dropping packet because we cant receive video or token acquire failed");
videoFrameDropper.dropPacket(rtmpMessage);
return;
}
// increment the number of times we had pending video frames sequentially
if (pendingVideos > 1) {
numSequentialPendingVideoFrames++;
} else {
// reset number of sequential pending frames if 1 or 0 are pending.
numSequentialPendingVideoFrames = 0;
}
if (pendingVideos > maxPendingVideoFramesThreshold
|| numSequentialPendingVideoFrames > maxSequentialPendingVideoFrames) {
log.debug("Pending: {} Threshold: {} Sequential: {}", new Object[] { pendingVideos,
maxPendingVideoFramesThreshold, numSequentialPendingVideoFrames });
// We drop because the client has insufficient bandwidth.
long now = System.currentTimeMillis();
if (bufferCheckInterval > 0 && now >= nextCheckBufferUnderrun) {
// Notify client about frame dropping (keyframe)
sendInsufficientBandwidthStatus(currentItem);
nextCheckBufferUnderrun = now + bufferCheckInterval;
}
videoFrameDropper.dropPacket(rtmpMessage);
return;
}
videoFrameDropper.sendPacket(rtmpMessage);
}
}
首先Red5根据Stream的Codec来决定是不是需要启用丢包处理。Red5共定义了三种Codec,分别为ScreenVideo,SorensonVideo和AVCVideo,其中ScreenVideo是用于屏幕截取,Red5的缺省实现是,不可以采取丢包处理,而SorensonVideo和AVCVideo分别用于手机和视频播放,Red5的缺省实现是可以采取丢包处理。如果我们需要在采用ScreenVideo的时候也启用丢包处理,则需要修改ScreenVideo的代码,如下所示:
/** {@inheritDoc} */
public boolean canDropFrames() {
return false;
}
在Red5的代码中,之所有在此处直接返回false,不支持丢包,主要是因为ScreenVideo这种Codec的Video data的Decode依赖于前后帧,如果丢弃了一帧,很可能接下来的好几帧数据都不能正确Decode。当然如果网络非常差的情况下,还是通过修改ScreenVideo的canDropFrames(),使其返回true,则可在低带宽条件下启动丢包处理,只不过这样在播放端就会出现连续的花屏现象。
在判断Codec是否支持Drop frames后,Red5主要根据Mina通道里的pendingVideos的数量来决定是否丢弃Video data。由上面的代码可以得知,pendingVideos 是通过方法pendingVideoMessages()获取的。pendingVideoMessages的返回的是RTMPConnection里面的pendingVideos的值(当往Mina的通道里写入一个),在Red5的代码中,如果pendingVideos超过最大允许的等待帧数,则启动丢包处理:
// increment the number of times we had pending video frames sequentially
if (pendingVideos > 1) {
numSequentialPendingVideoFrames++;
} else {
// reset number of sequential pending frames if 1 or 0 are pending.
numSequentialPendingVideoFrames = 0;
}
if (pendingVideos > maxPendingVideoFramesThreshold
|| numSequentialPendingVideoFrames > maxSequentialPendingVideoFrames) {
log.debug("Pending: {} Threshold: {} Sequential: {}", new Object[] { pendingVideos,
maxPendingVideoFramesThreshold, numSequentialPendingVideoFrames });
// We drop because the client has insufficient bandwidth.
long now = System.currentTimeMillis();
if (bufferCheckInterval > 0 && now >= nextCheckBufferUnderrun) {
// Notify client about frame dropping (keyframe)
sendInsufficientBandwidthStatus(currentItem);
nextCheckBufferUnderrun = now + bufferCheckInterval;
}
videoFrameDropper.dropPacket(rtmpMessage);
return;
}
这里之所以用pendingVideos和numSequentialPendingVideoFrames同时作为是否启用丢包的判断条件,主要是为了保证统计的实时性和准确性。
上面分析了Red5如何判断是否应该丢包,及采取什么样的丢包策略,因此在实际应用的时候可以根据具体的需求,对上述流程进行调节和改动,以适用于不同的应用场景。
分享到:
相关推荐
针对RED队列丢包概率模型在计算丢包概率时精确性不足且未考虑网络流量的自相似性问题,提出了基于数据包入队速率平均变化率和队列空闲长度的队列丢包概率模型(DRED),给出了相应的实现算法。DRED将网络流量状态...
网络ns2仿真实验分析(RED、丢包率、端到端延迟、吞吐量)附源码
很好的red的仿真程序,能得到队列长度和丢包率的文件夹
eclipse装好red5插件后,想要编写第一个demo需要red5-server.jar(前提:你已经装好了red-server。注:red5-server和red5插件是两个东西,我已经上传过,可以去我那儿下载查看)。完美运行window7+64位系统。
Red5_0.9.1 + MyEclipse10.7 中单步调试Demo Publisher : 编译通过Red_091 后,调试参数设置如下 。 右键项目 - Debug As -- Debug Configurations --Environment : 设置 RED5_HOME 环境变量 "Main class...
red5部署到tomcat需要的jar包red5部署到tomcat需要的jar包red5部署到tomcat需要的jar包
red5 与 tomcat项目集成
red5-service.jar red5 服务开发必备!!
re5流媒体服务器免安装zip包。实现本地搭建流媒体服务器。
Red5 是一个采用 Java 开发的开源免费 Flash 流媒体服务器。Red5 基于 Java 和一些功能强大的开源框架,为企业级应用奠定了标准。它使用 RTMP,RTMPT,RTMPS 和 RTMPE 流媒体协议, 支持:将音频(MP3)和视频(FLV,...
EMQx和NodeRed部署资源打包
Red5的0.9.1版本
red5-1.0.5免安装版,适用于window64位(需要先安装jdk1.7,注意是red5-1.0.5需要的是1.7,在这之前装了好几个最新的red5,比如1.0.8,需要的jdk是1.8),解压后,可以设置conf中的red5.properties,也可不设置。...
red5 免安装版 red5 1.00 自己试过了!可以正常运行和启动
red5 0.8 reference Red5 - Reference Documentation Red5 Open Source Flash Server
关于red5的一些学习文档,资料很齐全。 d5_demo 服务器端调用客户端as的方法 as3.0+red5 --- hello world FMS&Red5 RED5 – Project Roadmap Open Source Flash 等等文档
red5 1.0 final 与 tomcat 整合 ,导入myeclipse可以直接使用。
本资源是使用 Java servlets 将文件上传到 Red5 服务器的源代码。chapter2 是服务器 Red5 源文件,UploadToRed5Proj 是客户端 Flex3 源文件。 关于使用 Flex 和Java servlets 将文件上传到 RED5 服务器的步骤,请...
red5项目示例,简单配置使用RED5入门
《使用Red5入门》 《red5入门》 《red5入门教程》 《RED5安装与配置》 《red5流媒体服务器入门基础》