client.jar向Red5服务器发布实时视频数据

这篇文章是回答我自己在百度知道上提出的问题的,真痛恨那些百度知道上面不好好回答到处灌水的人。(居然还帮我选了最佳答案,难道是我百度密码被盗了)

问题:?oldq=1

使用juv-client-client.jar主要是尽快地完成毕业设计里面手机端向网页端发送实时视频的功能,由于实习和做毕业设计的时间冲突,因此完成毕业设计只花了1个多月时间。

(万恶的形式主义,论文格式改了我老久老久)因此代码上面会存在一些问题,并且也是单纯的实现了摄像头视频的实时传输,麦克风的实时语音没有实现。

自我感觉这个毕业设计没有多大价值,但是有参考意义,特把实现记录一下,用作纪念!

原理:

juv-client-client.jar提供了很多与Red5的交互操作,比如连接,流数据发布,方法互相调用等等。

在发布实时视频数据的之前,我们需要建立手机端和服务器端的RTMP连接。

使用类库里的NetConnection类:

关键代码如下:

private void connectRed5() {//key的值官方网站上可以申请到免费试用版本:#request_evaluation_keyLicense.setKey("63140-D023C-D7420-00B15-91FC7");connection = new NetConnection();//对连接进行配置connection.configuration().put(NetConnection.Configuration.INACTIVITY_TIMEOUT, -1);connection.configuration().put(NetConnection.Configuration.RECEIVE_BUFFER_SIZE, 256 * 1024);connection.configuration().put(NetConnection.Configuration.SEND_BUFFER_SIZE, 256 * 1024);connection.client(new ClientHandler());connection.addEventListener(new NetConnectionListener());connection.connect(red5_url);}其中new ClientHandler类是继承Object,里面写的方法可以被服务器调用。

new NetConnectionListener可以继承NetConnection.ListenerAdapter或者实现Listener接口,用于显示处理建立RTMP连接时候的一些网络状况。

例如:

private class ClientHandler extends Object {public ClientHandler() {}public void fun1() {}public void fun2() {}}private class NetConnectionListener extends NetConnection.ListenerAdapter {public NetConnectionListener() {}@Overridepublic void onAsyncError(final INetConnection source, final String message, final Exception e) {System.out.println("NetConnection#onAsyncError: " + message + " "+ e);}@Overridepublic void onIOError(final INetConnection source, final String message) {System.out.println("NetConnection#onIOError: " + message);}@Overridepublic void onNetStatus(final INetConnection source, final Map<String, Object> info) {System.out.println("NetConnection#onNetStatus: " + info);final Object code = info.get("code");if (NetConnection.CONNECT_SUCCESS.equals(code)) {}}}以上就是建立连接的过程,判断是否建立了连接在System.out.println("NetConnection#onNetStatus: " + info);是会有消息打出来的。

建立RTMP连接以后我们就可以通过Android的Camera类进行视频的采集,然后进行实时发送。

这里我不得不说的是,实现Android端的视频采集比网页端的复杂,因为这个类库提供的摄像头类和麦克风类都是两个抽象类或者是接口,必须要自己实现它。而网页端却有封装好的摄像头和麦克风,调用简单。

我的方法是实现类库里的AbstractCamera抽象类,想到Android里面自己也提供了一个摄像头的Camera类,于是我想到了用面向对象的组合和多接口实现,于是我打算实现一个AndroidCamera类。

这里有个问题:为什么要实现AbstractCamera类?

因为这个类里面有一个protected的fireOnVideoData方法。可以给继承它的类使用,该方法的作用,我猜想是把一个个数据包封装成流数据。

继续实现AndroidCamera类,用类图表示我的实现方案:

可以看到我用Android里的Camera类、SurfaceView类、SurfaceHolder类组成了我自己的AndroidCamera类,并且需要实现SurfaceHolder.CallBack接口以及Camera的PreviewCallBack接口。

这么做的原因有两个:1、实现预览。2、预览的同时通过Camera的PreviewCallBack接口里的onPreviewFrame方法获取到实时帧数据,进而转码打包生成流数据。(注意我这里并没有进行视频的编码压缩,时间和能力有限)

直接上代码了:

public class AndroidCamera extends AbstractCamera implements SurfaceHolder.Callback, Camera.PreviewCallback {private SurfaceView surfaceView;private SurfaceHolder surfaceHolder;private Camera camera;private int width;private int height;private boolean init;int blockWidth;int blockHeight;int timeBetweenFrames; // 1000 / frameRateint frameCounter;byte[] previous;public AndroidCamera(Context context) {surfaceView = (SurfaceView)((Activity) context).findViewById(R.id.surfaceView);//我是把Activity里的context传进入然后获取到SurfaceView,也可以之间传入SurfaceView进行实例surfaceHolder = surfaceView.getHolder();surfaceHolder.addCallback(AndroidCamera.this);surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);width = 320;height = 240;init = false;Log.d("DEBUG", "AndroidCamera()");}private void startVideo() {Log.d("DEBUG", "startVideo()");netStream = new NetStream(connection);netStream.addEventListener(new NetStream.ListenerAdapter() {@Overridepublic void onNetStatus(final INetStream source, final Map<String, Object> info){System.out.println("Publisher#NetStream#onNetStatus: " + info);Log.d("DEBUG", "Publisher#NetStream#onNetStatus: " + info);final Object code = info.get("code");if (NetStream.PUBLISH_START.equals(code)) {if (aCamera != null) {netStream.attachCamera(aCamera, -1 /*snapshotMilliseconds*/);Log.d("DEBUG", "aCamera.start()");aCamera.start();} else {Log.d("DEBUG", "camera == null");}}}});netStream.publish(VideoName, NetStream.RECORD);}public void start() {camera.startPreview();}@Overridepublic void onPreviewFrame(byte[] arg0, Camera arg1) {// TODO Auto-generated method stubif (!active) return;if (!init) {blockWidth = 32;blockHeight = 32;timeBetweenFrames = 100; // 1000 / frameRateframeCounter = 0;previous = null;init = true;}final long ctime = System.currentTimeMillis();byte[] current = RemoteUtil.decodeYUV420SP2RGB(arg0, width, height);try {final byte[] packet = RemoteUtil.encode(current, previous, blockWidth, blockHeight, width, height);Log.d("DEBUG", packet.toString());fireOnVideoData(new MediaDataByteArray(timeBetweenFrames, new ByteArray(packet)));previous = current;if (++frameCounter % 10 == 0) previous = null;}catch (Exception e) {e.printStackTrace();}final int spent = (int) (System.currentTimeMillis() – ctime);try {Thread.sleep(Math.max(0, timeBetweenFrames – spent));} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width,int height) {// TODO Auto-generated method stubstartVideo();}@Overridepublic void surfaceCreated(SurfaceHolder holder) {// TODO Auto-generated method stubcamera = Camera.open();try {camera.setPreviewDisplay(surfaceHolder);camera.setPreviewCallback(this);Camera.Parameters params = camera.getParameters();params.setPreviewSize(width, height);camera.setParameters(params);} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();camera.release();camera = null;}}@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {// TODO Auto-generated method stubif (camera != null) {camera.stopPreview();camera.release();camera = null;}}} //AndroidCamera上面的实现原理是基于类库自带的ExDesktopPublisher.java实现的,因此有些我自己也无法看懂。(因为我不懂多媒体)快忘了那些不高兴的事吧!你看就连今天的阳光都如此明媚灿烂,

client.jar向Red5服务器发布实时视频数据

相关文章:

你感兴趣的文章:

标签云: