在处理视频的时候,有个画中画的需求,需要展示视频的一张静态图,作为占位;所以选择把AVFrame转成UIImage供后面需要调用的地方使用,当然如果截屏的操作也可以这么做;但是后面在使用UIImage过程中会遇到一个问题,如下所示;

分析原因大概就是要访问的这片内存空间不可被读取,结合之前使用UIImage做视频渲染所遇到的问题:
即AVFrame->UIImage->render->release;
也是遇到同样的问题,报错定位在Release;
CGColorSpaceRelease(colorSpace);
现在的步骤是:
即AVFrame->UIImage->saveCache->release->waitRender;
所以分析原因还是图片在使用之前时候已经被释放掉了,所以此时考虑对图片做一次深拷贝,保证图片颜色内存空间跟数据缓存区不被释放;
处理方法是,对图片进行缩放(因为占位小图不需要那么大的size),再对图片信息进行压缩,最后再转成image缓存起来;
result = [UIImage imageWithCGImage:cgImage];
UIImage *uimage = (UIImage *)result;
CGFloat zoomWidth = kScreenWidth/3 * 2;
// 转一下,才能保证后续在使用的时候不报错,缩小尺寸,减少内存占用
uimage = [uimage transformWidth:zoomWidth Height:zoomWidth*kPreviewImageScale];
NSData *imageData = UIImageJPEGRepresentation(uimage, 0.5);
result = [UIImage imageWithData:imageData];
完整的AVFrame转UIImage的代码
// type:0、获取识别到的人脸数组 1、获取转码的image
- (id)getFaceResultData:(const AVFrame *)frame type:(int)type {
int width = frame->width;
int height = frame->height;
enum AVPixelFormat format = AV_PIX_FMT_RGB24;// (enum AVPixelFormat)srcFrame->format;
AVFrame *picture = av_frame_alloc();
picture->width = width;
picture->height = height;
int ret = av_image_alloc(
picture->data,
picture->linesize,
picture->width,
picture->height,
format, 1);
SwsContext *sws_ctx = NULL;
sws_ctx = sws_getContext(width, height, (enum AVPixelFormat)frame->format,
width, height, AV_PIX_FMT_RGB24, SWS_BICUBIC, NULL, NULL, NULL);
ret = sws_scale(sws_ctx, // 转换格式上下文
frame->data, // 输入图像每个颜色AV_PIX_FMT_YUV420通道数据的指针
frame->linesize, // 输入图像每个颜色通道的跨度
0, // 处理的开始位置(这里从图像开头处理)
frame->height, // 处理的范围(这里处理的范围是整个图像)
picture->data, // 输出图像数据位置
picture->linesize); // 输出图像每个颜色通道的跨度
CFDataRef data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, picture->data[0], picture->linesize[0]*height,kCFAllocatorNull);
CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault;
CGDataProviderRef provider = CGDataProviderCreateWithCFData(data);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGImageRef cgImage = CGImageCreate(width,
height,
8,
24,
picture->linesize[0],
colorSpace,
bitmapInfo,
provider,
NULL,
NO,
kCGRenderingIntentDefault);
CIImage *image = [CIImage imageWithCGImage:cgImage];
id result = nil;
if (type == 1) {
result = [UIImage imageWithCGImage:cgImage];
UIImage *uimage = (UIImage *)result;
CGFloat zoomWidth = kScreenWidth/3 * 2;
// 转一下,才能保证后续在使用的时候不报错,缩小尺寸,减少内存占用
uimage = [uimage transformWidth:zoomWidth Height:zoomWidth*kPreviewImageScale];
NSData *imageData = UIImageJPEGRepresentation(uimage, 0.5);
result = [UIImage imageWithData:imageData];
} else {
// CIDetector 屏幕左下角是坐标原点,需要进行坐标系转换
#warning TODO 识别度不高,需要坐标系转换
result = [self.detector featuresInImage:image];
}
#warning TODO frame #0: 0x00000001ab5175fc CoreGraphics`ERROR_CGDataProvider_BufferIsNotReadable
CGColorSpaceRelease(colorSpace);
CGImageRelease(cgImage);
CGDataProviderRelease(provider);
CFRelease(data);
sws_freeContext(sws_ctx);
if(picture){
av_freep(&picture->data[0]);
av_frame_free(&picture);
}
return result;
}
以上,就是我在处理AVFrame转UIImage时遇到的问题的一些解决思路,如有不妥或者更好的方式,欢迎留言探讨指正!
网友评论