【问题标题】:AVAssetWriterInputPixelBufferAdaptor returns null pixel buffer poolAVAssetWriterInputPixelBufferAdaptor 返回空像素缓冲池
【发布时间】:2011-08-14 05:40:26
【问题描述】:

我确定我的缓冲区属性有问题,但我不清楚是什么——它没有很好地记录应该去那里的东西,所以我根据CVPixelBufferPoolCreate 猜测——核心基础很漂亮对我来说是一本合上的书。

    // "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

【问题讨论】:

  • 你好,我也有同样的问题,你找到解决办法了吗?
  • 并非如此。我只是为每一帧创建一个像素缓冲区,而不是使用池。 :(
  • 好的,我们找到了相同的解决方案。谢谢!
  • 嗨@DavidMoles,您找到解决方案了吗,或者您是否有“为每一帧创建像素缓冲区”的工作代码?
  • @IraniyaNaynesh 抱歉,我已经好几年没看过这个了。但是docs for pixelBufferPool 现在说“在第一次调用 startSessionAtTime: 关联的 AVAssetWriter 对象之前,此属性为 NULL。”那么也许这就是问题所在?

标签: ios core-foundation avassetwriter core-video


【解决方案1】:

当pixelBufferPool返回null时,检查如下:

    1. AVAssetsWriter 的输出文件不存在。
    2.在AVAssetsWriter上调用startSessionAtTime:后使用pixelbuffer。
    3. AVAssetWriterInput 和 AVAssetWriterInputPixelBufferAdaptor 的设置正确。
    4. appendPixelBuffer 使用次数不一样。

【讨论】:

  • #1 也为我做了诀窍。这么简单的解决方案!我真的看得太深了。顺便说一句,我的失败是当我调用 CVPixelBufferPoolCreatePixelBuffer 时它返回 -6661。
  • #1 也为我做了。谢谢!
  • 你们是如何用第一名解决这个问题的?我正在迅速使用 NSHomeDirectory。有人可以发布一个github示例吗?
  • 对我来说也是#1。
  • 我不明白 #1 - 为什么文件必须存在?如果我正在录制新视频,它可能不存在。我从来不需要先在我制作的任何其他应用程序上“创建”文件。 --- 更新 --- 如果文件确实存在并且您试图覆盖它,您将收到错误消息。尝试重命名您的目标文件。
【解决方案2】:

我遇到了同样的问题,我想可能是因为你没有正确配置你的AVAssetWriterInput。完成此操作后,我的游泳池开始工作。特别是,除非我在AVVideoCompressionPropertiesKey 中提供数据,否则池不会给我像素缓冲区。首先,创建并完全配置AVAssetWriter ( 在/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.sdk/System/Library/Frameworks/AVFoundation.framework/Headers/AVVideoSettings.h 中查找outputSettingscompressionSettings 的键和值):

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];

创建像素缓冲区适配器:

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];

然后使用以下方法从其池中检索像素缓冲区:

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

【讨论】:

  • 你没有使用 pixBufSettings
  • 但是如果你将 nil 传递给 sourcePixelBufferAttributes,那么适配器就不可能创建任何像素缓冲区
【解决方案3】:

根据文档:

“在关联的 AVAssetWriter 对象上第一次调用 startSessionAtTime 之前,此属性为 NULL。”

因此,如果您尝试过早访问池,它将为 NULL。我自己只是在学习这些东西,所以目前无法详细说明。

【讨论】:

  • 太早了是什么意思??我可以向您保证,在调用应该在assetWriter 上调用的方法之后,我调用了 CVPixelBufferPoolCreatePixelBuffer (kCFAllocatorDefault, _pixelBufferAdaptor.pixelBufferPool, &pixelBuffer) 并且仍然返回错误,因为显然没有创建缓冲池
【解决方案4】:

对于每个仍在寻找解决方案的人: 首先,通过检查其状态来确保您的 AVAssetWriter 工作正常。我遇到了这个问题,在检查了状态之后,虽然我已经调用了一些东西,但是作者还没有开始。(在我的情况下,我已经将写入路径指向了一个现有文件,所以在删除之后它,它就像一个魅力)

【讨论】:

    【解决方案5】:

    我搞定了!将选项字典设置为兼容性后,他们说可以使用缓冲池,这是工作示例和代码,用于在没有缓冲区的情况下进行编写,但它是一个很好的起点。

    这里是示例代码link

    这是您需要的代码:

    - (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;
    }
    

    【讨论】:

    • 你能解释一下这个解决方案应该使用哪个pixelBuffer吗?
    • Apple 应该解雇编写糟糕、骇人听闻、可怕和令人作呕的不完整、模糊、误导性文件的整个部门。他们是一种耻辱。
    【解决方案6】:

    outputURL 没有文件时,它可以工作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)")
            }
        }
    }
    

    用法

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-06-17
      • 2021-07-17
      • 1970-01-01
      • 2015-06-01
      • 2021-01-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多