rtmp推音频流和流(使用MediaCodec和RTMP做直播推流)

本项目完全开源 项目Github地址:AndroidInstantVideo 码云地址:AndroidInstantVideo

目前开源的项目或市面上的Android直播客户端主要是用ffmpeg来实现推流的。本文将介绍使用Android原生的视频编码类MediaCodec实现直播推流。

数据流及大致原理

这里所说的直播,就是将你的客户端产生的视频数据,实时发送到服务器上。服务器上的数据再实时地发送到播放客户端上。

  • 以视频数据为例:

获取Camera画面 首先是摄像头拍摄得到原始画面数据,这里原始画面数据的格式我们不用管,因为我们使用的是MediaCodec,所以我们会使用 camera.setPreviewTexture(surfaceTexture) 来利用Camera获取到的画面。

此处的原理可忽略,大致说明的话,就是Camera会把获得的画面保存为OpenGL的一个纹理,我们使用这个纹理就能使用Camera的画面。

绘制画面 在获得画面之后,我们要把这个画面(纹理)“画”到MediaCodec上。

如何画? MediaCodec提供一张’白纸’,也就是一个Surface,供我们把纹理画到上面。此处的API是 MediaCodec.createInputSurface()

怎么画?用Canvas画。当然不是一般的Canvas,我用了这个开源项目android-openGL-canvas。

H264数据 画上去后,MediaCodec就会帮我们把原始画面数据,压缩成相应的视频数据,目前我这里是压缩成H264数据。 所谓的H264数据,其实只是一堆堆的byte[]数组。在项目的例子,我把H264数据写成了文件,可以用某些播放器播放(例如PotPlayer)。

Android推流端

rtmp推音频流和流(使用MediaCodec和RTMP做直播推流)(1)

视频帧图像处理

前面提到视频帧的图像处理,实际上也是利用了android-openGL-canvas。

关键代码如下:

... streamPublisher.prepareEncoder(streamPublisherParam, new H264Encoder.OnDrawListener() { @Override public void onGLDraw(ICanvasGL canvasGL, SurfaceTexture surfaceTexture, RawTexture rawTexture, @Nullable SurfaceTexture outsideSurfaceTexture, @Nullable BasicTexture outsideTexture) { drawVideoFrame(canvasGL, outsideSurfaceTexture, outsideTexture); Loggers.i("DEBUG", "gl draw"); } }); ... private void drawVideoFrame(ICanvasGL canvasGL, @Nullable SurfaceTexture outsideSurfaceTexture, @Nullable BasicTexture outsideTexture) { // Here you can do video process // 此处可以视频处理,例如加水印等等 TextureFilter textureFilterLT = new BasicTextureFilter(); TextureFilter textureFilterRT = new HueFilter(180); int width = outsideTexture.getWidth(); int height = outsideTexture.getHeight(); canvasGL.drawSurfaceTexture(outsideTexture, outsideSurfaceTexture, 0, 0, width /2, height /2, textureFilterLT); canvasGL.drawSurfaceTexture(outsideTexture, outsideSurfaceTexture, 0, height/2, width/2, height, textureFilterRT); } ...

如上所示,可以使用各种Filter实现对视频帧图像的处理。总而言之,可以像Canvas那样在视频帧上绘制各种东西。当然要在图上画文字就只能用bitmap代替了。

码率bit/s

在使用MediaCodec时,需要设置码率。这个码率是根据视频分辨率,色彩格式算出来的。

public H264Encoder(int width, int height, int bitRate, int frameRate, int iframeInterval, final EglContextWrapper eglCtx) throws IOException

其中bitRate就是码率,单位bit/s

一些计算方法可以参考此文: What bitrate should I use when encoding my video? Output size Bitrate Filesize 320x240 pixels 400 kbps 3MB / minute 480x270 pixels 700 kbps 5MB / minute 1024 x 576 pixels 1500 kbps 11MB / minute 1280x720 pixels 2500 kbps 19MB / minute 1920x1080 pixels 4000 kbps 30MB / minute

此方法大部分情况下够用,但是对于复杂视频处理还欠缺。 例如 对比下图的无处理效果(一张纹理)

rtmp推音频流和流(使用MediaCodec和RTMP做直播推流)(2)

对于下图这样处理效果(2个画面用的是与上图同样大小的纹理,虽然我设置显示的尺寸不一样),码率是上图的2倍左右。

rtmp推音频流和流(使用MediaCodec和RTMP做直播推流)(3)

测试服务器

需要测试的话,请自行搭建RTMP服务器。我用的是自己搭建的Nginx服务器,用的Module是nginx-rtmp-module。搭建服务器不需要写代码,根据教程敲几行命令就行。 可以用开源直播软件OBS对比播放效果。 播放器用各种都行,VLC,PotPlayer,ffplay都可以。 我用的是ffplay,注意,因为只是简单的服务器,所以要先开播放器连接后再开始启动推流。 我使用的命令是 .\ffplay.exe "rtmp://localhost:19305/live/roomlive=1"

另外可以使用一下软件查看生成的文件的详情。

看H264文件 H.264视频码流解析--雷霄骅

rtmp推音频流和流(使用MediaCodec和RTMP做直播推流)(4)

看aac文件 AAC音频码流解析--雷霄骅

rtmp推音频流和流(使用MediaCodec和RTMP做直播推流)(5)

看flv文件 FLV封装格式解析--雷霄骅

rtmp推音频流和流(使用MediaCodec和RTMP做直播推流)(6)

感谢雷神。

声明

本项目完全开源,项目Github地址:AndroidInstantVideo 本项目为个人开源项目,目前只做过简单的测试,如果要使用的话,请自行多测试,有问题可以到我的Github项目地址提出。

,

免责声明:本文仅代表文章作者的个人观点,与本站无关。其原创性、真实性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容文字的真实性、完整性和原创性本站不作任何保证或承诺,请读者仅作参考,并自行核实相关内容。文章投诉邮箱:anhduc.ph@yahoo.com

    分享
    投诉
    首页