源码下载
不愿意看博客,上来就想抄的,尽情开始吧
RtmpPusher.zip
想了解下原理,和大概流程的,请继续往下看
通过本Demo可以学到的知识点
如何选择最合适的摄像头分辨率
安卓摄像头画面采集方向和预览方向的区别
预览画面时,如何正确旋转预览数据
推流画面时,如何正确旋转采集数据
SurfaceView的生命周期
Surface发生改变时(比如横竖屏切换),如何调整预览和推流工作
摄像头切换时,如何调整预览和推流工作
YUV画面旋转和翻转
RTMP和FLV数据包格式
如何将AAC音频数据封装为RTMPPacket
如何将YUV视频数据封装为RTMPPacket
如何通过librtmp推送音视频数据
推流器初始化,开始,暂停,销毁流程如何设计
推流时断线如何重连
整体流程 / PlayActivity
- 创建和初始化native接口RtmpPusher
- 创建EventListener,用于处理事件回调
- 创建AudioRecordHandler,用于录音和推音频数据
- 创建CameraPreviewHandler,用于预览和推视频数据
- 将EventListener设置给AudioRecordHandler,CameraPreviewHandler
- 调用RtmpPusher.setAudioEncodeInfo通知native层音频参数
- 调用AudioRecordHandler.setAudioEncodeInfo设置录音时的音频参数
- 调用AudioRecordHandler.start开始录音
- SurfaceView.onCreate触发时,调用创建CameraPreviewHandler.startPreview启动Camera,调用CameraPreviewHandler.setPreviewDisplay开始预览
- SurfaceView.surfaceChanged触发时,调用CameraPreviewHandler.stopPreview停止旧的Camera,再重启新的Camera和预览
- SurfaceView.surfaceDestroyed触发时,调用CameraPreviewHandler.stopPreview停止Camera
- 屏幕方向发生变化时,调用CameraPreviewHandler.setPreviewOrientation来刷新预览方向
- Activity.onDestroy触发时,调用创建AudioRecordHandler.stop停止录音,调用CameraPreviewHandler.stopPreview停止Camera
录音流程 / AudioRecordHandler
- AudioRecordHandler.setAudioEncodeInfo,设置录音参数,采样率,通道数,单次解码样本数
- AudioRecordHandler.start,创建AudioRecord,用于录音
- AudioRecord.read,创建线程,循环从AudioRecord读取录制数据,并转交给EventListener处理
- AudioRecordHandler.stop,停止录音线程,同时销毁AudioRecord,录音结束
视频采集流程 / CameraPreviewHandler
- CameraPreviewHandler.startPreview,开始预览
- – Camera.setParameters,设置摄像头采集和预览参数
- – 调用EventListener.onVideoParamChange,通知native层视频参数改变
- – 调用Camera.setPreviewCallback,监听预览数据
- – 调用Camera.startPreview,启动摄像头预览
- – 调用CameraPreviewHandler.setPreviewOrientation,设置预览图像显示方向
- CameraPreviewHandler.setPreviewDisplay,设置用于显示预览图像的Surface
- Camera.PreviewCallback回调执行,将帧数据转交给EventListener处理
- EventListener将视频数据推给RtmpPusher
- CameraPreviewHandler.switchCamera,切换摄像头
- – 根据Camera的FaceInfo,切换新的Camera
- – 调用EventListener.onCameraSwitch,重启摄像头预览
- Activity方向改变,重启摄像头预览,重新设置预览方向
- CameraPreviewHandler.stopPreview,停止预览,并释放Camera
RTMP推流流程 / RtmpPusher
- 调用RtmpPusher.initialize,初始化AudioChannel,VideoChannel,PacketQueue
- 调用AudioChannel.setAudioEncodeInfo,设置音频参数
- – 调用libaac.faacEncOpen,创建AAC编码器
- – 调用libaac.faacEncSetConfiguration,设置AAC编码器参数
- 调用VideoChannel.setVideoEncodeInfo,设置视频参数
- – 调用libx264.x264_param_default_preset和libx264.x264_param_apply_profile,创建H264编码配置
- – 调用libx264.x264_encoder_open,创建H264编码器
- – 调用libx264.x264_picture_alloc,分配一个H264编码输出缓存区
- 调用RtmpPusher.prepare,设置URL,连接服务器
- – 调用librtmp.RTMP_Alloc,创建RTMP对象
- – 调用librtmp.RTMP_Init,初始化RTMP对象
- – 调用librtmp.RTMP_SetupURL,设置RTMP地址
- – 配置rtmp.Link.timeout,设置RTMP超时时间
- – 调用librtmp.RTMP_EnableWrite,设置RTMP为推流模式,另一个模式是取流模式
- – 调用librtmp.RTMP_Connect,连接RTMP服务器
- – 调用librtmp.RTMP_ConnectStream,连接RTMP流
- – 调用librtmp.RTMP_GetTime,记录开始的时间戳
- – 创建push线程
- 调用libaac.faacEncGetDecoderSpecificInfo,创建AudioSpecificConfig,封装为RTMPPacket,作为首个数据包推送给服务器
- push线程不断从PacketQueue中取出RTMPPacket,推送给RTMP服务器
- 调用RtmpPusher.pushAudioFrame,向native层推送PCM音频数据
- – 调用libaac.faacEncEncode,将PCM编码为AAC裸数据,再封装为RTMPPacket,放入PacketQueue
- 调用RtmpPusher.pushVideoFrame,向native层推送NV21视频数据
- – 将NV21字节,转换为I420字节,拷贝到输出缓存区
- – 调用libx264.x264_encoder_encode,将I420编码为H264
- – 将H264封装为RTMPPacket,放入PacketQueue
- – SPS和PPS帧封装为一个Packet,其它Slice帧封装为一个Packet
- 调用RtmpPusher.pause,暂停PacketQueue推流工作
- 调用RtmpPusher.resume,恢复PacketQueue推流工作
- 调用RtmpPusher.release
- – 停止PacketQueue,结束push线程,释放RTMP对象
摄像头预览角度,和推流画面旋转角度的控制方法