UIImageWriteToSavedPhotosAlbum 导致 EXC_BAD_ACCESS

发布于 2024-10-07 01:24:56 字数 3417 浏览 3 评论 0原文

我开发了一个 CGImage,当程序使用以下命令将其显示在屏幕上时,它工作正常:

[output_view.layer performSelectorOnMainThread:@selector(setContents:) withObject: (id) image waitUntilDone:YES];

现在,这样做会使应用程序崩溃:

UIImageWriteToSavedPhotosAlbum([UIImage imageWithCGImage: image)],nil,nil,nil);

我根本不明白它。这是崩溃期间的堆栈:

#0  0x33b5db6e in memmove (Line 65)
#1  0x341ddee2 in CGAccessSessionGetBytes
#2  0x31ab4488 in alphaProviderGetBytes
#3  0x341ddf52 in CGAccessSessionGetBytes
#4  0x31abbc80 in writeOne
#5  0x31abbdae in _CGImagePluginWriteJPEG
#6  0x31ab2ddc in CGImageDestinationFinalize
#7  0x3037eda2 in imageDataFromImageWithFormatAndProperties
#8  0x3037effc in imageDataFromImageRef
#9  0x3038ea3c in __-[PLAssetsSaver _saveImage:imageData:properties:completionBlock:]_block_invoke_1
#10 0x33c32680 in _dispatch_call_block_and_release
#11 0x33c32ba0 in _dispatch_worker_thread2
#12 0x33bd7250 in _pthread_wqthread

这是出现问题的方法:

-(void)captureOutput: (AVCaptureOutput *) captureOutput didOutputSampleBuffer: (CMSampleBufferRef) sampleBuffer fromConnection: (AVCaptureConnection *) conenction{
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    // Get a CMSampleBuffer's Core Video image buffer for the media data
    CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer); 
    // Lock the base address of the pixel buffer
    CVPixelBufferLockBaseAddress(imageBuffer, 0); 
    // Get the number of bytes per row for the pixel buffer
    UInt8 * image_data = CVPixelBufferGetBaseAddress(imageBuffer); 
    // Get the number of bytes per row for the pixel buffer
    size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer); 
    // Get the pixel buffer width and height
    size_t width = CVPixelBufferGetWidth(imageBuffer); 
    size_t height = CVPixelBufferGetHeight(imageBuffer);
    //Removed part here which modifies the CVPixelBuffer pixels with a particular algorithm.
    [bottom_view setNeedsDisplay];
    [bottom_view performSelectorOnMainThread:@selector(setBackgroundColor:) withObject: [UIColor colorWithRed:0 green:av/255.0 blue:0 alpha:1] waitUntilDone: YES];
    // Create a device-dependent RGB color space
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    // Create a Quartz image from the pixel data
    CGDataProviderDirectCallbacks providerCallbacks = { 0, GetBytePointer, ReleaseBytePointer, GetBytesAtPosition, 0 };
    CGDataProviderRef d_provider = CGDataProviderCreateDirect(image_data,pixels*4,&providerCallbacks);
    CGImageRef image = CGImageCreate (width,height,8,32,bytesPerRow,colorSpace,kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst,d_provider,NULL,true,kCGRenderingIntentDefault);
    //Draw image
    if (needs_photo) {
        UIImageWriteToSavedPhotosAlbum([UIImage imageWithCGImage: image],nil,nil,nil);
        needs_photo = NO;
    }
    if (recording) {
        [writer_input appendSampleBuffer:sampleBuffer];
    }
    [output_view.layer performSelectorOnMainThread:@selector(setContents:) withObject: (id) image waitUntilDone:YES];
    // Unlock the pixel buffer
    CVPixelBufferUnlockBaseAddress(imageBuffer,0);
    // Free up the context and color space
    CGColorSpaceRelease(colorSpace);
    CGImageRelease(image);
    CGDataProviderRelease(d_provider);
    [pool drain];
 }

感谢您对此问题的任何帮助。

I develop a CGImage and it works fine when the program displays it on the screen using this:

[output_view.layer performSelectorOnMainThread:@selector(setContents:) withObject: (id) image waitUntilDone:YES];

Now, doing this crashes the application:

UIImageWriteToSavedPhotosAlbum([UIImage imageWithCGImage: image)],nil,nil,nil);

I don't understand it at all. Here's the stack during the crash:

#0  0x33b5db6e in memmove (Line 65)
#1  0x341ddee2 in CGAccessSessionGetBytes
#2  0x31ab4488 in alphaProviderGetBytes
#3  0x341ddf52 in CGAccessSessionGetBytes
#4  0x31abbc80 in writeOne
#5  0x31abbdae in _CGImagePluginWriteJPEG
#6  0x31ab2ddc in CGImageDestinationFinalize
#7  0x3037eda2 in imageDataFromImageWithFormatAndProperties
#8  0x3037effc in imageDataFromImageRef
#9  0x3038ea3c in __-[PLAssetsSaver _saveImage:imageData:properties:completionBlock:]_block_invoke_1
#10 0x33c32680 in _dispatch_call_block_and_release
#11 0x33c32ba0 in _dispatch_worker_thread2
#12 0x33bd7250 in _pthread_wqthread

Here is the method with the problem:

-(void)captureOutput: (AVCaptureOutput *) captureOutput didOutputSampleBuffer: (CMSampleBufferRef) sampleBuffer fromConnection: (AVCaptureConnection *) conenction{
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    // Get a CMSampleBuffer's Core Video image buffer for the media data
    CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer); 
    // Lock the base address of the pixel buffer
    CVPixelBufferLockBaseAddress(imageBuffer, 0); 
    // Get the number of bytes per row for the pixel buffer
    UInt8 * image_data = CVPixelBufferGetBaseAddress(imageBuffer); 
    // Get the number of bytes per row for the pixel buffer
    size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer); 
    // Get the pixel buffer width and height
    size_t width = CVPixelBufferGetWidth(imageBuffer); 
    size_t height = CVPixelBufferGetHeight(imageBuffer);
    //Removed part here which modifies the CVPixelBuffer pixels with a particular algorithm.
    [bottom_view setNeedsDisplay];
    [bottom_view performSelectorOnMainThread:@selector(setBackgroundColor:) withObject: [UIColor colorWithRed:0 green:av/255.0 blue:0 alpha:1] waitUntilDone: YES];
    // Create a device-dependent RGB color space
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    // Create a Quartz image from the pixel data
    CGDataProviderDirectCallbacks providerCallbacks = { 0, GetBytePointer, ReleaseBytePointer, GetBytesAtPosition, 0 };
    CGDataProviderRef d_provider = CGDataProviderCreateDirect(image_data,pixels*4,&providerCallbacks);
    CGImageRef image = CGImageCreate (width,height,8,32,bytesPerRow,colorSpace,kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst,d_provider,NULL,true,kCGRenderingIntentDefault);
    //Draw image
    if (needs_photo) {
        UIImageWriteToSavedPhotosAlbum([UIImage imageWithCGImage: image],nil,nil,nil);
        needs_photo = NO;
    }
    if (recording) {
        [writer_input appendSampleBuffer:sampleBuffer];
    }
    [output_view.layer performSelectorOnMainThread:@selector(setContents:) withObject: (id) image waitUntilDone:YES];
    // Unlock the pixel buffer
    CVPixelBufferUnlockBaseAddress(imageBuffer,0);
    // Free up the context and color space
    CGColorSpaceRelease(colorSpace);
    CGImageRelease(image);
    CGDataProviderRelease(d_provider);
    [pool drain];
 }

Thank you for any help with this problem.

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

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

发布评论

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

评论(10

瑾兮 2024-10-14 01:24:57

您可以尝试此代码而不是您的代码,看看它是否有效,也许您的输入流有问题,而不是保存操作有问题。

#import <OpenGLES/ES1/gl.h>

NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

float width = 64;
float height = 64;

GLubyte *buffer = (GLubyte *) malloc(width * height * 4);
CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, buffer, (width * height * 4), NULL);

// set up for CGImage creation
int bitsPerComponent = 8;
int bitsPerPixel = 32;
int bytesPerRow = 4 * width;
CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault;
CGImageRef imageRef = CGImageCreate(width, height, bitsPerComponent, bitsPerPixel, bytesPerRow, colorSpaceRef, bitmapInfo, provider, NULL, NO, 0);

UIImageWriteToSavedPhotosAlbum([UIImage imageWithCGImage:imageRef],nil,nil,nil);

CGColorSpaceRelease(colorSpaceRef);
CGImageRelease(imageRef);
CGDataProviderRelease(provider);

[pool drain];

因此,

如果这有效,请一点一点地添加原始代码的一部分,看看它何时崩溃。

You can try this code instead of yours and see if it's working, maybe your input stream is faulty and not the save operation.

#import <OpenGLES/ES1/gl.h>

NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

float width = 64;
float height = 64;

GLubyte *buffer = (GLubyte *) malloc(width * height * 4);
CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, buffer, (width * height * 4), NULL);

// set up for CGImage creation
int bitsPerComponent = 8;
int bitsPerPixel = 32;
int bytesPerRow = 4 * width;
CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault;
CGImageRef imageRef = CGImageCreate(width, height, bitsPerComponent, bitsPerPixel, bytesPerRow, colorSpaceRef, bitmapInfo, provider, NULL, NO, 0);

UIImageWriteToSavedPhotosAlbum([UIImage imageWithCGImage:imageRef],nil,nil,nil);

CGColorSpaceRelease(colorSpaceRef);
CGImageRelease(imageRef);
CGDataProviderRelease(provider);

[pool drain];

so

if this is working, add parts of your original code little by little to see when it crashes.

一场春暖 2024-10-14 01:24:57

我认为你需要保留保存的 UIImage 直到成功保存到照片库中。 UIImageWriteToSavedPhotoAlbum 有一个委托方法来通知保存图像完成。

I think you need to keep the saving UIImage until it is successful to save in the photo library. The UIImageWriteToSavedPhotoAlbum has a delegate method to notify the completation of saving image.

丘比特射中我 2024-10-14 01:24:57

您的图像数据(或更可能是其派生自的 UIImage 对象)已被释放或自动释放一次太频繁,或者未能保留一次或多次。没有其他解释。

Your image data (or more likely, the UIImage object it's derived from) has been released or autoreleased once too often, or failed to be retained one or more times. No other explanation.

枯寂 2024-10-14 01:24:57

您能否向我们展示如何获取原始的CGImageRef?由于它在 memmove() 中崩溃,听起来您正在指定一个未完全分配或过早释放的图像数据块。这意味着它可能会成功保存大约一半的图像,但随后会在另一半上崩溃,这可能会超出范围。

Can you show us how you obtain the original CGImageRef? Since it's crashing in memmove(), it sounds like you are specifying a block of image data which isn't fully allocated, or is prematurely freed. This means that it might successfully save about half of your image, but then crash on the other half, which might be out-of-bounds.

心房敞 2024-10-14 01:24:57

我认为这是因为您从主线程之外的另一个线程调用 UIImageWriteToSavedPhotosAlbum (我认为您这样做是因为“output_view.layer PerformSelectorOnMainThread”向下一些行。

请注意,这些 UI 图形函数不是完全线程安全的。

也许尝试移动“保存到相册”调用主线程的“setContent”函数进行测试,如果它也在那里崩溃,我真的不知道为什么会发生。

I think it's caused because you call UIImageWriteToSavedPhotosAlbum from another thread than the main thread (I think you do because of the "output_view.layer performSelectorOnMainThread" some lines down.

Be aware that those UI-graphics functions are not fully threadsafe.

Perhaps try moving the "save to album" call into main thread's "setContent" function for testing. If it crashes there too i really don't know why it happens.

羞稚 2024-10-14 01:24:57

到目前为止,所有答案都假设崩溃发生在 UIImageWriteToSavedPhotosAlbum() 中,但堆栈跟踪 imageDataFromImageRef 中的行向我表明它崩溃在 [UIImage imageWithCGImage:图像]。也许您可以将该调用移至中间变量来确定。

All of the answers so far assume that the crash is in UIImageWriteToSavedPhotosAlbum(), but the line in the stack trace imageDataFromImageRef suggests to me that it's crashing in [UIImage imageWithCGImage: image]. Perhaps you could move that call to a intermediate variable to find out for sure.

作业与我同在 2024-10-14 01:24:57

如何调用以下方法

-(void)captureOutput: (AVCaptureOutput *) captureOutput didOutputSampleBuffer: (CMSampleBufferRef) sampleBuffer fromConnection: (AVCaptureConnection *) conenction{

如果您使用其他线程(主线程除外)调用此方法,那么只需要使用 NSAutoReleasePool 否则它将释放一些变量,因此它可能会释放一些变量碰撞。

还有一件事,

你使用这个,

[output_view.layer performSelectorOnMainThread:@selector(setContents:) withObject: (id) image waitUntilDone:YES];

为什么你使用performSelector,你可以直接调用像

[output_view.layer setContents:image];

尝试上面那些方法。
你可能会解决问题。

问候,

萨蒂亚

How you are calling the following method

-(void)captureOutput: (AVCaptureOutput *) captureOutput didOutputSampleBuffer: (CMSampleBufferRef) sampleBuffer fromConnection: (AVCaptureConnection *) conenction{

If you called this method using some other thread(other than Main Thread), then only you need to use NSAutoReleasePool Other wise it will release some variables, because of that it may crash.

And one more thing,

You are using this,

[output_view.layer performSelectorOnMainThread:@selector(setContents:) withObject: (id) image waitUntilDone:YES];

Why you are using performSelector, you can directly call the method like

[output_view.layer setContents:image];

Try the above those.
you may get solve the problem.

Regards,

Satya

忆梦 2024-10-14 01:24:57

对我来说 EXC_BAD_ACCESS 意味着您使用了一个不再存在的对象(我知道它不正确,但如果我得到它,这就是最主要的原因)。调试所有对象/变量并查看它们中是否仍有值。

尝试 UIImageWriteToSavedPhotosAlbum([[UIImage imageWithCGImage: image]retain],nil,nil,nil);

启用 NSZombieEnabled 并再次运行 (Executable -> Arguments -> NSZombieEnabled =是的)

for me EXC_BAD_ACCESS means you using an object which no longer exist (I know it's not correct but thats the most reason if I get it). Debug all your objects / variables and see if they have still values in it.

try UIImageWriteToSavedPhotosAlbum([[UIImage imageWithCGImage: image]retain],nil,nil,nil);

Enable NSZombieEnabled and run again (Executable -> Arguments -> NSZombieEnabled = YES)

烧了回忆取暖 2024-10-14 01:24:57

万一其他人遇到此问题,我发现在我的特定情况下,它是由这些功能之一引起的,不太确定,但一旦我在我的应用程序中全部注释掉它们,它就开始工作

CGImageRelease(imageRef);
CGDataProviderRelease(provider);
CGColorSpaceRelease(colorSpaceRef);

In case anyone else is having issues with this, I found in my particular case it was caused by one of these functions, not exactly sure but once I commented them all out all over my app it started to work

CGImageRelease(imageRef);
CGDataProviderRelease(provider);
CGColorSpaceRelease(colorSpaceRef);
孤独难免 2024-10-14 01:24:56

请尝试以下操作:

UIImageWriteToSavedPhotosAlbum(image, self, @selector(imageSavedToPhotosAlbum: didFinishSavingWithError: contextInfo:), context);

它会解决你的问题。如果您仍然遇到同样的问题,请告诉我。我想解决你的问题。

Please try this:

UIImageWriteToSavedPhotosAlbum(image, self, @selector(imageSavedToPhotosAlbum: didFinishSavingWithError: contextInfo:), context);

It will solve your problem. If you still get the same problem please let me know. I would like to solve your problem.

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