如果播放完整流,Red5 RTMPClient播放示例将开始丢弃消息

时间:2012-04-06 18:52:43

标签: java streaming red5 playback rtmp

以下客户端旨在运行oflaDemo应用程序,在localhost上的red5上运行。它包含阿凡达电影促销。

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

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

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

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

app的结构如下:

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

我发现挂起后数据包开始掉线。 drop方法是RTMPProtocolEncoder#dropMessage()

更新3

我看到'迟到'正在以实时速度增加。当它超过8000时,开始下降。

更新4

更确切地说,在服务器端,该过程大约在经过8秒后开始丢弃数据包。这可能是容差时间8000的值。在同一时刻,数据包时间戳达到大约15-16秒。客户端一直玩到这个时候才停止。

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

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

更新5

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

MAGIC SOLUTION

在使用oflaDemo客户端和我的应用程序播放流时观察日志中的差异时,我发现标准客户端报告的缓冲区大小为5000毫秒,而我的客户端则没有。我不明白它是如何发挥作用的,但当我向我的应用程序添加RTMP ping时,它开始工作。神奇的线条如下

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

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

1 个答案:

答案 0 :(得分:0)

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