使用Spydroid(libstreaming)作为rtsp server

来源:互联网 发布:细说php第二版 编辑:程序博客网 时间:2024/06/10 21:55

实现android视频直播的库,主要实现的功能有RTSP协议、H263/H264编码、RTP/RTCP协议打包等


1、分析net.majorkernelpanic.streaming.rtp:

 

1)H264Packetizer

H264Packetizer负责读取h264的视频帧,然后打包封装为rtp包。Rtp头是在RtpSocket初始化时默认生成了的。

当读取到NALUtype 5时, 会先将NALU type 7 (SPS) and 8 (PPS)转化为STAP-ANAL (NAL type 24)封为一个RTP包发送出去,然后再打包发送NALU type 5。

打包时,如果包大小小于MTU,默认使用Single NAL unit的方式打包为Rtp包,包时去除 "00 00 01" 或 "00 00 0001" 的开始码, 把其他数据封包的 RTP 包即可。

如果包大小大于MTU,则会利用FU-A方式分包发送。

H264Packetizer和RtpSocket同时会计算好各个包的sequencenumber和timestamp。


图H264中的NALU类型定义


图 Rtp中的NALU类型定义

 

 

2)RtpSocket

RtpSocket在初始化时,默认生成了FIFO Buffers,并在每个Buffer上初始化好了Rtp head。当调用setDestination时,准备好MulticastSocket来发送UDP。当调用setOutputStream时,利用传进来的socket的OutputStream来发送TCP。

RTP协议用来传送编码后的语音,RTCP协议用来传送控制信息,RtpSocket里的SenderReport完成对RTCP协议的管理和发送。RtpSocket用UDP,SenderReport也用UDP,RtpSocket用TCP,SenderReport也用TCP。

 

2、分析net.majorkernelpanic.streaming.rtsp:

1)RtspServer

当客户端发起请求时,在processRequest里处理各个指令。


图 简单的rtsp交互过程

 

收到DESCRIBE指令时,调用mSession.syncConfigure开始配置。以h264为例,mSession.syncConfigure -> H264Stream.configure(stream.configure)。

H264Stream.configure里面调用了MediaStream.configure,里面做了不少事情:  

1、调用Packetizer的setDestination和RtpSocket的setOutputStream,做好了通过UDP或者TCP来发送RTP的准备。

2、调用了testH264,通过打开camera录制一段视频,然后通过MP4Config分析此视频的PPS和SPS。

 

 

当收到SETUP指令时,调用mSession.syncStart开始视频。

这里以h264为例,mSession.syncStart -> H264Stream.start(stream.start) 。

H264Stream.start里也做了不少事情:

1、调用了H264Stream.configure,再走一次DESCRIBE时走过的流程。

2、调用H264Packetizer.setStreamParameters,将PPS和SPS设置给H264Packetizer,以供打包。

3、调用VideoStream.start(super.start)  ->MediaStream.start(super.start),MediaStream.start里调用了encodeWithMediaCodec,即VideoStream.encodeWithMediaCodec,在这里选择录制方式,打开镜头,开始h264编码,并通过rtp的MediaCodecInputStream将h264的帧传给rtp的H264Packetizer。然后调用H264Packetizer的start,开始启动H264Packetizer来将h264打包为rtp包并发送出去。

 

3、分析net.majorkernelpanic.streaming.gl:

 

图 enhanced surfaceview

 

当手机支持android.media.MediaCodec的时候,默认使用MODE_MEDIACODEC_API的方式,否则默认使用MODE_MEDIARECORDER_API。


图 android 的几种不同的encoded方式的选择

 

如果想使用MODE_MEDIACODEC_API_2的话,在H264Stream.configure的开头加上setStreamingMethod(MODE_MEDIACODEC_API_2)即可。

 

MODE_MEDIACODEC_API的时候,camera直接绑定mSurfaceView.getHolder(),直接渲染到了SurfaceView上面。然后利用Camera.PreviewCallback的onPreviewFrame来直接获取数据,通过添加到mMediaCodec.queueInputBuffer里来解码。

 

而MODE_MEDIACODEC_API_2的时候,就是enhancedsurfaceview发威的时候了,enhancedsurfaceview里面包含有mViewSurfaceManager、mCodecSurfaceManager和mTextureManager:

1、camera和mTextureManager创建的SurfaceTexture绑定,每次渲染到mTextureManager.getSurfaceTexture上,并回调onFrameAvailable通知enhancedsurfaceview。

2、enhancedsurfaceview属于surfaceview的getHolder().getSurface()交给了mViewSurfaceManager管理,mViewSurfaceManager在这里将其初始化为GL环境。

3、mMediaCodec.createInputSurface创建的解码的surface通过addMediaCodecSurface交给了mCodecSurfaceManager,mCodecSurfaceManager也在这里将其初始化为GL环境,其中mEGLSharedContext使用了mViewSurfaceManager的mEGLContext。

4、enhancedsurfaceview创建渲染线程,当onFrameAvailable回调来时,通过notifyAll同步给渲染线程,然后在渲染线程里将mTextureManager.getSurfaceTexture渲染到mViewSurfaceManager和mCodecSurfaceManager上。


图 enhanced surfaceview的渲染

 

注意:mTextureManager的SurfaceTexture的Texture 是在当前made current的EGLsurface(mViewSurfaceManager)下createProgram创建的,即是mViewSurfaceManager下的texture,如果mCodecSurfaceManager没有与mViewSurfaceManagerSharedContext的话,则无法使用mTextureManager来渲染。

eglCreateContext( EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint*attrib_list )

share_context:Specifiesthe EGL rendering context with which to share texture objects. EGL_NO_CONTEXTindicates that no sharing is to take place.

 

关于SurfaceTexture的texture使用GL_TEXTURE_EXTERNAL_OES创建,网上有如下解释:如果EGLClientBuffer的数据是YUV格式的,还可以使用纹理Target为GL_TEXTURE_EXTERNAL_OES。

 

MODE_MEDIACODEC_API_2利用起了opengl,想要做变化渲染都会方便许多。


0 0