2016-12-24 3 views
0

내 iOS 앱에서 동영상의 크기를 조정하려고합니다.ios - 요청한 크기를 준수하지 않는 동영상 크기 조정

fileprivate func resize(url: URL, height: CGFloat, completion: @escaping ((URL) -> Void)) { 
    let video = AVAsset(url: url) 
    guard let track = video.tracks(withMediaType: AVMediaTypeVideo).first 
    else { return } 
    let size = track.naturalSize 

    // detect video rotation 
    let txf = track.preferredTransform 
    let videoAngle = atan2(txf.b, txf.a) 
    let isRotated = videoAngle == CGFloat(M_PI_2) || videoAngle == CGFloat(M_PI_2 * 3) 
    let videoW = isRotated ? size.height : size.width 
    let videoH = isRotated ? size.width : size.height 
    // get output width that keeps aspect ratio 
    let width = height/videoH * videoW 

    print("desired width \(width) height \(height)") 
    print("original width \(size.width) height \(size.height)") 

    // resize the video 
    let videoComposition = AVMutableVideoComposition() 
    videoComposition.renderSize = CGSize(width: width, height: height) 
    videoComposition.frameDuration = CMTimeMake(1, 30) 
    let instruction = AVMutableVideoCompositionInstruction() 
    instruction.timeRange = CMTimeRangeMake(kCMTimeZero, video.duration) 
    videoComposition.instructions = [instruction] 
    let outputURL = Constants.cacheDirectory.appendingPathComponent(
    "\(String.random(ofLength: 10)).mp4") 

    guard let exporter = AVAssetExportSession(
    asset: video, 
    presetName: AVAssetExportPresetMediumQuality 
) else { return } 
    exporter.videoComposition = videoComposition 
    exporter.outputURL = outputURL 
    exporter.outputFileType = AVFileTypeQuickTimeMovie 

    exporter.exportAsynchronously(completionHandler: {() -> Void in 
    DispatchQueue.main.async { 
     let asset = AVAsset(url: outputURL) 
     let track = asset.tracks(withMediaType: AVMediaTypeVideo).first! 
     print("result size \(track.naturalSize)") 
     completion(outputURL) 
    } 
    }) 
} 

내가 1280.0 x 720.0을하고 90도 회전을 가지고 비디오에 720의 높이로 resize를 호출 할 때, 나는 320.0 x 568.0 인 결과를 얻을 내 로그는 다음과 같습니다 : 내 코드는 다음과

desired width 405.0 height 720.0 
original width 1280.0 height 720.0 
result size (320.0, 568.0) 

그 숫자가 어디에서 왔는지 관계를 찾을 수 없습니다. 애스펙트 비가 동일하게 유지된다는 것뿐입니다.

+0

당신이 아이폰 5 5S를 사용하고 있습니까? –

+0

iPhone 6이 중요하지 않습니까? – Guig

+0

결과 크기 (320.0, 568.0)이 크기는 iphone 5 및 5s입니다. –

답변

1

비디오 리사이즈가 훨씬 더 복잡해 보이기 때문에 다른 방법을 택했습니다. SDAVAssetExportSession은 모든 것을 처리하는 데 큰 도움이되며, code을 보면 상당히해야 할 일이 있습니다.

어쨌든, 내 마지막 코드는 다음과 같습니다

import SDAVAssetExportSession 

fileprivate func resize(url: URL, height: CGFloat, completion: @escaping ((Error?) -> Void)) { 
    let video = AVAsset(url: url) 

    guard let track = video.tracks(withMediaType: AVMediaTypeVideo).first 
    else { return } 
    let size = track.naturalSize 

    let txf = track.preferredTransform 
    let videoAngle = atan2(txf.b, txf.a) 
    let isRotated = videoAngle == CGFloat(M_PI_2) || videoAngle == CGFloat(M_PI_2 * 3) 
    let videoW = isRotated ? size.height : size.width 
    let videoH = isRotated ? size.width : size.height 
    let width = height/videoH * videoW 

    let outputURL = Constants.cacheDirectory.appendingPathComponent(
    "\(String.random(ofLength: 10)).mp4") 

    if let encoder = SDAVAssetExportSession(asset: AVAsset(url: url)) { 
    encoder.outputFileType = AVFileTypeMPEG4 
    encoder.outputURL = outputURL 
    encoder.videoSettings = [ 
     AVVideoCodecKey: AVVideoCodecH264, 
     AVVideoWidthKey: width, 
     AVVideoHeightKey: height, 
     AVVideoCompressionPropertiesKey: [ 
     AVVideoAverageBitRateKey: 1000000, 
     AVVideoProfileLevelKey: AVVideoProfileLevelH264High40, 
     AVVideoMaxKeyFrameIntervalKey: 60, 
     ], 
    ] 

    encoder.exportAsynchronously(completionHandler: { 
     if encoder.status == AVAssetExportSessionStatus.completed { 
     DispatchQueue.main.async { 
      self.url = outputURL 
      let asset = AVAsset(url: outputURL) 
      let track = asset.tracks(withMediaType: AVMediaTypeVideo).first! 
      completion(nil) 
     } 
     } else if encoder.status == AVAssetExportSessionStatus.cancelled { 
     completion(nil) 
     } else { 
     completion(encoder.error) 
     } 
    }) 
    } 
}