2017-11-27 9 views
0

AVCaptureDeviceFormat을 변경 한 후 240fps 비디오를 녹화했습니다. 비디오를 사진 라이브러리에 저장하면 저속 효과가 나타납니다. 하지만 AVPlayer를 사용하여 문서 디렉토리에서 해당 파일을 재생하면 슬로우 모션 효과를 볼 수 없습니다.iOS AVPlayer cant 240fps 비디오 재생

코드는 비디오를 재생하기 :

AVPlayerItem *playerItem = [AVPlayerItem playerItemWithAsset:[AVAsset assetWithURL:[NSURL fileURLWithPath:fullPath]]]; 

    AVPlayer *feedVideoPlayer = [AVPlayer playerWithPlayerItem:playerItem]; 

    AVPlayerViewController *playerController = [[AVPlayerViewController alloc] init]; 

playerController.view.frame = CGRectMake(0, 0, videoPreviewView.frame.size.width, videoPreviewView.frame.size.height); 

playerController.player = feedVideoPlayer; 
+0

가능한 [iOS AVPlayer 속도 저하] (https://stackoverflow.com/questions/37249146/ios-avplayer-slow-down) – the4kman

답변

0

그것은 조금 짜증나,하지만 난 당신이 품질을 잃고 싶지 않는 경우가 AVComposition에서 비디오를 다시 만들어야합니다 생각합니다. 다른 방법이 있는지 알고 싶지만 이것이 내가 생각해 낸 것입니다. 기술적으로 AVAssetExportSession을 통해 비디오를 내보낼 수 있지만 패스 스루 (PassThrough) 품질을 사용하면 동일한 비디오 파일이 만들어 지므로 느리게 움직이지 않습니다. 품질을 떨어 뜨리는 코드 변환이 필요합니다 (AFAIK 해당 솔루션의 경우 Issue playing slow-mo AVAsset in AVPlayer 참조) .


가장 먼저해야 할 일은 원본 미디어의 원래 시간 매핑 개체를 가져 오는 것입니다. 원래 미디어 (문서 디렉토리에 앉아 하나)의 timeMappings이 있으면

let options = PHVideoRequestOptions() 
options.version = PHVideoRequestOptionsVersion.current 
options.deliveryMode = .highQualityFormat 

PHImageManager().requestAVAsset(forVideo: phAsset, options: options, resultHandler: { (avAsset, mix, info) in 

    guard let avAsset = avAsset else { return } 

    let originalTimeMaps = avAsset.tracks(withMediaType: AVMediaTypeVideo) 
     .first? 
     .segments 
     .flatMap { $0.timeMapping } ?? [] 

} 

, 당신은 그 매체의 URL과 원래 CMTimeMapping 객체에 전달할 수 있습니다 당신이 싶습니다 그래서 같은 것을 당신은 할 수있다 재창조해라. 그런 다음 AVPlayer에서 재생할 준비가 된 새 AVComposition을 만듭니다. 이 유사한 클래스가 필요합니다

class CompositionMapper { 

let url: URL 
let timeMappings: [CMTimeMapping] 

init(for url: URL, with timeMappings: [CMTimeMapping]) { 
    self.url = url 
    self.timeMappings = timeMappings 
} 

init(with asset: AVAsset, and timeMappings: [CMTimeMapping]) { 
    guard let asset = asset as? AVURLAsset else { 
     print("cannot get a base URL from this asset.") 
     fatalError() 
    } 

    self.timeMappings = timeMappings 
    self.url = asset.url 
} 

func compose() -> AVComposition { 
    let composition = AVMutableComposition(urlAssetInitializationOptions: [AVURLAssetPreferPreciseDurationAndTimingKey: true]) 

    let emptyTrack = composition.addMutableTrack(withMediaType: AVMediaTypeVideo, preferredTrackID: kCMPersistentTrackID_Invalid) 
    let audioTrack = composition.addMutableTrack(withMediaType: AVMediaTypeAudio, preferredTrackID: kCMPersistentTrackID_Invalid) 

    let asset = AVAsset(url: url) 
    guard let videoAssetTrack = asset.tracks(withMediaType: AVMediaTypeVideo).first else { return composition } 

    var segments: [AVCompositionTrackSegment] = [] 
    for map in timeMappings { 

     let segment = AVCompositionTrackSegment(url: url, trackID: kCMPersistentTrackID_Invalid, sourceTimeRange: map.source, targetTimeRange: map.target) 
     segments.append(segment) 
    } 

    emptyTrack.preferredTransform = videoAssetTrack.preferredTransform 
    emptyTrack.segments = segments 

    if let _ = asset.tracks(withMediaType: AVMediaTypeVideo).first { 
     audioTrack.segments = segments 
    } 

    return composition.copy() as! AVComposition 
} 

그런 다음 CMTimeMapping 객체를 존중해야 당신에게 AVPlayer에서 재생할 준비가있는 AVComposition를 제공하려면 CompositionMapper 클래스의 compose() 기능을 사용할 수 있습니다 당신 들어갔다.

let compositionMapper = CompositionMapper(for: someAVAssetURL, with: originalTimeMaps) 
let mappedComposition = compositionMapper.compose() 

let playerItem = AVPlayerItem(asset: mappedComposition) 
let player = AVPlayer(playerItem: playerItem) 
playerItem.audioTimePitchAlgorithm = AVAudioTimePitchAlgorithmVarispeed 

이것을 Objective-C로 변환하는 데 도움이 필요하시면 알려주세요.하지만 비교적 간단합니다.