2016-12-24 13 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

あなたはiphone 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) 
     } 
    }) 
    } 
} 
関連する問題