저는 비디오를 재생하고 사용자가 비디오에서 앞뒤로 문질러 쓸 수있는 응용 프로그램을 만들고 있습니다. 스크러빙이 원활하게 이루어져야하므로 비디오 압축 속성이 AVVideoMaxKeyFrameIntervalKey:@1
인 SDAVAssetExportSession
으로 비디오를 다시 쓰면 각 프레임이 키 프레임이되고 원활한 역 스크럽이 가능합니다. 이것은 훌륭하게 작동하고 부드러운 재생을 제공합니다. 이 응용 프로그램은 다양한 소스의 비디오를 사용하며 안드로이드 또는 iOS 장치에 기록 할 수 있으며 웹에서 다운로드하여 응용 프로그램에 추가 할 수도 있으므로 완전히 다른 인코딩으로 끝납니다. 일부는 이미 스크러빙에 적합합니다 (각 프레임 키 프레임). 불필요한 비디오 처리를 피할 수 있도록 비디오 파일의 키 프레임 간격을 감지하는 방법이 있습니까? AVFoundation의 문서를 많이 읽었으며이 정보를 얻는 확실한 방법을 찾지 못했습니다. 이것에 대한 도움을 주셔서 감사합니다.AVAsset에서 현재 키 프레임 간격을 감지합니다.
답변
AVAssetReaderTrackOutput
을 080으로 생성하여 이미지를 디코딩하지 않고 파일을 빠르게 구문 분석 할 수있는 경우 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 %의 키 프레임을 반환합니다. 왜 더 정확한지 알고 싶지만 결정적인 요인으로 그 숫자를 사용하고 있습니다. 나는이 결정을 내리기 위해 전체 20 분짜리 비디오를 읽을 필요가 없기 때문에 첫 번째 600 프레임이나 비디오의 끝 (둘 중 처음으로 오는 것) 만보고 있습니다.
+ (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;
}
죄송합니다 - 당신이 목적을 사용하고 있었는지 몰랐습니다. 질문에 태그가 지정되어 있지 않습니다. –
걱정하지 않아도됩니다. 언어에별로 중요하지 않습니다. 이것에 대한 귀하의 도움에 감사드립니다. 나는 비슷한 것을 가지고 있었고 수 많은 문서를 읽고 있었지만 kCMSampleAttachmentKey_DependsOnOthers가이를 결정하는 데 사용될 수 있다는 것을 알지 못했습니다. – johnrechd
답변 해 주셔서 감사합니다. 나는 이것을 오늘 (목표 C) 구현했다. AVPlayer 및 AVPlayerLayer와 함께 사용자 지정 UIView를 사용하고 있습니다. 이것은 상당히 정확하고 모든 키 프레임을 사용하도록 인코딩 한 비디오의 약 96 % 키 프레임을 반환합니다. 다른 압축 설정이있는 동영상의 경우 훨씬 적습니다. 스크러버는 스크롤 속도를 한 번에 한 프레임 씩 이동하는 스크럽 루프로 변환하는 휠 (scrollView)입니다. Q에 대한 답변으로 내 방법을 게시 할 수 있습니다. 나는 이것의 Objective 버전을 게시 할 것이다. – johnrechd
쿨! 나는 그것을보기를 고대합니다. 누락 된 4 %는 이상합니다. 나는 그 설명이 무엇인지 궁금해. –