【发布时间】:2014-05-18 10:37:43
【问题描述】:
我正在尝试使用 AVFoundation 从图像创建视频。 关于这种方法已经有多个线程,但我相信其中许多都与我在这里面临的问题相同。
视频在 iPhone 上可以正常播放,但不能在 VLC 上播放,例如在 Facebook 和 Vimeo 上也不能正常播放(有时有些帧不同步)。 VLC 说视频的帧率为 0.58 fps,但应该超过 24 吧?
有谁知道是什么导致了这种行为?
这是用于创建视频的代码:
self.videoWriter = [[AVAssetWriter alloc] initWithURL:[NSURL fileURLWithPath:videoOutputPath] fileType:AVFileTypeMPEG4 error:&error];
// Codec compression settings
NSDictionary *videoSettings = @{
AVVideoCodecKey : AVVideoCodecH264,
AVVideoWidthKey : @(self.videoSize.width),
AVVideoHeightKey : @(self.videoSize.height),
AVVideoCompressionPropertiesKey : @{
AVVideoAverageBitRateKey : @(20000*1000), // 20 000 kbits/s
AVVideoProfileLevelKey : AVVideoProfileLevelH264High40,
AVVideoMaxKeyFrameIntervalKey : @(1)
}
};
AVAssetWriterInput* videoWriterInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:videoSettings];
AVAssetWriterInputPixelBufferAdaptor *adaptor = [AVAssetWriterInputPixelBufferAdaptor
assetWriterInputPixelBufferAdaptorWithAssetWriterInput:videoWriterInput
sourcePixelBufferAttributes:nil];
videoWriterInput.expectsMediaDataInRealTime = NO;
[self.videoWriter addInput:videoWriterInput];
[self.videoWriter startWriting];
[self.videoWriter startSessionAtSourceTime:kCMTimeZero];
[adaptor.assetWriterInput requestMediaDataWhenReadyOnQueue:self.photoToVideoQueue usingBlock:^{
CMTime time = CMTimeMakeWithSeconds(0, 1000);
for (Segment* segment in segments) {
@autoreleasepool {
UIImage* image = segment.segmentImage;
CVPixelBufferRef buffer = [self pixelBufferFromImage:image withImageSize:self.videoSize];
[ImageToVideoManager appendToAdapter:adaptor pixelBuffer:buffer atTime:time];
CVPixelBufferRelease(buffer);
CMTime millisecondsDuration = CMTimeMake(segment.durationMS.integerValue, 1000);
time = CMTimeAdd(time, millisecondsDuration);
}
}
[videoWriterInput markAsFinished];
[self.videoWriter endSessionAtSourceTime:time];
[self.videoWriter finishWritingWithCompletionHandler:^{
NSLog(@"Video writer has finished creating video");
}];
}];
- (CVPixelBufferRef)pixelBufferFromImage:(UIImage*)image withImageSize:(CGSize)size{
CGImageRef cgImage = image.CGImage;
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);
if (status != kCVReturnSuccess){
DebugLog(@"Failed to create pixel buffer");
}
CVPixelBufferLockBaseAddress(pxbuffer, 0);
void *pxdata = CVPixelBufferGetBaseAddress(pxbuffer);
CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(pxdata, size.width, size.height, 8, 4*size.width, rgbColorSpace, 2);
CGContextConcatCTM(context, CGAffineTransformMakeRotation(0));
CGContextDrawImage(context, CGRectMake(0, 0, CGImageGetWidth(cgImage), CGImageGetHeight(cgImage)), cgImage);
CGColorSpaceRelease(rgbColorSpace);
CGContextRelease(context);
CVPixelBufferUnlockBaseAddress(pxbuffer, 0);
return pxbuffer;
}
+ (BOOL)appendToAdapter:(AVAssetWriterInputPixelBufferAdaptor*)adaptor
pixelBuffer:(CVPixelBufferRef)buffer
atTime:(CMTime)time{
while (!adaptor.assetWriterInput.readyForMoreMediaData) {
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
}
return [adaptor appendPixelBuffer:buffer withPresentationTime:time];
}
【问题讨论】:
标签: avfoundation video-processing frame-rate avassetwriter