我正在研究播放视频并允许用户在视频中向前和向后擦除的应用程序。清理过程必须顺利进行,因此我们总是使用SDAVAssetExportSession
重新编写视频压缩属性为AVVideoMaxKeyFrameIntervalKey:@1
的视频,以便每个帧都将成为关键帧并允许平滑的反向清理。这很好,并提供流畅的播放。该应用程序使用来自各种来源的视频,可以在Android或iOS设备上录制,甚至可以从网上下载并添加到应用程序中,因此我们最终得到的编码格式完全不同,其中一些编码已经适用于清理(每帧是一个关键帧)。有没有办法检测视频文件的关键帧间隔,以避免不必要的视频处理?我经历了AVFoundation的大部分文档,并没有看到获取这些信息的明显方法。感谢您的帮助。在AVAsset中检测当前关键帧间隔
回答
如果您可以通过创建AVAssetReaderTrackOutput
而无需对图像进行解码来快速解析文件,并且无outputSettings
。你遇到的帧样本缓冲区有一个附件数组,包含一个包含有用信息的字典,包括该帧是依赖于其他帧还是依赖于其他帧。我会将前者解释为指示关键帧,尽管它给了我一些较低的数字(一个文件中的关键帧为4%?)。无论如何,代码:
let asset = AVAsset(url: inputUrl)
let reader = try! AVAssetReader(asset: asset)
let videoTrack = asset.tracks(withMediaType: AVMediaTypeVideo)[0]
let trackReaderOutput = AVAssetReaderTrackOutput(track: videoTrack, outputSettings: nil)
reader.add(trackReaderOutput)
reader.startReading()
var numFrames = 0
var keyFrames = 0
while true {
if let sampleBuffer = trackReaderOutput.copyNextSampleBuffer() {
// NB: not every sample buffer corresponds to a frame!
if CMSampleBufferGetNumSamples(sampleBuffer) > 0 {
numFrames += 1
if let attachmentArray = CMSampleBufferGetSampleAttachmentsArray(sampleBuffer, false) as? NSArray {
let attachment = attachmentArray[0] as! NSDictionary
// print("attach on frame \(frame): \(attachment)")
if let depends = attachment[kCMSampleAttachmentKey_DependsOnOthers] as? NSNumber {
if !depends.boolValue {
keyFrames += 1
}
}
}
}
} else {
break
}
}
print("\(keyFrames) on \(numFrames)")
N.B.这仅适用于本地文件资产。
p.s.你不会说你如何洗刷或玩耍。一个AVPlayerViewController
和一个AVPlayer
?
下面是相同答案的Objective C版本。在实现并使用它之后,应该包含所有关键帧的视频将从此代码返回大约96%的关键帧。我不确定为什么,所以我使用这个数字作为决定因素,尽管我希望它更准确。我也只是通过前600帧或视频结尾(以先到者为准),因为我不需要通读整个20分钟的视频来做出这个决定。
+ (BOOL)videoNeedsProcessingForSlomo:(NSURL*)fileUrl {
BOOL needsProcessing = YES;
AVAsset* anAsset = [AVAsset assetWithURL:fileUrl];
NSError *error;
AVAssetReader *assetReader = [AVAssetReader assetReaderWithAsset:anAsset error:&error];
if (error) {
DLog(@"Error:%@", error.localizedDescription);
return YES;
}
AVAssetTrack *videoTrack = [[anAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
AVAssetReaderTrackOutput *trackOutput = [AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack:videoTrack outputSettings:nil];
[assetReader addOutput:trackOutput];
[assetReader startReading];
float numFrames = 0;
float keyFrames = 0;
while (numFrames < 600) { // If the video is long - only parse through 20 seconds worth.
CMSampleBufferRef sampleBuffer = [trackOutput copyNextSampleBuffer];
if (sampleBuffer) {
// NB: not every sample buffer corresponds to a frame!
if (CMSampleBufferGetNumSamples(sampleBuffer) > 0) {
numFrames += 1;
NSArray *attachmentArray = ((NSArray*)CMSampleBufferGetSampleAttachmentsArray(sampleBuffer, false));
if (attachmentArray) {
NSDictionary *attachment = attachmentArray[0];
NSNumber *depends = attachment[(__bridge NSNumber*)kCMSampleAttachmentKey_DependsOnOthers];
if (depends) {
if (depends.boolValue) {
keyFrames += 1;
}
}
}
}
}
else {
break;
}
}
needsProcessing = keyFrames/numFrames < 0.95f; // If more than 95% of the frames are keyframes - don't decompress.
return needsProcessing;
}
对不起 - 我不知道你使用的是目标c,这个问题没有标记 –
不用担心,对我来说语言无关紧要。感谢您的帮助。我有类似的东西,并通过大量的文档阅读,但不知道kCMSampleAttachmentKey_DependsOnOther可用于确定这一点。 – johnrechd
- 1. 检测RTP流中的VP8关键帧(I帧)
- 2. chrome.idle:如何查询当前检测间隔?
- 3. 在Maya中的属性上设置关键帧时检测?
- 4. 检索当前帧号
- 5. as3当前帧检查
- 6. 检查时间间隔之间的当前时间android
- 7. 如何设置RTMFP流的关键帧间隔?
- 8. 无法更改视频关键帧间隔使用的ffmpeg
- 9. 使用安卓相机更改关键帧间隔
- 10. 关键字检测
- 11. 在关键帧动画之间暂停
- 12. 当我在UITextView中时,如何检测键盘关闭?
- 13. 在Matlab中的SIFT关键点检测
- 14. 如何在Android中检查当前时间是否与未来有间隔?
- 15. 在一系列时间间隔中搜索当前时间
- 16. 处理AVAsset中的所有帧
- 17. 使用当前背景颜色的CSS关键帧动画
- 18. matplotlib FuncAnimation帧间隔
- 19. 使用JQuery事件检测特定CSS关键帧动画
- 20. 使用JavaScript检测特定的CSS3关键帧
- 21. 使用WMASFWriter生成在每个关键帧间隔处暂停的视频
- 22. 在PostgreSQL中添加间隔到当前时间戳
- 23. angularjs:检测时,当在中间
- 24. 如何在关注控件之前检测keydown键
- 25. XCUItest:检测当前SKView
- 26. 检测当前页面
- 27. 检测当前标签
- 28. 。ActionScript 3中的当前帧
- 29. Swift:检测UIWebView中的当前URL
- 30. 间隔由STARTDATE当前日期后
感谢您的回答。我今天实施了这个(目标c虽然)。我正在使用AVPlayer和AVPlayerLayer的自定义UIView。这似乎相当准确,并返回我编码为使用所有关键帧的视频中大约96%的关键帧。其他压缩设置的视频少得多。 Scrubber是一个滚轮(scrollView),它将滚动速度转换为逐步扫描一帧的擦洗循环。我可以将我的方法作为Q的答案发布,如果我这样做,我会链接。我也会发布这个Objective C版本。 – johnrechd
酷!我期待着看到它。奇怪的是4%的失踪。我想知道可能的解释。 –