流媒体传输知识整理(四)
来源:互联网 发布:存活的数据叫删失数据 编辑:程序博客网 时间:2024/06/04 20:46
(3) 事件处理类:RtspServerHandler.java
public class RtspServerHandler extends SimpleChannelHandler {
@Override
public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e)
throws Exception {
// TODO Auto-generated method stub
super.channelOpen(ctx, e);
LOGGER.info("Rtsp服务器端channel opened :"+ctx.getChannel().getRemoteAddress());
}
@Override
public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e)
throws Exception {
// TODO Auto-generated method stub
super.channelConnected(ctx, e);
LOGGER.info("Rtsp服务器端channel connected");
}
private static final Logger LOGGER = Logger.getLogger(RtspServerHandler.class);
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e)
throws Exception {
HttpRequest objMessage = (HttpRequest) e.getMessage();
LOGGER.info("Rtsp服务器端接收到数据:"+objMessage);
if(objMessage instanceof HttpRequest){
// DefaultHttpRequest request = (DefaultHttpRequest) objMessage;
// HttpRequest req = new DefaultHttpRequest(RtspVersions.RTSP_1_0,RtspMethods.PLAY, "shanglenidexindewodexinhaoshangxin.mp3");
// e.getChannel().write(req);
// if(request.getContent() instanceof CompositeChannelBuffer){
// CompositeChannelBuffer ccb = (CompositeChannelBuffer) request.getContent();
// byte[] b0 = ccb.getBuffer(0).array();
// System.out.println(Utils.bytesToHex(b0));
// byte[] b1 = ccb.getBuffer(b0.length).array();
// System.out.println(Utils.bytesToHex(b1));
//
// }
writeMsg(objMessage,e.getFuture().getChannel());
}
}
private void writeMsg(HttpRequest request , Channel channel) throws IOException{
ChannelBuffer cbuffer = new DynamicChannelBuffer(8192);
// cbuffer.writeBytes("hello".getBytes(Constants.UTF8ENCODER));
DefaultHttpResponse response = new DefaultHttpResponse(RtspVersions.RTSP_1_0, RtspResponseStatuses.OK);
if (request.getMethod().equals(RtspMethods.DESCRIBE)) {
LOGGER.info("DESCRIBE,流向:C-->S;参数要求:推荐;功能:检查演示或媒体对象的描述,也允许使用接收头指定用户理解的描述格式。DESCRIBE的答复-响应组成媒体RTSP初始阶段");
} else if (request.getMethod().equals(RtspMethods.ANNOUNCE)) {
LOGGER.info("ANNOUNCE,流向:C<-->S;参数要求:可选;功能:当从用户发往服务器时,ANNOUNCE将请求URL识别的演示或媒体对象描述发送给服务器;反之,ANNOUNCE实时更新连接描述。如新媒体流加入演示,整个演示描述再次发送,而不仅仅是附加组件,使组件能被删除");
} else if (request.getMethod().equals(RtspMethods.GET_PARAMETER)) {
LOGGER.info("GET_PARAMETER,流向:C<-->S;参数要求:可选;功能:GET_PARAMETER请求检查RUL指定的演示与媒体的参数值。没有实体体时,GET_PARAMETER也许能用来测试用户与服务器的连通情况");
} else if (request.getMethod().equals(RtspMethods.OPTIONS)) {
LOGGER.info("OPTIONS,流向:C<-->S;参数要求:要求;功能:可在任意时刻发出OPTIONS请求,如用户打算尝试非标准请求,并不影响服务器状态");
} else if (request.getMethod().equals(RtspMethods.PAUSE)) {
LOGGER.info("PAUSE,流向:C-->S;参数要求:推荐;功能:PAUSE请求引起流发送临时中断。如请求URL命名一个流,仅回放和记录被停止;如请求URL命名一个演示或流组,演示或组中所有当前活动的流发送都停止。恢复回放或记录后,必须维持同步。在SETUP消息中连接头超时参数所指定时段期间被暂停后,尽管服务器可能关闭连接并释放资源,但服务器资源会被预订");
} else if (request.getMethod().equals(RtspMethods.PLAY)) {
LOGGER.info("PLAY,流向:C-->S;参数要求:要求;功能:PLAY告诉服务器以SEFUP指定的机制开始发送数据;直到一些SETUP请求被成功响应,客户端才可发布PLAY请求。PLAY请求将正常播放时间设置在所指定范围的起始处,发送流数据直到范围的结束处。PLAY请求可排成队列,服务器将PLAY请求排成队列,顺序执行");
} else if (request.getMethod().equals(RtspMethods.RECORD)) {
LOGGER.info("RECORD,流向:C-->S;参数要求:可选;功能:该方法根据演示描述初始化媒体数据记录范围,时标反映开始和结束时间;如没有给出时间范围,使用演示描述提供的开始和结束时间。如连接已经启动,立即开始记录,服务器数据请求URL或其他URL决定是否存储记录的数据;如服务器没有使用URL请求,响应应为201(创建),并包含描述请求状态和参考新资源的实体与位置头。支持现场演示记录的媒体服务器必须支持时钟范围格式,smpte格式没有意义");
} else if (request.getMethod().equals(RtspMethods.REDIRECT)) {
LOGGER.info("REDIRECT,流向:S-->C;参数要求:可选;功能:重定向请求通知客户端连接到另一服务器地址。它包含强制头地址,指示客户端发布URL请求;也可能包括参数范围,以指明重定向何时生效。若客户端要继续发送或接收URL媒体,客户端必须对当前连接发送TEARDOWN请求,而对指定主执新连接发送SETUP请求");
} else if (request.getMethod().equals(RtspMethods.SET_PARAMETER)) {
LOGGER.info("SET_PARAMETER,流向:C<-->S;参数要求:可选;功能:这个方法请求设置演示或URL指定流的参数值。请求仅应包含单个参数,允许客户端决定某个特殊请求为何失败。如请求包含多个参数,所有参数可成功设置,服务器必须只对该请求起作用。服务器必须允许参数可重复设置成同一值,但不让改变参数值。注意:媒体流传输参数必须用SETUP命令设置。将设置传输参数限制为SETUP有利于防火墙。将参数划分成规则排列形式,结果有更多有意义的错误指示");
} else if (request.getMethod().equals(RtspMethods.SETUP)) {
LOGGER.info("SETUP,流向:C-->S;参数要求:要求;功能:对URL的SETUP请求指定用于流媒体的传输机制。客户端对正播放的流发布一个SETUP请求,以改变服务器允许的传输参数。如不允许这样做,响应错误为“455 Method Not Valid In This State”。为了透过防火墙,客户端必须指明传输参数,即使对这些参数没有影响");
} else if (request.getMethod().equals(RtspMethods.TEARDOWN)) {
LOGGER.info("TEARDOWN,流向:C-->S;参数要求:要求;功能:TEARDOWN请求停止给定URL流发送,释放相关资源。如URL是此演示URL,任何RTSP连接标识不再有效。除非全部传输参数是连接描述定义的,SETUP请求必须在连接可再次播放前发布");
}
// HttpResponse response = new DefaultRtspResponse(RtspVersion.RTSP_1_0, RtspResponseStatuses.OK);
// response.setHeader(RtspHeaders.Names.CONNECTION, RtspHeaders.Values.KEEP_ALIVE);
// response.setHeader(RtspHeaders.Names.CONTENT_LENGTH, cbuffer.array().length);
// response.setProtocolVersion(RtspVersions.RTSP_1_0);
// response.setStatus(RtspResponseStatuses.OK);
// response.setHeader(RtspHeaders.Names.CSEQ, 5);
// response.setChunked(true);
// if(request.getMethod().getName().equals("GET")){
// shanglenidexindewodexinhaoshangxin.mp3
FileInputStream in = new FileInputStream("E://shanglenidexindewodexinhaoshangxin.mp3");
FileChannel fchannel = in.getChannel();
long length = fchannel.size();
MappedByteBuffer buffer = fchannel.map(FileChannel.MapMode.READ_ONLY, 0, length);
// ChannelBuffer cbuffer = new DynamicChannelBuffer(8192);//8KB
cbuffer.writeBytes(buffer);
// cbuffer.writeBytes(in, 65536);
response.setHeader(RtspHeaders.Names.CONTENT_LENGTH, cbuffer.array().length);
// response.setChunked(true);
response.setContent(cbuffer);
// StreamSource ss = new StreamSource(new File("E://shanglenidexindewodexinhaoshangxin.mp3"));
// FileInputStream in = new FileInputStream("E://shanglenidexindewodexinhaoshangxin.mp3");
// ChunkedStream cs = new ChunkedStream(in);
// response.setHeader(RtspHeaders.Names.CONTENT_TYPE, ChannelBuffer.class);
// response.setHeader(RtspHeaders.Names.CONTENT_LENGTH,in.available());
// response.setHeader(RtspHeaders.Names.RTP_INFO, cs);
// }
channel.write(response);
// channel.write(cs);
// channel.write(cbuffer);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e)
throws Exception {
super.exceptionCaught(ctx, e);
LOGGER.error("Rtsp服务器捕获异常", e.getCause());
}
}
public class RtspClient { private static final Logger LOGGER = Logger.getLogger(RtspClient.class); public URI uri; public RtspClient(URI uri) { this.uri = uri; } public void run(){ ChannelFactory factory = new NioClientSocketChannelFactory( Executors.newCachedThreadPool(), Executors.newCachedThreadPool()); ClientBootstrap bootstrap = new ClientBootstrap(factory); bootstrap.setPipelineFactory(new ChannelPipelineFactory() { public ChannelPipeline getPipeline() { ChannelPipeline pipeline = pipeline(); pipeline.addLast("aggregator", new HttpChunkAggregator(65536)); pipeline.addLast("encoder", new RtspRequestEncoder()); pipeline.addLast("decoder", new RtspResponseDecoder()); // pipeline.addLast("decoder", new RtspRequestDecoder()); // pipeline.addLast("stream", new ChunkedWriteHandler()); pipeline.addLast("handler", new RtspClientHandler()); return pipeline; } }); bootstrap.setOption("tcpNoDelay", true); bootstrap.setOption("keepAlive", true); int port = 554; if (uri.getPort() != -1) { port = uri.getPort(); } ChannelFuture channelAfterConnect = bootstrap.connect(new InetSocketAddress(uri.getHost(), port)); Channel channel = channelAfterConnect.awaitUninterruptibly().getChannel(); if (!channelAfterConnect.isSuccess()) { bootstrap.releaseExternalResources(); return; } LOGGER.info("channel已成功与服务器连接!"); HttpRequest request = new DefaultHttpRequest(RtspVersions.RTSP_1_0, RtspMethods.SETUP, uri.toString()); request.setHeader(RtspHeaders.Names.HOST, uri.getHost()); request.setHeader(RtspHeaders.Names.CONNECTION, RtspHeaders.Values.KEEP_ALIVE); ChannelBuffer content = new DynamicChannelBuffer(2); content.writeBytes("icome".getBytes()); request.setContent(content); channel.write(request); // ChannelBuffer cbuffer = new DynamicChannelBuffer(8192);//8KB // FileInputStream in; // in = new FileInputStream("E://shanglenidexindewodexinhaoshangxin.mp3"); // FileChannel fchannel = in.getChannel(); // long length = fchannel.size(); // MappedByteBuffer buffer = fchannel.map(FileChannel.MapMode.READ_ONLY, 0, length); // cbuffer.writeBytes(buffer); // request.setContent(cbuffer); // channel.write(request); // channelWriteMedia(request, channel); } // /** // * 流媒体数据写入发送 // * // * @author linfenliang // * @date 2012-11-20 // * @version V1.0.0 // * @param request // * @param channel // * void // */ // public static void channelWriteMedia(HttpRequest request , Channel channel){ // HttpPostRequestEncoder bodyRequestEncoder = null; // try { // File f = new File("E://shanglenidexindewodexinhaoshangxin.mp3"); //// ChunkedFile file = new ChunkedFile(new File("E://伤了你的心的我伤心.mp3")); // HttpDataFactory factory = new DefaultHttpDataFactory( // DefaultHttpDataFactory.MINSIZE); // Disk if size exceed MINSIZE // DiskFileUpload.deleteOnExitTemporaryFile = true; // should delete file on exit (in normal exit) // DiskFileUpload.baseDirectory = null; // system temp directory // DiskAttribute.deleteOnExitTemporaryFile = true; // should delete file on exit (in normal exit) // DiskAttribute.baseDirectory = null; // system temp directory // bodyRequestEncoder = new HttpPostRequestEncoder(factory, // request, true); // true => multipart // bodyRequestEncoder.addBodyFileUpload("mp3", f, "audio/x-mpeg", true); // bodyRequestEncoder.addBodyAttribute("Send", "Send"); // bodyRequestEncoder.finalizeRequest(); // } catch (NullPointerException e) { // // should not be since no null args // e.printStackTrace(); // } catch (ErrorDataEncoderException e) { // // test if method is a POST method // e.printStackTrace(); // }finally{ // channel.write(bodyRequestEncoder); // } // } // /** * * @author linfenliang * @date 2012-11-20 * @version V1.0.0 * @param args * void */ public static void main(String[] args) { String uriStr = "rtsp://192.168.1.130:554/hello,boy"; try { new RtspClient(new URI(uriStr)).run(); } catch (URISyntaxException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public class RtspClientHandler extends SimpleChannelHandler{ @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { HttpMessage messageObj = (HttpMessage)e.getMessage(); byte[] content = messageObj.getContent().array(); if(content!=null && content.length!=0){ LOGGER.info("客户端结束数据:"+Utils.bytesToHex(content)); } LOGGER.info("Rtsp客户端接收到服务器端消息:"+messageObj); // ChunkedStream cs = new ChunkedStream(in); } boolean isPrintErr = false; @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { // super.exceptionCaught(ctx, e); if(!isPrintErr){ isPrintErr = !isPrintErr; LOGGER.error("Rtsp客户端出现异常", e.getCause()); } } } } 此设计并未真正实现流媒体数据的传输。会产生异常,此处的客户端也可通过暴风影音等视频播放工具直接访问RTSP地址。然后,并未达到视频播放的效果。客户端代码设计
(1) 客户端模拟类:RtspClient.java
注意
- 流媒体传输知识整理(四)
- 流媒体传输知识整理(二)
- 流媒体传输知识整理(三)
- 流媒体传输知识整理(五)
- 流媒体传输知识整理(六)
- 流媒体传输知识整理(七)
- 流媒体传输知识整理(八)
- 流媒体传输知识整理(一)
- 流媒体技术基础-流媒体传输协议(四)
- JavaEE知识整理系列(四)JMX
- JavaEE知识整理系列(四)JMX .
- Struts2的知识整理总结(四)
- C语言知识整理(四)
- 计算机网络知识整理:传输层,TCP,UDP
- 流媒体知识
- 流媒体知识
- 流媒体知识
- Java知识整理(四)之SE.正则表达式
- 流媒体传输知识整理(一)
- redis value为对象的排序、分页的一种实现
- 流媒体传输知识整理(二)
- block
- 流媒体传输知识整理(三)
- 流媒体传输知识整理(四)
- 流媒体传输知识整理(五)
- 流媒体传输知识整理(六)
- 流媒体传输知识整理(七)
- 流媒体传输知识整理(八)
- 读书感悟
- C# Socket编程笔记
- 断鸿零雁记
- The story of a typical software project.