gpt4 book ai didi

ios - UIImage setImage 崩溃

转载 作者:塔克拉玛干 更新时间:2023-11-02 10:04:38 27 4
gpt4 key购买 nike

我用 ffmpeg 实现了一个视频播放器。每一帧都解码成功,可以保存为有效的jpg文件,在模拟器中运行时可以显示在UIImageView中。但是,当我在模拟器中运行我的应用程序时,内存会无限增长。此外,应用程序在设备上运行时执行 p_diaplayNextFrame 2 次后会崩溃。如果我评论 self.imageView.image = frame;,内存不会泄漏,应用程序不会在模拟器或设备上崩溃。

-(void)p_displayNextFrame
{
ZCVFrameSec *frameSec = [video getNextVideoFrameSec];
UIImage *frame = [frameSec toUIImage];
static int fi = 0;

NSAssert( [NSThread isMainThread], @"Fatal error: must be main thread" );
NSString *fileName = [Utilities documentsPath:[NSString stringWithFormat:@"image%06d.jpg",fi++]];
NSLog(@"p_displayNextFrame write image file: %@",fileName);

// frame is saved successfully as jpg, I can view it
[UIImageJPEGRepresentation(frame, 0.7) writeToFile:fileName atomically:YES];

// leak(but not crash) in emulator, crash on device
self.imageView.image = frame;

double delayInSeconds = 0.05;//1/30.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
[self p_displayNextFrame];
});
}

ZCVFrameSec 的toUIImage

- (UIImage*) toUIImage
{
CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault;
CFDataRef data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, [self.data bytes], self.width * self.height * 3,kCFAllocatorNull);
NSAssert( [self.data length] == self.width * self.height * 3,
@"Fatal error: data length:%d, width:%d, height:%d, mul3=%d",
[self.data length],
self.width, self.height, self.width * self.height * 3 );

CGDataProviderRef provider = CGDataProviderCreateWithCFData(data);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGImageRef cgImage = CGImageCreate(self.width,
self.height,
8,
24,
3 * self.width,
colorSpace,
bitmapInfo,
provider,
NULL,
NO,
kCGRenderingIntentDefault);
UIImage *image = [UIImage imageWithCGImage:cgImage];
CGImageRelease(cgImage);
CGColorSpaceRelease(colorSpace);
CGDataProviderRelease(provider);
CFRelease(data);

return image;
}

崩溃信息:

vImage`__vConvert_RGB888toBGRA8888_block_invoke98:
0x2d72aeb0: push {r4, r5, r6, r7, lr}
0x2d72aeb2: add r7, sp, #0xc
0x2d72aeb4: push.w {r8, r10}
0x2d72aeb8: ldr r2, [r0, #0x14]
0x2d72aeba: ldr r2, [r2, #0x4]
0x2d72aebc: ldr r2, [r2, #0x10]
0x2d72aebe: cmp r2, #0x0
0x2d72aec0: beq.w 0x2d72b076 ; __vConvert_RGB888toBGRA8888_block_invoke98 + 454
0x2d72aec4: vldr d16, [pc, #440]
0x2d72aec8: vmov.i32 q10, #0xff000000
0x2d72aecc: lsl.w r9, r1, #0x3
0x2d72aed0: vldr d18, [pc, #436]
0x2d72aed4: mov.w r12, #0x0
0x2d72aed8: ldr.w r8, [r0, #24]
0x2d72aedc: add.w r5, r0, #0x1c
0x2d72aee0: add.w r6, r12, r9
0x2d72aee4: ldm r5, {r2, r4, r5}
0x2d72aee6: ldr r3, [r0, #0x28]
0x2d72aee8: ldr r1, [r0, #0x2c]
0x2d72aeea: mla r2, r2, r6, r8
0x2d72aeee: mla lr, r5, r6, r4
0x2d72aef2: mla r3, r1, r6, r3
0x2d72aef6: tst.w r3, #0xf
0x2d72aefa: bne 0x2d72af44 ; __vConvert_RGB888toBGRA8888_block_invoke98 + 148
0x2d72aefc: tst.w r2, #0xf
0x2d72af00: bne 0x2d72af80 ; __vConvert_RGB888toBGRA8888_block_invoke98 + 208
0x2d72af02: ldr r4, [r0, #0x30]
0x2d72af04: movs r1, #0x0
0x2d72af06: tst.w lr, #0xf
0x2d72af0a: bne 0x2d72afbc ; __vConvert_RGB888toBGRA8888_block_invoke98 + 268
0x2d72af0c: cmp r4, #0x10
0x2d72af0e: blo 0x2d72aff2 ; __vConvert_RGB888toBGRA8888_block_invoke98 + 322
0x2d72af10: ldr r4, [r0, #0x34]
0x2d72af12: vld3.8 {d0, d2, d4}, [r2]!
Thread 1: EXC_BAD_ACCESS (code=1,address=0x7403000)

感谢任何提示!!!

最佳答案

我认为问题是因为 ZCVFrameSec *frameSec 在超出 -(void)p_displayNextFrame 方法的范围后被释放。

如果您在 frameSec 中的字节数组上使用了 CFDataCreateWithBytesNoCopy,那么字节数组可能会在您使用完 frameSec 之前消失cgImage,或者您可以说,在您的 UIImage *frame 中。这导致了 EXC_BAD_ACCESS 异常。

这就是为什么更改为 CFDataCreate 而不是 CFDataCreateWithBytesNoCopy 的原因。


要回答您的下一个问题,如何避免复制框架,我认为有很多方法可以做到这一点。您可以一直按住 frameSec,直到将 imageView 更改为下一帧,然后您可以释放

为此,您只能声明一个属性来保存当前帧。像这样:

-(void)p_displayNextFrame
{
ZCVFrameSec *frameSec = [video getNextVideoFrameSec];
UIImage *frame = [frameSec toUIImage];
static int fi = 0;

NSAssert( [NSThread isMainThread], @"Fatal error: must be main thread" );
NSString *fileName = [Utilities documentsPath:[NSString stringWithFormat:@"image%06d.jpg",fi++]];
NSLog(@"p_displayNextFrame write image file: %@",fileName);

// frame is saved successfully as jpg, I can view it
[UIImageJPEGRepresentation(frame, 0.7) writeToFile:fileName atomically:YES];

// leak(but not crash) in emulator, crash on device
self.imageView.image = frame;

// At your header you should declare : @property ZCVFrameSec *currentFrameSec;
self.currentFrameSec = frameSec;

double delayInSeconds = 0.05;//1/30.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
[self p_displayNextFrame];
});
}

关于ios - UIImage setImage 崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24179937/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com