需求
由于需求的原因要做到視頻的實(shí)時(shí)渲染但是并不改變?cè)曨l,也就是說(shuō)不是針對(duì)視頻本身去加濾鏡,所以就一直在網(wǎng)上找方法,網(wǎng)上大神說(shuō)是要拿到視頻的每一幀圖片進(jìn)行渲染赤炒。接下來(lái)就開(kāi)始動(dòng)手缆娃。
1.拿到視頻每一幀
在AVFoundation框架里有一個(gè)類AVPlayerItemVideoOutput,用來(lái)獲取視頻輸出的每一幀,具體看代碼
AVPlayerItem *item = [AVPlayerItem playerItemWithURL:videoUrl];
_videoOutPut = [[AVPlayerItemVideoOutput alloc] initWithOutputSettings:nil];
_player = [[AVPlayer alloc] initWithPlayerItem:item];
[self.player.currentItem addOutput:_videoOutPut];
上面初始化了一個(gè)item和videoOutPut,并且把videoOutPut加到了item上面,現(xiàn)在我們要在每一幀的時(shí)候去獲取buffer粪躬。
CMTime itemTime = [_videoOutPut itemTimeForHostTime:CACurrentMediaTime()];
if ([_videoOutPut hasNewPixelBufferForItemTime:itemTime]) {
CVPixelBufferRef pixelBuffer = [_videoOutPut copyPixelBufferForItemTime:itemTime itemTimeForDisplay:nil];
CIImage *ciImage = [CIImage imageWithCVPixelBuffer:pixelBuffer];
CVBufferRelease(pixelBuffer);
}else{
}
這樣我們就獲取到了視頻每一幀的CIImage,現(xiàn)在我們就可以加上濾鏡了。
2.加濾鏡
加濾鏡就簡(jiǎn)單用了系統(tǒng)的對(duì)比度,亮度之類的具體的大家可自行配置好看的濾鏡殿托。
CIFilter *filter = [CIFilter filterWithName:@"CIColorControls"];
[filter setValue:ciImg forKey:kCIInputImageKey];
[filter setDefaults];
// 修改亮度 -1---1 數(shù)越大越亮
[filter setValue:@(self.light) forKey:@"inputBrightness"];
// 修改飽和度 0---2
[filter setValue:@(self.saturation) forKey:@"inputSaturation"];
// 修改對(duì)比度 0---4
[filter setValue:@(self.contrast) forKey:@"inputContrast"];
CIImage *outputImage = [filter outputImage];
現(xiàn)在就剩顯示出來(lái)了,我們選擇了用opengl進(jìn)行渲染,用CPU的話會(huì)稍微有些卡頓霹菊。
3.顯示
初始化glkview,進(jìn)行配置。然后我們傳入一個(gè)經(jīng)過(guò)CIFilter處理的CIImage就可以渲染出來(lái)了碌尔。
- (void)initGlkView{
EAGLContext *eaglContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
_glkView = [[GLKView alloc] initWithFrame:CGRectZero context:eaglContext];
_glkView.delegate = self;
[_glkView bindDrawable];
_glkView.enableSetNeedsDisplay = NO;
[self addSubview:_glkView];
[EAGLContext setCurrentContext:eaglContext];
_imageContext = [CIContext contextWithEAGLContext:eaglContext options:@{kCIContextWorkingColorSpace:[NSNull null]}];
}
在傳入CIImage的方法里,調(diào)用display方法進(jìn)行繪制浇辜。
- (void)setRenderImg:(CIImage *)renderImg{
_renderImg = renderImg;
[self.glkView display];
}
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect{
[self.imageContext drawImage:self.renderImg inRect:CGRectMake(0, 0, self.glkView.drawableWidth, self.glkView.drawableHeight) fromRect:[self.renderImg extent]];
}