项目实战:四大音视频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发送。

推流架构图

Camera采集 Mic采集 视频编码(H.264) 音频编码(AAC) 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核心流程

  1. 信令交换:通过WebSocket交换SDP和ICE候选
  2. P2P连接:使用ICE框架建立直连
  3. 媒体协商:协商编解码器、分辨率等参数
  4. 数据传输:通过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。这个坑,我替你踩过了。

公众号:蓝海资料掘金营,微信deep3321