UIImageWriteToSavedPhotosAlbum вызывает EXC_BAD_ACCESS - PullRequest
6 голосов
/ 12 декабря 2010

Я разрабатываю 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];
 }

Спасибо за любую помощь в решении этой проблемы.

Ответы [ 10 ]

2 голосов
/ 16 декабря 2010

Пожалуйста, попробуйте это:

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

Это решит вашу проблему.Если проблема не исчезла, пожалуйста, дайте мне знать.Я хотел бы решить вашу проблему.

1 голос
/ 20 декабря 2010

Вы можете попробовать этот код вместо своего и посмотреть, работает ли он, возможно, ваш входной поток неисправен, а не операция сохранения.

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

так

если это работает, постепенно добавляйте части исходного кода, чтобы увидеть, когда он выйдет из строя.

1 голос
/ 12 декабря 2010

Я думаю, вам нужно сохранить UIImage до тех пор, пока его не удастся сохранить в библиотеке фотографий.UIImageWriteToSavedPhotoAlbum имеет метод делегата для уведомления о завершении сохранения изображения.

0 голосов
/ 21 ноября 2014

В случае, если у кого-то еще возникли проблемы с этим, я обнаружил, что в моем конкретном случае это было вызвано одной из этих функций, не совсем точно, но как только я закомментировал их во всем приложении, оно начало работать

CGImageRelease(imageRef);
CGDataProviderRelease(provider);
CGColorSpaceRelease(colorSpaceRef);
0 голосов
/ 19 декабря 2010

для меня EXC_BAD_ACCESS означает, что вы используете объект, который больше не существует (я знаю, что это не правильно, но это основная причина, если я его получу).Отладьте все ваши объекты / переменные и посмотрите, есть ли в них еще значения.

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

Включите NSZombieEnabled и запустите снова (Исполняемый файл -> Аргументы -> NSZombieEnabled = YES)

0 голосов
/ 18 декабря 2010

Как вы вызываете следующий метод

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

Попробуйте те, которые выше.Вы можете решить эту проблему.

С уважением,

Сатья

0 голосов
/ 17 декабря 2010

Все ответы до сих пор предполагают, что сбой находится в UIImageWriteToSavedPhotosAlbum(), но строка в трассировке стека imageDataFromImageRef подсказывает мне, что сбой происходит в [UIImage imageWithCGImage: image].Возможно, вы могли бы переместить этот вызов в промежуточную переменную, чтобы узнать наверняка.

0 голосов
/ 16 декабря 2010

Я думаю, что это вызвано тем, что вы вызываете UIImageWriteToSavedPhotosAlbum из другого потока, а не из основного потока (я думаю, вы делаете это из-за "output_view.layer executeSelectorOnMainThread" некоторых строк вниз.

Имейте в виду, что эти графические функции пользовательского интерфейса не являются полностью поточными.

Возможно, попробуйте переместить вызов "сохранить в альбом" в функцию setContent основного потока для тестирования. Если там тоже происходит сбой, я действительно не знаю, почему это происходит.

0 голосов
/ 12 декабря 2010

Можете ли вы показать нам, как вы получаете оригинал CGImageRef?Поскольку происходит сбой в memmove(), звучит так, будто вы указываете блок данных изображения, который не был полностью выделен или преждевременно освобожден.Это означает, что он может успешно сохранить около половины вашего изображения, но затем потерпеть крах на другой половине, что может быть за пределами допустимого.

0 голосов
/ 12 декабря 2010

Данные вашего изображения (или, более вероятно, объект UIImage, из которого он получен) слишком часто освобождаются или автоматически высвобождаются или не могут быть сохранены один или несколько раз.Других объяснений нет.

...