GPUImage解析(十) —— 一个简单的实例之实时更改视频的滤镜值(五)

版本记录

版本号 时间
V1.0 2017.09.05

前言

GPUImage是直接利用显卡实现视频或者图像处理的技术。感兴趣可以看上面几篇文章。
1. GPUImage解析(一) —— 基本概览(一)
2. GPUImage解析(二) —— 基本概览(二)
3. GPUImage解析(三) —— 基本概览(三)
4. GPUImage解析(四) —— 安装方法及框架介绍
5. GPUImage解析(五) —— 框架中的几个基类
6. GPUImage解析(六) —— 一个简单的实例(一)
7. GPUImage解析(七) —— 一个简单的实例结合GPUImageVideoCamera(二)
8. GPUImage解析(八) —— 一个简单的实例之多滤镜视频采集存储(三)
9. GPUImage解析(九) —— 一个简单的实例之GPUImageTiltShiftFilter滤镜处理(四)

功能要求

实时更改滤镜GPUImageSepiaFilterintensity值,达到实时更改视频的效果,并实现了存储。


功能实现

下面还是直接看代码。

1. JJGPUImageSliderRecordVC.m
#import "JJGPUImageSliderRecordVC.h"
#import "GPUImage.h"
#import "Masonry.h"
#import <AssetsLibrary/AssetsLibrary.h>

@interface JJGPUImageSliderRecordVC ()

@property (nonatomic, strong) GPUImageVideoCamera *videoCamera;
@property (nonatomic, strong) GPUImageSepiaFilter *sepiaFilter;
@property (nonatomic, strong) GPUImageView *imageView;
@property (nonatomic, strong) UIButton *recordButton;
@property (nonatomic, strong) UILabel *timeDisplayLabel;
@property (nonatomic, assign) NSInteger timeValue;
@property (nonatomic, strong) UISlider *slider;
@property (nonatomic, strong) GPUImageMovieWriter *movieWriter;
@property (nonatomic, strong) NSTimer *timer;

@end

@implementation JJGPUImageSliderRecordVC

#pragma mark - Override Base Function

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    self.view.backgroundColor = [UIColor whiteColor];
    
    [self setupUI];
    
    [self setupConfiguratuon];
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    
    self.navigationController.navigationBarHidden = YES;
}

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
    
    self.navigationController.navigationBarHidden = NO;
}

#pragma mark - Object Private Function

- (void)setupUI
{
    //实例化GPUImageView
    self.imageView = [[GPUImageView alloc] initWithFrame:self.view.frame];
    [self.view addSubview:self.imageView];
    
    //按钮实例化
    self.recordButton = [UIButton buttonWithType:UIButtonTypeCustom];
    [self.recordButton setTitle:@"录制" forState:UIControlStateNormal];
    [self.recordButton setTitle:@"结束" forState:UIControlStateSelected];
    [self.recordButton addTarget:self action:@selector(recordButtonDidClick:) forControlEvents:UIControlEventTouchUpInside];
    
    [self.view addSubview:self.recordButton];
    [self.recordButton sizeToFit];
    [self.recordButton mas_makeConstraints:^(MASConstraintMaker *make) {
        make.bottom.equalTo(self.imageView.mas_bottom).offset(-50);
        make.centerX.equalTo(self.imageView);
    }];
    
    //显示时间label实例化
    self.timeDisplayLabel = [[UILabel alloc] init];
    self.timeDisplayLabel.hidden = YES;
    self.timeDisplayLabel.textColor = [UIColor redColor];
    self.timeDisplayLabel.font = [UIFont systemFontOfSize:16.0];
    
    [self.view addSubview:self.timeDisplayLabel];
    [self.timeDisplayLabel sizeToFit];
    [self.timeDisplayLabel mas_makeConstraints:^(MASConstraintMaker *make) {
        make.centerX.equalTo(self.imageView);
        make.bottom.equalTo(self.recordButton.mas_top).offset(-15.0);
    }];
    
    //滑动条
    self.slider = [[UISlider alloc] init];
    [self.slider addTarget:self action:@selector(sliderDidSlide:) forControlEvents:UIControlEventValueChanged];
    
    [self.view addSubview:self.slider];
    [self.slider mas_makeConstraints:^(MASConstraintMaker *make) {
        make.bottom.equalTo(self.recordButton.mas_top).offset(-40.0);
        make.centerX.equalTo(self.slider);
        make.height.equalTo(@30);
        make.width.equalTo(@(self.view.bounds.size.height));
    }];
}

- (void)setupConfiguratuon
{
    //实例化GPUImageVideoCamera
    self.videoCamera = [[GPUImageVideoCamera alloc] initWithSessionPreset:AVCaptureSessionPreset640x480 cameraPosition:AVCaptureDevicePositionBack];
    self.videoCamera.outputImageOrientation = [UIApplication sharedApplication].statusBarOrientation;
    
    //实例化
    self.sepiaFilter = [[GPUImageSepiaFilter alloc] init];
    
    [self.videoCamera addTarget:self.sepiaFilter];
    [self.sepiaFilter addTarget:self.imageView];
    [self.videoCamera startCameraCapture];
}

#pragma mark - Action && Notification

- (void)recordButtonDidClick:(UIButton *)button
{
    button.selected = !button.selected;
    
    NSString *savePath = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents/Movie4.m4v"];
    NSURL *movieURL = [NSURL fileURLWithPath:savePath];
    if (button.selected) {
        unlink([savePath UTF8String]);
        self.movieWriter = [[GPUImageMovieWriter alloc] initWithMovieURL:movieURL size:CGSizeMake(480.0, 640.0)];
        self.movieWriter.encodingLiveVideo = YES;
        
        [self.sepiaFilter addTarget:self.movieWriter];
        self.videoCamera.audioEncodingTarget = self.movieWriter;
        [self.movieWriter startRecording];
        
        self.timeValue = 0;
        self.timeDisplayLabel.hidden = NO;
        
        self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerWork:) userInfo:nil repeats:YES];
    }
    else {
        self.timeDisplayLabel.hidden = YES;
        if (self.timer) {
            [self.timer invalidate];
            self.timer = nil;
        }
        
        [self.sepiaFilter removeTarget:self.movieWriter];
        self.videoCamera.audioEncodingTarget = nil;
        [self.movieWriter finishRecording];
    
        ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
        if (UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(savePath))
        {
            [library writeVideoAtPathToSavedPhotosAlbum:movieURL completionBlock:^(NSURL *assetURL, NSError *error)
             {
                 dispatch_async(dispatch_get_main_queue(), ^{
                     
                     if (error) {
                         NSLog(@"保存失败");
                     }
                     else {
                         NSLog(@"保存成功");
                     }
                 });
             }];
        }
    }
}

- (void)timerWork:(NSTimer *)timer
{
    NSLog(@"%ld", self.timeValue);
    
    self.timeDisplayLabel.text = [NSString stringWithFormat:@"录制时间:%ld", self.timeValue ++];
    [self.timeDisplayLabel sizeToFit];
}

- (void)sliderDidSlide:(UISlider *)slider
{
    NSInteger factor = 5;
    [self.sepiaFilter setIntensity:slider.value * factor];
}

@end

下面看输出结果

2017-09-05 16:32:53.614617+0800 JJOC[2153:1364795] 0
2017-09-05 16:32:54.614526+0800 JJOC[2153:1364795] 1
2017-09-05 16:32:55.614576+0800 JJOC[2153:1364795] 2
2017-09-05 16:32:56.614534+0800 JJOC[2153:1364795] 3
2017-09-05 16:32:57.615191+0800 JJOC[2153:1364795] 4
2017-09-05 16:32:58.614548+0800 JJOC[2153:1364795] 5
2017-09-05 16:32:59.614562+0800 JJOC[2153:1364795] 6
2017-09-05 16:33:00.614702+0800 JJOC[2153:1364795] 7
2017-09-05 16:33:01.619716+0800 JJOC[2153:1364795] 8
2017-09-05 16:33:02.614597+0800 JJOC[2153:1364795] 9
2017-09-05 16:33:03.614647+0800 JJOC[2153:1364795] 10
2017-09-05 16:33:04.852523+0800 JJOC[2153:1364795] 保存成功

功能效果

下面我们就看一下功能实现的效果。

由于简书最多只能上传5M,所以gif我只是录制的一部分,大家凑合着看吧,其实还是可以看到效果的,滤镜效果发生了改变,为了效果明显,在代码中我将slider的值乘以5作为了滤镜强度因子的数值。

后记

未完,待续~~

推荐阅读更多精彩内容