Android 录播

OceanGopro, 纯原生API实现的屏幕录播SDK,支持暂停、局部录制、前置摄像头影像。
github地址:https://github.com/98ki/OceanGopro

Point

视频

帧率,码率,I帧间隔,颜色格式(YUV帧、RGB帧)

编码

硬编码: 用设备GPU去实现编解码,这样可以减轻CPU的压力。 MediaCodecs使用硬编码。 软编码: 让CPU来进行编解码,在c层代码来进行编解码,因为c/c++有很多好的编解码库。FFMPEG 就是软编码。

不同的编码方式又有不同的参数,比如 H264有:Profile(baseline, main, high),Profile Level, Bitrate mode(CBR, CQ, VBR)。 H264还有16位对齐要求,由于h264的编码块大小一般是16x16,于是乎在一开始设置视频的宽高的时候,如果设置了一个没有对齐16的大小,例如960x540,在某些cpu上,最终编码出来的视频就会直接花屏!

软硬编码对比: 硬编的好处主要在于速度快,而且系统自带不需要引入外部的库,但是特性支持有限,而且硬编的压缩率一般偏低,而对于软编码来说,虽然速度较慢,但是压缩率比较高,而且支持的H264特性也会比硬编码多很多,相对来说比较可控。硬编码会受硬件设备支持的影响。

在Android 4.1之前没有提供硬编解码的API,所以基本都是采用开源的那些库,比如著名的FFMpeg实现软编解码。但是通常情况下,同一平台同一硬件环境,硬编码的速度快于软件编码,软编码使用CPU来进行计算,会消耗一些app的运算效率。在Android4.1出来了一个新的API:MediaCodec可以支持硬编解码,MediaCodec可以支持对音频和视频的编解码.

MediaCodec从api16开始提供,它能够访问更底层的多媒体编解码器组件。MediaCodec是更底层的apis,是Android底层多媒体支持基础架构的一部分(通常与MediaExtractor, MediaSync, MediaMuxer, MediaCrypto, MediaDrm, Image, Surface, 以及AudioTrack一起使用)。

MediaCodec

MediaCodec(API level 16),用来处理 Android平台中媒体文件编解码的 API, 经常配合MediaExtractor, MediaSync, MediaMuxer, MediaCrypto, MediaDrm, Image, Surface, 和 AudioTrack使用。
编解码器可以处理三种类型的数据:
* 压缩数据(即为经过H254. H265. 等编码的视频数据或AAC等编码的音频数据)
* 原始音频数据
* 原始视频数据
初始化MediaCodec作为视频的编码器,然后只需要不停传入原始的YUV数据进入编码器就可以直接输出编码好的h264流,整个API设计模型来看,就是同时包含了输入端和输出端的两条队列: 三种类型的数据均可以利用ByteBuffers进行处理,但是对于原始视频数据应提供一个Surface以提高编解码器的性能。Surface直接使用本地视频数据缓存(native video buffers),而没有映射或复制数据到ByteBuffers,因此,这种方式会更加高效。也就是说可以如果需要输入的是原始数据可以利用Surface作为源,这样效率更高。

SurfaceTexture

SurfaceTexture从Android 3.0(API level 11)加入。它对图像流的处理并不直接显示,而是转为GL外部纹理,因此可用于图像流数据的二次处理(如Camera滤镜,桌面特效等)。比如Camera的预览数据,变成纹理后可以交给GLSurfaceView直接显示,也可以通过SurfaceTexture交给TextureView作为View heirachy中的一个硬件加速层来显示。首先,SurfaceTexture从图像流(来自Camera预览,视频解码,GL绘制场景等)中获得帧数据,当调用updateTexImage()时,根据内容流中最近的图像更新SurfaceTexture对应的GL纹理对象,接下来,就可以像操作普通GL纹理一样操作它了。
updateTexImage()
将从图片流中将最近的一帧更新到纹理中。Update the texture image to the most recent frame from the image stream. This may only be * called while the OpenGL ES context that owns the texture is current on the calling thread. * It will implicitly bind its texture to the GLTEXTUREEXTERNAL_OES texture target.

Muxer

MediaMuxer(API level 18),用来合并流,目前支持输出MP4, Webm 和 3GP 文件。

Process Flow Chat

Track Modification

创建一个新的SurfaceTexture,将图片流传输给指定的OpenGL纹理。

mDrawer = new GLDrawer2D(true);  
mTexId = mDrawer.initTex();  
mSourceTexture = new SurfaceTexture(mTexId);  
mSourceSurface = new Surface(mSourceTexture);  

将 mMediaProjection创建的 VirtualDisplay 渲染到mSourceSurface上。

  display = mMediaProjection.createVirtualDisplay(
                "Capturing Display",mWidth, mHeight,mDensity,DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,mSourceSurface, mCallback, mHandler);

注册SurfaceTexture的监听:

mSourceTexture.setOnFrameAvailableListener(mOnFrameAvailableListener, mHandler);  

preparesurfaceencoder 方法返回值是MediaCodec.createInputSurface(), 将mSurface 作为MediaCodec 视频 Track 的输入, 并由此 surface创建EglSurface。

mSurface = prepare_surface_encoder(MIME_TYPE, videoEncodeConfig);

mEncoderSurface = getEgl().createFromSurface(mSurface);

在 SurfaceTexture 的监听回调中,sourceTexture 执行updateTexImage()方法, 将关联的OpenGLES中纹理对象的内容更新为Image Stream中最新的图片,每次updateTexImage()被调用时,纹理矩阵都可能发生变化。所以,每次texture image被更新时,getTransformMatrix ()也应该被调用,来转换纹理坐标。 mTexMatrix是16位的 float,形如(s,t,0,1的)OpenGL ES 二维纹理坐标列向量。

mSourceTexture.updateTexImage();                    mSourceTexture.getTransformMatrix(mTexMatrix);  

SurfaceTexture绘制Surface中接收的图像以输入MediaCodec

mEncoderSurface.makeCurrent();  
mDrawer.draw(mTexId, mTexMatrix, 0);  
mEncoderSurface.swap();  

Android 5.0(Lollipop)中的SurfaceTexture,TextureView, SurfaceView和GLSurfaceView

张鹏宇

继续阅读此作者的更多文章