Closed Tulakshana closed 5 years ago
Hi, Use this code compress video, project will crash, are you the same?
Hi,
I'm sorry, I didn't use this code. So I'm unable to answer your question. I have the code below working though.
static func compressFile(video: AVAsset, bitRate: Float, outputURL: URL, completion:@escaping (_ errorMsg: String?)->Void){
var audioFinished = false
var videoFinished = false
//create asset reader
var assetReader: AVAssetReader?
do{
assetReader = try AVAssetReader(asset: video)
} catch{
completion(error.localizedDescription)
return
}
guard let reader = assetReader else{
completion("Could not read asset")
return
}
let videoTrack = video.tracks(withMediaType: AVMediaType.video).first!
let audioTrack = video.tracks(withMediaType: AVMediaType.audio).first!
let videoReaderSettings: [String:Any] = [kCVPixelBufferPixelFormatTypeKey as String:kCVPixelFormatType_32ARGB ]
// ADJUST BIT RATE OF VIDEO HERE
let videoSettings:[String:Any] = [
AVVideoCompressionPropertiesKey: [AVVideoAverageBitRateKey: bitRate],
AVVideoCodecKey: AVVideoCodecType.h264,
AVVideoHeightKey: videoTrack.naturalSize.height,
AVVideoWidthKey: videoTrack.naturalSize.width
]
let assetReaderVideoOutput = AVAssetReaderTrackOutput(track: videoTrack, outputSettings: videoReaderSettings)
let assetReaderAudioOutput = AVAssetReaderTrackOutput(track: audioTrack, outputSettings: nil)
if reader.canAdd(assetReaderVideoOutput){
reader.add(assetReaderVideoOutput)
}else{
completion("Couldn't add video output reader")
return
}
if reader.canAdd(assetReaderAudioOutput){
reader.add(assetReaderAudioOutput)
}else{
completion("Couldn't add audio output reader")
return
}
let audioInput = AVAssetWriterInput(mediaType: AVMediaType.audio, outputSettings: nil)
let videoInput = AVAssetWriterInput(mediaType: AVMediaType.video, outputSettings: videoSettings)
videoInput.transform = videoTrack.preferredTransform
//we need to add samples to the video input
let videoInputQueue = DispatchQueue(label: "videoQueue")
let audioInputQueue = DispatchQueue(label: "audioQueue")
var assetWriter: AVAssetWriter?
do{
assetWriter = try AVAssetWriter(outputURL: outputURL, fileType: AVFileType.mov)
}catch{
print("Composer " + #function + ": " + error.localizedDescription)
assetWriter = nil
}
guard let writer = assetWriter else{
completion("Could not write asset")
return
}
writer.shouldOptimizeForNetworkUse = true
writer.add(videoInput)
writer.add(audioInput)
writer.startWriting()
reader.startReading()
writer.startSession(atSourceTime: CMTime.zero)
let closeWriter:()->Void = {
if (audioFinished && videoFinished){
assetWriter?.finishWriting(completionHandler: {
completion(nil)
})
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) {
while(videoInput.isReadyForMoreMediaData){
let sample = assetReaderVideoOutput.copyNextSampleBuffer()
if (sample != nil){
videoInput.append(sample!)
}else{
videoInput.markAsFinished()
DispatchQueue.main.async {
videoFinished = true
closeWriter()
}
break;
}
}
}
}
Bit rate is achieved as shown below,
//Write video size
let numPixels = kScreenWidth * kScreenHeight
//bits per pixel
let bitsPerPixel = pow(2.0, x) // 'x' is the value you want to change for the compression
let bitRate = numPixels * bitsPerPixel
estimatedDataRate property of the video track in the AVAsset will give you the current bit rate.
Hi,
Can I ask whether I could achieve video compression by changing the value passed for AVVideoAverageBitRateKey? If yes, how to determine the range based on the properties of the original video?
Thanks!