UIImagePickerController로 만든 동영상의 파일 크기를 줄이려면 어떻게해야합니까?
사용자가 동영상을 녹화 한 UIImagePickerController
다음 YouTube에 업로드 할 수있는 앱이 있습니다 . 문제는 동영상의 UIImagePickerController
길이가 5 초에 불과하더라도 생성 되는 동영상 파일 이 거대 하다는 것 입니다. 예를 들어 5 초 길이의 비디오는 16-20MB입니다. 동영상을 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의 사진 앱에서 "YouTube에서 공유" 를 선택 하면 동영상 파일을 자동으로 처리하여 업로드하기에 충분히 작기 때문에 제가하는 일이 가능하다는 것을 알고 있습니다. 내 앱에서 동일한 작업을하고 싶습니다.
어떻게하면 되나요?
를 사용 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];
편집 : 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
서버에 업로드 합니다.
참고 내 프로젝트에서 ARC를 활성화 한 일부 추가해야합니다, 그래서 release
ARC가 당신에 꺼져 있으면 전화를.
에 UImagePickerController
당신이 videoQuality
재산 UIImagePickerControllerQualityType
유형을 기록 영화뿐만 아니라 당신이 (트랜스 코딩 단계에서 발생) 라이브러리에서 선택 고른하는 사람에 적용됩니다.
또는 라이브러리에없는 기존 자산 (파일)을 처리해야하는 경우 다음 사전 설정을 살펴볼 수 있습니다.
AVAssetExportPresetLowQuality
AVAssetExportPresetMediumQuality
AVAssetExportPresetHighestQuality
과
AVAssetExportPreset640x480
AVAssetExportPreset960x540
AVAssetExportPreset1280x720
AVAssetExportPreset1920x1080
그 중 하나 를 클래스의 이니셜 라이저 에 전달합니다 AVAssetExportSession
. 나는 당신이 무엇인지에 대한 정확한 설명이없는 한 특정 콘텐츠에 대한 사람들과 재생이 두려워 low
및 medium
품질이나되는 품질이 사용됩니다 640x480
또는에 대한 1280x720
사전 설정은. 문서에서 유일하게 유용한 정보는 다음과 같습니다.
장치에 적합한 QuickTime 파일의 사전 설정 이름 내보내기 이러한 내보내기 옵션을 사용하여 현재 장치에 적합한 비디오 크기로 QuickTime .mov 파일을 생성 할 수 있습니다.
내보내기는 더 작은 크기에서 비디오를 확대하지 않습니다. 비디오는 H.264를 사용하여 압축됩니다. 오디오는 AAC를 사용하여 압축됩니다.
일부 장치는 일부 크기를 지원하지 않습니다.
그 외에도 프레임 속도 또는 자유형 크기 등과 같은 품질을 정확하게 제어 한 기억이 없습니다. AVFoundation
내가 틀렸다. 언급 한 모든 매개 변수를 조정하는 방법이 있으며 실제로 AVAssetWriter입니다. UIImage 배열을 동영상으로 내보내려면 어떻게해야합니까?
btw, 여기에 코드 샘플이있는 유사한 질문에 대한 링크가 있습니다. iPhone : 녹화 된 비디오를 프로그래밍 방식으로 압축하여 공유 하시겠습니까?
Erik의 대답은 그가 작성했을 때 정확했을 수 있습니다. 그러나 이제 iOS8에서는 왼쪽과 오른쪽이 충돌하고 몇 시간을 보냈습니다.
당신은 AVAssetWriter와 작업에 박사 학위를 필요로 - 그것은 아닌 사소한 : https://developer.apple.com/library/mac/documentation/AudioVideo/Conceptual/AVFoundationPG/Articles/05_Export.html#//apple_ref/doc/uid/ TP40010188-CH9-SW1
비트 전송률 변경과 같은 더 중요한 기능으로 AVAssetExportSession 드롭 인 대체물 인 원하는 작업을 정확하게 수행 할 수있는 놀라운 라이브러리가 있습니다 : 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);
}
}];
}
Erik Wegener 코드가 신속한 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];
Erik Wegener 코드가 신속하게 재 작성되었습니다.
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 의 응답 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
스위프트 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)
})
}
}
}
})
}
}
}
})
}
Use exportSession.fileLengthLimit = 1048576 * 10 //10 MB
10MB는 하드 코딩 된 숫자입니다. 필요한 비트 전송률에 따라 사용하십시오.
fileLengthLimit
session should not exceed. Depending on the content of the source asset, it is possible for the output to slightly exceed the file length limit. The length of the output file should be tested if you require that a strict limit be observed before making use of the output. See also maxDuration and timeRange.Indicates the file length that the output of the
ReferenceURL : https://stackoverflow.com/questions/11751883/how-can-i-reduce-the-file-size-of-a-video-created-with-uiimagepickercontroller
'IT TIP' 카테고리의 다른 글
TFS에서 특정 사용자의 체크인 기록을 보는 방법은 무엇입니까? (0) | 2020.12.28 |
---|---|
Android 기기의 CURRENT 방향 (ActivityInfo.SCREEN_ORIENTATION_ *)은 어떻게 얻습니까? (0) | 2020.12.28 |
Java에서 현재 요소를 유지하면서 배열 크기를 조정합니까? (0) | 2020.12.28 |
Django Rest Framework로 여러 모델 인스턴스를 생성하려면 어떻게해야합니까? (0) | 2020.12.28 |
C #의 날짜 시간 추가 일 (0) | 2020.12.28 |