Search code examples
iosobjective-cavplayeruislidercifilter

How to change CIFilter value of video using UISlider?


I am trying to add CIFilters to video. But I change the values using UISliders because of AVPlayer take time to play filter added video. I search of this issue, UISlider values continuously changing and it takes float values as well. Because of every time filter add to video and play. I want to know how to change values of CIFilter and without delay of AVPlayer when slider value change continuously.

float value = sender.value;
CIFilter *filter = [CIFilter filterWithName:@"CIColorControls"];
AVVideoComposition *composition = [AVVideoComposition videoCompositionWithAsset:tempAVAsset applyingCIFiltersWithHandler:
                                   ^(AVAsynchronousCIImageFilteringRequest *request){
                                       NSError *err = nil;
                                       CIImage *filtered = [request.sourceImage imageByClampingToExtent];
                                       [filter setDefaults];
                                       [filter setValue:filtered forKey:kCIInputImageKey];

                                       [filter setValue:[NSNumber numberWithFloat:0.00] forKey:@"inputSaturation"];
                                       [filter setValue:[NSNumber numberWithFloat:0.00] forKey:@"inputBrightness"];
                                       [filter setValue:[NSNumber numberWithFloat:value] forKey:@"inputContrast"];

                                       CIImage *output = [filter.outputImage imageByCroppingToRect:request.sourceImage.extent];
                                       if (filtered)
                                           [request finishWithImage:output context:nil];
                                       else
                                           [request finishWithError:err];

                                   }];

Solution

  • You can just change the filter parameter outside of your composition block when the slider value changes and don't re-set it inside the block. So just do

    [adjustFilter setValue:[NSNumber numberWithFloat:sender.value] forKey:@"inputContrast"];
    

    inside your valueChanged callback instead of inside the composition block. This way the filter always gets the most current value and will use it for the next video frame.

    Edit:

    Here are some parts of a possible implementation inside a view controller:

    @interface DemoViewController ()
    
    @property (strong, nonatomic) CIFilter *filter;
    @property (strong, nonatomic) AVPlayer *player;
    @property (strong, nonatomic) AVAsset *tempAVAsset;
    
    @end
    
    @implementation DemoViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
    
        // setup filter
        self.filter = [CIFilter filterWithName:@"CIColorControls"];
        [self.filter setDefaults];
        [self.filter setValue:[NSNumber numberWithFloat:0.00] forKey:@"inputSaturation"];
        [self.filter setValue:[NSNumber numberWithFloat:0.00] forKey:@"inputBrightness"];
    
        AVVideoComposition *composition = [AVVideoComposition videoCompositionWithAsset:self.tempAVAsset applyingCIFiltersWithHandler:
            ^(AVAsynchronousCIImageFilteringRequest *request){
                NSError *err = nil;
                CIImage *filtered = [request.sourceImage imageByClampingToExtent];
    
                [self.filter setValue:filtered forKey:kCIInputImageKey];
                CIImage *output = [self.filter.outputImage imageByCroppingToRect:request.sourceImage.extent];
                if (filtered)
                   [request finishWithImage:output context:nil];
                else
                   [request finishWithError:err];
            }
        ];
    
        // setup player with composition
        // ...
    }
    
    
    - (IBAction)sliderValueChanged:(UISlider*)sender
    {
        // get the new slider value and assign it to the filter
        [self.filter setValue:[NSNumber numberWithFloat:sender.value] forKey:@"inputContrast"];
    }
    
    @end