使用 AVAssetWriter 从图像创建电影在 3GS 设备上无法按预期工作

发布于 2024-11-01 20:01:52 字数 5799 浏览 7 评论 0原文

对appendPixelBuffer的调用在3GS设备(IOS 4.1)上返回NO,但在iPhone 4设备上运行良好。

以下对appendPixelBuffer的调用是问题的根源:

CVPixelBufferRef buffer = NULL;
buffer = [self pixelBufferFromCGImage:[[UIImage imageNamed:@"frame1.png"] CGImage]];
BOOL result = [adaptor appendPixelBuffer:buffer withPresentationTime:kCMTimeZero];

if (result == NO) //failes on 3GS, but works on iphone 4
    NSLog(@"failed to append buffer");

}

完整代码:

-(void)writeImagesAsMovie:(NSArray *)array toPath:(NSString*)path {


NSLog(path);

NSError *error = nil;
AVAssetWriter *videoWriter = [[AVAssetWriter alloc] initWithURL:
                              [NSURL fileURLWithPath:path] fileType:AVFileTypeQuickTimeMovie
                                                          error:&error];

if(error) {
    NSLog(@"error creating AssetWriter: %@",[error description]);
}

错误(仅在3GS上,iphone 4没问题)是

错误域=AVFoundationErrorDomain Code=-11800 "该操作不能 完全的。 (AVFoundationErrorDomain 错误-11800。)”UserInfo=0x4970530 {NSUnderlyingError=0x496d2c0“ 操作无法完成。 (OSStatus 错误 -12908。)"}

NSDictionary *videoSettings = [NSDictionary dictionaryWithObjectsAndKeys:
                               AVVideoCodecH264, AVVideoCodecKey,
                               [NSNumber numberWithInt:frameSize.width], AVVideoWidthKey,
                               [NSNumber numberWithInt:frameSize.height], AVVideoHeightKey,
                               nil];



AVAssetWriterInput* writerInput = [[AVAssetWriterInput
                                    assetWriterInputWithMediaType:AVMediaTypeVideo
                                    outputSettings:videoSettings] retain];

NSMutableDictionary *attributes = [[NSMutableDictionary alloc]init];
[attributes setObject:[NSNumber numberWithUnsignedInt:kCVPixelFormatType_32ARGB] forKey:(NSString*)kCVPixelBufferPixelFormatTypeKey];
[attributes setObject:[NSNumber numberWithUnsignedInt:frameSize.width] forKey:(NSString*)kCVPixelBufferWidthKey];
[attributes setObject:[NSNumber numberWithUnsignedInt:frameSize.height] forKey:(NSString*)kCVPixelBufferHeightKey];

AVAssetWriterInputPixelBufferAdaptor *adaptor = [AVAssetWriterInputPixelBufferAdaptor
                                                 assetWriterInputPixelBufferAdaptorWithAssetWriterInput:writerInput
                                                 sourcePixelBufferAttributes:attributes];

[videoWriter addInput:writerInput];

// fixes all errors
writerInput.expectsMediaDataInRealTime = YES;

//Start a session:
BOOL start = [videoWriter startWriting];
NSLog(@"Session started? %d", start);

[videoWriter startSessionAtSourceTime:kCMTimeZero];

CVPixelBufferRef buffer = NULL;
buffer = [self pixelBufferFromCGImage:[[UIImage imageNamed:@"frame1.png"] CGImage]];
BOOL result = [adaptor appendPixelBuffer:buffer withPresentationTime:kCMTimeZero];

if (result == NO) //failes on 3GS, but works on iphone 4
    NSLog(@"failed to append buffer");

if(buffer)
    CVBufferRelease(buffer);

[NSThread sleepForTimeInterval:0.05];
//for (int i = 1;i<[array count]; i++)
for (int i = 1;i<20; i++)
{
    if (adaptor.assetWriterInput.readyForMoreMediaData) 
    {
        NSLog(@"inside for loop %d",i);
        CMTime frameTime = CMTimeMake(1, 15);
        CMTime lastTime=CMTimeMake(i, 15); 
        CMTime presentTime=CMTimeAdd(lastTime, frameTime);
        NSString *imgName = [NSString stringWithFormat:@"frame%d.png",i];
        UIImage *imgFrame = [UIImage imageNamed:imgName] ;
        buffer = [self pixelBufferFromCGImage:[imgFrame CGImage]];
        BOOL result = [adaptor appendPixelBuffer:buffer withPresentationTime:presentTime];

        if (result == NO) //failes on 3GS, but works on iphone 4
        {
            NSLog(@"failed to append buffer");
            NSLog(@"The error is %@", [videoWriter error]);
        }
        if(buffer)
            CVBufferRelease(buffer);
        [NSThread sleepForTimeInterval:0.05];
    }
    else
    {
        NSLog(@"error");
        i--;
    }
}

//Finish the session:
[writerInput markAsFinished];
[videoWriter finishWriting];
CVPixelBufferPoolRelease(adaptor.pixelBufferPool);
[videoWriter release];
[writerInput release];

NSLog(@"Movie created successfully");

}

- (CVPixelBufferRef) pixelBufferFromCGImage: (CGImageRef) image
{
    NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
                             [NSNumber numberWithBool:YES], kCVPixelBufferCGImageCompatibilityKey,
                             [NSNumber numberWithBool:YES], kCVPixelBufferCGBitmapContextCompatibilityKey,
                             nil];
    CVPixelBufferRef pxbuffer = NULL;

    CVPixelBufferCreate(kCFAllocatorDefault, self.view.frame.size.width,
                        self.view.frame.size.height, kCVPixelFormatType_32ARGB, (CFDictionaryRef) options, 
                        &pxbuffer);

    CVPixelBufferLockBaseAddress(pxbuffer, 0);
    void *pxdata = CVPixelBufferGetBaseAddress(pxbuffer);

    CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef context = CGBitmapContextCreate(pxdata, self.view.frame.size.width,
                                                 self.view.frame.size.height, 8, 4*self.view.frame.size.width, rgbColorSpace, 
                                                 kCGImageAlphaNoneSkipFirst);

    CGContextConcatCTM(context, CGAffineTransformMakeRotation(0));
    CGContextDrawImage(context, CGRectMake(0, 0, CGImageGetWidth(image), 
                                           CGImageGetHeight(image)), image);
    CGColorSpaceRelease(rgbColorSpace);
    CGContextRelease(context);

    CVPixelBufferUnlockBaseAddress(pxbuffer, 0);

    return pxbuffer;
}

The call to appendPixelBuffer is returning NO on 3GS device (IOS 4.1), but is working well on iPhone 4 devices.

The following call to appendPixelBuffer is the source of the problem:

CVPixelBufferRef buffer = NULL;
buffer = [self pixelBufferFromCGImage:[[UIImage imageNamed:@"frame1.png"] CGImage]];
BOOL result = [adaptor appendPixelBuffer:buffer withPresentationTime:kCMTimeZero];

if (result == NO) //failes on 3GS, but works on iphone 4
    NSLog(@"failed to append buffer");

}

Full Code:

-(void)writeImagesAsMovie:(NSArray *)array toPath:(NSString*)path {


NSLog(path);

NSError *error = nil;
AVAssetWriter *videoWriter = [[AVAssetWriter alloc] initWithURL:
                              [NSURL fileURLWithPath:path] fileType:AVFileTypeQuickTimeMovie
                                                          error:&error];

if(error) {
    NSLog(@"error creating AssetWriter: %@",[error description]);
}

The error (ONLY ON 3GS, iphone 4 is fine) is

Error Domain=AVFoundationErrorDomain
Code=-11800 "The operation couldn’t be
completed. (AVFoundationErrorDomain
error -11800.)" UserInfo=0x4970530
{NSUnderlyingError=0x496d2c0 "The
operation couldn’t be completed.
(OSStatus error -12908.)"}

NSDictionary *videoSettings = [NSDictionary dictionaryWithObjectsAndKeys:
                               AVVideoCodecH264, AVVideoCodecKey,
                               [NSNumber numberWithInt:frameSize.width], AVVideoWidthKey,
                               [NSNumber numberWithInt:frameSize.height], AVVideoHeightKey,
                               nil];



AVAssetWriterInput* writerInput = [[AVAssetWriterInput
                                    assetWriterInputWithMediaType:AVMediaTypeVideo
                                    outputSettings:videoSettings] retain];

NSMutableDictionary *attributes = [[NSMutableDictionary alloc]init];
[attributes setObject:[NSNumber numberWithUnsignedInt:kCVPixelFormatType_32ARGB] forKey:(NSString*)kCVPixelBufferPixelFormatTypeKey];
[attributes setObject:[NSNumber numberWithUnsignedInt:frameSize.width] forKey:(NSString*)kCVPixelBufferWidthKey];
[attributes setObject:[NSNumber numberWithUnsignedInt:frameSize.height] forKey:(NSString*)kCVPixelBufferHeightKey];

AVAssetWriterInputPixelBufferAdaptor *adaptor = [AVAssetWriterInputPixelBufferAdaptor
                                                 assetWriterInputPixelBufferAdaptorWithAssetWriterInput:writerInput
                                                 sourcePixelBufferAttributes:attributes];

[videoWriter addInput:writerInput];

// fixes all errors
writerInput.expectsMediaDataInRealTime = YES;

//Start a session:
BOOL start = [videoWriter startWriting];
NSLog(@"Session started? %d", start);

[videoWriter startSessionAtSourceTime:kCMTimeZero];

CVPixelBufferRef buffer = NULL;
buffer = [self pixelBufferFromCGImage:[[UIImage imageNamed:@"frame1.png"] CGImage]];
BOOL result = [adaptor appendPixelBuffer:buffer withPresentationTime:kCMTimeZero];

if (result == NO) //failes on 3GS, but works on iphone 4
    NSLog(@"failed to append buffer");

if(buffer)
    CVBufferRelease(buffer);

[NSThread sleepForTimeInterval:0.05];
//for (int i = 1;i<[array count]; i++)
for (int i = 1;i<20; i++)
{
    if (adaptor.assetWriterInput.readyForMoreMediaData) 
    {
        NSLog(@"inside for loop %d",i);
        CMTime frameTime = CMTimeMake(1, 15);
        CMTime lastTime=CMTimeMake(i, 15); 
        CMTime presentTime=CMTimeAdd(lastTime, frameTime);
        NSString *imgName = [NSString stringWithFormat:@"frame%d.png",i];
        UIImage *imgFrame = [UIImage imageNamed:imgName] ;
        buffer = [self pixelBufferFromCGImage:[imgFrame CGImage]];
        BOOL result = [adaptor appendPixelBuffer:buffer withPresentationTime:presentTime];

        if (result == NO) //failes on 3GS, but works on iphone 4
        {
            NSLog(@"failed to append buffer");
            NSLog(@"The error is %@", [videoWriter error]);
        }
        if(buffer)
            CVBufferRelease(buffer);
        [NSThread sleepForTimeInterval:0.05];
    }
    else
    {
        NSLog(@"error");
        i--;
    }
}

//Finish the session:
[writerInput markAsFinished];
[videoWriter finishWriting];
CVPixelBufferPoolRelease(adaptor.pixelBufferPool);
[videoWriter release];
[writerInput release];

NSLog(@"Movie created successfully");

}

- (CVPixelBufferRef) pixelBufferFromCGImage: (CGImageRef) image
{
    NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
                             [NSNumber numberWithBool:YES], kCVPixelBufferCGImageCompatibilityKey,
                             [NSNumber numberWithBool:YES], kCVPixelBufferCGBitmapContextCompatibilityKey,
                             nil];
    CVPixelBufferRef pxbuffer = NULL;

    CVPixelBufferCreate(kCFAllocatorDefault, self.view.frame.size.width,
                        self.view.frame.size.height, kCVPixelFormatType_32ARGB, (CFDictionaryRef) options, 
                        &pxbuffer);

    CVPixelBufferLockBaseAddress(pxbuffer, 0);
    void *pxdata = CVPixelBufferGetBaseAddress(pxbuffer);

    CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef context = CGBitmapContextCreate(pxdata, self.view.frame.size.width,
                                                 self.view.frame.size.height, 8, 4*self.view.frame.size.width, rgbColorSpace, 
                                                 kCGImageAlphaNoneSkipFirst);

    CGContextConcatCTM(context, CGAffineTransformMakeRotation(0));
    CGContextDrawImage(context, CGRectMake(0, 0, CGImageGetWidth(image), 
                                           CGImageGetHeight(image)), image);
    CGColorSpaceRelease(rgbColorSpace);
    CGContextRelease(context);

    CVPixelBufferUnlockBaseAddress(pxbuffer, 0);

    return pxbuffer;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

久夏青 2024-11-08 20:01:52

检查设备的控制台登录管理器。
我在 Ipod 2nd Gen 上遇到了同样的错误,并且控制台日志报告了

com.apple.mediaserverd[18] : VTSelectAndCreateVideoEncoderInstance:没有找到“avc1”的视频编码器

确切地说,这意味着仍在处理中,但是它为我指明了方向。

Check Console Log in Organizer for device.
I got same error on Ipod 2nd Gen and Console Log Reported

com.apple.mediaserverd[18] : VTSelectAndCreateVideoEncoderInstance: no video encoder found for 'avc1'

Exactly what that means still working on, however it points me in a direction.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文