项目实战:四大音视频App开发
说实话,到了第30章,我觉得是时候把前面学的所有东西串起来了。你想想看,我们学了采集、编码、推流、播放、传输……这些零散的知识点,最终都要落到具体的App里才有价值。
这一章,我会带你手撸四个项目:短视频录制、直播推流、视频播放器、音视频通话。每个项目我都会讲清楚核心架构,以及我踩过的坑。
一、短视频录制App
短视频录制,说白了就是Camera + MediaCodec + MediaMuxer的组合。我当年第一次做这个功能时,以为很简单——打开相机,录个MP4不就行了?结果踩了一堆坑。
核心架构
关键链路: Camera预览 → 视频编码(H.264) → 音频编码(AAC) → MP4封装
这里我建议用Camera2 API,虽然代码量比Camera1大,但灵活性高很多。特别是你要做美颜、滤镜时,Camera2的SurfaceTexture能让你轻松拿到每一帧。
// 核心代码片段:MediaCodec配置
MediaFormat videoFormat = MediaFormat.createVideoFormat(
MediaFormat.MIME_TYPE_AVC, // H.264
width, height
);
videoFormat.setInteger(MediaFormat.KEY_BIT_RATE, 2_000_000); // 2Mbps
videoFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 30);
videoFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1); // 关键帧间隔1秒
MediaCodec encoder = MediaCodec.createEncoderByType(MediaFormat.MIME_TYPE_AVC);
encoder.configure(videoFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
我的经验:比特率不要设太高。2Mbps对于720p视频已经够用,设高了手机发热严重,而且文件太大。我曾经给客户设了10Mbps,结果录5分钟手机烫得能煎鸡蛋。
避坑指南
- 音视频同步:用MediaCodec的BufferInfo.presentationTimeUs,确保音频和视频的时间戳对齐
- 旋转问题:竖屏录制时,记得在MediaFormat里设置KEY_ROTATION,否则播放出来是横着的
- 内存泄漏:Camera的回调一定要在onPause里释放,我见过太多App切后台后相机还亮着的
二、直播推流App
直播推流和短视频录制最大的区别在于:它没有终点。你要持续不断地把数据发出去,而且延迟要低。
我个人习惯用RTMP协议推流,虽然老,但兼容性好。核心流程是:采集 → 编码 → 打包FLV → RTMP发送。
推流架构图
注意:推流时一定要做断线重连。我曾经有个项目上线后,用户网络一波动就断流,而且不会自动重连,被骂惨了。后来我加了指数退避重连策略,效果好了很多。
关键优化点
| 优化项 | 做法 | 效果 |
|---|---|---|
| 降低延迟 | 减小GOP间隔,设置1秒一个关键帧 | 延迟从3秒降到1秒以内 |
| 抗丢包 | 使用FEC前向纠错 | 丢包率10%时仍可观看 |
| 码率自适应 | 根据网络状况动态调整编码参数 | 弱网下不卡顿 |
三、视频播放器App
播放器看起来简单,不就是MediaPlayer吗?但真正要做得好用,坑多着呢。我建议用ExoPlayer,Google官方维护,支持HLS、DASH,而且扩展性好。
播放器核心能力
- 多协议支持:本地文件、HTTP点播、HLS直播、RTMP
- 硬解/软解切换:有些设备硬解有问题,要能fallback到软解
- 缓存策略:边播边缓存,下次播放秒开
- 手势控制:亮度、音量、进度拖拽
// ExoPlayer基础配置
SimpleExoPlayer player = new SimpleExoPlayer.Builder(context)
.setMediaCodecSelector(new CustomMediaCodecSelector()) // 自定义解码器选择
.build();
MediaItem mediaItem = MediaItem.fromUri(videoUrl);
player.setMediaItem(mediaItem);
player.prepare();
player.play();
我的经验:缓存策略很重要。我做过一个教育类App,用户经常看同一个视频。加了本地缓存后,第二次打开几乎是秒开,用户满意度提升了一大截。
四、音视频通话App
音视频通话是这四个项目里最复杂的。它涉及两个核心问题:一是实时传输,二是回声消除。
我建议直接用WebRTC,别自己造轮子。WebRTC把NAT穿透、抖动缓冲、回声消除都帮你做好了。
WebRTC核心流程
- 信令交换:通过WebSocket交换SDP和ICE候选
- P2P连接:使用ICE框架建立直连
- 媒体协商:协商编解码器、分辨率等参数
- 数据传输:通过SRTP加密传输音视频
// WebRTC PeerConnection创建
PeerConnectionFactory factory = PeerConnectionFactory.builder()
.setVideoEncoderFactory(new DefaultVideoEncoderFactory(eglBase, true, true))
.setVideoDecoderFactory(new DefaultVideoDecoderFactory(eglBase))
.createPeerConnectionFactory();
PeerConnection.RTCConfiguration config = new PeerConnection.RTCConfiguration(iceServers);
PeerConnection connection = factory.createPeerConnection(config, observer);
注意:回声消除是通话质量的命门。WebRTC自带的AEC效果不错,但要注意扬声器和麦克风的距离。我遇到过用户把手机放在桌上开免提,回声特别严重,后来加了自适应滤波器才解决。
项目对比总结
| 项目 | 核心技术 | 难点 | 推荐方案 |
|---|---|---|---|
| 短视频录制 | Camera + MediaCodec + MediaMuxer | 音视频同步、旋转处理 | Camera2 + MediaCodec |
| 直播推流 | 采集 + 编码 + RTMP | 低延迟、断线重连 | librtmp + 自定义编码器 |
| 视频播放器 | ExoPlayer + 缓存 | 多协议支持、硬解兼容性 | ExoPlayer + CacheDataSource |
| 音视频通话 | WebRTC + 信令服务器 | NAT穿透、回声消除 | WebRTC + Socket.IO |
这四个项目,你如果都能完整做一遍,Android音视频这块基本就通了。说实话,我当年也是一个个项目啃过来的,每个项目都踩过不少坑。但正是这些坑,让我真正理解了底层原理。
嗯,最后说一句:代码写完了记得测试弱网环境。很多App在WiFi下跑得飞起,一到4G就卡成PPT。这个坑,我替你踩过了。