UIImageWriteToSavedPhotosAlbum 导致 EXC_BAD_ACCESS
我开发了一个 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(10)
您可以尝试此代码而不是您的代码,看看它是否有效,也许您的输入流有问题,而不是保存操作有问题。
因此,
如果这有效,请一点一点地添加原始代码的一部分,看看它何时崩溃。
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.
so
if this is working, add parts of your original code little by little to see when it crashes.
我认为你需要保留保存的 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.
您的图像数据(或更可能是其派生自的 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.
您能否向我们展示如何获取原始的
CGImageRef
?由于它在 memmove() 中崩溃,听起来您正在指定一个未完全分配或过早释放的图像数据块。这意味着它可能会成功保存大约一半的图像,但随后会在另一半上崩溃,这可能会超出范围。Can you show us how you obtain the original
CGImageRef
? Since it's crashing inmemmove()
, 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.我认为这是因为您从主线程之外的另一个线程调用 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.
到目前为止,所有答案都假设崩溃发生在
UIImageWriteToSavedPhotosAlbum()
中,但堆栈跟踪imageDataFromImageRef
中的行向我表明它崩溃在[UIImage imageWithCGImage:图像]
。也许您可以将该调用移至中间变量来确定。All of the answers so far assume that the crash is in
UIImageWriteToSavedPhotosAlbum()
, but the line in the stack traceimageDataFromImageRef
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.如何调用以下方法
如果您使用其他线程(主线程除外)调用此方法,那么只需要使用
NSAutoReleasePool
否则它将释放一些变量,因此它可能会释放一些变量碰撞。还有一件事,
你使用这个,
为什么你使用
performSelector
,你可以直接调用像尝试上面那些方法。
你可能会解决问题。
问候,
萨蒂亚
How you are calling the following method
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,
Why you are using
performSelector
, you can directly call the method likeTry the above those.
you may get solve the problem.
Regards,
Satya
对我来说 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)万一其他人遇到此问题,我发现在我的特定情况下,它是由这些功能之一引起的,不太确定,但一旦我在我的应用程序中全部注释掉它们,它就开始工作
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
请尝试以下操作:
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.