视频录制后需要上传,但是录制视频要想压缩,有几个可以压缩的点:比特率、帧率、分辨率
比特率:单位像素所占的比特值
帧率:单位时间内的视频帧数
分辨率:图片所占的像素点的一个度量 w * h
这里我们在最低的比特率和分辨率的情况下(不改变清晰度),降低帧率也能压缩视频大小,只是视频卡顿了点
自定义丢帧:
下面一个刻度6个视频帧 ,1s(1000ms)假设有30帧 ’-‘代表一帧,’|‘代表刻度
目的:丢帧处理后1s(1000ms) 5帧
每个视频帧都有在视频中特定的位置,如果其后的视频帧丢失,就会拿当前展示的视频帧代替展示,知道有新的视频帧来替换,所以丢帧也就是适当的时间内取合适的帧,如下5个刻度代表1s,一共有30帧,要想丢帧至5帧/s,就要丢掉25帧,为了视频卡顿程度最低,我们间隔取帧的时间间隔不能太长,最好越均匀约好,结果:每一刻度内同一位置取帧,例如都取刻度内第一帧
|------
|------
|------
|------
|------
|
|-
-----|-
-----|-
-----|-
-----|-
-----|
但是录屏视频帧并不都是稳定的:例如当前iPhone6s及其以下设备所装iOS系统会针对性能进行优化:性能占用越高,录屏帧越低,例如:①录屏时高频操作手机,视频帧率就会降低;②录屏界面无变化时帧率会降低;
只有无操作或者低频操作的或者界面有变化的录屏帧率才越稳定,经测试iPhone6s的帧率变化范围大约为3帧/s ~ 30帧/s,普通操作的帧率在22帧/s 附近波动
只有iPhone7及其以上视频帧率稳定在30帧/s附近小幅波动
所以丢帧就行为就变成了不是绝对的稳定了,能够适配所有iPhone7及其以上手机的录屏视频丢帧后稳定在5帧/s,iPhone7以下只能在正常操作下在3~4帧/s
为了稳定帧率,我的处理就是取每一刻度的第一帧,不管此刻度有几帧,如果是均匀的,那丢帧后也是均匀的,如果不均匀,丢帧后就相对均匀
代码:
var appenedAgoSampleBuffer:CMSampleBuffer?//已经拼里面的前一帧
var lastSameBuffer:CMSampleBuffer?
var firstTime:Double = 0.0
override func processSampleBuffer(_ sampleBuffer: CMSampleBuffer, with sampleBufferType: RPSampleBufferType) {
switch sampleBufferType {
case RPSampleBufferType.video:
if assetWriter.status == AVAssetWriter.Status.failed || assetWriter.status == AVAssetWriter.Status.completed || assetWriter.status == AVAssetWriter.Status.cancelled {
print("assetWrite状态:\(assetWriter.status)")
return
}
if assetWriter.status == AVAssetWriter.Status.unknown {
//num = 0
assetWriter.startWriting()
assetWriter.startSession(atSourceTime: CMSampleBufferGetPresentationTimeStamp(sampleBuffer))
print("AVAssetWriter.Status.unknown")
}
if assetWriter.status == AVAssetWriter.Status.writing {
if videoInput.isReadyForMoreMediaData
{
print("AVAssetWriter.Status.writing")
let position:CMTime = CMSampleBufferGetOutputPresentationTimeStamp(sampleBuffer) ;
print("====================\(CMTimeGetSeconds(position))")
var canAppend = false
if lastSameBuffer == nil {//第一帧
canAppend = true
let firstPosition:CMTime = CMSampleBufferGetOutputPresentationTimeStamp(sampleBuffer);//第一帧的时间戳
firstTime = CMTimeGetSeconds(firstPosition)*1000//第一帧的时间
appenedAgoSampleBuffer = sampleBuffer
}else{
let appenedAgoPosition:CMTime = CMSampleBufferGetOutputPresentationTimeStamp(appenedAgoSampleBuffer!);//前一帧时间戳
let time = CMTimeGetSeconds(position)*1000 - firstTime//当前帧和第一帧的时间差
let appenedAgoTime = CMTimeGetSeconds(appenedAgoPosition)*1000 - firstTime//前一帧的时间
if (Int(time)/200) > (Int(appenedAgoTime)/200) {
canAppend = true
appenedAgoSampleBuffer = sampleBuffer
}
}
if canAppend {
let success:Bool = videoInput.append(sampleBuffer)
lastSameBuffer = sampleBuffer
if !success {
print("AVAssetWriter.Status.faild")
self.stopRecording()
}
print("appended")
}
}
}
break
case RPSampleBufferType.audioApp:
// Handle audio sample buffer for app audio
break
case RPSampleBufferType.audioMic:
// Handle audio sample buffer for mic audio
break
@unknown default:
// Handle other sample buffer types
fatalError("Unknown type of sample buffer")
}
}