Flutter video_thumbnail旧iOS设备生成缩略图失败求助
问题场景
使用video_thumbnail: ^0.5.3 Flutter包生成视频首帧时,旧iOS设备在加载缩略图列表(即使是同一URL)时多数缩略图无法加载,Android设备无此问题。
代码示例
Future<Uint8List?> generateThumbnail(String videoUrl) async { try { final thumbnail = await VideoThumbnail.thumbnailData(video: 'https://sample-videos.com/video123/mp4/720/big_buck_bunny_720p_30mb.mp4'); return thumbnail; } catch (e) { if (kDebugMode) { print('Error generating thumbnail: $e'); } return null; } }
报错信息
couldn't generate thumbnail, error:Error Domain=AVFoundationErrorDomain Code=-11800 "The operation could not be completed" UserInfo={NSLocalizedFailureReason=An unknown error occurred (-12792), NSLocalizedDescription=The operation could not be completed, NSUnderlyingError=0x283be6730 {Error Domain=NSOSStatusErrorDomain Code=-12792 "(null)"}}
关键信息
- 仅iOS设备出现该问题
- 仅旧设备会触发
- 视频文件未损坏
- 加载同一URL的多个缩略图时,部分成功部分失败
- 已尝试卸载重建应用,无效
- Android设备无此问题
解决方案
1. 限制并发请求数
旧iOS设备的AVFoundation资源池有限,批量生成时并发请求过多会导致资源耗尽。可以用信号量控制并发数:
// 先添加semaphore依赖:semaphore: ^0.1.0 import 'package:semaphore/semaphore.dart'; final _semaphore = Semaphore(2); // 控制同时处理2个请求 Future<Uint8List?> generateThumbnail(String videoUrl) async { return _semaphore.acquire(() async { try { return await VideoThumbnail.thumbnailData( video: videoUrl, imageFormat: ImageFormat.JPEG, maxHeight: 100, maxWidth: 100, quality: 75, ); } catch (e) { if (kDebugMode) print('生成缩略图失败: $e'); return null; } }); }
2. 降低缩略图资源消耗
明确指定缩略图的尺寸和质量,减少AVFoundation处理时的内存占用:
final thumbnail = await VideoThumbnail.thumbnailData( video: videoUrl, imageFormat: ImageFormat.JPEG, maxHeight: 100, // 根据需求调整 maxWidth: 100, quality: 70, );
3. 缓存已生成的缩略图
同一URL无需重复生成,用内存缓存避免重复请求:
final _thumbnailCache = <String, Uint8List?>{}; Future<Uint8List?> generateThumbnail(String videoUrl) async { if (_thumbnailCache.containsKey(videoUrl)) { return _thumbnailCache[videoUrl]; } try { final thumbnail = await VideoThumbnail.thumbnailData( video: videoUrl, imageFormat: ImageFormat.JPEG, maxHeight: 100, maxWidth: 100, ); _thumbnailCache[videoUrl] = thumbnail; return thumbnail; } catch (e) { if (kDebugMode) print('生成缩略图失败: $e'); _thumbnailCache[videoUrl] = null; return null; } }
4. 先下载视频到本地再生成缩略图
旧iOS设备处理远程视频缩略图容易出错,先下载到临时目录再处理:
import 'package:path_provider/path_provider.dart'; import 'dart:io'; import 'dart:typed_data'; Future<Uint8List?> generateThumbnail(String videoUrl) async { try { final tempDir = await getTemporaryDirectory(); final fileName = Uri.parse(videoUrl).pathSegments.last; final tempFile = File('${tempDir.path}/$fileName'); if (!await tempFile.exists()) { final client = HttpClient(); final request = await client.getUrl(Uri.parse(videoUrl)); final response = await request.close(); final bytes = await response.expand((b) => b).toList(); await tempFile.writeAsBytes(bytes); client.close(); } return await VideoThumbnail.thumbnailData( video: tempFile.path, imageFormat: ImageFormat.JPEG, maxHeight: 100, maxWidth: 100, ); } catch (e) { if (kDebugMode) print('生成缩略图失败: $e'); return null; } }
5. 适配旧iOS系统
AVFoundation在iOS 12及以下版本对远程视频缩略图支持有限,可针对旧版本做降级处理,比如用WebView加载视频并截图,或者提示用户升级系统。
内容的提问来源于stack exchange,提问作者genericUser

