Xamarin C# iOS端通过AVAsset将.mov转码为.mp4报错问题求助
iOS端视频转码路径错误及AVFoundation -11800报错修复方案
核心根因
- 路径拼接错误:通过MediaGallery选中的媒体文件不会默认存储在
Environment.SpecialFolder.Personal目录下,自行拼接路径会导致找不到文件,File.Exists(input)直接返回false - 转码预设不兼容:使用
AVAssetExportSession.PresetPassthrough预设不会做编码转换,仅直接拷贝原文件流,如果原.mov采用了ProRes、ALAC等MP4容器不兼容的编码格式,就会触发-11800通用错误 - 异步逻辑漏洞:原生
ConvertVideo方法标记为async Task但未等待导出完成就返回,上层调用会误认为转码已完成,出现时序问题
修复步骤
1. 修复共享层路径获取逻辑
不要自行拼接输入路径,直接读取MediaPicker返回的文件全路径:
try { MediaPickResult pickresult = await MediaGallery.PickAsync(1, MediaFileType.Video); if (pickresult != null) { foreach (var video in pickresult.Files) { string guid = Guid.NewGuid().ToString(); blobupload.BlobID = guid + ".mp4"; // 直接使用Picker返回的全路径,不要自行拼接 string input = video.FullPath; string output = Path.Combine(AzureStorage.localpath, guid + ".mp4"); if (File.Exists(input)) { await IVideoConverter.ConvertVideo(input, output); } else { System.Diagnostics.Debug.WriteLine($"视频文件不存在,路径:{input}"); } } } } catch (Exception ex) { System.Diagnostics.Debug.WriteLine($"选择视频异常:{ex.Message}"); }
2. 修复iOS原生转码逻辑
替换兼容预设、补全异步等待逻辑和异常校验:
public async Task ConvertVideo(string inputpath, string outputpath) { // 前置校验输入文件 if (!File.Exists(inputpath)) throw new FileNotFoundException("输入视频文件不存在", inputpath); // 清空已存在的输出文件,避免覆盖报错 if (File.Exists(outputpath)) File.Delete(outputpath); AVAsset asset = AVAsset.FromUrl(NSUrl.FromFilename(inputpath)); if (asset == null) throw new InvalidOperationException("无法加载视频为AVAsset"); // 自动匹配兼容的H264编码预设,保证输出MP4安卓可播放,不再使用Passthrough var supportPresets = AVAssetExportSession.GetCompatibleExportPresets(asset, new[] { AVAssetExportSession.PresetH264_1920x1080, AVAssetExportSession.PresetMediumQuality }); var exportPreset = supportPresets.FirstOrDefault() ?? AVAssetExportSession.PresetMediumQuality; AVAssetExportSession export = new AVAssetExportSession(asset, exportPreset); if (export == null) throw new InvalidOperationException("无法创建视频导出会话"); export.OutputUrl = NSUrl.FromFilename(outputpath); export.OutputFileType = AVFileType.Mpeg4; export.ShouldOptimizeForNetworkUse = true; // 将回调式异步转为Task等待,保证方法返回时转码真实完成 var tcs = new TaskCompletionSource<bool>(); export.ExportAsynchronously(() => { if (export.Error != null) { tcs.TrySetException(new NSErrorException(export.Error)); System.Diagnostics.Debug.WriteLine($"导出失败:{export.Error.LocalizedDescription}"); } else if (export.Status == AVAssetExportSessionStatus.Completed) { tcs.TrySetResult(true); } else { tcs.TrySetException(new InvalidOperationException($"导出失败,状态码:{export.Status}")); } }); await tcs.Task; }
补充注意事项
- 若应用适配iOS14及以上版本,需要确认已经申请了相册读取权限,否则选中的文件会出现无权访问的问题
- 导出预设可以根据业务对清晰度的要求调整,要求文件更小可以用
PresetLowQuality,要求更高清晰度可以用PresetH264_3840x2160
内容的提问来源于stack exchange,提问作者BigMarty
相关产品推荐
相关产品推荐

