在我的应用程序中,我试图动态合并视频剪辑。我有两个属性保存上一个记录,然后将下一个记录附加到末尾。这基本上是作为一个暂停功能,然后用户可以即时播放。
我让应用程序将第一个剪辑写入 docs 目录中的“video.mp4”。这被设置为先前的记录。然后我将下一个剪辑写入“video2.mp4”,将其设置为下一个录制,并使用 AVMutableComposition 将它们合并在一起:
AVMutableComposition *mashVideosTogether = [AVMutableComposition composition];
NSError *error;
if([mashVideosTogether insertTimeRange:
CMTimeRangeMake(kCMTimeZero, [self.previousRecording duration])
ofAsset:self.previousRecording
atTime:kCMTimeZero
error:&error]) NSLog(@"Successfully added one");
else NSLog(@"error: %@", error.description);
if([mashVideosTogether insertTimeRange:
CMTimeRangeMake(kCMTimeZero, [self.nextRecording duration])
ofAsset:self.nextRecording
atTime:CMTimeAdd(kCMTimeZero, [self.previousRecording duration])
error:&error]) NSLog(@"Success on 2");
else NSLog(@"error: %@", error.description);
这会附加第一个和第二个视频。然后我将视频导出到“combined.mp4”,当这成功完成后,我删除“video.mp4”处的文件,并将组合视频导出到“video.mp4”(所以此时组合视频存在在两个地方)。这在我的播放器中播放良好。如果用户再次点击录制,则将“video.mp4”处新组合的视频设置为上一次录制,将新录制的剪辑设置为下一次录制,重复整个过程。它们被附加并再次导出以重复该过程。
但是,一旦我添加了第三个(或更多)剪辑,创建的合成中的第一个剪辑就会在播放中变黑。它们的持续时间仍然保持不变,但没有视频或声音。基本上,每当我从旧作品创作新作品时,第一个作品都是空白的,然后唯一保留的就是它们的持续时间和新的录音。当组合物被制成另一个组合物时,这些数据是否会丢失?我需要手动将它们添加为曲目吗?任何帮助表示赞赏!
解决了
我阅读了 Apple 的 AVEditDemo,似乎我最初的假设是正确的——当我单独使用 AVMutableComposition 将视频附加在一起时(也就是不创建单独的轨道文件并合并它们),这些轨道的数据在添加到另一个时丢失了作品。
所以我只是为每个剪辑的音频和视频创建了单独的轨道来合并它们,现在我有一个工作设置,我可以动态地拍摄视频,停止,然后再次开始拍摄,它们将在运行中连接起来。
if(self.previousRecording && self.nextRecording) {
NSArray *assetArray = [NSArray arrayWithObjects:
self.previousRecording, self.nextRecording, nil];
NSURL *fileURL = [self getURLWithPathComponent:@"combined.mp4"];
AVMutableComposition *mashVideosTogether = [AVMutableComposition composition];
NSError *error;
CMTime nextClipStartTime = kCMTimeZero;
AVMutableCompositionTrack *compositionVideoTrack =
[mashVideosTogether addMutableTrackWithMediaType:AVMediaTypeVideo
preferredTrackID:kCMPersistentTrackID_Invalid];
AVMutableCompositionTrack *compositionAudioTrack =
[mashVideosTogether addMutableTrackWithMediaType:AVMediaTypeAudio
preferredTrackID:kCMPersistentTrackID_Invalid];
for(int i=0; i<[assetArray count]; i++) {
AVURLAsset *asset = [assetArray objectAtIndex:i];
CMTimeRange timeRangeInAsset = CMTimeRangeMake(kCMTimeZero, [asset duration]);
AVAssetTrack *clipVideoTrack =
[[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
[compositionVideoTrack insertTimeRange:timeRangeInAsset
ofTrack:clipVideoTrack atTime:nextClipStartTime error:nil];
AVAssetTrack *clipAudioTrack =
[[asset tracksWithMediaType:AVMediaTypeAudio]objectAtIndex:0];
[compositionAudioTrack insertTimeRange:timeRangeInAsset
ofTrack:clipAudioTrack atTime:nextClipStartTime error:nil];
nextClipStartTime = CMTimeAdd(nextClipStartTime, timeRangeInAsset.duration);
}
//do exports down here and then reset previous recording, etc.
}