iphone - How to properly use CFRelease in a context of captureStillImageAsynchronouslyFromConnection? -
not familiar memory management (only started on journey ios pampered arc), wanted girl , avoid leaking knew how to.
i capture still image video connection avfoundations capturestillimageasynchronouslyfromconnection
, because want access image bytes. using core foundation , core graphics.
now bad access exception, when ios finishes capture block , tries release objects. must have overdone it.
i think have correctly:
- released core graphics thingies create in correct sequence
- neither retained nor released cvimagebufferref, because get-something , keeps original ownership
- released copy of camera buffers metadata
edit: added optimization example code, curtesy of matthias bauch: there error in memory handling cfdatacreatewithbytesnocopy
, cfrelease
correctly now. not causing problem.
edit 2: matthias bauch, have been able narrow down called method. leaving else inside method, can make many snapshots without exceptions. added code of 1 below capturestillimageasynchronouslyfromconnection
block calls it. continue in way find out wrong...
edit 3: inside called method, there 2 thingies released not responsible for. newacct, explained point point, have working method. post working code below.
capturestillimageasynchronouslyfromconnection
block:
[[self imageoutput] capturestillimageasynchronouslyfromconnection:videoconnection completionhandler: ^(cmsamplebufferref imagesamplebuffer, nserror *error) { // time stamp image capture nsdate *timestamp = [nsdate date]; //get metadata in image cfdictionaryref metadata = cmcopydictionaryofattachments(kcfallocatordefault, imagesamplebuffer, kcmattachmentmode_shouldpropagate); // image reference cvimagebufferref imagebuffer = cmsamplebuffergetimagebuffer(imagesamplebuffer); // >>>>>>>>>> lock buffer address cvpixelbufferlockbaseaddress(imagebuffer, 0); //get information image uint8_t *baseaddress = (uint8_t *)cvpixelbuffergetbaseaddress(imagebuffer); size_t datasize = cvpixelbuffergetdatasize(imagebuffer); size_t bytesperrow = cvpixelbuffergetbytesperrow(imagebuffer); size_t width = cvpixelbuffergetwidth(imagebuffer); size_t height = cvpixelbuffergetheight(imagebuffer); // create pointer image data cfdataref rawimagebytes = cfdatacreatewithbytesnocopy(kcfallocatordefault, baseaddress, datasize, kcfallocatornull); // create color space current device cgcolorspaceref colorspace = cgcolorspacecreatedevicergb(); //create bitmap context cgcontextref newcontext = cgbitmapcontextcreate(baseaddress, width, height, 8, bytesperrow, colorspace, kcgbitmapbyteorder32little | kcgimagealphapremultipliedfirst); // <<<<<<<<<< unlock buffer address cvpixelbufferunlockbaseaddress(imagebuffer, 0); // release core graphics object cgcolorspacerelease(colorspace); // create bitmap image data supplied context. cgimageref newimage = cgbitmapcontextcreateimage(newcontext); // release core graphics object cgcontextrelease(newcontext); bool saved = false; // save cgimage tiff file objective-c saved = [[self photoiocontroller] writetosubdirectorywithimageref:newimage orientation:[self orientation] timestamp: timestamp andmetadata: metadata]; // create uiimage (need change orientation of image image displayed correctly) uiimage *image= [uiimage imagewithcgimage:newimage scale:1.0 orientation:uiimageorientationright]; // release core graphics object cgimagerelease(newimage); // set property display in stillimageviewcontroller [self setstillimage: image]; // release core foundation object cfrelease(rawimagebytes); // release core foundation object cfrelease(metadata); // send notification camera container view controller when image has been taken [[nsnotificationcenter defaultcenter] postnotificationname:kimagecapturedsuccessfully object:nil]; }];
the method seems cause exception:
the parameters:
imageref
cgimageref newimage = cgbitmapcontextcreateimage(newcontext);
orientation
uideviceorientation
uideviceorientationdidchangenotification
, filtered minus ones not react totimestamp
nsdate *timestamp = [nsdate date];
metadata
cfdictionaryref metadata = cmcopydictionaryofattachments(kcfallocatordefault, imagesamplebuffer, kcmattachmentmode_shouldpropagate);
the code:
-(bool) writetosubdirectorywithimageref: (cgimageref) imageref orientation: (uideviceorientation) orientation timestamp: (nsdate*) timestamp andmetadata: (cfdictionaryref) metadata { int imageorientation; // according apple documentation on key kcgimagepropertyorientation, /* http://developer.apple.com/library/ios/documentation/graphicsimaging/reference/cgimageproperties_reference/reference/reference.html#//apple_ref/doc/uid/tp40005103-ch3g-sw37 */ // values same in tiff , exif (so use libtiff definitions) switch (orientation) { case uideviceorientationportrait: imageorientation = orientation_righttop; break; case uideviceorientationportraitupsidedown: imageorientation = orientation_leftbot; break; case uideviceorientationlandscapeleft: imageorientation = orientation_topleft; break; case uideviceorientationlandscaperight: imageorientation = orientation_botright; break; default: imageorientation = orientation_righttop; break; } // mutable metadata copy cfmutabledictionaryref mutablemetadata = cfdictionarycreatemutablecopy(kcfallocatordefault, cfdictionarygetcount(metadata), metadata); // set key-value-pair cfstringref mykey = kcgimagepropertyorientation; // not release! cftyperef myvalue = cfnumbercreate(null, kcfnumberinttype, &imageorientation); cfdictionaryreplacevalue(mutablemetadata, mykey, myvalue); // time stamp nsdateformatter *dateformatter = [[nsdateformatter alloc] init]; [dateformatter setdateformat:kdermaappphototimestampformat]; nsstring *stimestamp = [dateformatter stringfromdate:timestamp]; if ([self pathdermaappsubdirectory] != nil) { nsstring *filepath = [nsstring stringwithformat:(@"%@/%@%@"),[self pathdermaappsubdirectory],stimestamp,ktiffimagenameending]; // log file path hlsloggerdebug(@"tiff image filepath = %@",filepath); cfurlref url = (__bridge cfurlref)[nsurl fileurlwithpath:filepath isdirectory:no]; cgimagedestinationref destination = cgimagedestinationcreatewithurl(url, kuttypetiff, 1, null); // bridge: not release! cgimagedestinationaddimage(destination, imageref, mutablemetadata); if (cgimagedestinationfinalize(destination)) { [self setpathlastimagesave:filepath]; // release core foundation object cfrelease(destination); // release core foundation object cfrelease(mutablemetadata); // release core foundation object cfrelease(myvalue); return true; } else { [self setpathlastimagesave:nil]; hlsloggerfatal(@"failed write image %@", filepath); } // release core foundation object cfrelease(destination); } // release core foundation object cfrelease(mutablemetadata); // release core foundation object cfrelease(myvalue); return false; }
the memory management of core foundation objects memory management of objective-c objects in cocoa -- if retained it, must release it; if didn't retain it, must not release it. naming conventions different. whereas "retaining" methods in cocoa have names starting alloc
, retain
, new
, copy
, , mutablecopy
, in core foundation, it's if function name contains create
or copy
.
so in mind, let's @ code.
in first piece of code:
metadata
: returnedcopy
, it's retained, must releaseimagebuffer
: returned functionget
, notcopy
orcreate
, it's not retained, must not releaserawimagebytes
: returnedcreate
, it's retained, must releasecolorspace
: returnedcreate
, it's retained, must releasenewcontext
: returnedcreate
, it's retained, must releasenewimage
: returnedcreate
, it's retained, must release
in writetosubdirectorywithimageref:
:
imageref
,orientation
, ,metadata
: they're parameters, didn't retain it, must not release itmutablemetadata
: returnedcreate
, hence retained, must release itmykey
: not retained, must not release itmyvalue
: returnedcreate
, it's retained, releaseurl
: it's bridged directly (not bridge-retained or bridge-transfered), , method name doesn't have of retaining prefixes, it's not retained, must not releasedestination
: returnedcreate
, it's retained, release
see? it's pretty easy.
Comments
Post a Comment