Xamarin iOS中AVAssetExportSession转MOV为MP4时视频末尾截断的解决方法
Fixing Truncated MP4 Exports in Xamarin iOS with AVAssetExportSession
I’ve run into this exact issue before—truncated video exports usually happen because the AVAsset isn’t fully loaded before we start the export process, or there’s a lack of proper error checking for the export session’s final status. Let’s walk through the fixes step by step:
Common Causes & Solutions
- Incomplete Asset Loading: When you create an
AVAssetfrom a file URL, it doesn’t immediately load all metadata (like full video duration). Starting the export too early can lead to the session using incomplete duration data, resulting in a truncated output. - Missing Export Status Checks: Your original code only waits for the export task to finish but doesn’t verify if it succeeded. A failed export might leave you with a partial file without warning.
- Network Optimization Conflicts: The
ShouldOptimizeForNetworkUseflag can sometimes cause unexpected truncation on certain video files, especially those with non-standard encoding.
Modified Working Code
Here’s your updated code incorporating these fixes:
var basePath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); var inputFilePath = Path.Combine(basePath, Path.ChangeExtension(_vm.Model.AnswerName, "mov")); var outputFilePath = Path.Combine(basePath, $"{_vm.Model.AnswerName}.mp4"); // Explicitly add .mp4 extension // Create asset and wait for critical metadata to load fully var asset = AVAsset.FromUrl(NSUrl.FromFilename(inputFilePath)); var loadStatus = asset.LoadValuesAsynchronously(new string[] { "tracks" }, out NSError loadError); if (loadStatus != AVKeyValueStatus.Loaded) { System.Diagnostics.Debug.WriteLine($"Failed to load asset metadata: {loadError?.LocalizedDescription}"); return; } // Initialize export session and validate it AVAssetExportSession exportSession = new AVAssetExportSession(asset, AVAssetExportSession.PresetHighestQuality); if (exportSession == null) { System.Diagnostics.Debug.WriteLine("Export session could not be created (unsupported preset or asset type)"); return; } exportSession.OutputUrl = NSUrl.FromFilename(outputFilePath); exportSession.OutputFileType = AVFileType.Mpeg4; exportSession.ShouldOptimizeForNetworkUse = false; // Disable if truncation persists exportSession.TimeRange = new CMTimeRange(CMTime.Zero, asset.Duration); // Explicitly set full video range try { await exportSession.ExportTaskAsync(); // Use await instead of Wait() to avoid deadlocks // Check export status and handle results switch (exportSession.Status) { case AVAssetExportSessionStatus.Completed: System.Diagnostics.Debug.WriteLine("Export completed successfully!"); // Delete original MOV file only if export succeeded var fileHelper = new FileHelper(); var originalMovPath = Path.Combine(basePath, Path.ChangeExtension(_vm.Model.AnswerName, "mov")); if (fileHelper.FileExists(originalMovPath)) { fileHelper.DeleteFile(originalMovPath); } break; case AVAssetExportSessionStatus.Failed: System.Diagnostics.Debug.WriteLine($"Export failed: {exportSession.Error?.LocalizedDescription}"); // Clean up partial output file if (File.Exists(outputFilePath)) File.Delete(outputFilePath); break; case AVAssetExportSessionStatus.Cancelled: System.Diagnostics.Debug.WriteLine("Export was cancelled"); break; } } catch (Exception ex) { System.Diagnostics.Debug.WriteLine($"Export exception: {ex.Message}"); // Clean up partial output file if (File.Exists(outputFilePath)) File.Delete(outputFilePath); }
Key Improvements
- Explicit File Extension: Adding
.mp4to the output path avoids ambiguity with file type associations. - Async/Await: Replacing
Wait()withawaitprevents potential deadlocks in async code. - Full Time Range: Explicitly setting
TimeRangeensures the export session uses the complete video duration. - Comprehensive Error Handling: Checking the export session’s
Statusgives clear feedback on success or failure, plus cleanup of partial files when things go wrong.
内容的提问来源于stack exchange,提问作者Prachi Karapurkar
相关产品推荐
相关产品推荐

