如何在视频A指定帧/时长后插入视频B?AVMutableComposition可行吗?
Great question—yes, AVMutableComposition absolutely supports this exact use case, and you don’t need to jump through hoops manually splitting Video A into two separate files first. The framework handles segmenting the original video clips based on time ranges, so you can build the desired timeline cleanly in code.
Here’s a step-by-step breakdown tailored to your scenario:
1. Capture the Key Time Point
When the user pauses Video A, record the exact pause time as a CMTime value. This is your insertion marker—let’s call it insertionTime.
2. Set Up Your Assets
First, get AVAsset instances for both Video A and Video B (you’d typically load these from the user’s media library or local file system):
let videoA = AVAsset(url: URL(fileURLWithPath: "path/to/videoA.mp4")) let videoB = AVAsset(url: URL(fileURLWithPath: "path/to/videoB.mp4"))
3. Build the Composition Timeline
Create an AVMutableComposition and add segmented clips of Video A, followed by Video B, followed by the remaining part of Video A:
let composition = AVMutableComposition() // Create mutable tracks for video and audio (match the original assets' media types) guard let videoTrack = composition.addMutableTrack(withMediaType: .video, preferredTrackID: kCMPersistentTrackID_Invalid), let audioTrack = composition.addMutableTrack(withMediaType: .audio, preferredTrackID: kCMPersistentTrackID_Invalid), let videoATrack = videoA.tracks(withMediaType: .video).first, let audioATrack = videoA.tracks(withMediaType: .audio).first, let videoBTrack = videoB.tracks(withMediaType: .video).first, let audioBTrack = videoB.tracks(withMediaType: .audio).first else { // Handle missing tracks error return } // Define time ranges for each segment let videoAPreRange = CMTimeRange(start: .zero, end: insertionTime) let videoBFullRange = CMTimeRange(start: .zero, end: videoB.duration) let videoAPostRange = CMTimeRange(start: insertionTime, end: videoA.duration) // Add segments to the composition tracks (video first, then audio) do { try videoTrack.insertTimeRange(videoAPreRange, of: videoATrack, at: .zero) try videoTrack.insertTimeRange(videoBFullRange, of: videoBTrack, at: insertionTime) try videoTrack.insertTimeRange(videoAPostRange, of: videoATrack, at: insertionTime + videoB.duration) // Repeat for audio tracks to keep sync try audioTrack.insertTimeRange(videoAPreRange, of: audioATrack, at: .zero) try audioTrack.insertTimeRange(videoBFullRange, of: audioBTrack, at: insertionTime) try audioTrack.insertTimeRange(videoAPostRange, of: audioATrack, at: insertionTime + videoB.duration) } catch { // Handle insertion error print("Error inserting tracks: \(error.localizedDescription)") }
4. Export the Final Composition
Use AVAssetExportSession to render the composition into a single video file:
guard let exportSession = AVAssetExportSession(asset: composition, presetName: AVAssetExportPresetHighestQuality) else { // Handle export session creation error return } exportSession.outputURL = URL(fileURLWithPath: "path/to/finalVideo.mp4") exportSession.outputFileType = .mp4 exportSession.shouldOptimizeForNetworkUse = true exportSession.exportAsynchronously { switch exportSession.status { case .completed: // Success! Use the output URL print("Export completed successfully") case .failed, .cancelled: // Handle failure/cancellation print("Export failed: \(exportSession.error?.localizedDescription ?? "Unknown error")") default: break } }
Why This Works (And Why You Don’t Need to Split Video A)
Unlike some basic video merging examples that just append one clip to the end, AVMutableComposition operates on a timeline of time ranges. It doesn’t modify your original video files—it just references the segments you specify. So splitting Video A into "pre-insertion" and "post-insertion" segments is done entirely within the composition, no need to create separate physical files first.
This approach is efficient, flexible, and exactly what Apple’s AVFoundation framework is designed for.
内容的提问来源于stack exchange,提问作者Bogdan R

