I read the documentation and related questions, and nothing seems to help my situation. I am trying to create a * .mp4 file using AVAssetWriter from one still image.
I cannot force an asset to call it a trailing block using finishWritingWithCompletionHandler:
I maintain a strong reference to the AVAssetWriter object.
Any help or understanding will be appreciated.
- (void)videoFromImage:(UIImage *)image
{
NSError *error;
self.videoWriter = [[AVAssetWriter alloc] initWithURL:
[NSURL fileURLWithPath:[[self applicationDocumentsDirectory] stringByAppendingPathComponent:@"output.mp4"]] fileType:AVFileTypeQuickTimeMovie
error:&error];
if (!error) {
NSParameterAssert(self.videoWriter);
NSDictionary *videoSettings = [NSDictionary dictionaryWithObjectsAndKeys:
AVVideoCodecH264, AVVideoCodecKey,
[NSNumber numberWithInt:image.size.width], AVVideoWidthKey,
[NSNumber numberWithInt:image.size.height], AVVideoHeightKey,
nil];
AVAssetWriterInput* videoWriterInput = [AVAssetWriterInput
assetWriterInputWithMediaType:AVMediaTypeVideo
outputSettings:videoSettings];
AVAssetWriterInputPixelBufferAdaptor *adaptor = [AVAssetWriterInputPixelBufferAdaptor
assetWriterInputPixelBufferAdaptorWithAssetWriterInput:videoWriterInput
sourcePixelBufferAttributes:nil];
NSParameterAssert(videoWriterInput);
NSParameterAssert([self.videoWriter canAddInput:videoWriterInput]);
[self.videoWriter addInput:videoWriterInput];
[self.videoWriter startWriting];
[self.videoWriter startSessionAtSourceTime:kCMTimeZero];
if (adaptor.assetWriterInput.readyForMoreMediaData) {
CVPixelBufferRef buffer = [self pixelBufferFromImage:image];
[adaptor appendPixelBuffer:buffer withPresentationTime:kCMTimeZero];
}
[videoWriterInput markAsFinished];
[self.videoWriter finishWritingWithCompletionHandler:^{
NSLog(@"finished");
}];
}
else {
NSLog(@"%@", error.localizedDescription);
}
}
EDIT: AVAssetWriter could not write the file because a file with the same name already exists. Added
NSFileManager *manager = [[NSFileManager alloc] init];
if ([manager fileExistsAtPath:[[self applicationDocumentsDirectory] stringByAppendingPathComponent:@"output.mp4"]]) {
NSError *fileError;
[manager removeItemAtPath:[[self applicationDocumentsDirectory] stringByAppendingPathComponent:@"output.mp4"] error:&fileError];
if (fileError) NSLog(@"%@", fileError.localizedDescription);
}
and it works great.
Colin source
share