2017-04-10 6 views
1

저는 비디오를 재생하고 사용자가 비디오에서 앞뒤로 문질러 쓸 수있는 응용 프로그램을 만들고 있습니다. 스크러빙이 원활하게 이루어져야하므로 비디오 압축 속성이 AVVideoMaxKeyFrameIntervalKey:@1SDAVAssetExportSession으로 비디오를 다시 쓰면 각 프레임이 키 프레임이되고 원활한 역 스크럽이 가능합니다. 이것은 훌륭하게 작동하고 부드러운 재생을 제공합니다. 이 응용 프로그램은 다양한 소스의 비디오를 사용하며 안드로이드 또는 iOS 장치에 기록 할 수 있으며 웹에서 다운로드하여 응용 프로그램에 추가 할 수도 있으므로 완전히 다른 인코딩으로 끝납니다. 일부는 이미 스크러빙에 적합합니다 (각 프레임 키 프레임). 불필요한 비디오 처리를 피할 수 있도록 비디오 파일의 키 프레임 간격을 감지하는 방법이 있습니까? AVFoundation의 문서를 많이 읽었으며이 정보를 얻는 확실한 방법을 찾지 못했습니다. 이것에 대한 도움을 주셔서 감사합니다.AVAsset에서 현재 키 프레임 간격을 감지합니다.

답변

1

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. 당신은 어떻게 닦거나 놀고 있는지 말하지 않습니다. AVPlayerViewControllerAVPlayer?

+0

답변 해 주셔서 감사합니다. 나는 이것을 오늘 (목표 C) 구현했다. AVPlayer 및 AVPlayerLayer와 함께 사용자 지정 UIView를 사용하고 있습니다. 이것은 상당히 정확하고 모든 키 프레임을 사용하도록 인코딩 한 비디오의 약 96 % 키 프레임을 반환합니다. 다른 압축 설정이있는 동영상의 경우 훨씬 적습니다. 스크러버는 스크롤 속도를 한 번에 한 프레임 씩 이동하는 스크럽 루프로 변환하는 휠 (scrollView)입니다. Q에 대한 답변으로 내 방법을 게시 할 수 있습니다. 나는 이것의 Objective 버전을 게시 할 것이다. – johnrechd

+0

쿨! 나는 그것을보기를 고대합니다. 누락 된 4 %는 이상합니다. 나는 그 설명이 무엇인지 궁금해. –

1

다음은 같은 대답의 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; 
} 
+0

죄송합니다 - 당신이 목적을 사용하고 있었는지 몰랐습니다. 질문에 태그가 지정되어 있지 않습니다. –

+0

걱정하지 않아도됩니다. 언어에별로 중요하지 않습니다. 이것에 대한 귀하의 도움에 감사드립니다. 나는 비슷한 것을 가지고 있었고 수 많은 문서를 읽고 있었지만 kCMSampleAttachmentKey_DependsOnOthers가이를 결정하는 데 사용될 수 있다는 것을 알지 못했습니다. – johnrechd