大家好,在这里需要快速帮助;我试图使用在线教程将图像转换为视频。该过程完成并在iphone / i设备和QuickTime上正确播放,但是在其他任何播放器(例如VLC Realplayer,Web播放器等)上播放时,则不会播放。看完最终文件后,我可以看到视频的fps在0到0.16之间(理想情况下应该在24-30 fps之间)。任何人都可以提出一种修复fps的方法。我使用的代码如下:
+ (void)createVideoWithImages:(NSArray <NSString *> *)images withDuration:(long int)duration completion:(void (^) (BOOL success, NSString *output, NSError *error))completion
{
__block BOOL success = NO;
__block NSString *videoOutputPath = [ViewController newfNameWithPath];
NSError *error = nil;
double width = 0;
double height = 0;
CGSize imageSize = CGSizeZero;
NSUInteger framesPerSecond = 30;
NSMutableArray *imageArray = [[NSMutableArray alloc] initWithCapacity:images.count];
for (NSUInteger i = 0; i < [images count]; i++)
{
NSString *imagePath = [images objectAtIndex:i];
[imageArray addObject:[UIImage imageWithContentsOfFile:imagePath]];
UIImage *newImage = [ViewController createImage:((UIImage *)[imageArray objectAtIndex:i])];
UIImage *img = [ViewController imageOrientation:newImage];
[imageArray replaceObjectAtIndex:i withObject:img];
width = (width > ((UIImage *)[imageArray lastObject]).size.width) ? width : ((UIImage *)[imageArray lastObject]).size.width;
height = (height > ((UIImage *)[imageArray lastObject]).size.height) ? height : ((UIImage *)[imageArray lastObject]).size.height;
}
imageSize = CGSizeMake(1280, 720);
AVAssetWriter *videoWriter = [[AVAssetWriter alloc] initWithURL:[ViewController getURL:videoOutputPath] fileType:AVFileTypeQuickTimeMovie error:&error];
NSParameterAssert(videoWriter);
NSDictionary *videoCleanApertureSettings = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:1280], AVVideoCleanApertureWidthKey,
[NSNumber numberWithInt:720], AVVideoCleanApertureHeightKey,
[NSNumber numberWithInt:10], AVVideoCleanApertureHorizontalOffsetKey,
[NSNumber numberWithInt:10], AVVideoCleanApertureVerticalOffsetKey,
nil];
NSDictionary *aspectRatioSettings = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:3], AVVideoPixelAspectRatioHorizontalSpacingKey,
[NSNumber numberWithInt:3],AVVideoPixelAspectRatioVerticalSpacingKey,
nil];
NSDictionary *codecSettings = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:960000], AVVideoAverageBitRateKey,
[NSNumber numberWithInt:1],AVVideoMaxKeyFrameIntervalKey,
videoCleanApertureSettings, AVVideoCleanApertureKey,
aspectRatioSettings, AVVideoPixelAspectRatioKey,
//AVVideoProfileLevelH264Main30, AVVideoProfileLevelKey,
nil];
NSDictionary *videoSettings = [NSDictionary dictionaryWithObjectsAndKeys:
AVVideoCodecH264, AVVideoCodecKey,
codecSettings,AVVideoCompressionPropertiesKey,
[NSNumber numberWithInt: 1280], AVVideoWidthKey,
[NSNumber numberWithInt: 720], AVVideoHeightKey,
nil];
AVAssetWriterInput* videoWriterInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:videoSettings];
AVAssetWriterInputPixelBufferAdaptor *adaptor = [AVAssetWriterInputPixelBufferAdaptor assetWriterInputPixelBufferAdaptorWithAssetWriterInput:videoWriterInput sourcePixelBufferAttributes:nil];
NSParameterAssert(videoWriterInput);
NSParameterAssert([videoWriter canAddInput:videoWriterInput]);
videoWriterInput.expectsMediaDataInRealTime = YES;
[videoWriter addInput:videoWriterInput];
videoWriterInput.transform = CGAffineTransformMakeRotation(M_PI_2 * 2);
if (![videoWriter startWriting])
{
completion(success, nil, videoWriter.error);
}
[videoWriter startSessionAtSourceTime:kCMTimeZero];
CVPixelBufferRef buffer = NULL;
int frameCount = 0;
double numberOfSecondsPerFrame = duration / [imageArray count];
double frameDuration = framesPerSecond * numberOfSecondsPerFrame;
for(UIImage *image in imageArray)
{
buffer = [ViewController pixelBufferFromCGImage:[image CGImage] withSize:imageSize];
BOOL completeWitnNoError = NO;
int counter = 0;
while (!completeWitnNoError && counter < 30)
{
NSLog(@"writing image: %ld at frame: %d",(long)frameCount, counter);
if (adaptor.assetWriterInput.readyForMoreMediaData)
{
CMTime frameTime = CMTimeMake(frameCount*frameDuration, (int32_t)framesPerSecond);
CMTimeShow(frameTime);
completeWitnNoError = [adaptor appendPixelBuffer:buffer withPresentationTime:frameTime];
if(!completeWitnNoError)
{
if(buffer)
CVPixelBufferRelease(buffer);
completion(!completion, nil, videoWriter.error);
}
}
else
{
if(buffer)
CVPixelBufferRelease(buffer);
NSLog(@"adaptor not ready %d, %d\n", frameCount, counter);
[NSThread sleepForTimeInterval:0.1];
}
counter++;
}
if(buffer)
CVPixelBufferRelease(buffer);
if (!completeWitnNoError)
{
NSDictionary *userInfo = @{
NSLocalizedDescriptionKey: NSLocalizedString(@"Error\n", nil),
NSLocalizedFailureReasonErrorKey: NSLocalizedString(@"Images to video writing failed ", nil),
NSLocalizedRecoverySuggestionErrorKey: NSLocalizedString(@"Images to video writing failed ", nil)
};
NSError *error = [NSError errorWithDomain:@"Images to video error" code: -1005 userInfo:userInfo];
completion(!completion, nil, error);
}
frameCount++;
}
[videoWriterInput markAsFinished];
[videoWriter finishWritingWithCompletionHandler:^{
switch ([videoWriter status])
{
case AVAssetReaderStatusReading:
break;
case AVAssetReaderStatusCompleted:
{
NSLog(@"IMAGES TO VIDEO WRITE SUCCESS");
success = !success;
completion(success, videoOutputPath, videoWriter.error);
break;
}
case AVAssetReaderStatusCancelled:
{
NSLog(@"IMAGES TO VIDEO WRITE FAILURE");
completion(success, nil, videoWriter.error);
[videoWriter cancelWriting];
break;
}
case AVAssetReaderStatusFailed:
{
NSLog(@"IMAGES TO VIDEO WRITE FAILURE");
completion(success, nil, videoWriter.error);
[videoWriter cancelWriting];
break;
}
case AVAssetReaderStatusUnknown:
{
NSLog(@"IMAGES TO VIDEO WRITE FAILURE");
completion(success, nil, videoWriter.error);
[videoWriter cancelWriting];
break;
}
}
}];
return;
}
和缓冲区:
+ (CVPixelBufferRef) pixelBufferFromCGImage:(CGImageRef)image withSize:(CGSize)size
{
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], kCVPixelBufferCGImageCompatibilityKey,
[NSNumber numberWithBool:YES], kCVPixelBufferCGBitmapContextCompatibilityKey,
nil];
CVPixelBufferRef pxbuffer = NULL;
CVReturn status = CVPixelBufferCreate(kCFAllocatorDefault,
size.width,
size.height,
kCVPixelFormatType_32ARGB,
(__bridge CFDictionaryRef) options,
&pxbuffer);
NSParameterAssert(status == kCVReturnSuccess && pxbuffer != NULL);
if (status != kCVReturnSuccess)
{
NSString *description = [NSString stringWithFormat:@"Failed to create pixel buffer."];
NSDictionary *userInfo = @{
NSLocalizedDescriptionKey: NSLocalizedString(description, nil),
NSLocalizedFailureReasonErrorKey: NSLocalizedString(@"Could create buffer", nil),
NSLocalizedRecoverySuggestionErrorKey: NSLocalizedString(@"Try again", nil)
};
NSError *error = [NSError errorWithDomain:@"CVPixelBufferRef" code: -1005 userInfo:userInfo];
NSLog(@"ALERT: %@", [error localizedDescription]);
}
CVPixelBufferLockBaseAddress(pxbuffer, 0);
void *pxdata = CVPixelBufferGetBaseAddress(pxbuffer);
NSParameterAssert(pxdata != NULL);
CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(pxdata, size.width,
size.height, 8, 4*size.width, rgbColorSpace,
kCGImageAlphaPremultipliedFirst);
CGContextConcatCTM(context, CGAffineTransformMakeRotation(0));
CGContextDrawImage(context, CGRectMake((size.width/(CGImageGetWidth(image) / 2)), (size.height/(CGImageGetWidth(image) / 2)), 1280, 720), image);
CGColorSpaceRelease(rgbColorSpace);
CGContextRelease(context);
CVPixelBufferUnlockBaseAddress(pxbuffer, 0);
return pxbuffer;
}
有什么建议么??
最佳答案
尝试使用CEMovieMaker,我以前使用过它,并且像魅力一样工作,因为我认为您的问题出在videoCodec中
https://github.com/cameronehrlich/CEMovieMaker
@interface ViewController ()
@property (nonatomic, strong) CEMovieMaker *movieMaker;
@end
- (IBAction)process:(id)sender
{
NSMutableArray *frames = [[NSMutableArray alloc] init];
UIImage *icon1 = [UIImage imageNamed:@"icon1"];
UIImage *icon2 = [UIImage imageNamed:@"icon2"];
UIImage *icon3 = [UIImage imageNamed:@"icon3"];
NSDictionary *settings = [CEMovieMaker videoSettingsWithCodec:AVVideoCodecH264 withHeight:icon1.size.width andWidth:icon1.size.height];
self.movieMaker = [[CEMovieMaker alloc] initWithSettings:settings];
for (NSInteger i = 0; i < 10; i++) {
[frames addObject:icon1];
[frames addObject:icon2];
[frames addObject:icon3];
}
[self.movieMaker createMovieFromImages:[frames copy] withCompletion:^(BOOL success, NSURL *fileURL){
if (success) {
[self viewMovieAtUrl:fileURL];
}
}];
}
- (void)viewMovieAtUrl:(NSURL *)fileURL
{
MPMoviePlayerViewController *playerController = [[MPMoviePlayerViewController alloc] initWithContentURL:fileURL];
[playerController.view setFrame:self.view.bounds];
[self presentMoviePlayerViewControllerAnimated:playerController];
[playerController.moviePlayer prepareToPlay];
[playerController.moviePlayer play];
[self.view addSubview:playerController.view];
}
关于ios - 将图像转换为视频具有错误的FPS iOS,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/37532222/