
当前,市场上的开源项目或Android实时流客户端主要使用ffmpeg来实现流. 本文将介绍使用Android本机视频编码类MediaCodec实现实时流式传输.
数据流和一般原则
此处提到的实时广播是将客户端生成的视频数据实时发送到服务器. 服务器上的数据被实时发送到回放客户端.
以视频数据为例:
camera.setPreviewTexture(surfaceTexture)
这里的原理可以忽略. 粗略地说potplayer打不开rtmp,相机会将获取的图像保存为OpenGL的纹理. 我们可以使用此图像来使用相机图像.
绘制图片
获取图片后,我们需要将该图片(纹理)“绘制”到MediaCodec.
如何绘制?
MediaCodec提供了一张“白皮书”(即Surface),供我们在其上绘制纹理. 这里的API是
MediaCodec.createInputSurface()

如何绘制?用画布绘制. 当然,它不是通用的Canvas,我使用了这个开源项目android-openGL-canvas.
H264数据
绘制后,MediaCodec将帮助我们将原始屏幕数据压缩为相应的视频数据. 目前,我将其压缩为H264数据.
所谓的H264数据实际上只是一堆字节[]数组. 在该项目的示例中,我将H264数据作为文件编写,可以与某些播放器(例如PotPlayer)一起播放.
RTMP
我使用了一个开放源代码项目,该项目可以将视频数据密封成RTMP数据包并将其发送到服务器.
LibRtmp-Client-for-Android
摘要
数据流可以这样看
相机-> SurfaceTexture->表面-> MediaCodec->编码数据(字节[])-> RTMPMuxer->服务器
音频数据:

相对简单,它是从AudioRecord获取原始音频数据(字节[]),将其编码为AAC数据(也为字节[]),然后将其封装到RTMPMuxer中,然后将其发送到服务器
麦克风MIC-> AudioRecord->语音数据(即字节[])-> MediaCodec->编码数据(即字节[])-> RTMPMuxer->服务器
Muxer
如前所述,存在用于视频的RTMP数据包和用于音频的RTMP数据包. 它们是打包为RTMP数据包并发送到服务器的单元H264和单元AAC. 这些软件包之间的规则是什么?
数据包按时间顺序排列. 当MediaCodec返回编码数据时,它将返回编码数据的时间戳. 但是请注意,在编码为RTMP数据包时,会采用相对时间戳. 也就是说,在获取时间戳时,需要计算与前一个数据包的时间戳之差并将其写入RTMP数据包.
此外,RTMP流本质上是FLV格式的音频和视频,在这里还提供了写入FLV文件的功能.
效果图片

Android推送流结束

视频帧图像处理

如前所述,视频帧的图像处理实际上使用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);
}
...
如上所述,可以使用各种过滤器来处理视频帧图像. 简而言之,您可以在视频帧上绘制各种东西,例如Canvas. 当然,要在地图上绘制文本,您只能使用位图.
比特率/比特 s>
使用MediaCodec时,需要设置编码率. 该比特率是根据视频分辨率和颜色格式计算的.
public H264Encoder(int width, int height, int bitRate, int frameRate, int iframeInterval, final EglContextWrapper eglCtx) throws IOException
其中bitRate是比特率,单位bit / s
某些计算方法可以参考本文:
编码视频时应该使用什么比特率?
输出大小比特率文件大小

320x240像素400 kbps 3MB /分钟
480x270像素700 kbps 5MB /分钟
1024 x 576像素1500 kbps 11MB /分钟
1280x720像素2500 kbps 19MB /分钟
1920x1080像素4000 kbps 30MB /分钟
在大多数情况下,此方法已足够potplayer打不开rtmp,但对于复杂的视频处理仍然缺乏.
例如
对比下图的无处理效果(一种纹理)

对于下一张图片的处理效果(两个屏幕使用与上一张图片相同的大小纹理,尽管我将显示尺寸设置为不同),其编码率约为上一张图片的两倍.

测试服务器
如果需要测试,请设置自己的RTMP服务器. 我使用了自己构建的Nginx服务器,而我使用的模块是nginx-rtmp-module. 您无需编写代码即可构建服务器. 只需根据教程输入几行即可. 您可以使用开源直播软件OBS比较播放效果.
各种播放器,VLC,PotPlayer和ffplay都可以. 我用ffplay. 请注意,由于它只是一台简单的服务器,因此需要在开始开始流式传输之前打开播放器连接. 我使用的命令是. \ Ffplay.exe“ rtmp: // //本地主机: 19305 / live /室内直播= 1”
作者: chillingvan;原始链接:
本文来自电脑杂谈,转载请注明本文网址:
https://www.pc-fly.com/a/bofangqi/article-165938-1.html
我承认我的确也写的一般
也说明了小米肯关注此事
任何一个门槛低的行业