假设有如下代码,从Socket中读取视频流并显示。
FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(clientSocket.getInputStream()); grabber.setFormat("h264"); grabber.setOption("rtsp_transport", "tcp"); grabber.start(); Java2DFrameConverter java2dFrameConverter = new Java2DFrameConverter(); while(true) { Frame frame = grabber.grabImage(); BufferedImage image = java2dFrameConverter.convert(frame); if(frame != null){ simulatorScreenView.setIcon(new ImageIcon(image)); }else { grabber.stop(); grabber.close(); throw new IOException("The connection is broken"); } }
可能很多人都会碰到grabber.start()一直阻塞的问题,因为在start()方法中会调用avformat_find_stream_info()方法,该方法会读取一部分源文件的音视频数据,来分析文件信息,并产生一个回调函数。因此,解决方法如下:
// 设置maximumSize为0,禁用 seek 回调,从而减少启动时间 FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(clientSocket.getInputStream(), 0); grabber.setFormat("h264"); // 设置读取的最大数据,单位字节 grabber.setOption("probesize", "10000"); // 设置分析的最长时间,单位微秒 grabber.setOption("analyzeduration", "10000"); grabber.setOption("rtsp_transport", "tcp"); grabber.start(); Java2DFrameConverter java2dFrameConverter = new Java2DFrameConverter(); while(true) { Frame frame = grabber.grabImage(); BufferedImage image = java2dFrameConverter.convert(frame); if(frame != null){ simulatorScreenView.setIcon(new ImageIcon(image)); }else { grabber.stop(); grabber.close(); throw new IOException("The connection is broken"); } }
可能会遇到如下这种错误,这种可能是因为传输端和接收端的编码不一致造成。比如笔者亲身经历,使用Android中的c2.android.avc.encoder编码器进行编码传输视频,就产生了以下的错误。笔者的解决方案就是将Android中的编码器改为OMX.qcom.video.encoder.avc。
有时候遇到较长的延时可能因为发送方编码的原因导致较长的延时。这时候如果找错方向,一味的调整接收方代码,只会无功而返。比如作为发送方的Android端使用OMX.google.h264.encoder和c2.android.avc.encoder就很慢,笔者推荐使用OMX.qcom.video.encoder.avc。