这个项目是一个完全开源的项目Github地址:AndroidInstantVideo码云地址:AndroidInstantVideo
目前市面上的开源项目或者Android直播客户端主要使用ffmpeg实现流媒体。本文将介绍使用MediaCodec实现直播流,media codec是Android自带的视频编码类。
和数据流的一般原理。
这里的直播是指将你的客户端生成的视频数据实时发送到服务器。然后,服务器上的数据被实时发送到播放客户端。
以视频数据为例:获取摄像机图像,首先,摄像机拍摄原始图像数据。在这里,我们不关心原始图像数据的格式。因为我们使用MediaCodec,所以我们会使用camera.setPreviewTexture(表面纹理)来利用相机获取的图像。
这里的原理可以忽略。一般来说,相机会将获取的图像保存为OpenGL的一个纹理,我们可以通过使用这个纹理来使用相机图像。
画图得到图片后,我们会把这张图片(纹理)“画”到MediaCodec上。
怎么画?MediaCodec提供了一张“白纸”,即一个供我们绘制纹理的表面。这里的API是MediaCodec.createInputSurface()
怎么画?用画布画画。当然不是一般的画布。我用的是这个开源项目android-openGL-canvas。
H264数据画好之后,MediaCodec会帮我们把原来的图片数据压缩成相应的视频数据。目前我这里压缩成H264数据。所谓的H264数据,其实只是成堆的byte[]数组。在项目示例中,我将H264数据写入一个文件,该文件可以由一些播放器(例如PotPlayer)播放。
RTMP我使用了一个开源项目,它可以将视频数据封装到RTMP包中并发送到服务器。LibRtmp-Android客户端
总结一下数据流,可以看看相机-表面纹理-表面-media codec-编码数据(byte[])-rtmp mixer-服务器。
音频:相对简单,就是从AudioRecord中获取原始音频数据(byte[]),编码成AAC数据(也是byte[]),然后交给RTMPMuxer,打包成RTMP包,发送给服务器。
麦克风-录音-语音数据(字节[])-媒体编解码器-编码数据(字节[])-rtmp混合器-服务器
Muxer前面提到了带视频的RTMP包和带音频的RTMP包,它们把单元H264和单元AAC打包成RTMP包并发送给服务器。这些包之间的规则是什么?这些数据包是按时间顺序排列的。当MediaCodec返回编码数据时,它将返回编码数据的时间戳。但是需要注意的是,在编码成RTMP包时,取的是相对时间戳,也就是说,在取时间戳时,需要计算时间戳与前一个包的差值,并写入RTMP包。
另外,RTMP流本质上是FLV格式的音视频,这里也提供了写入FLV文件的功能。
翻译
PC播放端
安卓推送终端
视频帧图像处理
前面提到的视频帧的图像处理,其实用的是android-openGL-canvas。
关键代码如下:
.stream publisher . prepare encoder(streampublisher param,new H264Encoder。OnDrawListener(){ @ Override public void onGLDraw(ICanvasGL canvasGL,SurfaceTexture surfaceTexture,RawTexture rawTexture,@ Nullable surface texture outsideSurfaceTexture,@ Nullable basic texture outside texture){ drawvideo frame(canvasGL,outsideSurfaceTexture,outside texture);Loggers.i(\’DEBUG\ ‘,\ ‘ GL draw \ ‘);} });private void drawVideoFrame(ICanvasGL canvasGL,@ Nullable surface texture outsideSurfaceTexture,@ Nullable basic texture outsides texture){//这里可以做视频处理//这里可以做视频处理,比如水印等。texture filter texture filter=NewbasicTextureFilter();texture filter texture filter=new hue filter(180);int width=outside texture . getwidth();int height=outside texture . get height();canvasgl . drawsurfacetexture(outside texture,outsideSurfaceTexture,0,0,width /2,height /2,texture filter lt);canvasgl . drawsurfacetexture(outside texture,outsideSurfaceTexture,0,height/2,width/2,height,textureFilterRT} .如上所示,可以使用各种滤波器来实现对视频帧图像的处理。总而言之,你可以像画布一样在视频帧上画各种东西。当然,如果要在图片上画字,只能用位图代替。
比特率/秒
使用MediaCodec时,需要设置码率。这个比特率是根据视频分辨率和颜色格式计算的。
H264编码器(int width,int height,int bitRate,int framerate,int iframe interval,final eglcontextwrapper eglctx)抛出io异常,其中bitRate是比特率,以bit/s为单位。
一些计算方法可以参考这篇文章:对我的视频进行编码时应该用什么码率输出大小码率文件大小320×240像素400kbps 3mb/分钟480×270像素700 kbps 5MB /分钟1024 x 576像素1500 kbps 11MB /分钟1280×720像素2500 kbps 19MB /分钟1920×1080像素4000 kbps 30MB /分钟
这种方法在大多数情况下是足够的,但是对于复杂的视频处理是不够的。例如,比较下面显示的未经处理的效果(一种纹理)。
对于下图所示的处理效果(两张图片使用了与上图相同的纹理大小,虽然我设置了不同的显示大小),比特率大约是上图的两倍。
测试服务器
如果有必要,请建立自己的RTMP服务器。我用的是自己的Nginx服务器,用的模块是nginx-rtmp-module。您不需要编写代码来构建服务器。按照教程输入几行命令就可以了。可以用开源直播软件OBS来对比播放效果。你可以使用各种播放器,VLC,PotPlayer和ffplay。我用的是ffplay。注意,因为它只是一个简单的服务器,所以我必须在启动推送流之前打开播放器连接。我的命令是。\ ffplay.exe \ ‘ rtmp ://localhost 336019305/live/room live=1 \ ‘
您还可以使用软件查看生成文件的详细信息。
看H.264文件的H.264视频流分析-雷小华
见aac文件AAC音频码流分析-雷晓华
看flv文件FLV包格式分析-雷小华
感谢托尔。
声明
这个项目是完全开源的,它的Github地址:AndroidInstantVideo。这个项目是个人开源项目,目前只是简单测试了一下。如果要用,请自行测试。如果有任何问题,可以到我的Github项目地址问我。