版本记录
| 版本号 | 时间 | 
|---|---|
| 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滤镜处理(四)
功能要求
实时更改滤镜GPUImageSepiaFilter的intensity值,达到实时更改视频的效果,并实现了存储。
功能实现
下面还是直接看代码。
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作为了滤镜强度因子的数值。
后记
未完,待续~~
