使用MediaCodec和RTMP做直播推流

原创 2017年06月11日 11:33:44

本项目完全开源,项目Github地址: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)。

RTMP
我使用了一个开源项目,可以将视频数据封成RTMP包,发送到服务器上。
LibRtmp-Client-for-Android

总结
数据流可以这样看
Camera -> SurfaceTexture -> Surface -> MediaCodec -> encode data(byte[]) -> RTMPMuxer -> Server

  • 音频数据:

相对简单一些,就是从AudioRecord里获取原始音频数据(byte[]),编码成AAC数据(也是byte[]),然后给RTMPMuxer,封装成RTMP包,发到服务器

麦克风MIC -> AudioRecord -> voice data(就是byte[]) -> MediaCodec -> encode data(就是byte[]) -> RTMPMuxer -> Server

  • Muxer

前面有提到有视频的RTMP包和音频的RTMP包,分别是将单元H264和单元AAC封装成RTMP包,发到服务器。这些包之间有什么规律?
这些包之间是按时间顺序排列的,MediaCodec返回编码数据时,会返回编码数据的时间戳。但注意编码成RTMP包时,取的是相对时间戳,也就是说取到时间戳时,需要计算与上一个包的时间戳的差值,写到RTMP包里。

另外RTMP流本质上是FLV格式的音视频,这里也提供了写成FLV文件的功能。

效果图

PC播放端

PC播放端
Android推流端

process

视频帧图像处理

前面提到视频帧的图像处理,实际上也是利用了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

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

one

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

测试服务器

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

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

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

h264

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

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

flv

感谢雷神。

声明

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

最后

您的打赏是对作者的最大支持(左侧栏目)!!当然在Github上点个Star也是很大的支持哈哈。

版权声明:本文为博主原创文章,未经博主允许不得转载。

【Android】使用MediaCodec硬编码实现视频直播推流端(一)

纯java代码实现视频直播推流,参考github中begeekmyfriend大神的开源项目yasea,其实就是抄袭,哈哈...
  • gitzzp
  • gitzzp
  • 2016年06月15日 18:37
  • 5945

EasyPusher安卓Android手机直播推送之MediaCodec 硬编码H264格式

本文主要介绍如何通过Camera一帧一帧的获取画面,并通过MediaCodec硬编码方式编码成H264格式的视频数据,希望对想了解MediaCodec的你能够有所帮助。...
  • u013758734
  • u013758734
  • 2016年03月09日 13:51
  • 5345

Android实现录屏直播(三)MediaProjection + VirtualDisplay + librtmp + MediaCodec实现视频编码并推流到rtmp服务器

请尊重分享成果,转载请注明出处,本文来自Coder包子哥,原文链接:http://blog.csdn.net/zxccxzzxz/article/details/54254244看到有网友在后台私信和...
  • zxccxzzxz
  • zxccxzzxz
  • 2017年02月16日 00:32
  • 8617

Android中使用MediaCodec硬件解码,高效率得到YUV格式帧

http://www.cnblogs.com/welhzh/p/6079631.html Android中使用MediaCodec硬件解码,高效率得到YUV格式帧,快速保存JPEG图...
  • STN_LCD
  • STN_LCD
  • 2016年12月16日 10:18
  • 7183

EasyPusher安卓Android手机直播推送之MediaCodec 硬编码H264格式

最近在研究EasyDarwin的Push库EasyPusher,EasyPusher可以推送H264视频到EasyDarwin服务器,终端可以通过rtsp协议访问该实时流,达到手机直播的功能,延迟基本...
  • yelin042
  • yelin042
  • 2017年11月02日 15:35
  • 280

Android Mediacodec硬解H264并显示

Android H264 硬解
  • WificamSDK7
  • WificamSDK7
  • 2016年04月14日 09:41
  • 7424

最简单的基于FFmpeg的推流器(以推送RTMP为例)

本文记录一个最简单的基于FFmpeg的推流器(simplest ffmpeg streamer)。推流器的作用就是将本地的视频数据推送至流媒体服务器。本文记录的推流器,可以将本地的 MOV / AVI...
  • leixiaohua1020
  • leixiaohua1020
  • 2014年10月06日 00:35
  • 144019

RTMP推流及协议学习

前期准备 了解RTMP定义 准备RTMPDump中的librtmp 使用openssl中的libssllibcrypto 推流工作 整体框架图 使用libtrmp提供的API 将streaming封装...
  • lory17
  • lory17
  • 2017年03月13日 13:44
  • 4720

Android 使用Rtmp音视频推流

一、前言 本文介绍的是使用Android 摄像头、麦克风采集的音、视频进行编码。然后通过librtmp推送到流媒体服务器上的功能。 我所使用的环境:Android Studio 2.2.3 、...
  • a992036795
  • a992036795
  • 2017年01月17日 16:02
  • 7064

EasyRTMP实现的rtmp推流的基本协议流程

EasyRTMP介绍EasyRTMP是结合了多种音视频缓存及网络技术的一个rtmp直播推流端,包括:圆形缓冲区(circular buffer)、智能丢帧、自动重连、rtmp协议等等多种技术,能够非常...
  • xiejiashu
  • xiejiashu
  • 2016年10月31日 15:48
  • 4672
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:使用MediaCodec和RTMP做直播推流
举报原因:
原因补充:

(最多只允许输入30个字)