我一直在努力解决这个问题,但无法弄清楚我做错了什么。我想读取一个视频文件——处理帧......然后重新输出它:
我面临的问题是,由于某种原因,对 [self.audioOutput copyNextSampleBuffer]; 的调用会阻塞并且永远不会完成!
-(void) initializeAtPath:(NSURL*) inputPath withOutputPath:(NSURL*) outputPath{
NSDictionary *videoSettings = [NSDictionary dictionaryWithObjectsAndKeys:
AVVideoCodecH264, AVVideoCodecKey,
[NSNumber numberWithInt:352], AVVideoWidthKey,
[NSNumber numberWithInt:288], AVVideoHeightKey,
nil];
AVAsset * movieAsset = [AVAsset assetWithURL:inputPath];
self.reader = [[AVAssetReader alloc] initWithAsset:movieAsset error:nil];
NSDictionary *outputSettings = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:kCVPixelFormatType_32BGRA], (id)kCVPixelBufferPixelFormatTypeKey,nil];
self.frameOutput= [[AVAssetReaderTrackOutput alloc] initWithTrack:[[movieAsset tracks] objectAtIndex:0] outputSettings:outputSettings];
if([self.reader canAddOutput:self.frameOutput]){
[self.reader addOutput:self.frameOutput];
}
AudioChannelLayout channelLayout;
memset(&channelLayout, 0, sizeof(AudioChannelLayout));
channelLayout.mChannelLayoutTag = kAudioChannelLayoutTag_Stereo;
NSDictionary *audioSettings =[NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithInt:kAudioFormatLinearPCM], AVFormatIDKey, [NSNumber numberWithFloat:44100.0], AVSampleRateKey, [NSNumber numberWithInt:2], AVNumberOfChannelsKey, [NSData dataWithBytes:&channelLayout length:sizeof(AudioChannelLayout)], AVChannelLayoutKey, [NSNumber numberWithInt:16], AVLinearPCMBitDepthKey, [NSNumber numberWithBool:NO], AVLinearPCMIsNonInterleaved, [NSNumber numberWithBool:NO],AVLinearPCMIsFloatKey, [NSNumber numberWithBool:NO], AVLinearPCMIsBigEndianKey, nil];
NSArray * audioTracks = [movieAsset tracksWithMediaType:AVMediaTypeAudio];
self.audioOutput = [AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack:[audioTracks lastObject] outputSettings:nil];
if([self.reader canAddOutput:self.audioOutput]){
NSLog(@"ADDED");
[self.reader addOutput:self.audioOutput];
}
self.writer = [[AVAssetWriter alloc] initWithURL:outputPath fileType:AVFileTypeQuickTimeMovie error:nil];
self.writerInput = [[AVAssetWriterInput alloc] initWithMediaType:AVMediaTypeVideo outputSettings:videoSettings];
self.writerInput.expectsMediaDataInRealTime = YES;
[self.writerInput setTransform:CGAffineTransformMakeRotation(M_PI_2)];
self.audioWriterInput = [[AVAssetWriterInput alloc] initWithMediaType:AVMediaTypeAudio outputSettings:audioSettings];
self.audioWriterInput.expectsMediaDataInRealTime = YES;
[self.writer addInput:self.audioWriterInput];
[self.writer addInput:self.writerInput];
self.adaptor = [AVAssetWriterInputPixelBufferAdaptor assetWriterInputPixelBufferAdaptorWithAssetWriterInput:self.writerInput sourcePixelBufferAttributes:nil];
}
-(void) finish:(bool) success{
[self.writer finishWriting];
if(success && [self.delegate respondsToSelector:@selector(didFinishWritingMovieAtUrl:sender:)]){
dispatch_async(dispatch_get_main_queue(),^{
[self.delegate didFinishWritingMovieAtUrl:self.writer.outputURL sender:self];
});
}
if(!success && [self.delegate respondsToSelector:@selector(didFailToWriteMovieAtUrl:sender:)]){
dispatch_async(dispatch_get_main_queue(), ^{
[self.delegate didFailToWriteMovieAtUrl:self.writer.outputURL sender:self];
});
}
}
-(void) processAudioUsingQueue{
while([self.audioWriterInput isReadyForMoreMediaData]){
CMSampleBufferRef audioBuffer;
if (self.reader.status == AVAssetReaderStatusReading) {
NSLog(@"A");
audioBuffer = [self.audioOutput copyNextSampleBuffer];
NSLog(@"B");
bool result = [self.audioWriterInput appendSampleBuffer:audioBuffer];
if(!result){
[self.audioWriterInput markAsFinished];
[self.reader cancelReading];
break;
}
}else{
[self.audioWriterInput markAsFinished];
break;
}
}
[self finish:YES];
}
-(void) processFramesUsingQueue:(dispatch_queue_t) queue{
[self.writerInput requestMediaDataWhenReadyOnQueue:queue usingBlock:^{
while([self.writerInput isReadyForMoreMediaData]){
CMSampleBufferRef sampleBuffer;
if (self.reader.status == AVAssetReaderStatusReading && (sampleBuffer = [self.frameOutput copyNextSampleBuffer])) {
bool result = [self renderFrame:sampleBuffer];
if(!result){
[self.reader cancelReading];
break;
}
}else{
[self.writerInput markAsFinished];
switch(self.reader.status){
case AVAssetReaderStatusReading:
[self performSelectorOnMainThread:@selector(processAudioUsingQueue) withObject:nil waitUntilDone:YES];
break;
case AVAssetReaderStatusCompleted:
[self finish:YES];
break;
case AVAssetReaderStatusCancelled:
case AVAssetReaderStatusFailed:
[self finish:NO];
[self.writer cancelWriting];
break;
}
break;
}
}
}];
}
-(void) beginProcessingMovieAtPath:(NSURL*) inputPath withOutputPath:(NSURL*) outputPath startingTimeStamp:(CMTime) startTime{
if(!self.costumeViews || !self.costumeFrames) NSLog(@"Warning... missing parameters!");
[self initializeAtPath:inputPath withOutputPath:outputPath];
[self.reader startReading];
[self.writer startWriting];
self.startFrameTime = startTime;
[self.writer startSessionAtSourceTime:self.startFrameTime];
// start thread to pull video data:
dispatch_queue_t processvideo = dispatch_queue_create("process_queue", NULL);
[self processFramesUsingQueue:processvideo];
}