1 简介
Yasea是一个Android流媒体客户端。 它将来自摄像机和麦克风的YUV和PCM数据编码为H.264 / AAC,封装在FLV中并通过RTMP传输。
这篇文章的目的是初步了解yasea的流程,为后续优化做铺垫。
分支:
master:主分支,被我修改后,支持min SDK 18.
non-gpuimage:
android-16: Android API 16+.
aac-hev2: for Youtube live broadcast that is not compatible with conventional flash media players.
特性:
[x] Android mini API 21。
[x] H.264 / AAC硬编码。
[x] H.264软编码。
[x] 带状态回调处理程序的RTMP流。
[x] 纵向和横向屏幕方向自动旋转。
[x] 前后摄像头热切换。
[x] 直播时录制到MP4。
[x] GPUImage的美颜滤镜。
[x] 支持回声消除和自动增益控制。
2 工程结构
app模块:
MainActivity:主页
AndroidManifest.xml:声明权限
library模块:
cpp:用Android.mk方式编译C/C++
libenc:jni中间层代码
libx264:用于H264软编码
libyuv:包括YUV缩放和转换功能。
com.coremedia.iso:封装MP4
com.github.faucamp.simplertmp:SimpleRtmp是用于实现RTMP客户端的简单Java库。
com.googlecode.mp4parser:封装MP4
com.seu.magicfilter:滤镜
net.ossrs.yasea:UI层和业务逻辑层
3 总流程
打开camera,在预览的view加滤镜。在SrsPublisher预览回调,在libenc和libyuv进行YUV转换,用x264软编码或MediaCodec硬编码 ,在SrsMp4Muxer保存MP4,SrsFlvMuxer发送RTMP。
4 功能
预览
SrsCameraView:主页,自定义view,初始化camera分辨率、旋转,加滤镜,获取视频原始数据,是RGBA格式。
转换YUV和编码
SrsEncoder:声明native方法,转换和编码。我的手机支持COLOR_FormatYUV420SemiPlanar编码,所以要把yuv转成NV12。
YUV转换:
onSurfaceCreated - onSurfaceChanged - onDrawFrame - mGLIntBufferCache.add, 缓存
mGLIntBufferCache.poll - onGetRgbaFrame - hwRgbaFrame - libenc_RGBAToNV12 - convert_to_i420 - ConvertToI420 - I420Scale - ConvertFromI420
视频编码:onProcessedYuvFrame - onEncodedAnnexbFrame - vencoder.queueInputBuffer - vencoder.dequeueOutputBuffer - onEncodedAnnexbFrame
音频编码:onGetPcmFrame - aencoder.queueInputBuffer - aencoder.dequeueOutputBuffer - onEncodedAacFrame
保存MP4
SrsMp4Muxer:封装MP4?
视频流:onEncodedAnnexbFrame - writeSampleData - writeVideoSample - writeFrameByte - frameCache.add,record - frameCache.poll - writeSampleData,finishMovie
音频流:onEncodedAacFrame - writeSampleData - writeAudioSample - 同上
发送RTMP
SrsPublisher:各种业务逻辑、开关。
SrsFlvMuxer:to POST the h.264/avc annexb frame over RTMP.
SrsFlvFrame:the muxed flv frame.
SrsAllocator.Allocation:分配字节
SrsRawH264Stream:the raw h.264 stream, in annexb.
SrsFlv:remux the annexb to flv tags.
连接RTMP发送视频流:startPublish - mFlvMuxer.start- connect - publisher.publish - mFlvTagCache.poll - sendFlvTag - publisher.publishVideoData
发送前缓存视频流:onEncodedAnnexbFrame - writeSampleData - writeVideoSample - writeH264SpsPps - writeRtmpPacket - flvTagCacheAdd - mFlvTagCache.add
发送前缓存音频流:onEncodedAacFrame - writeSampleData - writeAudioSample - writeRtmpPacket - 同上
FAQ
为什么要封装flv?
为什么要RGBA转I420再转NV12,而不是直接RGBA转NV12?
可以不加滤镜吗?解:看non-gpuimage分支。
……
参考
begeekmyfriend/yasea: RTMP live streaming client for Android
https://github.com/begeekmyfriend/yasea
SEA(适用于Android的流编码器)通过HTTP-FLV将实时流发布到SRS。
yasea 基于 MediaCodec 硬编码 · Issue #31 · begeekmyfriend/yasea
https://github.com/begeekmyfriend/yasea/issues/31
请问摄像头返回的最初的NV21格式的数据在哪里 · Issue #752 · begeekmyfriend/yasea
https://github.com/begeekmyfriend/yasea/issues/752