水印相机-gpuimage
[self.myCamera setCaptureSessionPreset:AVCaptureSessionPreset640x480];//设置相机尺寸
[self.videoCamera rotateCamera];// 切换摄像头前后翻转
// 切换滤镜
-(void)change1:(UIButton*)sender{
[self.myCamera removeAllTargets];相机去除滤镜组和GPUImageView
[self.myFilterGroup removeAllTargets];//去除容器内的所有滤镜 (这种方式有问题实际上并没有去处数组里面的滤镜多次切换会内存溢出导致奔溃)
应该改为一下子2行代码:
self.myFilterGroup =nil;
self.myFilterGroup = [[GPUImageFilterGroup alloc]init];
GPUImageStretchDistortionFilter *stretchDistortionFilter0 = [[GPUImageStretchDistortionFilter alloc] init];
[selfaddGPUImageFilter:stretchDistortionFilter0];//重新添加滤镜
// GPUImageColorInvertFilter *stretchDistortionFilter = [[GPUImageColorInvertFilter alloc] init];
// [self addGPUImageFilter:stretchDistortionFilter];
[self.myCamera addTarget:self.myFilterGroup];//相机上添加滤镜组
[self.myFilterGroup addTarget:self.myGPUImageView];//相机上添加GPUImageView
}
#pragma mark 将滤镜加在FilterGroup中并且设置初始滤镜和末尾滤镜
- (void)addGPUImageFilter:(GPUImageFilter *)filter{
[self.myFilterGroup addFilter:filter];
GPUImageOutput *newTerminalFilter = filter;
NSInteger count = self.myFilterGroup.filterCount;
if(count ==1)
{
//设置初始滤镜
self.myFilterGroup.initialFilters=@[newTerminalFilter];
//设置末尾滤镜
self.myFilterGroup.terminalFilter= newTerminalFilter;
}else
{
GPUImageOutput *terminalFilter =self.myFilterGroup.terminalFilter;
NSArray*initialFilters =self.myFilterGroup.initialFilters;
[terminalFilteraddTarget:newTerminalFilter];
//设置初始滤镜
self.myFilterGroup.initialFilters=@[initialFilters[0]];
//设置末尾滤镜
self.myFilterGroup.terminalFilter= newTerminalFilter;
}
}
照片的水印,我是采用得到了带滤镜的uiimage和水印层获得uiimage 合成一张照片
一边录制一边加水印。其实是用了混合模式里的一些混合方式。选择2个数据源 1是所需要的滤镜组 另一就是水印层创建的GPUImageUIElement,可选择如果不需要不透明,直接贴上去建议使用GPUImageScreenBlendFilter屏幕混合方式 或者GPUImageDivideBlendFilter 分割混合。效果会好一些。不过还是会有一点模糊。
#pragma mark混合
-(void)Starwatervideo{
[_videoCamera removeAllTargets];
self.VideFilterGroup =nil;
self.VideFilterGroup = [[GPUImageFilterGroup alloc]init];
[self addVideoGPUImageFilter:self.BrightnessFilter];
[self addVideoGPUImageFilter:self.BeautifyFilter];
GPUImageUIElement *uiElement = [[GPUImageUIElement alloc] initWithView:self.tempview];
// _filter1 = [[GPUImageScreenBlendFilter alloc] init];
_filter1 = [[GPUImageDivideBlendFilter alloc] init];
// _filter1.mix = 0.5f;
[_videoCamera addTarget:self.VideFilterGroup];
[uiElementaddTarget:_filter1];
[self.VideFilterGroup addTarget:_filter1];
[_filter1 addTarget:self.filterView];
// [self addVideoGPUImageFilter:_filter1];
// [self.VideFilterGroup addTarget:_filterView];
[_videoCamera startCameraCapture];
//刷新
[self.VideFilterGroup setFrameProcessingCompletionBlock:^(GPUImageOutput *output, CMTime time) {
[uiElementupdate];
}];
}
#pragma mark开始录制和结束录制
-(void)takeVideIsStop:(BOOL)isstop{
NSString *pathToMovie = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents/Movie4.m4v"];
NSURL*movieURL = [NSURLfileURLWithPath:pathToMovie];
if(!isstop) {//开始拍摄
[self Starwatervideo];
unlink([pathToMovie UTF8String]); // 如果已经存在文件,AVAssetWriter会有异常,删除旧文件
// self.movieWriter = [[GPUImageMovieWriter alloc] initWithMovieURL:movieURL size:CGSizeMake(SCREEN_WIDTH, SCREEN_HEIGHT-STATUS_BAR_HIGHT)];
self.movieWriter= [[GPUImageMovieWriteralloc]initWithMovieURL:movieURLsize:CGSizeMake(SCREEN_WIDTH,SCREEN_HEIGHT)];
self.movieWriter.encodingLiveVideo = YES;
// [_VideFilterGroup addTarget:_movieWriter];
[_filter1 addTarget:_movieWriter];
_videoCamera.audioEncodingTarget = _movieWriter;
[self.movieWriter startRecording];
}else{//结束拍摄
// [_VideFilterGroup removeTarget:_movieWriter];
[_filter1 removeTarget:_movieWriter];
_videoCamera.audioEncodingTarget = nil;
[_movieWriter finishRecording];
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
if (UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(pathToMovie))
{
[librarywriteVideoAtPathToSavedPhotosAlbum:movieURLcompletionBlock:^(NSURL*assetURL,NSError*error)
{
dispatch_async(dispatch_get_main_queue(), ^{
if(error) {
UIAlertView*alert = [[UIAlertViewalloc]initWithTitle:@"视频保存失败"message:nil
delegate:nilcancelButtonTitle:@"OK"otherButtonTitles:nil];
[alertshow];
}else{
UIAlertView*alert = [[UIAlertViewalloc]initWithTitle:@"视频保存成功"message:nil
delegate:selfcancelButtonTitle:@"OK"otherButtonTitles:nil];
[alertshow];
}
});
}];
}else{
}
}
}
防止链接失效,下面一些内容来自上述链接
// 如果录像的额时候,图像高亮下,可以在初始化GPUImageVideoCamera的时候,加上
[_videoCamera addAudioInputsAndOutputs];
// //如果是调用前置摄像头就发现成的像是左右相反了,就看下是不是开启了镜像
// self.videoCamera.horizontallyMirrorFrontFacingCamera = YES;
// self.videoCamera.horizontallyMirrorRearFacingCamera = NO;
// 如果仅仅是暂停录制,不暂停摄像头画面
//录制暂停
[self.movieWriter setPaused:true];
//录制继续
[self.movieWriter setPaused:false];
// 如果是暂停录制,并且也要暂停摄像头画面
//录制暂停
[self.movieWriter setPaused:true];
//摄像头暂停
[_videoCamera pauseCameraCapture];
//录制继续
[self.movieWriter setPaused:false];
//摄像头继续
[_videoCamera resumeCameraCapture];
视频防抖
AVCaptureDevice *device = self.videoCamera.inputCamera;
AVCaptureConnection *connection = self.videoCamera.videoCaptureConnection;
AVCaptureVideoStabilizationMode stabilizationMode = AVCaptureVideoStabilizationModeCinematic;//强制开启视频防抖
if ([device.activeFormat isVideoStabilizationModeSupported:stabilizationMode]) {
[connectionsetPreferredVideoStabilizationMode:stabilizationMode];
}
利用lut文件映射出滤镜,用lut文件去ps生成一个64X64X64 的图如果是图片详细做法,网上有很多资料:比如这个
- (UIImage*)generateImage:(UIImage*)inputImage
{
UIImage*outputImage;
GPUImagePicture*stillImageSource = [[GPUImagePicturealloc]initWithImage:self.Image];
//添加滤镜
GPUImageLookupFilter *lookUpFilter = [[GPUImageLookupFilter alloc] init];
GPUImagePicture*lookupImg = [[GPUImagePicture alloc]initWithImage:inputImage];
[lookupImgaddTarget:lookUpFilteratTextureLocation:1];
[stillImageSourceaddTarget:lookUpFilteratTextureLocation:0];
[lookUpFilteruseNextFrameForImageCapture];
if([lookupImg processImageWithCompletionHandler:nil] && [stillImageSource processImageWithCompletionHandler:nil]) {
outputImage = [lookUpFilterimageFromCurrentFramebuffer];
}
returnoutputImage;
}
但是要在录制视频时候添加进去就需要生成对应的gpuimagefiter的滤镜。所以需要自定义一个GPUImageFilterGroup滤镜,然后把.m实现方法里的图片换成我们需要的,就生成了一个通用的我们想要的滤镜了
一遍录制一遍添加水印,网上也有资料比如这个 但是实际上会遇到2个问题,第一是清晰度第二个是色差
在添加水印时候是需要编辑更改等操作导致,水印并非一开始就和视频混合,先在一个图层说添加水印在这个图层可以进行编辑拖动更改甚至更换水印。直到开始录制才去和相机录制混合,这样就会有原版的水印图层和混合好的视频展示图层。两个地方都会有水印,这样如果两个位置不一样就会出现重复。所以需要计算好水印图层和视频添加水印时候的坐标。有2种解决方案
方案一:把整个水印层(水印的父是图)作为GPUImageUIElement 的目标图层。这样就不会出现位置问题,但是会出现水印模糊问题
推荐方案二:重新创建一个图层,宽高(像素点)和你所选择相机的质量的像素保持一致
比如:相机初始化选择了AVCaptureSessionPresetiFrame1280x720 那么图层的宽*高=720 *1280
然后水印生成图片,再用uiimageview添加到新图层上,位置和大小都要按照新图层的宽和原来的宽的比例去计算现在水印在新图层的X,Y,宽,高。这样做就是为了水印和视频源被同比例的拉伸达到不影响清晰的的效果。
如果有对视频做裁剪,那新图层的宽高是裁剪之后的。
网上的那些方法对于不透明的为1的水印没影响,但是对有带不透明的水印会造成色差,色彩或重或淡,原因是GPUImageAlphaBlendFilter 的像素点混合算法就是按照色彩叠加生成新色值的算法,所以需要改变计算方式自定义过一个混合滤镜。算法是这个
修改GPUImageAlphaBlendFilter 里面的关键算法就好了。