下面的客户端打算在oflaDemo应用程序上运行,在本地主机上运行red5。它包含了阿凡达电影宣传片。
问题是客户端读取15秒的电影并挂起。为什么?
要编译下面的程序,只需从这里下载red5 http://wiki.red5.org/wiki/1_0_RC1,安装并运行它。打开根页面http://localhost:5080并导航到演示安装页面。安装oflaDemo示例。然后导航到oflaDemo页面并检查它是否工作。
然后,使用red5中的所有jars作为库创建新的Java项目。运行red5运行它。
客户端通过端口1935与服务器通信。
app的结构如下:
1) connect()方法连接到应用程序
2)根据以前操作的结果创建新流;库函数不用于注入自定义流类。
3) createStreamCallback正在注入流的生成结果。
4)自定义流是MyClientStream,它只打印分派的内容。
在我的机器上,它工作到时间戳15203并挂起。
public class SSCCE_RTMPPlayer extends RTMPClient{
private String server = "localhost";
private int port = 1935;
private String application = "oflaDemo";
private String filename = "avatar.flv";
private static boolean finished = false;
public static void main(String[] args) throws InterruptedException {
final SSCCE_RTMPPlayer player = new SSCCE_RTMPPlayer ();
player.connect();
synchronized( SSCCE_RTMPPlayer.class ) {
if( !finished ) SSCCE_RTMPPlayer.class.wait();
}
System.out.println("Ended");
}
public void connect() {
connect(server, port, application, connectCallback);
setExceptionHandler(new ClientExceptionHandler() {
@Override
public void handleException(Throwable throwable) {
throwable.printStackTrace();
}
});
}
private IPendingServiceCallback connectCallback = new IPendingServiceCallback() {
@Override
public void resultReceived(IPendingServiceCall call) {
System.out.println("connectCallback");
invoke("createStream", null, createStreamCallback);
}
};
private IPendingServiceCallback createStreamCallback = new IPendingServiceCallback() {
@Override
public void resultReceived(IPendingServiceCall call) {
Integer streamIdInteger = (Integer) call.getResult();
MyClientStream myClientStream = new MyClientStream();
myClientStream.setStreamId(streamIdInteger.intValue());
myClientStream.setConnection(conn);
conn.addClientStream(myClientStream);
play(streamIdInteger.intValue(), filename, 0, -2);
}
};
protected void onInvoke(RTMPConnection conn, Channel channel, Header header, Notify notify, RTMP rtmp) {
super.onInvoke(conn, channel, header, notify, rtmp);
System.out.println("onInvoke, header = " + header.toString());
System.out.println("onInvoke, notify = " + notify.toString());
System.out.println("onInvoke, rtmp = " + rtmp.toString());
};
public static class MyClientStream extends AbstractClientStream implements IEventDispatcher {
@Override
public void start() {
// TODO Auto-generated method stub
}
@Override
public void stop() {
// TODO Auto-generated method stub
}
@Override
public void close() {
// TODO Auto-generated method stub
}
@Override
public void dispatchEvent(IEvent event) {
System.out.println("AudioListenerClientStream.dispachEvent()" + event.toString());
}
}
}更新1
传统setStreamEventDispatcher()版本的行为也是一样的。
public class SSCCE_RTMPPlayer2 extends RTMPClient {
private String server = "localhost";
private int port = 1935;
private String application = "oflaDemo";
private String filename = "avatar.flv";
private static boolean finished = false;
public static void main(String[] args) throws InterruptedException {
final SSCCE_RTMPPlayer2 player = new SSCCE_RTMPPlayer2();
player.connect();
synchronized( SSCCE_RTMPPlayer.class ) {
if( !finished ) SSCCE_RTMPPlayer.class.wait();
}
System.out.println("Ended");
}
public void connect() {
setExceptionHandler(new ClientExceptionHandler() {
@Override
public void handleException(Throwable throwable) {
throwable.printStackTrace();
}
});
setStreamEventDispatcher(streamEventDispatcher);
connect(server, port, application, connectCallback);
}
private IEventDispatcher streamEventDispatcher = new IEventDispatcher() {
@Override
public void dispatchEvent(IEvent event) {
System.out.println("AudioListenerClientStream.dispachEvent()" + event.toString());
}
};
private IPendingServiceCallback connectCallback = new IPendingServiceCallback() {
@Override
public void resultReceived(IPendingServiceCall call) {
System.out.println("connectCallback");
createStream(createStreamCallback);
}
};
private IPendingServiceCallback createStreamCallback = new IPendingServiceCallback() {
@Override
public void resultReceived(IPendingServiceCall call) {
Integer streamIdInteger = (Integer) call.getResult();
play(streamIdInteger.intValue(), filename, 0, -2);
}
};
protected void onInvoke(RTMPConnection conn, Channel channel, Header header, Notify notify, RTMP rtmp) {
super.onInvoke(conn, channel, header, notify, rtmp);
System.out.println("onInvoke, header = " + header.toString());
System.out.println("onInvoke, notify = " + notify.toString());
System.out.println("onInvoke, rtmp = " + rtmp.toString());
/*
ObjectMap<String, String> map = (ObjectMap) notify.getCall().getArguments()[0];
String code = map.get("code");
if (StatusCodes.NS_PLAY_STOP.equals(code)) {
synchronized( SSCCE_RTMPPlayer.class ) {
finished = true;
SSCCE_RTMPPlayer.class.notifyAll();
}
disconnect();
System.out.println("Disconnected");
}
*/
};
}更新2
我发现包在挂起后开始下降。滴法是RTMPProtocolEncoder#dropMessage()
更新3
我看到'tardiness`‘正在以实时的速度增长,当它超过8000的值时,就开始下降。
更新4
更确切地说,在服务器端,进程大约在经过8秒后才开始丢弃数据包。这可能是8000的值,也就是容忍时间。与此同时,数据包时间戳达到了大约15-16秒。客户端在此之前一直在播放,然后才停止。
因此,当服务器超过客户端2次时,当它达到某个限制时,它不会等待,而是开始丢弃数据包。
看来正确的行为会等到客户端到达时间戳,然后继续.
更新5
可能Client类不打算从服务器侦听流,因此不包含适当的同步逻辑?
幻解
在观察使用oflaDemo客户端和我的应用程序播放流时日志中的差异时,我发现标准客户端报告的缓冲区大小为5000 ms,而我的客户端则没有。我不明白这是怎么回事,但是当我将RTMP ping添加到我的应用程序中时,它就开始工作了。魔法线如下
conn.ping(new Ping(Ping.CLIENT_BUFFER, streamId, 5000));由于它的作用仅仅是通过它的值来改变延迟,我认为总体问题是由于red5错误,这使得它无法正确地计算延迟。
发布于 2012-05-01 17:18:43
一些文件的视频流出现了问题,导致播放停止。但是我已经在服务器中修复了它;使用Version4329或更高版本。供您参考的问题是:http://code.google.com/p/red5/issues/detail?id=200
https://stackoverflow.com/questions/10047898
复制相似问题