在 iOS 中压缩视频

问题描述 投票:0回答:3

我看过这个问题这个问题,都无法提供帮助。

我尝试过以下方法:

- (void)compress:(NSURL *)videoPath completionBlock:(void(^)(id data, BOOL result))block{
    self.outputFilePath = [[NSString alloc] initWithFormat:@"%@%@", NSTemporaryDirectory(), @"output.mov"];
    NSURL *outputURL = [NSURL fileURLWithPath:self.outputFilePath];
    [self compressVideoWithURL:self.movieURL outputURL:outputURL handler:^(AVAssetExportSession *exportSession) {

    }];
}

- (void)compressVideoWithURL:(NSURL*)inputURL
                   outputURL:(NSURL*)outputURL
                     handler:(void (^)(AVAssetExportSession*))handler {

    AVURLAsset *asset = [AVURLAsset assetWithURL:self.movieURL];
    AVAssetExportSession *exportSession = [[AVAssetExportSession alloc] initWithAsset:asset presetName:AVAssetExportPresetLowQuality];
    exportSession.fileLengthLimit = 3000000;
    exportSession.outputURL = outputURL;
    exportSession.outputFileType = AVFileTypeQuickTimeMovie;
    exportSession.shouldOptimizeForNetworkUse = YES;
    [exportSession exportAsynchronouslyWithCompletionHandler:^{
        NSData *newOutputData = [NSData dataWithContentsOfURL:outputURL];
        NSLog(@"Size of New Video(bytes):%d",[newOutputData length]);
    }];
}

我知道

self.movieUrl
不是
nil
。但是当我打印与视频相关的
NSData
的大小(以字节为单位)时,它们前后是相同的,都是 30,000,000 字节。

但是根据这个问题,上面的代码应该可以工作。

我究竟做错了什么?

ios avfoundation
3个回答
21
投票

在 Swift 3.0 中

从相机胶卷中选择视频

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
     if info[UIImagePickerControllerMediaType] as? String == (kUTTypeMovie as? String) {
        // here your video capture code
        let videoURL = info[UIImagePickerControllerMediaURL] as! NSURL!
        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 + ".m4v")
        compressVideo(inputURL: videoURL as! URL, outputURL: compressedURL) { (exportSession) in
                guard let session = exportSession else {
                    return
                }

                switch session.status {
                case .unknown:
                    break
                case .waiting:
                    break
                case .exporting:
                    break
                case .completed:
                    guard let compressedData = NSData(contentsOf: compressedURL) else {
                        return
                    }
                   print("File size after compression: \(Double(compressedData.length / 1048576)) mb")
                case .failed:
                    break
                case .cancelled:
                    break
                }
            }
       }
       self.dismiss(animated: true, completion: nil)
 }

压缩类型:

AVAssetExportPresetLowQuality
AVAssetExportPresetMediumQuality
AVAssetExportPresetHighestQuality
AVAssetExportPreset640x480 
AVAssetExportPreset960x540

压缩视频方法

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

            return
        }

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

输出:

File size before compression: 25.0 mb
File size after compression: 7.0 mb

10
投票

我已经弄清楚了,感谢这个问题(Swift 版本):IOS Video Compression Swift iOS 8 损坏的视频文件

我有 Objective C 版本。方法如下:

 - (void)compressVideo:(NSURL*)inputURL
        outputURL:(NSURL*)outputURL
          handler:(void (^)(AVAssetExportSession*))completion  {
AVURLAsset *urlAsset = [AVURLAsset URLAssetWithURL:inputURL options:nil];
AVAssetExportSession *exportSession = [[AVAssetExportSession alloc] initWithAsset:urlAsset presetName:AVAssetExportPresetMediumQuality];
exportSession.outputURL = outputURL;
exportSession.outputFileType = AVFileTypeQuickTimeMovie;
exportSession.shouldOptimizeForNetworkUse = YES;
[exportSession exportAsynchronouslyWithCompletionHandler:^{
    completion(exportSession);
  }];
}

并调用该方法:

NSURL* uploadURL = [NSURL fileURLWithPath:
                     [NSTemporaryDirectory() stringByAppendingPathComponent:@"temporaryPreview.mov"]];

[self compressVideo:self.movieURL outputURL:uploadURL handler:^(AVAssetExportSession *completion) {
    if (completion.status == AVAssetExportSessionStatusCompleted) {
        NSData *newDataForUpload = [NSData dataWithContentsOfURL:uploadURL];
        NSLog(@"Size of new Video after compression is (bytes):%d",[newDataForUpload length]);
    }
}];

这将我的视频文件大小从 32 MB 减少到 1.5 MB。


0
投票

您可以使用此方法进行视频压缩。

struct ReduceVideoSizeError: Error { }

func reduceVideoSize(inputURL: URL, outputURL: URL, completion: @escaping (Error?) -> Void) {
    let asset = AVAsset(url: inputURL)
    
    asset.loadTracks(withMediaType: .video) { videoTracks, error in
        guard let videoTrack = videoTracks?.first else {
            completion(NSError(domain: "YourAppDomain", code: 0, userInfo: [NSLocalizedDescriptionKey: "Failed to load video track"]))
            return
        }
        
        asset.loadTracks(withMediaType: .audio) { audioTracks, error in
            guard let audioTrack = audioTracks?.first else {
                completion(NSError(domain: "YourAppDomain", code: 0, userInfo: [NSLocalizedDescriptionKey: "Failed to load audio track"]))
                return
            }
            
            guard let exportSession = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetMediumQuality) else {
                completion(NSError(domain: "YourAppDomain", code: 0, userInfo: [NSLocalizedDescriptionKey: "Failed to create AVAssetExportSession"]))
                return
            }
            
            let videoSettings: [String : AnyObject] = [
                AVVideoCodecKey : AVVideoCodecType.h264 as AnyObject,
                AVVideoWidthKey : videoTrack.naturalSize.width as AnyObject,
                AVVideoHeightKey : videoTrack.naturalSize.height as AnyObject,
                AVVideoCompressionPropertiesKey : [
                    AVVideoAverageBitRateKey: 600000 // Adjust bitrate as needed
                ] as AnyObject
            ]
            
            let audioSettings: [String : AnyObject] = [
                AVFormatIDKey: kAudioFormatMPEG4AAC as AnyObject,
                AVNumberOfChannelsKey: 2 as AnyObject,
                AVSampleRateKey: 44100 as AnyObject,
                AVEncoderBitRateKey: 64000 as AnyObject
            ]
            
            exportSession.outputURL = outputURL
            exportSession.outputFileType = .mp4
            
            exportSession.timeRange = CMTimeRange(start: .zero, duration: asset.duration)
            
            exportSession.videoComposition = AVVideoComposition(asset: asset) { request in
                let source = request.sourceImage.clampedToExtent()
                request.finish(with: source, context: nil)
            }
            
            exportSession.audioMix = AVAudioMix() // Ensure audio settings are respected
            
            exportSession.exportAsynchronously {
                if exportSession.status == .completed {
                    completion(nil)
                } else if let error = exportSession.error {
                    completion(error)
                } else {
                    completion(NSError(domain: "YourAppDomain", code: 0, userInfo: [NSLocalizedDescriptionKey: "Unknown error"]))
                }
            }
        }
    }
}

private func getVideoWriterSettings(bitrate: Int, width: Int, height: Int) -> [String : AnyObject] {
    let videoWriterCompressionSettings = [
        AVVideoAverageBitRateKey: bitrate
    ]
    
    let videoWriterSettings: [String : AnyObject] = [
        AVVideoCodecKey: AVVideoCodecType.h264 as AnyObject,
        AVVideoCompressionPropertiesKey: videoWriterCompressionSettings as AnyObject,
        AVVideoWidthKey: width as AnyObject,
        AVVideoHeightKey: height as AnyObject
    ]
    
    return videoWriterSettings
}
© www.soinside.com 2019 - 2024. All rights reserved.