Red5 RTMPClient 播放示例在播放满流时开始丢弃消息

Posted

技术标签:

【中文标题】Red5 RTMPClient 播放示例在播放满流时开始丢弃消息【英文标题】:Red5 RTMPClient playback sample starts to drop messages if full stream played 【发布时间】:2012-04-06 18:52:42 【问题描述】:

下面的客户端旨在运行oflaDemo应用程序,在本地主机上的red5上运行。它包含阿凡达电影宣传片。

问题是客户端读取了 15 秒的电影并挂起。为什么?

要编译下面的程序,只需从这里http://wiki.red5.org/wiki/1_0_RC1下载red5,安装并运行它。打开根页面http://localhost:5080 并导航到演示安装页面。安装oflaDemo 示例。然后导航到 oflaDemo 页面并检查它是否正常工作。

然后使用 red5 中的所有 jar 作为库创建新的 Java 项目。用运行 red5 运行它。

客户端通过 1935 端口与服务器通信。

应用结构如下:

1) connect() 方法连接到应用程序

2) connectCallback 在先前操作的结果上创建新流;库函数不用于注入自定义流类

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

我看到“迟到”正在实时增加。当它超过 8000 的值时,开始下降。

更新 4

更准确地说,在服务器端,进程大约在 8 秒后开始丢弃数据包。这可能是 8000 的值,即容差时间。同时,数据包时间戳达到大约 15-16 秒。客户端一直播放到这个时间,然后才停止。

所以图片显示服务器超过客户端 2 次,当它达到某个限制时,它不会等待而是开始丢弃数据包。

看起来正确的行为会等到客户端到达时间戳并继续......

更新 5

可能 Client Stream 类不打算监听来自服务器的流,因此不包含适当的同步逻辑?

神奇的解决方案

在使用 oflaDemo 客户端和我的应用程序播放流时观察日志中的差异时,我发现标准客户端报告的缓冲区大小为 5000 毫秒,而我的客户端没有。我不明白这是怎么玩的,但是当我将 RTMP ping 添加到我的应用程序时,它就开始工作了。魔术线如下

conn.ping(new Ping(Ping.CLIENT_BUFFER, streamId, 5000));

由于它的作用只是通过它的价值来改变迟到,我认为整体问题是由于 red5 错误,这使得它无法正确计算迟到。

【问题讨论】:

如果您或任何人有任何改进计算的想法,我很想听听。 【参考方案1】:

存在导致播放停止的某些文件的视频流问题。但我已经在服务器中修复了它;使用修订版 4329 或更高版本。供您参考的问题在这里:http://code.google.com/p/red5/issues/detail?id=200

【讨论】:

以上是关于Red5 RTMPClient 播放示例在播放满流时开始丢弃消息的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Red5 播放视频?

Red5点播和直播的实现

用Red5搭建支持WEB播放的实时监控视频

视频转换 rtsp 流 转rtmp流播放(未完)

Red5流服务器搭建(实现在线直播,流媒体视频播放和在线视频会议)

Red5视频流录制正在中断