Android媒体开发 -(2)ExoPlayer高级功能:播放列表与动态资源加载
1. ExoPlayer播放列表基础操作在Android媒体开发中ExoPlayer的播放列表管理功能远比想象中强大。记得我第一次用MediaPlayer实现播放列表时不得不手动处理队列切换和状态同步而ExoPlayer通过ConcatenatingMediaSource和MediaItem的配合让这些操作变得异常简单。构建基础播放列表只需要三行核心代码ListMediaItem mediaItems new ArrayList(); mediaItems.add(MediaItem.fromUri(videoUri1)); mediaItems.add(MediaItem.fromUri(videoUri2)); player.setMediaItems(mediaItems);但实际开发中我们往往需要更灵活的操作。比如动态插入视频到指定位置// 在索引1的位置插入新视频 player.addMediaItem(1, MediaItem.fromUri(newVideoUri));这个操作会触发onTimelineChanged回调我们可以在这里处理UI更新。有次我在直播类App中遇到个坑当用户快速滑动切换视频时如果直接调用setMediaItems会导致画面闪烁。后来改用addMediaItem配合removeMediaItem的增量更新方式体验就流畅多了。循环模式设置也有学问player.setRepeatMode(Player.REPEAT_MODE_ALL); // 列表循环 player.setRepeatMode(Player.REPEAT_MODE_ONE); // 单曲循环实测发现个细节当设置REPEAT_MODE_ONE时如果播放列表只有一项系统会自动优化内存不会重复创建MediaSource。这在小内存设备上特别有用。2. 动态资源加载实战技巧网络视频播放最怕卡顿。ExoPlayer的分块加载机制能边下边播但需要正确配置才能发挥最大效果。先看网络视频的基础加载方式DataSource.Factory dataSourceFactory new DefaultDataSourceFactory( context, Util.getUserAgent(context, YourApp)); ProgressiveMediaSource mediaSource new ProgressiveMediaSource.Factory(dataSourceFactory) .createMediaSource(MediaItem.fromUri(networkVideoUrl));但这样还不够。去年做海外项目时用户反映视频首帧加载慢。通过分析发现是DNS解析耗时后来改用预加载机制优化// 提前创建并缓存MediaSource MediaSource preloadSource new ProgressiveMediaSource.Factory(dataSourceFactory) .setLoadErrorHandlingPolicy(new CustomErrorPolicy()) .createMediaSource(MediaItem.fromUri(preloadUrl)); // 实际播放时直接使用 player.setMediaSource(preloadSource);对于需要鉴权的视频可以通过自定义DataSource实现class AuthDataSource extends DefaultDataSource { Override public long open(DataSpec dataSpec) throws IOException { dataSpec dataSpec.withRequestHeaders(getAuthHeaders()); return super.open(dataSpec); } }遇到过最棘手的问题是视频码率切换。当网络环境变化时ExoPlayer可以自动切换不同清晰度的视频流。这需要配置AdaptiveMediaSourceFormat videoFormat Format.createVideoSampleFormat( null, MimeTypes.VIDEO_H264, null, Format.NO_VALUE, Format.NO_VALUE, 1280, 720, Format.NO_VALUE, null, null); MediaSource mediaSource new DashMediaSource.Factory( new DefaultDashChunkSource.Factory(dataSourceFactory), new DefaultDataSourceFactory(context, YourApp)) .createMediaSource(MediaItem.fromUri(dashManifestUrl));3. 混合资源加载方案实际项目中经常需要同时处理本地和网络资源。比如教育类App可能既有本地缓存的课程视频又有实时更新的在线内容。这时可以用ConcatenatingMediaSource实现无缝衔接ConcatenatingMediaSource concatenatedSource new ConcatenatingMediaSource(); concatenatedSource.addMediaSource(buildLocalSource(localUri)); concatenatedSource.addMediaSource(buildNetworkSource(networkUri));缓存优化是另一个重点。通过配置CacheDataSource可以大幅提升二次播放体验SimpleCache cache new SimpleCache( new File(context.getCacheDir(), mediaCache), new LeastRecentlyUsedCacheEvictor(100 * 1024 * 1024)); // 100MB缓存 CacheDataSource.Factory cacheDataSourceFactory new CacheDataSource.Factory() .setCache(cache) .setUpstreamDataSourceFactory( new DefaultDataSourceFactory(context, Util.getUserAgent(context, YourApp)));我在电商App中实测发现合理设置缓存策略可以使商品视频的重复播放加载时间从1.2秒降至0.3秒。但要注意及时调用cache.release()否则会导致内存泄漏。对于大文件下载场景可以结合DownloadManager实现DownloadRequest request new DownloadRequest.Builder() .setUri(videoUri) .setCustomCacheKey(videoId) // 唯一标识 .setData(byteArray) // 自定义元数据 .build(); downloadManager.enqueue(request);4. 异常处理与性能优化播放器稳定性直接影响用户体验。ExoPlayer的Player.Listener提供了完整的错误监控体系player.addListener(new Player.Listener() { Override public void onPlayerError(PlaybackException error) { int errorCode error.errorCode; if (errorCode PlaybackException.ERROR_CODE_IO_NETWORK_CONNECTION_FAILED) { // 网络异常处理 } else if (errorCode PlaybackException.ERROR_CODE_DECODING_FAILED) { // 解码失败处理 } } });有个容易忽视的细节缓冲策略配置。默认设置在小内存设备上可能引发OOM需要根据设备性能调整DefaultLoadControl loadControl new DefaultLoadControl.Builder() .setBufferDurationsMs( minBufferMs, // 最小缓冲时长(默认50s) maxBufferMs, // 最大缓冲时长(默认50s) bufferForPlaybackMs, // 开始播放时的缓冲时长(默认2.5s) bufferForPlaybackAfterRebufferMs) // 重新缓冲时的缓冲时长(默认5s) .build(); ExoPlayer player new ExoPlayer.Builder(context) .setLoadControl(loadControl) .build();内存泄漏排查经验曾经发现播放器页面退出后内存不释放最终定位是没调用player.release()。现在我的习惯是在onDestroy中统一处理Override protected void onDestroy() { super.onDestroy(); if (player ! null) { player.release(); player null; } if (cache ! null) { cache.release(); } }对于列表播放性能建议监控两个关键指标首帧渲染时间TTFF应控制在500ms内卡顿率Stutter Rate每小时的卡顿次数可以通过AnalyticsListener收集这些数据player.addAnalyticsListener(new EventLogger() { Override public void onVideoSizeChanged(EventTime eventTime, VideoSize videoSize) { // 视频尺寸变化时记录 } });
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2480797.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!