AVCaptureMovieFileOutput -- 写入时修剪文件
我正在使用 AVCaptureMovieFileOutput 录制视频。然而,我只想保留最后 2 分钟的视频,而不是在整个录制时间内保留捕获的视频。本质上,我想创建一个视频的尾随缓冲区。
我尝试通过将 movieFragmentInterval 设置为 15 秒来实现此目的。由于缓冲了这 15 秒,因此将使用以下代码修剪 MOV 文件的前 15 秒:
//This would be called 7 seconds after the video stream started buffering.
-(void)startTrimTimer
{
trimTimer = [NSTimer scheduledTimerWithTimeInterval:15 target:self selector:@selector(trimFlashbackBuffer) userInfo:nil repeats:YES];
}
-(void)trimFlashbackBuffer
{
//make sure that there is enough video before trimming off 15 seconds
if(trimReadyCount<3){
trimReadyCount++;
return;
}
AVURLAsset *videoAsset = [AVURLAsset URLAssetWithURL:[NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/flashbackBuffer.MOV",tripDirectory]] options:nil];
AVAssetExportSession *exportSession = [[AVAssetExportSession alloc] initWithAsset:videoAsset presetName:AVAssetExportPresetHighestQuality];
exportSession.outputURL = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/flashbackBuffer.MOV",tripDirectory]];
exportSession.outputFileType = AVFileTypeQuickTimeMovie;
CMTimeRange timeRange = CMTimeRangeMake(CMTimeMake(15000, 1000), CMTimeMake(120000, 1000));
exportSession.timeRange = timeRange;
[exportSession exportAsynchronouslyWithCompletionHandler:^{
switch (exportSession.status) {
case AVAssetExportSessionStatusCompleted:
// Custom method to import the Exported Video
[self loadAssetFromFile:exportSession.outputURL];
break;
case AVAssetExportSessionStatusFailed:
//
NSLog(@"Failed:%@",exportSession.error);
break;
case AVAssetExportSessionStatusCancelled:
//
NSLog(@"Canceled:%@",exportSession.error);
break;
default:
break;
}
}];
}
但是,每次调用 trimFlashbackBuffer
时我都会收到以下错误:
Failed:Error Domain=AVFoundationErrorDomain Code=-11823 "Cannot Save" UserInfo=0x12e710 {NSLocalizedRecoverySuggestion=Try saving again., NSLocalizedDescription=Cannot Save}
这是因为该文件已经是被 AVCaptureMovieFileOutput
写入?
如果此方法不起作用,如何才能实现无缝尾部视频缓冲区的效果?
谢谢!
I am recording video using AVCaptureMovieFileOutput
. Instead of retaining the captured video for the entire recording time, however, I would like only to retain the last 2 minutes of video. In essence, I would like to create a trailing buffer of video.
I have tried to implement this by setting movieFragmentInterval
equal to 15 seconds. As these 15 seconds buffered, the first 15 seconds of the MOV file would be trimmed off using this code:
//This would be called 7 seconds after the video stream started buffering.
-(void)startTrimTimer
{
trimTimer = [NSTimer scheduledTimerWithTimeInterval:15 target:self selector:@selector(trimFlashbackBuffer) userInfo:nil repeats:YES];
}
-(void)trimFlashbackBuffer
{
//make sure that there is enough video before trimming off 15 seconds
if(trimReadyCount<3){
trimReadyCount++;
return;
}
AVURLAsset *videoAsset = [AVURLAsset URLAssetWithURL:[NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/flashbackBuffer.MOV",tripDirectory]] options:nil];
AVAssetExportSession *exportSession = [[AVAssetExportSession alloc] initWithAsset:videoAsset presetName:AVAssetExportPresetHighestQuality];
exportSession.outputURL = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/flashbackBuffer.MOV",tripDirectory]];
exportSession.outputFileType = AVFileTypeQuickTimeMovie;
CMTimeRange timeRange = CMTimeRangeMake(CMTimeMake(15000, 1000), CMTimeMake(120000, 1000));
exportSession.timeRange = timeRange;
[exportSession exportAsynchronouslyWithCompletionHandler:^{
switch (exportSession.status) {
case AVAssetExportSessionStatusCompleted:
// Custom method to import the Exported Video
[self loadAssetFromFile:exportSession.outputURL];
break;
case AVAssetExportSessionStatusFailed:
//
NSLog(@"Failed:%@",exportSession.error);
break;
case AVAssetExportSessionStatusCancelled:
//
NSLog(@"Canceled:%@",exportSession.error);
break;
default:
break;
}
}];
}
However, I am receiving the following error every time trimFlashbackBuffer
is called:
Failed:Error Domain=AVFoundationErrorDomain Code=-11823 "Cannot Save" UserInfo=0x12e710 {NSLocalizedRecoverySuggestion=Try saving again., NSLocalizedDescription=Cannot Save}
Is this because the file is already being written to by AVCaptureMovieFileOutput
?
How could I achieve the effect of a seamless trailing video buffer, if this method cannot work?
Thanks!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
不确定您在这里想要实现的目标是否有效,这是因为就像您所说的,您在尝试修剪文件的同时编写文件,为什么不能录制视频并稍后修剪它?如果你真的想随时保留两分钟的视频,你可能想尝试使用 AVCaptureVideoDataOutput,使用它你将获得视频帧,你可以使用 AVAssetWriter 将其写入压缩并将帧写入文件,请查看此SO讨论如何做到这一点的问题 通过 AVAssetWriter 和 AVAssetWriterInputs 编写视频+音频的代码是不工作。为什么?
not sure that what you trying to achieve here will work, this is because like you said, you are writing the file while trying to trim it, why cant you record the video and trim it later? If you really want to just keep two minutes of videos at any time you might want to try using AVCaptureVideoDataOutput,using this you will get video frames and you can use AVAssetWriter to write it to compress and write frames to a file, check out this SO question which talks about how to do that This code to write video+audio through AVAssetWriter and AVAssetWriterInputs is not working. Why?
我怀疑您收到的错误是因为您试图覆盖导出 URL 中的同一文件。
该文档称“如果您尝试覆盖现有文件,或在应用程序沙箱之外写入文件,导出将会失败。如果需要覆盖现有文件,则必须先将其删除。”
要获取视频的最后两分钟,您可能需要首先使用另一个异步调用 loadValuesAsynchronouslyForKeys 获取其持续时间。使用此持续时间,您可以创建时间范围并通过将视频导出到不同的 URL 来修剪视频。
I suspect the error you are getting is because you are trying to overwrite the same file as in the export URL.
The documentation says "The export will fail if you try to overwrite an existing file, or write a file outside of the application’s sandbox. If you need to overwrite an existing file, you must remove it first."
To get the last two minutes of the video, you might want to obtain it's duration first using loadValuesAsynchronouslyForKeys which is another asynchronous call. Using this duration, you can create a time range and trim the video by exporting it to a different URL.