I try the following 2 methods of appending UIImage
s pixelbuffer to ASSETWriterInput
. Everything looks good except there's No data in the video file. What's wrong?
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];
I found that for some reason I needed to append the buffer more than once. The timing in this example from a test app I made might not be proper, but since it works it should give you a good idea.
+ (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]; }
This method is not required, but is used here as an example of a pixel buffer source:
+ (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; }
I've had a bit of a problem with this code. It geave me a skewed image as a result.
Changing:
CGContextRef context = CGBitmapContextCreate(pxdata, size.width, size.height, 8, 4 * size.width, rgbColorSpace, kCGImageAlphaNoneSkipFirst);
To:
CGContextRef context = CGBitmapContextCreate(pxdata, size.width, size.height, 8, CVPixelBufferGetBytesPerRow(pxbuffer), rgbColorSpace, kCGImageAlphaNoneSkipFirst);
helped.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With