rtsp协议的格式与http协议的格式是一样的, 因此可以使用netty的http解析器来处理rtsp交互数据.
netty中自带了一个RtspDecoder
, 但是它几乎没做什么事情, 只是将rtsp消息解析成HttpRequest
,HttpResonse
, HttpContent
.
因此, 最终还是需要开发者自己处理, 没有什么捷径. 因此本文只是说明netty的基本用法
public static void main(String[] args) throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup(); // (1)
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap(); // (2)
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class) // (3)
.childHandler(new ChannelInitializer() { // (4)
@Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline()
.addLast(new RtspDecoder()) /** 添加netty自带的rtsp消息解析器 */
.addLast(new RTSPHandler()) /** 上一步将消息解析完成之后, 再交给自定义的处理器 */
.addLast(new ReadTimeoutHandler(30)); /** idle超时处理 */
}
})
.option(ChannelOption.SO_BACKLOG, 128) // (5)
.childOption(ChannelOption.SO_KEEPALIVE, true); // (6)
ChannelFuture f = b.bind(80).sync(); // (7)
logger.info("start turn server success");
f.channel().closeFuture().sync();
} catch (Exception ex){
logger.error("start netty failed, ", ex);
} finally {
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
}
RTSPHandler实现
public class RTSPHandler extends ChannelInboundHandlerAdapter {
private final static Logger logger = LogManager.getLogger(RTSPHandler.class);
@Override
public void channelActive(final ChannelHandlerContext ctx) { // (1)
logger.info("channelActive: {}", ctx);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
logger.info("exceptionCaught: {}", cause);
ctx.close();
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception{
logger.info("[RTSPHandler]channelRead: {}", msg.getClass());
if(msg instanceof DefaultHttpRequest){
DefaultHttpRequest req = (DefaultHttpRequest)msg;
HttpMethod method = req.method();
String methodName = method.name();
logger.info("method: {}", methodName);
/** 以下就是具体消息的处理, 需要开发者自己实现 */
if(methodName.equalsIgnoreCase("OPTIONS") ||
methodName.equalsIgnoreCase("DESCRIBE")){
}else{
}
}else if(msg instanceof HttpContent){
HttpContent content = (HttpContent)msg;
if(content.content().isReadable()) {
/** 此时, 才表示HttpContent是有内容的, 否则,它是空的, 不需要处理 */
}
}
}
}
既然要用netty来搞rtsp相关的东西, 而不是用live555之类的东西来做, 那肯定是有某些特殊需求. 比如用它来做直播? 视频流转换?
ChannelInboundHandlerAdapter
ctx.channel().pipeline().addLast(upstreamHandler);
ctx_.channel().pipeline().remove(RtspDecoder.class);
如果本handler处理ByteBuf, 发现还有一些数据需要抛给一下handler处理, 可以这样做
if (buf != null) {
int readable = buf.readableBytes();
if (readable > 0) {
ByteBuf bytes = buf.readBytes(readable);
buf.release();
ctx.fireChannelRead(bytes);
} else {
buf.release();
}
ctx.fireChannelReadComplete();
}`
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception{
/** 发现这个数据不是本handler能处理的, 抛给下一个handler处理 */
// ....
ctx.fireChannelRead(msg);
}