问题
I am trying to trim and then compress a video file.
- For trimming I am using
AVAssetExportSession
- For compression I am using
AVAssetWriter
.
If I use both codes individually every thing works fine but If I trim and then feed the trim output for compression I got compressed but corrupt video.
- (void)viewDidLoad
{
[super viewDidLoad];
[self trimVideo];
}
Trimming Code
-(void)trimVideo {
AVAsset *anAsset = [[AVURLAsset alloc]initWithURL:[self.asset valueForProperty:ALAssetPropertyAssetURL] options:nil];
AVAssetExportSession *exportSession = [[AVAssetExportSession alloc] initWithAsset:anAsset presetName:AVAssetExportPresetPassthrough];
NSString *fName = [NSString stringWithFormat:@"%@.%@", @"tempVid", @"mp4"];
saveURL = [NSURL fileURLWithPath:[[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:fName]];
NSString *fName1 = [NSString stringWithFormat:@"%@.%@", @"tempVid1", @"mp4"];
saveURL1 = [NSURL fileURLWithPath:[[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:fName1]];
exportSession.outputURL = saveURL;
exportSession.outputFileType = AVFileTypeMPEG4;
CMTime start = CMTimeMakeWithSeconds(1.0, 600);
CMTime duration = CMTimeMakeWithSeconds(180.0, 600);
CMTimeRange range = CMTimeRangeMake(start, duration);
exportSession.timeRange = range;
[exportSession exportAsynchronouslyWithCompletionHandler:^{
switch ([exportSession status]) {
case AVAssetExportSessionStatusFailed:
NSLog(@"Export failed: %@", [[exportSession error] localizedDescription]);
break;
case AVAssetExportSessionStatusCancelled:
NSLog(@"Export canceled");
break;
case AVAssetExportSessionStatusCompleted:
[self convertVideoToLowQuailtyWithInputURL:saveURL outputURL:saveURL1];
break;
default:
break;
}
}];
}
Compression Code
- (void)convertVideoToLowQuailtyWithInputURL:(NSURL*)inputURL outputURL:(NSURL*)outputURL
{
AVAsset *videoAsset = [[AVURLAsset alloc] initWithURL:inputURL options:nil];
AVAssetTrack *videoTrack = [[videoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
//CGSize videoSize = videoTrack.naturalSize;
NSDictionary* settings = [NSDictionary dictionaryWithObjectsAndKeys:AVVideoCodecH264, AVVideoCodecKey,
[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:960000],AVVideoAverageBitRateKey, AVVideoProfileLevelH264Main32, AVVideoProfileLevelKey,
[NSNumber numberWithInt:24], AVVideoMaxKeyFrameIntervalKey, [NSNumber numberWithInt:0.0], AVVideoMaxKeyFrameIntervalDurationKey, nil],
AVVideoCompressionPropertiesKey, [NSNumber numberWithInt:640], AVVideoWidthKey, [NSNumber numberWithInt:320], AVVideoHeightKey, nil];
AVAssetWriterInput* videoWriterInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:settings];
videoWriterInput.expectsMediaDataInRealTime = YES;
videoWriterInput.transform = videoTrack.preferredTransform;
AVAssetWriter *videoWriter = [[AVAssetWriter alloc] initWithURL:outputURL fileType:AVFileTypeQuickTimeMovie error:nil];
[videoWriter addInput:videoWriterInput];
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];
AVAssetWriterInput* audioWriterInput = [AVAssetWriterInput
assetWriterInputWithMediaType:AVMediaTypeAudio
outputSettings:nil];
audioWriterInput.expectsMediaDataInRealTime = NO;
[videoWriter addInput:audioWriterInput];
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];
[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:^(){
NSLog(@"Success");
}];
}
}
}
}
];
}
}
}
}
];
}
回答1:
You must use AVMutableCompositionTrack
class and for media file trimming you must need use - (void)removeTimeRange:(CMTimeRange)timeRange
method.
AVAsset *videoAsset = <#AVAsset with at least one video track#>;
AVAssetTrack *videoAssetTrack = [[videoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
AVMutableComposition *mutableComposition = [AVMutableComposition composition];
AVMutableCompositionTrack *compatibleCompositionTrack = [mutableComposition mutableTrackCompatibleWithTrack:videoAssetTrack];
if (compatibleCompositionTrack) {
// Implementation continues.
[compatibleCompositionTrack removeTimeRange: yourTimeRange];
//Export Now your media file using exportSession
AVAssetExportSession* _assetExport = [[AVAssetExportSession alloc] initWithAsset:compatibleCompositionTrack presetName:AVAssetExportPresetHighestQuality];
exportSession.outputFileType = AVFileTypeMPEG4;
_assetExport.outputURL = outputFileUrl;
[_assetExport exportAsynchronouslyWithCompletionHandler:
^(void ) {
switch ([exportSession status]) {
case AVAssetExportSessionStatusFailed:
NSLog(@"Export failed: %@", [[exportSession error] localizedDescription]);
break;
case AVAssetExportSessionStatusCancelled:
NSLog(@"Export canceled");
break;
case AVAssetExportSessionStatusCompleted:
[self convertVideoToLowQuailtyWithInputURL:saveURL outputURL:saveURL1];
break;
default:
break;
}
}
];
}
来源:https://stackoverflow.com/questions/26423304/avassetwriter-corrupting-the-video-trimmed-by-avassetexportsession