Metal导出视频压缩大小方案

  1. 实际测试发现,默认视频导出的情况下自定义分辨率时码率较高,但很多分辨率根本不需要设置那么高的码率即可满足需求,设置码率太高会导致导出视频过大,浪费了磁盘空间。
  2. 现有两种方案设置视频导出的码率,经测试发现,原导出19MB的视频,用方案二导出时仅占用4.6MB,且肉眼看不出明显区别。

方案一:
采用AVAssetReader和AVAssetWriter边读视频边写本地的方式,支持修改视频码率。
https://www.jianshu.com/p/4f69c22c6dce
对应的swift版本我已经翻译出来了,见
https://github.com/wangfangshuai/SDAVAssetExportSession中的SDAVAssetExportSession.swift文件。

方案二:
写一个根据码率及不同分辨率适配计算一个文件大小,设置到AVAssetExportSession对象的fileLimit中。

/**
 autoQuality: 自动根据分辨率计算合适的码率。
 customQuality:
 0-1之间的值,自定义质量,值越高码率越大。
 值为0时是autoQuality的0.5,值为1时是autoQuality的1.5,值为0.5时等于autoQuality
 */
public enum CompressRate {
    case auto
    case custom(rate: CGFloat)
}

/**
 videoQuality: 视频品质
 size: 视频分辨率
 duration: 视频时长,单位(秒)
 */
public func videoFileLimit(compressRate: CompressRate, size: CGSize, duration: Double) -> Int64 {
    
    //设置基于720p的码率大小
    let default720CodeRate: CGFloat = 3072000
    
    //基于720p的每像素码率适配到不同的分辨率中,需要拿到default720CodeRatePerPixel和useCodeRatePerPixel
    let default720CodeRatePerPixel: CGFloat = 3.333333333
    let codeRatePerPixels = [
        (424 * 240, 5.660377358),
        (640 * 360, 3.888888889),
        (768 * 432, 3.279320988),
        (848 * 480, 3.773584906),
        (1024 * 576, 3.689236111),
        (1280 * 720, 3.333333333),
        (1920 * 1080, 3.641975309),
    ]
    var useCodeRatePerPixel: CGFloat = 3.641975309
    for index in 0 ... codeRatePerPixels.count - 2 {
        let (pixel, codeRatePerPixel) = codeRatePerPixels[index]
        let (pixel2, _) = codeRatePerPixels[index + 1]
        
        //当前尺寸到下一个尺寸之间大小的0.3也适配到当前尺寸所属的数组值中。
        if size.width * size.height <= CGFloat(CGFloat(pixel2 - pixel) * 0.3 + CGFloat(pixel)) {
            useCodeRatePerPixel = CGFloat(codeRatePerPixel)
            break
        }
    }
    
    //每像素文件大小 = 3100000时的每像素文件大小 * 新码率 / 3100000
    var bytesPerPixel = (CGFloat(0.446279674546814) * default720CodeRate / CGFloat(3100000))
    
    //拿到不同分辨率对应的每像素文件大小
    bytesPerPixel = bytesPerPixel * useCodeRatePerPixel / default720CodeRatePerPixel
    
    //适配Rate得到压缩适配的每像素文件大小
    var compressFitBytes = CGFloat()
    switch compressRate {
    case .custom(var rate):
        let minBytes = bytesPerPixel * 0.5
        let maxBytes = bytesPerPixel * 2.5
        if rate < 0 { rate = 0 }
        if rate > 1 { rate = 1 }
        compressFitBytes = rate * (maxBytes - minBytes) + minBytes
    case .auto:
        compressFitBytes = bytesPerPixel
    }
    let fileLimit = Int64(compressFitBytes * size.width * size.height * CGFloat(duration))
    return fileLimit
}

你可能感兴趣的:(Metal导出视频压缩大小方案)