Flutter播放HLS视频触发ExoPlaybackException错误求助
Flutter播放HLS视频遇ExoPlaybackException: Source error的解决思路
问题背景
播放Akamai提供的HLS视频时抛出以下错误:
PlatformException(VideoError, Video player had error com.google.android.exoplayer2.ExoPlaybackException: Source error, null, null)
手动携带{"watchsb": "sbstream"}请求头请求目标m3u8 URL,能正常获取包含TS片段的播放列表,但通过VideoPlayerController.network传入相同URL和请求头仍无法播放。
可能的原因及解决方法
1. 请求头未传递到TS片段请求
HLS播放时,除了主m3u8文件的请求,每个TS片段的请求也需要携带相同的验证头,但默认video_player插件仅会给主m3u8请求添加头,TS片段请求不会自动继承该配置。
解决方式:自定义ExoPlayer的数据源工厂
针对Android平台,直接配置ExoPlayer的HttpDataSource.Factory,让所有请求都带上指定头:
import 'package:video_player/video_player.dart'; import 'package:video_player_android/video_player_android.dart'; import 'package:exoplayer_hls/src/exoplayer.dart'; @override void initState() { super.initState(); final targetUrl = widget.videoFile.data[0].fileUrl; final headers = widget.videoFile.headers; // 创建带全局请求头的数据源工厂 final dataSourceFactory = DefaultHttpDataSource.Factory() ..setDefaultHeaders(headers); // 构建HLS媒体源 final mediaSource = HlsMediaSource.Factory(dataSourceFactory) .createMediaSource(MediaItem.fromUri(Uri.parse(targetUrl))); _controller = VideoPlayerController.network( targetUrl, httpHeaders: headers, ); if (_controller is AndroidVideoPlayerController) { final androidController = _controller as AndroidVideoPlayerController; androidController.updateExoPlayerConfiguration((player) { player.setMediaSource(mediaSource); }); } _controller.initialize().then((_) { _controller.play(); setState(() {}); }).catchError((error) { print('初始化错误详情: $error'); }); }
注意:需要添加video_player_android及对应ExoPlayer相关依赖,版本需与video_player兼容。
2. 验证请求头的正确性
打印widget.videoFile.headers的实际内容,确认键值对完全匹配{"watchsb": "sbstream"}——部分服务器对Header键名的大小写敏感,需确保无格式错误。
调试代码:
@override void initState() { super.initState(); print('请求头内容: ${widget.videoFile.headers}'); // 确认头是否正确 // ... 后续初始化代码 }
3. 捕获详细错误日志
默认的PlatformException仅返回表层错误,添加错误捕获可获取更具体的失败原因(比如403 Forbidden,说明请求头未生效):
_controller.initialize().then((_) { _controller.play(); setState(() {}); }).catchError((error, stackTrace) { print('初始化失败: $error'); print('堆栈信息: $stackTrace'); });
4. 临时测试方案:预加载m3u8内容
先通过http或dio库手动获取m3u8内容,验证是否能正常拿到播放列表,再尝试用VideoPlayerController加载该内容,排除请求头之外的问题:
import 'package:http/http.dart' as http; Future<void> loadVideo() async { final url = widget.videoFile.data[0].fileUrl; final headers = widget.videoFile.headers; final response = await http.get(Uri.parse(url), headers: headers); if (response.statusCode == 200) { _controller = VideoPlayerController.network( url, httpHeaders: headers, ); await _controller.initialize(); _controller.play(); setState(() {}); } }
内容的提问来源于stack exchange,提问作者Omega500
相关产品推荐
相关产品推荐

