【问题标题】:How to compress a video in swift?如何快速压缩视频?
【发布时间】:2023-03-09 21:10:02
【问题描述】:

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

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

更新 3:

我正在寻找一个可以输出压缩后的URL的功能,而且我应该可以控制压缩质量...

更新 2:

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

                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
}

【问题讨论】:

  • 或许这篇文章有帮助 - blog.testfairy.com/…
  • @Nina,我一直在努力让它工作,但它似乎不起作用,我实现了类和使用方法,但它似乎无法通过 //compress 部分
  • 文末作者提供了源码的Github链接。样本本身没有按您想要的方式工作?
  • 我对这个压缩代码的唯一问题是 2:1。它很慢,2。它水平翻转视频@Nina

标签: ios swift compression


【解决方案1】:

我查看了您的代码。实际上,您正在以中等质量压缩视频,这将与您拥有的原始视频大致相同。因此,您必须在导出会话初始化中更改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

您可以根据您的要求使用上述所有格式来压缩您的视频。 我希望这会对你有所帮助。

【讨论】:

  • 看下面的例子。它不是在录制视频,但工作正常:ufile.io/zbchdu27
【解决方案2】:

如果您想要更多使用AVAssetWriter 的可自定义压缩过滤器,请考虑我写的library。您可以使用一般质量设置或比特率、fps、比例等更多细节过滤器来压缩视频。

FYVideoCompressor.shared.compressVideo(yourVideoPath, quality: .lowQuality) { result in
    switch result {
    case .success(let compressedVideoURL):
    case .failure(let error):
    }
 }

或:

let config = FYVideoCompressor.CompressionConfig(videoBitrate: 1000_000,
                                                 videomaxKeyFrameInterval: 10,
                                                 fps: 24,
                                                 audioSampleRate: 44100,          
                                                 audioBitrate: 128_000,
                                                 fileType: .mp4,
                                                 scale: CGSize(width: 640, height: 480))           
FYVideoCompressor.shared.compressVideo(yourVideoPath, config: config) { result in
    switch result {
    case .success(let compressedVideoURL):
    case .failure(let error):
    }
 }

【讨论】:

    猜你喜欢
    • 2016-02-03
    • 2019-01-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-13
    • 2017-12-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多