????????項目用到GPUImage錄制視頻,同時還要加水印錄制,錄制的教程大把,但是這個庫15年就不維護了,導致很多坑沒有補。有些坑在githud問題里找到答案,也是不明所以,不過也有朋友遇到類似的問題,就開個帖子記錄下,順便給有需要的朋友參考。?
? ? ? ? 當我照著網上的demo擼了一個錄制的視頻,一開始就遇到填坑,程序崩潰,報錯:Tried to overrelease a framebuffer, did you forget to call -useNextFrameForImageCapture before using -imageFromCurrentFramebuffer!
網上問了很多人也查了很多資料,GPUImageFramebuffer是處理視頻幀的類,報錯是因為framebufferReferenceCount這個屬性等于0,framebufferReferenceCount這個屬性是用來做類似ARC中的內存計數一樣的存在,可能是為了防止過度釋放什么的。
最簡單的修復方法,肯定就是把NSAssert(framebufferReferenceCount > 0, @"Tried to overrelease a framebuffer, did you forget to call -useNextFrameForImageCapture before using -imageFromCurrentFramebuffer?");這句代碼注釋掉了,不過githud上查了所有issue,發現有大神提出以下修復方法,在sdk庫里找到GPUImageUIElement.h文件,updateWithTimestamp方法里添加以下語句[outputFramebuffer????disableReferenceCounting];// Add this line, because GPUImageTwoInputFilter.m frametime updatedMovieFrameOppositeStillImage is YES, but the secondbuffer not lock(意思大概是第二個幀buffer沒有鎖住)
#pragma mark GPU源碼修改 修復crash
[currentTargetsetInputFramebuffer:outputFramebufferatIndex:textureIndexOfTarget];// add this line, because the outputFramebuffer is update above
完整的方法
- (void)updateWithTimestamp:(CMTime)frameTime;
{
[GPUImageContextuseImageProcessingContext];
CGSizelayerPixelSize = [selflayerSizeInPixels];
GLubyte*imageData = (GLubyte*)calloc(1, (int)layerPixelSize.width* (int)layerPixelSize.height*4);
CGColorSpaceRefgenericRGBColorspace =CGColorSpaceCreateDeviceRGB();
CGContextRefimageContext =CGBitmapContextCreate(imageData, (int)layerPixelSize.width, (int)layerPixelSize.height,8, (int)layerPixelSize.width*4, genericRGBColorspace,kCGBitmapByteOrder32Little|kCGImageAlphaPremultipliedFirst);
//CGContextRotateCTM(imageContext, M_PI_2);
CGContextTranslateCTM(imageContext,0.0f, layerPixelSize.height);
CGContextScaleCTM(imageContext,layer.contentsScale, -layer.contentsScale);
//CGContextSetBlendMode(imageContext, kCGBlendModeCopy); // From Technical Q&A QA1708:http://developer.apple.com/library/ios/#qa/qa1708/_index.html
[layerrenderInContext:imageContext];
CGContextRelease(imageContext);
CGColorSpaceRelease(genericRGBColorspace);
// TODO: This may not work
outputFramebuffer= [[GPUImageContextsharedFramebufferCache]fetchFramebufferForSize:layerPixelSizetextureOptions:self.outputTextureOptionsonlyTexture:YES];
#pragma mark GPU源碼修改 修復crash
[outputFramebufferdisableReferenceCounting];// Add this line, because GPUImageTwoInputFilter.m frametime updatedMovieFrameOppositeStillImage is YES, but the secondbuffer not lock
glBindTexture(GL_TEXTURE_2D, [outputFramebuffertexture]);
// no need to use self.outputTextureOptions here, we always need these texture options
glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA, (int)layerPixelSize.width, (int)layerPixelSize.height,0,GL_BGRA,GL_UNSIGNED_BYTE, imageData);
free(imageData);
for(id currentTargetintargets)
{
if(currentTarget !=self.targetToIgnoreForUpdates)
{
NSIntegerindexOfObject = [targetsindexOfObject:currentTarget];
NSIntegertextureIndexOfTarget = [[targetTextureIndicesobjectAtIndex:indexOfObject]integerValue];
[currentTargetsetInputSize:layerPixelSizeatIndex:textureIndexOfTarget];
#pragma mark GPU源碼修改 修復crash
[currentTargetsetInputFramebuffer:outputFramebufferatIndex:textureIndexOfTarget];// add this line, because the outputFramebuffer is update above
[currentTargetnewFrameReadyAtTime:frameTimeatIndex:textureIndexOfTarget];
}
}
}
?不過用了以上方法雖然不會崩潰了,但是偶爾會出現只錄制了5秒視頻的bug,方法就是在出現丟幀的時候,重新錄制,雖然有點蠢。。。只能這樣了