Как я могу уменьшить размер файла видео, созданного с помощью UIImagePickerController?
у меня есть приложение, которое позволяет пользователю записывать видео с UIImagePickerController
и затем загрузить его на YouTube. Проблема в том, что видео файл, который UIImagePickerController
создает огромный, даже когда видео составляет всего 5 секунд. Например, 5-секундное видео занимает 16-20 мегабайт. Я хочу сохранить видео в качестве 540 или 720, но я хочу уменьшить размер файла.
я экспериментировал с AVFoundation и AVAssetExportSession
чтобы попытаться получить меньший размер файла. Я пробовал следующее код:
AVAsset *video = [AVAsset assetWithURL:videoURL];
AVAssetExportSession *exportSession = [AVAssetExportSession exportSessionWithAsset:video presetName:AVAssetExportPresetPassthrough];
exportSession.shouldOptimizeForNetworkUse = YES;
exportSession.outputFileType = AVFileTypeMPEG4;
exportSession.outputURL = [pathToSavedVideosDirectory URLByAppendingPathComponent:@"vid1.mp4"];
[exportSession exportAsynchronouslyWithCompletionHandler:^{
NSLog(@"done processing video!");
}];
но это не уменьшило размер файла в все. Я знаю, что я делаю, возможно, потому что в приложении Apple Photos, когда вы выбираете "поделиться на YouTube", будет автоматически обрабатывать видеофайл, так что его достаточно мало, чтобы загрузить. Я хочу сделать то же самое в мое приложение.
как я могу это сделать?
10 ответов:
С
AVCaptureSession
иAVAssetWriter
вы можете установить параметры сжатия, как например:NSDictionary *settings = @{AVVideoCodecKey:AVVideoCodecH264, AVVideoWidthKey:@(video_width), AVVideoHeightKey:@(video_height), AVVideoCompressionPropertiesKey: @{AVVideoAverageBitRateKey:@(desired_bitrate), AVVideoProfileLevelKey:AVVideoProfileLevelH264Main31, /* Or whatever profile & level you wish to use */ AVVideoMaxKeyFrameIntervalKey:@(desired_keyframe_interval)}}; AVAssetWriterInput* writer_input = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:settings];
Edit: я думаю, если вы настаиваете на использовании
UIImagePicker
чтобы создать фильм в первую очередь, вам придется использоватьAVAssetReader's
copyNextSampleBuffer
иAVAssetWriter's
appendSampleBuffer
методы перекодирования.
yourfriendzak прав: установка
cameraUI.videoQuality = UIImagePickerControllerQualityTypeLow;
это не решение здесь. Решение проблемы заключается в снижении скорости передачи данных, или скорость передачи данных, которая является то, что jgh предлагает.у меня есть три способа. Первый метод обрабатывает
UIImagePicker
метод делегата:// For responding to the user accepting a newly-captured picture or movie - (void) imagePickerController: (UIImagePickerController *) picker didFinishPickingMediaWithInfo: (NSDictionary *) info { // Handle movie capture NSURL *movieURL = [info objectForKey: UIImagePickerControllerMediaURL]; NSURL *uploadURL = [NSURL fileURLWithPath:[[NSTemporaryDirectory() stringByAppendingPathComponent:[self randomString]] stringByAppendingString:@".mp4"]]; // Compress movie first [self convertVideoToLowQuailtyWithInputURL:movieURL outputURL:uploadURL]; }
второй метод преобразует видео в более низкий битрейт, а не в более низкие размеры.
- (void)convertVideoToLowQuailtyWithInputURL:(NSURL*)inputURL outputURL:(NSURL*)outputURL { //setup video writer AVAsset *videoAsset = [[AVURLAsset alloc] initWithURL:inputURL options:nil]; AVAssetTrack *videoTrack = [[videoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0]; CGSize videoSize = videoTrack.naturalSize; NSDictionary *videoWriterCompressionSettings = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:1250000], AVVideoAverageBitRateKey, nil]; NSDictionary *videoWriterSettings = [NSDictionary dictionaryWithObjectsAndKeys:AVVideoCodecH264, AVVideoCodecKey, videoWriterCompressionSettings, AVVideoCompressionPropertiesKey, [NSNumber numberWithFloat:videoSize.width], AVVideoWidthKey, [NSNumber numberWithFloat:videoSize.height], AVVideoHeightKey, nil]; AVAssetWriterInput* videoWriterInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:videoWriterSettings]; videoWriterInput.expectsMediaDataInRealTime = YES; videoWriterInput.transform = videoTrack.preferredTransform; AVAssetWriter *videoWriter = [[AVAssetWriter alloc] initWithURL:outputURL fileType:AVFileTypeQuickTimeMovie error:nil]; [videoWriter addInput:videoWriterInput]; //setup video reader NSDictionary *videoReaderSettings = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange] forKey:(id)kCVPixelBufferPixelFormatTypeKey]; AVAssetReaderTrackOutput *videoReaderOutput = [[AVAssetReaderTrackOutput alloc] initWithTrack:videoTrack outputSettings:videoReaderSettings]; AVAssetReader *videoReader = [[AVAssetReader alloc] initWithAsset:videoAsset error:nil]; [videoReader addOutput:videoReaderOutput]; //setup audio writer AVAssetWriterInput* audioWriterInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeAudio outputSettings:nil]; audioWriterInput.expectsMediaDataInRealTime = NO; [videoWriter addInput:audioWriterInput]; //setup audio reader AVAssetTrack* audioTrack = [[videoAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0]; AVAssetReaderOutput *audioReaderOutput = [AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack:audioTrack outputSettings:nil]; AVAssetReader *audioReader = [AVAssetReader assetReaderWithAsset:videoAsset error:nil]; [audioReader addOutput:audioReaderOutput]; [videoWriter startWriting]; //start writing from video reader [videoReader startReading]; [videoWriter startSessionAtSourceTime:kCMTimeZero]; dispatch_queue_t processingQueue = dispatch_queue_create("processingQueue1", NULL); [videoWriterInput requestMediaDataWhenReadyOnQueue:processingQueue usingBlock: ^{ while ([videoWriterInput isReadyForMoreMediaData]) { CMSampleBufferRef sampleBuffer; if ([videoReader status] == AVAssetReaderStatusReading && (sampleBuffer = [videoReaderOutput copyNextSampleBuffer])) { [videoWriterInput appendSampleBuffer:sampleBuffer]; CFRelease(sampleBuffer); } else { [videoWriterInput markAsFinished]; if ([videoReader status] == AVAssetReaderStatusCompleted) { //start writing from audio reader [audioReader startReading]; [videoWriter startSessionAtSourceTime:kCMTimeZero]; dispatch_queue_t processingQueue = dispatch_queue_create("processingQueue2", NULL); [audioWriterInput requestMediaDataWhenReadyOnQueue:processingQueue usingBlock:^{ while (audioWriterInput.readyForMoreMediaData) { CMSampleBufferRef sampleBuffer; if ([audioReader status] == AVAssetReaderStatusReading && (sampleBuffer = [audioReaderOutput copyNextSampleBuffer])) { [audioWriterInput appendSampleBuffer:sampleBuffer]; CFRelease(sampleBuffer); } else { [audioWriterInput markAsFinished]; if ([audioReader status] == AVAssetReaderStatusCompleted) { [videoWriter finishWritingWithCompletionHandler:^(){ [self sendMovieFileAtURL:outputURL]; }]; } } } } ]; } } } } ]; }
в случае успеха, третий способ,
sendMovieFileAtURL:
называется, который загружает сжатое видео вoutputURL
to сервер.отметим, что я включил ARC в своем проекте, так что вам придется добавить некоторые
release
звонки, если ARC выключен в вашем.
On
UImagePickerController
у васvideoQuality
собственностьUIImagePickerControllerQualityType
тип, и будет применяться к записанным фильмам, а также к тем, которые вы выбрали из библиотеки (что происходит во время фазы транскодирования).или если вам нужно иметь дело с существующим активом (файлом) не из библиотеки, вы можете посмотреть на эти пресеты:
AVAssetExportPresetLowQuality AVAssetExportPresetMediumQuality AVAssetExportPresetHighestQuality
и
AVAssetExportPreset640x480 AVAssetExportPreset960x540 AVAssetExportPreset1280x720 AVAssetExportPreset1920x1080
и передайте один из них инициализатор на
AVAssetExportSession
класса. Я боюсь, что вам придется играть с ними для вашего конкретного контента, поскольку нет точного описания того, что естьlow
иmedium
качество или какое качество будет использоваться для640x480
или1280x720
предустановки. Единственная полезная информация в документах заключается в следующем:экспорт предустановленных имен для устройств-соответствующие файлы QuickTime Эти параметры экспорта используются для создания QuickTime .mov файлы с размером видео, соответствующим текущему устройству.
в экспорт не будет масштабировать видео с меньшего размера. Видео сжимается с помощью H. 264; аудио сжимается с помощью AAC
некоторые устройства не могут поддерживать некоторые размеры.
кроме того, я не помню точного контроля над качеством, таким как частота кадров или размер свободной формы и т. д. ВAVFoundation
я был неправ, есть способ настроить все параметры, которые вы упоминаете, и это AVAssetWriter действительно:как я экспортировать массив UIImage в виде фильма?
кстати, вот ссылка на аналогичный вопрос с примером кода:iPhone: программное сжатие записанного видео для обмена?
ответ Эрика, возможно, был правильным в то время, когда он писал его, но теперь с iOS8 он просто рушится влево и вправо, я сам потратил на это несколько часов.
вам нужен кандидат наук для работы с AVAssetWriter - это нетривиально: https://developer.apple.com/library/mac/documentation/AudioVideo/Conceptual/AVFoundationPG/Articles/05_Export.html#//apple_ref/doc/uid/TP40010188-CH9-SW1
есть удивительная библиотека для делать именно то, что вы хотите, что просто avassetexportsession drop-in замена с более важными функциями, такими как изменение скорости передачи данных:https://github.com/rs/SDAVAssetExportSession
вот как это использовать:
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info { SDAVAssetExportSession *encoder = [SDAVAssetExportSession.alloc initWithAsset:[AVAsset assetWithURL:[info objectForKey:UIImagePickerControllerMediaURL]]]; NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *documentsDirectory = [paths objectAtIndex:0]; self.myPathDocs = [documentsDirectory stringByAppendingPathComponent: [NSString stringWithFormat:@"lowerBitRate-%d.mov",arc4random() % 1000]]; NSURL *url = [NSURL fileURLWithPath:self.myPathDocs]; encoder.outputURL=url; encoder.outputFileType = AVFileTypeMPEG4; encoder.shouldOptimizeForNetworkUse = YES; encoder.videoSettings = @ { AVVideoCodecKey: AVVideoCodecH264, AVVideoCompressionPropertiesKey: @ { AVVideoAverageBitRateKey: @2300000, // Lower bit rate here AVVideoProfileLevelKey: AVVideoProfileLevelH264High40, }, }; encoder.audioSettings = @ { AVFormatIDKey: @(kAudioFormatMPEG4AAC), AVNumberOfChannelsKey: @2, AVSampleRateKey: @44100, AVEncoderBitRateKey: @128000, }; [encoder exportAsynchronouslyWithCompletionHandler:^ { int status = encoder.status; if (status == AVAssetExportSessionStatusCompleted) { AVAssetTrack *videoTrack = nil; AVURLAsset *asset = [AVAsset assetWithURL:encoder.outputURL]; NSArray *videoTracks = [asset tracksWithMediaType:AVMediaTypeVideo]; videoTrack = [videoTracks objectAtIndex:0]; float frameRate = [videoTrack nominalFrameRate]; float bps = [videoTrack estimatedDataRate]; NSLog(@"Frame rate == %f",frameRate); NSLog(@"bps rate == %f",bps/(1024.0 * 1024.0)); NSLog(@"Video export succeeded"); // encoder.outputURL <- this is what you want!! } else if (status == AVAssetExportSessionStatusCancelled) { NSLog(@"Video export cancelled"); } else { NSLog(@"Video export failed with error: %@ (%d)", encoder.error.localizedDescription, encoder.error.code); } }]; }
код Эрика Вегенера переписан на swift 3:
class func convertVideoToLowQuailtyWithInputURL(inputURL: NSURL, outputURL: NSURL, onDone: @escaping () -> ()) { //setup video writer let videoAsset = AVURLAsset(url: inputURL as URL, options: nil) let videoTrack = videoAsset.tracks(withMediaType: AVMediaTypeVideo)[0] let videoSize = videoTrack.naturalSize let videoWriterCompressionSettings = [ AVVideoAverageBitRateKey : Int(125000) ] let videoWriterSettings:[String : AnyObject] = [ AVVideoCodecKey : AVVideoCodecH264 as AnyObject, AVVideoCompressionPropertiesKey : videoWriterCompressionSettings as AnyObject, AVVideoWidthKey : Int(videoSize.width) as AnyObject, AVVideoHeightKey : Int(videoSize.height) as AnyObject ] let videoWriterInput = AVAssetWriterInput(mediaType: AVMediaTypeVideo, outputSettings: videoWriterSettings) videoWriterInput.expectsMediaDataInRealTime = true videoWriterInput.transform = videoTrack.preferredTransform let videoWriter = try! AVAssetWriter(outputURL: outputURL as URL, fileType: AVFileTypeQuickTimeMovie) videoWriter.add(videoWriterInput) //setup video reader let videoReaderSettings:[String : AnyObject] = [ kCVPixelBufferPixelFormatTypeKey as String: Int(kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange) as AnyObject ] let videoReaderOutput = AVAssetReaderTrackOutput(track: videoTrack, outputSettings: videoReaderSettings) let videoReader = try! AVAssetReader(asset: videoAsset) videoReader.add(videoReaderOutput) //setup audio writer let audioWriterInput = AVAssetWriterInput(mediaType: AVMediaTypeAudio, outputSettings: nil) audioWriterInput.expectsMediaDataInRealTime = false videoWriter.add(audioWriterInput) //setup audio reader let audioTrack = videoAsset.tracks(withMediaType: AVMediaTypeAudio)[0] let audioReaderOutput = AVAssetReaderTrackOutput(track: audioTrack, outputSettings: nil) let audioReader = try! AVAssetReader(asset: videoAsset) audioReader.add(audioReaderOutput) videoWriter.startWriting() //start writing from video reader videoReader.startReading() videoWriter.startSession(atSourceTime: kCMTimeZero) let processingQueue = DispatchQueue(label: "processingQueue1") videoWriterInput.requestMediaDataWhenReady(on: processingQueue, using: {() -> Void in while videoWriterInput.isReadyForMoreMediaData { let sampleBuffer:CMSampleBuffer? = videoReaderOutput.copyNextSampleBuffer(); if videoReader.status == .reading && sampleBuffer != nil { videoWriterInput.append(sampleBuffer!) } else { videoWriterInput.markAsFinished() if videoReader.status == .completed { //start writing from audio reader audioReader.startReading() videoWriter.startSession(atSourceTime: kCMTimeZero) let processingQueue = DispatchQueue(label: "processingQueue2") audioWriterInput.requestMediaDataWhenReady(on: processingQueue, using: {() -> Void in while audioWriterInput.isReadyForMoreMediaData { let sampleBuffer:CMSampleBuffer? = audioReaderOutput.copyNextSampleBuffer() if audioReader.status == .reading && sampleBuffer != nil { audioWriterInput.append(sampleBuffer!) } else { audioWriterInput.markAsFinished() if audioReader.status == .completed { videoWriter.finishWriting(completionHandler: {() -> Void in onDone(); }) } } } }) } } } }) }
вы можете установить качество видео, когда вы хотите открыть
UIImagePickerController
к любому из следующих :
UIImagePickerControllerQualityType640x480
UIImagePickerControllerQualityTypeLow
UIImagePickerControllerQualityTypeMedium
UIImagePickerControllerQualityTypeHigh
UIImagePickerControllerQualityTypeIFrame960x540
UIImagePickerControllerQualityTypeIFrame1280x720
попробуйте этот код для изменения типа качества при открытии
UIImagePickerController
:if (([UIImagePickerController isSourceTypeAvailable: UIImagePickerControllerSourceTypeCamera] == NO)) return NO; UIImagePickerController *cameraUI = [[UIImagePickerController alloc] init]; cameraUI.sourceType = UIImagePickerControllerSourceTypeCamera; cameraUI.mediaTypes = [[NSArray alloc] initWithObjects: (NSString *) kUTTypeMovie, nil]; cameraUI.allowsEditing = NO; cameraUI.delegate = self; cameraUI.videoQuality = UIImagePickerControllerQualityTypeLow;//you can change the quality here [self presentModalViewController:cameraUI animated:YES];
код Эрика Вегенера переписан на swift:
class func convertVideoToLowQuailtyWithInputURL(inputURL: NSURL, outputURL: NSURL, onDone: () -> ()) { //setup video writer let videoAsset = AVURLAsset(URL: inputURL, options: nil) let videoTrack = videoAsset.tracksWithMediaType(AVMediaTypeVideo)[0] let videoSize = videoTrack.naturalSize let videoWriterCompressionSettings = [ AVVideoAverageBitRateKey : Int(125000) ] let videoWriterSettings:[String : AnyObject] = [ AVVideoCodecKey : AVVideoCodecH264, AVVideoCompressionPropertiesKey : videoWriterCompressionSettings, AVVideoWidthKey : Int(videoSize.width), AVVideoHeightKey : Int(videoSize.height) ] let videoWriterInput = AVAssetWriterInput(mediaType: AVMediaTypeVideo, outputSettings: videoWriterSettings) videoWriterInput.expectsMediaDataInRealTime = true videoWriterInput.transform = videoTrack.preferredTransform let videoWriter = try! AVAssetWriter(URL: outputURL, fileType: AVFileTypeQuickTimeMovie) videoWriter.addInput(videoWriterInput) //setup video reader let videoReaderSettings:[String : AnyObject] = [ kCVPixelBufferPixelFormatTypeKey as String: Int(kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange) ] let videoReaderOutput = AVAssetReaderTrackOutput(track: videoTrack, outputSettings: videoReaderSettings) let videoReader = try! AVAssetReader(asset: videoAsset) videoReader.addOutput(videoReaderOutput) //setup audio writer let audioWriterInput = AVAssetWriterInput(mediaType: AVMediaTypeAudio, outputSettings: nil) audioWriterInput.expectsMediaDataInRealTime = false videoWriter.addInput(audioWriterInput) //setup audio reader let audioTrack = videoAsset.tracksWithMediaType(AVMediaTypeAudio)[0] let audioReaderOutput = AVAssetReaderTrackOutput(track: audioTrack, outputSettings: nil) let audioReader = try! AVAssetReader(asset: videoAsset) audioReader.addOutput(audioReaderOutput) videoWriter.startWriting() //start writing from video reader videoReader.startReading() videoWriter.startSessionAtSourceTime(kCMTimeZero) let processingQueue = dispatch_queue_create("processingQueue1", nil) videoWriterInput.requestMediaDataWhenReadyOnQueue(processingQueue, usingBlock: {() -> Void in while videoWriterInput.readyForMoreMediaData { let sampleBuffer:CMSampleBuffer? = videoReaderOutput.copyNextSampleBuffer(); if videoReader.status == .Reading && sampleBuffer != nil { videoWriterInput.appendSampleBuffer(sampleBuffer!) } else { videoWriterInput.markAsFinished() if videoReader.status == .Completed { //start writing from audio reader audioReader.startReading() videoWriter.startSessionAtSourceTime(kCMTimeZero) let processingQueue = dispatch_queue_create("processingQueue2", nil) audioWriterInput.requestMediaDataWhenReadyOnQueue(processingQueue, usingBlock: {() -> Void in while audioWriterInput.readyForMoreMediaData { let sampleBuffer:CMSampleBufferRef? = audioReaderOutput.copyNextSampleBuffer() if audioReader.status == .Reading && sampleBuffer != nil { audioWriterInput.appendSampleBuffer(sampleBuffer!) } else { audioWriterInput.markAsFinished() if audioReader.status == .Completed { videoWriter.finishWritingWithCompletionHandler({() -> Void in onDone(); }) } } } }) } } } }) }
есть удивительный пользовательский класс(SDAVAssetExportSession) для сжатия видео. Вы можете скачать его с этого ссылке.
после загрузки добавить SDAVAssetExportSession.h И SDAVAssetExportSession.m файлов в ваш проект, а затем использовать ниже код для сжатия. в приведенном ниже коде вы можете сжать видео, указав разрешение и битрейт
#import "SDAVAssetExportSession.h" - (void)compressVideoWithInputVideoUrl:(NSURL *) inputVideoUrl { /* Create Output File Url */ NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *documentsDirectory = [paths objectAtIndex:0]; NSFileManager *fileManager = [NSFileManager defaultManager]; NSString *finalVideoURLString = [documentsDirectory stringByAppendingPathComponent:@"compressedVideo.mp4"]; NSURL *outputVideoUrl = ([[NSURL URLWithString:finalVideoURLString] isFileURL] == 1)?([NSURL URLWithString:finalVideoURLString]):([NSURL fileURLWithPath:finalVideoURLString]); // Url Should be a file Url, so here we check and convert it into a file Url SDAVAssetExportSession *compressionEncoder = [SDAVAssetExportSession.alloc initWithAsset:[AVAsset assetWithURL:inputVideoUrl]]; // provide inputVideo Url Here compressionEncoder.outputFileType = AVFileTypeMPEG4; compressionEncoder.outputURL = outputVideoUrl; //Provide output video Url here compressionEncoder.videoSettings = @ { AVVideoCodecKey: AVVideoCodecH264, AVVideoWidthKey: @800, //Set your resolution width here AVVideoHeightKey: @600, //set your resolution height here AVVideoCompressionPropertiesKey: @ { AVVideoAverageBitRateKey: @45000, // Give your bitrate here for lower size give low values AVVideoProfileLevelKey: AVVideoProfileLevelH264High40, }, }; compressionEncoder.audioSettings = @ { AVFormatIDKey: @(kAudioFormatMPEG4AAC), AVNumberOfChannelsKey: @2, AVSampleRateKey: @44100, AVEncoderBitRateKey: @128000, }; [compressionEncoder exportAsynchronouslyWithCompletionHandler:^ { if (compressionEncoder.status == AVAssetExportSessionStatusCompleted) { NSLog(@"Compression Export Completed Successfully"); } else if (compressionEncoder.status == AVAssetExportSessionStatusCancelled) { NSLog(@"Compression Export Canceled"); } else { NSLog(@"Compression Failed"); } }]; }
Для Отмены Сжатия Используйте Ниже Строки код
[compressionEncoder cancelExport]; //Video compression cancel
Я поддерживаю etayluz ' s ответ SDAVAssetExportSession это удивительный пользовательский класс для сжатия видео. Вот мой рабочий код. Вы можете скачать SDAVAssetExportSession отсюда ссылке.
после загрузки добавить SDAVAssetExportSession.h И SDAVAssetExportSession.m файлов в ваш проект, а затем использовать ниже код для сжатия. в приведенном ниже коде вы можете сжать видео, указав разрешение и битрейт
#import "SDAVAssetExportSession.h" - (void)compressVideoWithInputVideoUrl:(NSURL *) inputVideoUrl { /* Create Output File Url */ NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *documentsDirectory = [paths objectAtIndex:0]; NSFileManager *fileManager = [NSFileManager defaultManager]; NSString *finalVideoURLString = [documentsDirectory stringByAppendingPathComponent:@"compressedVideo.mp4"]; NSURL *outputVideoUrl = ([[NSURL URLWithString:finalVideoURLString] isFileURL] == 1)?([NSURL URLWithString:finalVideoURLString]):([NSURL fileURLWithPath:finalVideoURLString]); // Url Should be a file Url, so here we check and convert it into a file Url SDAVAssetExportSession *compressionEncoder = [SDAVAssetExportSession.alloc initWithAsset:[AVAsset assetWithURL:inputVideoUrl]]; // provide inputVideo Url Here compressionEncoder.outputFileType = AVFileTypeMPEG4; compressionEncoder.outputURL = outputVideoUrl; //Provide output video Url here compressionEncoder.videoSettings = @ { AVVideoCodecKey: AVVideoCodecH264, AVVideoWidthKey: @800, //Set your resolution width here AVVideoHeightKey: @600, //set your resolution height here AVVideoCompressionPropertiesKey: @ { AVVideoAverageBitRateKey: @45000, // Give your bitrate here for lower size give low values AVVideoProfileLevelKey: AVVideoProfileLevelH264High40, }, }; compressionEncoder.audioSettings = @ { AVFormatIDKey: @(kAudioFormatMPEG4AAC), AVNumberOfChannelsKey: @2, AVSampleRateKey: @44100, AVEncoderBitRateKey: @128000, }; [compressionEncoder exportAsynchronouslyWithCompletionHandler:^ { if (compressionEncoder.status == AVAssetExportSessionStatusCompleted) { NSLog(@"Compression Export Completed Successfully"); } else if (compressionEncoder.status == AVAssetExportSessionStatusCancelled) { NSLog(@"Compression Export Canceled"); } else { NSLog(@"Compression Failed"); } }]; }
чтобы отменить сжатие используйте ниже строки кода
[compressionEncoder cancelExport]; //Video compression cancel
Swift 4:
func convertVideoToLowQuailtyWithInputURL(inputURL: NSURL, outputURL: NSURL, completion: @escaping (Bool) -> Void) { let videoAsset = AVURLAsset(url: inputURL as URL, options: nil) let videoTrack = videoAsset.tracks(withMediaType: AVMediaType.video)[0] let videoSize = videoTrack.naturalSize let videoWriterCompressionSettings = [ AVVideoAverageBitRateKey : Int(125000) ] let videoWriterSettings:[String : AnyObject] = [ AVVideoCodecKey : AVVideoCodecH264 as AnyObject, AVVideoCompressionPropertiesKey : videoWriterCompressionSettings as AnyObject, AVVideoWidthKey : Int(videoSize.width) as AnyObject, AVVideoHeightKey : Int(videoSize.height) as AnyObject ] let videoWriterInput = AVAssetWriterInput(mediaType: AVMediaType.video, outputSettings: videoWriterSettings) videoWriterInput.expectsMediaDataInRealTime = true videoWriterInput.transform = videoTrack.preferredTransform let videoWriter = try! AVAssetWriter(outputURL: outputURL as URL, fileType: AVFileType.mov) videoWriter.add(videoWriterInput) //setup video reader let videoReaderSettings:[String : AnyObject] = [ kCVPixelBufferPixelFormatTypeKey as String: Int(kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange) as AnyObject ] let videoReaderOutput = AVAssetReaderTrackOutput(track: videoTrack, outputSettings: videoReaderSettings) var videoReader: AVAssetReader! do{ videoReader = try AVAssetReader(asset: videoAsset) } catch { print("video reader error: \(error)") completion(false) } videoReader.add(videoReaderOutput) //setup audio writer let audioWriterInput = AVAssetWriterInput(mediaType: AVMediaType.audio, outputSettings: nil) audioWriterInput.expectsMediaDataInRealTime = false videoWriter.add(audioWriterInput) //setup audio reader let audioTrack = videoAsset.tracks(withMediaType: AVMediaType.audio)[0] let audioReaderOutput = AVAssetReaderTrackOutput(track: audioTrack, outputSettings: nil) let audioReader = try! AVAssetReader(asset: videoAsset) audioReader.add(audioReaderOutput) videoWriter.startWriting() //start writing from video reader videoReader.startReading() videoWriter.startSession(atSourceTime: kCMTimeZero) let processingQueue = DispatchQueue(label: "processingQueue1") videoWriterInput.requestMediaDataWhenReady(on: processingQueue, using: {() -> Void in while videoWriterInput.isReadyForMoreMediaData { let sampleBuffer:CMSampleBuffer? = videoReaderOutput.copyNextSampleBuffer(); if videoReader.status == .reading && sampleBuffer != nil { videoWriterInput.append(sampleBuffer!) } else { videoWriterInput.markAsFinished() if videoReader.status == .completed { //start writing from audio reader audioReader.startReading() videoWriter.startSession(atSourceTime: kCMTimeZero) let processingQueue = DispatchQueue(label: "processingQueue2") audioWriterInput.requestMediaDataWhenReady(on: processingQueue, using: {() -> Void in while audioWriterInput.isReadyForMoreMediaData { let sampleBuffer:CMSampleBuffer? = audioReaderOutput.copyNextSampleBuffer() if audioReader.status == .reading && sampleBuffer != nil { audioWriterInput.append(sampleBuffer!) } else { audioWriterInput.markAsFinished() if audioReader.status == .completed { videoWriter.finishWriting(completionHandler: {() -> Void in completion(true) }) } } } }) } } } }) }