AVAssetWriterInputPixelBufferAdaptor returns a pool of zero pixel buffer

Iโ€™m sure that something is wrong with my buffer attributes, but I donโ€™t understand that - he did not document well what should go there, so I assume that based on CVPixelBufferPoolCreate - and the Core Foundation is a pretty closed book for me.

  // "width" and "height" are const ints CFNumberRef cfWidth = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &width); CFNumberRef cfHeight = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &height); CFStringRef keys[] = { kCVPixelBufferWidthKey, kCVPixelBufferHeightKey, kCVPixelBufferCGImageCompatibilityKey }; CFTypeRef values[] = { cfWidth, cfHeight, kCFBooleanTrue }; int numValues = sizeof(keys) / sizeof(keys[0]); CFDictionaryRef bufferAttributes = CFDictionaryCreate(kCFAllocatorDefault, (const void **)&keys, (const void **)&values, numValues, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks ); AVAssetWriterInputPixelBufferAdaptor *adaptor = [[AVAssetWriterInputPixelBufferAdaptor assetWriterInputPixelBufferAdaptorWithAssetWriterInput:writerInput sourcePixelBufferAttributes:(NSDictionary*)bufferAttributes] retain]; CVPixelBufferPoolRef bufferPool = adaptor.pixelBufferPool; NSParameterAssert(bufferPool != NULL); // fails 
+8
source share
6 answers

When pixelBufferPool returns zero, check the following:

    1. AVAssetsWriter output file does not exist.
    2. use the pixel buffer after calling startSessionAtTime: on AVAssetsWriter.
    3. the settings of AVAssetWriterInput and AVAssetWriterInputPixelBufferAdaptor are correct.
    4. The current usage times of appendPixelBuffer do not match.
+15
source

I had the same problem and I think it is possible because you did not configure your AVAssetWriterInput . My pool started working after I did it. In particular, the pool will not give me pixel buffers if I have not provided data in AVVideoCompressionPropertiesKey . First create and fully configure AVAssetWriter (See /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.sdk/System/Library/Frameworks/AVFoundation.framework/Headers/AVVideoSettings.h for keys and values โ€‹โ€‹for outputSettings and compressionSettings ):

 NSError * err = 0; AVAssetWriter * outputWriter = [AVAssetWriter assetWriterWithURL: [NSURL fileURLWithPath:outputPath] fileType: AVFileTypeAppleM4V error: & err]; NSMutableDictionary * outputSettings = [[NSMutableDictionary alloc] init]; [outputSettings setObject: AVVideoCodecH264 forKey: AVVideoCodecKey]; [outputSettings setObject: [NSNumber numberWithInt: width_] forKey: AVVideoWidthKey]; [outputSettings setObject: [NSNumber numberWithInt: height_] forKey: AVVideoHeightKey]; NSMutableDictionary * compressionProperties = [[NSMutableDictionary alloc] init]; [compressionProperties setObject: [NSNumber numberWithInt: 1000000] forKey: AVVideoAverageBitRateKey]; [compressionProperties setObject: [NSNumber numberWithInt: 16] forKey: AVVideoMaxKeyFrameIntervalKey]; [compressionProperties setObject: AVVideoProfileLevelH264Main31 forKey: AVVideoProfileLevelKey]; [outputSettings setObject: compressionProperties forKey: AVVideoCompressionPropertiesKey]; AVAssetWriterInput * writerInput = [AVAssetWriterInput assetWriterInputWithMediaType: AVMediaTypeVideo outputSettings: outputSettings]; [compressionProperties release]; [outputSettings release]; 

Create a pixel buffer adapter:

 NSMutableDictionary * pixBufSettings = [[NSMutableDictionary alloc] init]; [pixBufSettings setObject: [NSNumber numberWithInt: kCVPixelFormatType_32BGRA] forKey: (NSString *) kCVPixelBufferPixelFormatTypeKey]; [pixBufSettings setObject: [NSNumber numberWithInt: width_] forKey: (NSString *) kCVPixelBufferWidthKey]; [pixBufSettings setObject: [NSNumber numberWithInt: height_] forKey: (NSString *) kCVPixelBufferHeightKey]; AVAssetWriterInputPixelBufferAdaptor * outputPBA = [AVAssetWriterInputPixelBufferAdaptor assetWriterInputPixelBufferAdaptorWithAssetWriterInput: outputInput sourcePixelBufferAttributes: nil]; 

Then retrieve the pixel buffers from the pool using:

 CVReturn res = CVPixelBufferPoolCreatePixelBuffer (NULL , [outputPBA pixelBufferPool] , & outputFrame); 
+3
source

According to the documentation:

"This is a NULL property before the first call to startSessionAtTime: on the associated AVAssetWriter."

So, if you try to access the pool too soon, it will be NULL. I just study this material myself, so I canโ€™t understand it in detail now.

+2
source

For anyone who is still looking for a solution: First, make sure your AVAssetWriter is working correctly by checking its status. I had this problem, and after checking the status, although I am causing something to start, the writer has not started yet. (In my case, I indicate the path to the existing file, so after deleting it, it works like a charm)

+1
source

I did it all! Using the compatibility dictionary, they talk about the possibility of using a buffer pool. Here are working samples and code for writing without a buffer, but this is a good place to run.

Here is a sample code link

Here is the code you need:

 - (void) testCompressionSession { CGSize size = CGSizeMake(480, 320); NSString *betaCompressionDirectory = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents/Movie.m4v"]; NSError *error = nil; unlink([betaCompressionDirectory UTF8String]); //----initialize compression engine AVAssetWriter *videoWriter = [[AVAssetWriter alloc] initWithURL:[NSURL fileURLWithPath:betaCompressionDirectory] fileType:AVFileTypeQuickTimeMovie error:&error]; NSParameterAssert(videoWriter); if(error) NSLog(@"error = %@", [error localizedDescription]); NSDictionary *videoSettings = [NSDictionary dictionaryWithObjectsAndKeys:AVVideoCodecH264, AVVideoCodecKey, [NSNumber numberWithInt:size.width], AVVideoWidthKey, [NSNumber numberWithInt:size.height], AVVideoHeightKey, nil]; AVAssetWriterInput *writerInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:videoSettings]; NSDictionary *sourcePixelBufferAttributesDictionary = [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithInt:kCVPixelFormatType_32ARGB], kCVPixelBufferPixelFormatTypeKey, nil]; AVAssetWriterInputPixelBufferAdaptor *adaptor = [AVAssetWriterInputPixelBufferAdaptor assetWriterInputPixelBufferAdaptorWithAssetWriterInput:writerInput sourcePixelBufferAttributes:sourcePixelBufferAttributesDictionary]; NSParameterAssert(writerInput); NSParameterAssert([videoWriter canAddInput:writerInput]); if ([videoWriter canAddInput:writerInput]) NSLog(@"I can add this input"); else NSLog(@"i can't add this input"); [videoWriter addInput:writerInput]; [videoWriter startWriting]; [videoWriter startSessionAtSourceTime:kCMTimeZero]; //--- // insert demo debugging code to write the same image repeated as a movie CGImageRef theImage = [[UIImage imageNamed:@"Lotus.png"] CGImage]; dispatch_queue_t dispatchQueue = dispatch_queue_create("mediaInputQueue", NULL); int __block frame = 0; [writerInput requestMediaDataWhenReadyOnQueue:dispatchQueue usingBlock:^{ while ([writerInput isReadyForMoreMediaData]) { if(++frame >= 120) { [writerInput markAsFinished]; [videoWriter finishWriting]; [videoWriter release]; break; } CVPixelBufferRef buffer = (CVPixelBufferRef)[self pixelBufferFromCGImage:theImage size:size]; if (buffer) { if(![adaptor appendPixelBuffer:buffer withPresentationTime:CMTimeMake(frame, 20)]) NSLog(@"FAIL"); else NSLog(@"Success:%d", frame); CFRelease(buffer); } } }]; NSLog(@"outside for loop"); } - (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); // CVReturn status = CVPixelBufferPoolCreatePixelBuffer(NULL, adaptor.pixelBufferPool, &pxbuffer); 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, kCGImageAlphaPremultipliedFirst); NSParameterAssert(context); CGContextDrawImage(context, CGRectMake(0, 0, CGImageGetWidth(image), CGImageGetHeight(image)), image); CGColorSpaceRelease(rgbColorSpace); CGContextRelease(context); CVPixelBufferUnlockBaseAddress(pxbuffer, 0); return pxbuffer; } 
0
source

It works when there is no file in AVAssetWriter for AVAssetWriter .

 extension FileManager { func removeItemIfExist(at url: URL) { do { if FileManager.default.fileExists(atPath: url.path) { try FileManager.default.removeItem(at: url) } } catch { fatalError("\(error)") } } } 

Usage

Usage
 let assetWriter = try? AVAssetWriter(outputURL: outputURL, fileType: .mov) FileManager.default.removeItemIfExist(at: outputURL) // do something 
0
source

Source: https://habr.com/ru/post/886840/


All Articles