如何快速压缩视频?

时间:2019-06-02 18:58:20

标签: ios swift compression

TLDR:跳至更新。我正在寻找一种压缩或降低视频输出质量的方法,最好不要在创建后立即进行,但是如果那是唯一的方法,那么就这样

此外,如果您知道有什么好的可可豆荚可以做到这一点,那就很好了。

更新3:

我正在寻找一个可以输出压缩URL的函数,并且我应该能够控制压缩质量...

更新2:

尝试使函数在当前状态下工作后,它不起作用。 Yeilding nil。我认为是由于以下原因:

                let outputURL = urlToCompress
            assetWriter = try AVAssetWriter(outputURL: outputURL, fileType: AVFileType.mov)

我正在尝试快速压缩视频。到目前为止,所有解决方案都已在创建过程中使用。我想知道创建后是否有压缩方式?仅使用视频网址?

如果没有,那我该如何做一个压缩功能来压缩视频并返回压缩的URL?

我一直在使用的代码:

func compressVideo(videoURL: URL) -> URL {
        let data = NSData(contentsOf: videoURL as URL)!
        print("File size before compression: \(Double(data.length / 1048576)) mb")
        let compressedURL = NSURL.fileURL(withPath: NSTemporaryDirectory() + NSUUID().uuidString + ".mov")
        compressVideoHelperMethod(inputURL: videoURL , outputURL: compressedURL) { (exportSession) in

        }
        return compressedURL
    }

    func compressVideoHelperMethod(inputURL: URL, outputURL: URL, handler:@escaping (_ exportSession: AVAssetExportSession?)-> Void) {
        let urlAsset = AVURLAsset(url: inputURL, options: nil)
        guard let exportSession = AVAssetExportSession(asset: urlAsset, presetName: AVAssetExportPresetMediumQuality) else {
            handler(nil)

            return
        }

        exportSession.outputURL = outputURL
        exportSession.outputFileType = AVFileType.mov
        exportSession.shouldOptimizeForNetworkUse = true
        exportSession.exportAsynchronously { () -> Void in
            handler(exportSession)
        }
    }

更新:

所以我找到了下面的代码。我尚未对其进行测试,但是我不知道如何制作,以便选择压缩质量:

var assetWriter:AVAssetWriter?
var assetReader:AVAssetReader?
let bitrate:NSNumber = NSNumber(value:250000)

func compressFile(urlToCompress: URL, outputURL: URL, completion:@escaping (URL)->Void){
    //video file to make the asset

    var audioFinished = false
    var videoFinished = false

    let asset = AVAsset(url: urlToCompress);

    let duration = asset.duration
    let durationTime = CMTimeGetSeconds(duration)

    print("Video Actual Duration -- \(durationTime)")

    //create asset reader
    do{
        assetReader = try AVAssetReader(asset: asset)
    } catch{
        assetReader = nil
    }

    guard let reader = assetReader else{
        fatalError("Could not initalize asset reader probably failed its try catch")
    }

    let videoTrack = asset.tracks(withMediaType: AVMediaType.video).first!
    let audioTrack = asset.tracks(withMediaType: AVMediaType.audio).first!

    let videoReaderSettings: [String:Any] =  [(kCVPixelBufferPixelFormatTypeKey as String?)!:kCVPixelFormatType_32ARGB ]

    // ADJUST BIT RATE OF VIDEO HERE

    if #available(iOS 11.0, *) {
        let videoSettings:[String:Any] = [
            AVVideoCompressionPropertiesKey: [AVVideoAverageBitRateKey:self.bitrate],
            AVVideoCodecKey: AVVideoCodecType.h264,
            AVVideoHeightKey: videoTrack.naturalSize.height,
            AVVideoWidthKey: videoTrack.naturalSize.width
        ]
    } else {
        // Fallback on earlier versions
    }


    let assetReaderVideoOutput = AVAssetReaderTrackOutput(track: videoTrack, outputSettings: videoReaderSettings)
    let assetReaderAudioOutput = AVAssetReaderTrackOutput(track: audioTrack, outputSettings: nil)


    if reader.canAdd(assetReaderVideoOutput){
        reader.add(assetReaderVideoOutput)
    }else{
        fatalError("Couldn't add video output reader")
    }

    if reader.canAdd(assetReaderAudioOutput){
        reader.add(assetReaderAudioOutput)
    }else{
        fatalError("Couldn't add audio output reader")
    }

    let audioInput = AVAssetWriterInput(mediaType: AVMediaType.audio, outputSettings: nil)
    let videoInput = AVAssetWriterInput(mediaType: AVMediaType.video, outputSettings: videoReaderSettings)
    videoInput.transform = videoTrack.preferredTransform
    //we need to add samples to the video input

    let videoInputQueue = DispatchQueue(label: "videoQueue")
    let audioInputQueue = DispatchQueue(label: "audioQueue")

    do{
        assetWriter = try AVAssetWriter(outputURL: outputURL, fileType: AVFileType.mov)
    }catch{
        assetWriter = nil
    }
    guard let writer = assetWriter else{
        fatalError("assetWriter was nil")
    }

    writer.shouldOptimizeForNetworkUse = true
    writer.add(videoInput)
    writer.add(audioInput)


    writer.startWriting()
    reader.startReading()
    writer.startSession(atSourceTime: CMTime.zero)


    let closeWriter:()->Void = {
        if (audioFinished && videoFinished){
            self.assetWriter?.finishWriting(completionHandler: {
                print("------ Finish Video Compressing")                    
                completion((self.assetWriter?.outputURL)!)
            })

            self.assetReader?.cancelReading()
        }
    }


    audioInput.requestMediaDataWhenReady(on: audioInputQueue) {
        while(audioInput.isReadyForMoreMediaData){
            let sample = assetReaderAudioOutput.copyNextSampleBuffer()
            if (sample != nil){
                audioInput.append(sample!)
            }else{
                audioInput.markAsFinished()
                DispatchQueue.main.async {
                    audioFinished = true
                    closeWriter()
                }
                break;
            }
        }
    }

    videoInput.requestMediaDataWhenReady(on: videoInputQueue) {
        //request data here
        while(videoInput.isReadyForMoreMediaData){
            let sample = assetReaderVideoOutput.copyNextSampleBuffer()
            if (sample != nil){
                let timeStamp = CMSampleBufferGetPresentationTimeStamp(sample!)
                let timeSecond = CMTimeGetSeconds(timeStamp)
                let per = timeSecond / durationTime
                print("Duration --- \(per)")
                videoInput.append(sample!)
            }else{
                videoInput.markAsFinished()
                DispatchQueue.main.async {
                    videoFinished = true
                    closeWriter()
                }
                break;
            }
        }
    }
}

如何更改此设置以设置质量?我正在寻找约0.6的压缩率

我现在正在处理以下代码,问题是它不断显示错误(似乎不起作用):

    func convertVideoToLowQuailty(withInputURL inputURL: URL?, outputURL: URL?, handler: @escaping (AVAssetExportSession?) -> Void) {
    do {
        if let outputURL = outputURL {
            try FileManager.default.removeItem(at: outputURL)
        }
    } catch {
    }
    var asset: AVURLAsset? = nil
    if let inputURL = inputURL {
        asset = AVURLAsset(url: inputURL, options: nil)
    }
    var exportSession: AVAssetExportSession? = nil
    if let asset = asset {
        exportSession = AVAssetExportSession(asset: asset, presetName:AVAssetExportPresetMediumQuality)
    }
    exportSession?.outputURL = outputURL
    exportSession?.outputFileType = .mov
    exportSession?.exportAsynchronously(completionHandler: {
        handler(exportSession)
    })
}

func compressVideo(videoURL: URL) -> URL {
    var outputURL = URL(fileURLWithPath: "/Users/alexramirezblonski/Desktop/output.mov")
    convertVideoToLowQuailty(withInputURL: videoURL, outputURL: outputURL, handler: { exportSession in
        print("fdshljfhdlasjkfdhsfsdljk")
        if exportSession?.status == .completed {
            print("completed\n", exportSession!.outputURL!)
            outputURL = exportSession!.outputURL!
        } else {
            print("error\n")
            outputURL = exportSession!.outputURL!//this needs to be fixed and may cause errors
        }
    })
    return outputURL
}

1 个答案:

答案 0 :(得分:3)

我查看了您的代码。实际上,您正在压缩中等质量的视频,其质量与原始视频大致相同。因此,您必须在导出会话初始化中更改presetName,如下所示:

exportSession = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetLowQuality)

您可以传递AVAssetExportPresetMediumQuality,因此可以按预期进行压缩。

以下列出了可用于压缩视频的格式。

1。在iOS 11.0中可用

  • AVAssetExportPresetHEVCHighestQuality
  • AVAssetExportPresetHEVC1920x1080
  • AVAssetExportPresetHEVC3840x2160

2。在iOS 4.0中可用

  • AVAssetExportPresetLowQuality
  • AVAssetExportPresetMediumQuality
  • AVAssetExportPresetHighestQuality
  • AVAssetExportPreset640x480
  • AVAssetExportPreset960x540
  • AVAssetExportPreset1280x720
  • AVAssetExportPreset1920x1080
  • AVAssetExportPreset3840x2160
  • AVAssetExportPresetAppleM4A

您可以根据需要使用所有格式来压缩视频。 希望对您有帮助。