UIImage
sピクセルバッファをASSETWriterInput
に追加する次の2つの方法を試してみます。ビデオファイルにデータがないことを除いて、すべてが良さそうです。どうしましたか?
AVAssetWriterInputPixelBufferAdaptor * avAdaptor = [AVAssetWriterInputPixelBufferAdaptor assetWriterInputPixelBufferAdaptorWithAssetWriterInput:writerInput sourcePixelBufferAttributes:NULL];
[avAdaptor appendPixelBufferixelBuffer withPresentationTime:CMTimeMake(1, 10)];
// Create sample buffer.
CMSampleBufferRef sampleBuffer = NULL;
result = CMSampleBufferCreateForImageBuffer(kCFAllocatorDef ault, pixelBuffer, true, NULL, NULL, videoInfo, &timing, &sampleBuffer);
// Ship out the frame.
NSParameterAssert(CMSampleBufferDataIsReady(sample Buffer));
NSParameterAssert([writerInput isReadyForMoreMediaData]);
BOOL success = [writerInput appendSampleBuffer:sampleBuffer];
何らかの理由で、バッファを複数回追加する必要があることがわかりました。私が作成したテストアプリからのこの例のタイミングは適切ではないかもしれませんが、それが機能するので、それはあなたに良い考えを与えるはずです。
+ (void)writeImageAsMovie:(UIImage*)image toPath:(NSString*)path size:(CGSize)size duration:(int)duration
{
NSError *error = nil;
AVAssetWriter *videoWriter = [[AVAssetWriter alloc] initWithURL:
[NSURL fileURLWithPath:path] fileType:AVFileTypeQuickTimeMovie
error:&error];
NSParameterAssert(videoWriter);
NSDictionary *videoSettings = [NSDictionary dictionaryWithObjectsAndKeys:
AVVideoCodecH264, AVVideoCodecKey,
[NSNumber numberWithInt:size.width], AVVideoWidthKey,
[NSNumber numberWithInt:size.height], AVVideoHeightKey,
nil];
AVAssetWriterInput* writerInput = [[AVAssetWriterInput
assetWriterInputWithMediaType:AVMediaTypeVideo
outputSettings:videoSettings] retain];
AVAssetWriterInputPixelBufferAdaptor *adaptor = [AVAssetWriterInputPixelBufferAdaptor
assetWriterInputPixelBufferAdaptorWithAssetWriterInput:writerInput
sourcePixelBufferAttributes:nil];
NSParameterAssert(writerInput);
NSParameterAssert([videoWriter canAddInput:writerInput]);
[videoWriter addInput:writerInput];
//Start a session:
[videoWriter startWriting];
[videoWriter startSessionAtSourceTime:kCMTimeZero];
//Write samples:
CVPixelBufferRef buffer = [Utils pixelBufferFromCGImage:image.CGImage size:size];
[adaptor appendPixelBuffer:buffer withPresentationTime:kCMTimeZero];
[adaptor appendPixelBuffer:buffer withPresentationTime:CMTimeMake(duration-1, 2)];
//Finish the session:
[writerInput markAsFinished];
[videoWriter endSessionAtSourceTime:CMTimeMake(duration, 2)];
[videoWriter finishWriting];
}
この方法は必須ではありませんが、ここではピクセルバッファソースの例として使用されています。
+ (CVPixelBufferRef) pixelBufferFromCGImage:(CGImageRef)image size:(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, (CFDictionaryRef) options,
&pxbuffer);
status=status;//Added to make the stupid compiler not show a stupid warning.
NSParameterAssert(status == kCVReturnSuccess && pxbuffer != NULL);
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,
kCGImageAlphaNoneSkipFirst);
NSParameterAssert(context);
//CGContextTranslateCTM(context, 0, CGImageGetHeight(image));
//CGContextScaleCTM(context, 1.0, -1.0);//Flip vertically to account for different Origin
CGContextDrawImage(context, CGRectMake(0, 0, CGImageGetWidth(image),
CGImageGetHeight(image)), image);
CGColorSpaceRelease(rgbColorSpace);
CGContextRelease(context);
CVPixelBufferUnlockBaseAddress(pxbuffer, 0);
return pxbuffer;
}
このコードで少し問題が発生しました。その結果、歪んだ画像が表示されます。
変化:
CGContextRef context = CGBitmapContextCreate(pxdata,
size.width,
size.height,
8,
4 * size.width,
rgbColorSpace,
kCGImageAlphaNoneSkipFirst);
に:
CGContextRef context = CGBitmapContextCreate(pxdata,
size.width,
size.height,
8,
CVPixelBufferGetBytesPerRow(pxbuffer),
rgbColorSpace,
kCGImageAlphaNoneSkipFirst);
助けた。
@Peter DeWeeseからの回答は従うべき方向ですが、コードには2つの大きな問題があります。1つは、システムが新しいメディアを追加する準備ができるまで待つ必要があること、もう1つは、優れたメモリを備えていることです。ビデオライターに追加された後にバッファーを解放する必要があるため、リークが発生します。
これはまさにあなたの場合に当てはまりますが、次のように複数のフレームでループしたい一般的な場合にはさらに当てはまります。
NSInteger i = 0;
for (; i<n; i++) {
image = allImages[i];
CVPixelBufferRef buffer = [self pixelBufferFromCGImage:image.CGImage cropFrame:frame];
// wait for more media data is ready
while (adaptor.assetWriterInput.readyForMoreMediaData == FALSE) {
NSDate *maxDate = [NSDate dateWithTimeIntervalSinceNow:0.1];
[[NSRunLoop currentRunLoop] runUntilDate:maxDate];
}
NSLog(@"Panorama: appending frame %ld out of %ld", (long)i, (long)n);
// Append data
[adaptor appendPixelBuffer:buffer withPresentationTime:CMTimeMake(i, freq)];//kCMTimeZero];
// release the buffer
CVPixelBufferRelease(buffer);
}