- 实际测试发现,默认视频导出的情况下自定义分辨率时码率较高,但很多分辨率根本不需要设置那么高的码率即可满足需求,设置码率太高会导致导出视频过大,浪费了磁盘空间。
- 现有两种方案设置视频导出的码率,经测试发现,原导出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
}
网友评论