TLDR: Перейти к обновлениям. Я ищу способ сжатия или понижения качества видеоизображения, желательно не сразу после создания, но если это единственный способ, пусть будет так
Также, если вы знаете о каких-либо хороших какао-бобах, которые могут это сделать, это было бы хорошо.
Обновление 3:
Я ищу функцию, которая может выводить сжатый URL, и я должен иметь возможность контролировать качество сжатия ...
Обновление 2:
После попытки заставить функцию работать в ее текущем состоянии, она не работает. Приносит ноль. Я думаю в результате следующее:
let outputURL = urlToCompress
assetWriter = try AVAssetWriter(outputURL: outputURL, fileType: AVFileType.mov)
Я пытаюсь сжать видео по-быстрому. До сих пор все решения для этого были для использования при создании. Мне интересно, есть ли способ сжатия после создания? только используя URL видео?
Если нет, то как я могу создать функцию сжатия, которая сжимает видео и возвращает сжатый URL?
Код, с которым я работал:
func compressVideo(videoURL: URL) -> URL {
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 + ".mov")
compressVideoHelperMethod(inputURL: videoURL , outputURL: compressedURL) { (exportSession) in
}
return compressedURL
}
func compressVideoHelperMethod(inputURL: URL, outputURL: URL, handler:@escaping (_ exportSession: AVAssetExportSession?)-> Void) {
let urlAsset = AVURLAsset(url: inputURL, options: nil)
guard let exportSession = AVAssetExportSession(asset: urlAsset, presetName: AVAssetExportPresetMediumQuality) else {
handler(nil)
return
}
exportSession.outputURL = outputURL
exportSession.outputFileType = AVFileType.mov
exportSession.shouldOptimizeForNetworkUse = true
exportSession.exportAsynchronously { () -> Void in
handler(exportSession)
}
}
Обновление:
Итак, я нашел код ниже. Я еще не тестировал его, но я не знаю, как сделать так, чтобы я выбрал качество сжатия:
var assetWriter:AVAssetWriter?
var assetReader:AVAssetReader?
let bitrate:NSNumber = NSNumber(value:250000)
func compressFile(urlToCompress: URL, outputURL: URL, completion:@escaping (URL)->Void){
//video file to make the asset
var audioFinished = false
var videoFinished = false
let asset = AVAsset(url: urlToCompress);
let duration = asset.duration
let durationTime = CMTimeGetSeconds(duration)
print("Video Actual Duration -- \(durationTime)")
//create asset reader
do{
assetReader = try AVAssetReader(asset: asset)
} catch{
assetReader = nil
}
guard let reader = assetReader else{
fatalError("Could not initalize asset reader probably failed its try catch")
}
let videoTrack = asset.tracks(withMediaType: AVMediaType.video).first!
let audioTrack = asset.tracks(withMediaType: AVMediaType.audio).first!
let videoReaderSettings: [String:Any] = [(kCVPixelBufferPixelFormatTypeKey as String?)!:kCVPixelFormatType_32ARGB ]
// ADJUST BIT RATE OF VIDEO HERE
if #available(iOS 11.0, *) {
let videoSettings:[String:Any] = [
AVVideoCompressionPropertiesKey: [AVVideoAverageBitRateKey:self.bitrate],
AVVideoCodecKey: AVVideoCodecType.h264,
AVVideoHeightKey: videoTrack.naturalSize.height,
AVVideoWidthKey: videoTrack.naturalSize.width
]
} else {
// Fallback on earlier versions
}
let assetReaderVideoOutput = AVAssetReaderTrackOutput(track: videoTrack, outputSettings: videoReaderSettings)
let assetReaderAudioOutput = AVAssetReaderTrackOutput(track: audioTrack, outputSettings: nil)
if reader.canAdd(assetReaderVideoOutput){
reader.add(assetReaderVideoOutput)
}else{
fatalError("Couldn't add video output reader")
}
if reader.canAdd(assetReaderAudioOutput){
reader.add(assetReaderAudioOutput)
}else{
fatalError("Couldn't add audio output reader")
}
let audioInput = AVAssetWriterInput(mediaType: AVMediaType.audio, outputSettings: nil)
let videoInput = AVAssetWriterInput(mediaType: AVMediaType.video, outputSettings: videoReaderSettings)
videoInput.transform = videoTrack.preferredTransform
//we need to add samples to the video input
let videoInputQueue = DispatchQueue(label: "videoQueue")
let audioInputQueue = DispatchQueue(label: "audioQueue")
do{
assetWriter = try AVAssetWriter(outputURL: outputURL, fileType: AVFileType.mov)
}catch{
assetWriter = nil
}
guard let writer = assetWriter else{
fatalError("assetWriter was nil")
}
writer.shouldOptimizeForNetworkUse = true
writer.add(videoInput)
writer.add(audioInput)
writer.startWriting()
reader.startReading()
writer.startSession(atSourceTime: CMTime.zero)
let closeWriter:()->Void = {
if (audioFinished && videoFinished){
self.assetWriter?.finishWriting(completionHandler: {
print("------ Finish Video Compressing")
completion((self.assetWriter?.outputURL)!)
})
self.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) {
//request data here
while(videoInput.isReadyForMoreMediaData){
let sample = assetReaderVideoOutput.copyNextSampleBuffer()
if (sample != nil){
let timeStamp = CMSampleBufferGetPresentationTimeStamp(sample!)
let timeSecond = CMTimeGetSeconds(timeStamp)
let per = timeSecond / durationTime
print("Duration --- \(per)")
videoInput.append(sample!)
}else{
videoInput.markAsFinished()
DispatchQueue.main.async {
videoFinished = true
closeWriter()
}
break;
}
}
}
}
Как я могу изменить это, чтобы иметь возможность установить качество? Я ищу сжатие около 0,6
Сейчас я играюсь со следующим кодом, проблема в том, что он продолжает печатать ошибку (похоже, не работает):
func convertVideoToLowQuailty(withInputURL inputURL: URL?, outputURL: URL?, handler: @escaping (AVAssetExportSession?) -> Void) {
do {
if let outputURL = outputURL {
try FileManager.default.removeItem(at: outputURL)
}
} catch {
}
var asset: AVURLAsset? = nil
if let inputURL = inputURL {
asset = AVURLAsset(url: inputURL, options: nil)
}
var exportSession: AVAssetExportSession? = nil
if let asset = asset {
exportSession = AVAssetExportSession(asset: asset, presetName:AVAssetExportPresetMediumQuality)
}
exportSession?.outputURL = outputURL
exportSession?.outputFileType = .mov
exportSession?.exportAsynchronously(completionHandler: {
handler(exportSession)
})
}
func compressVideo(videoURL: URL) -> URL {
var outputURL = URL(fileURLWithPath: "/Users/alexramirezblonski/Desktop/output.mov")
convertVideoToLowQuailty(withInputURL: videoURL, outputURL: outputURL, handler: { exportSession in
print("fdshljfhdlasjkfdhsfsdljk")
if exportSession?.status == .completed {
print("completed\n", exportSession!.outputURL!)
outputURL = exportSession!.outputURL!
} else {
print("error\n")
outputURL = exportSession!.outputURL!//this needs to be fixed and may cause errors
}
})
return outputURL
}