如何在 iOS 中为正在运行的视频添加动态视觉效果?
Posted
技术标签:
【中文标题】如何在 iOS 中为正在运行的视频添加动态视觉效果?【英文标题】:How to add Dynamic Visual effects to running videos in iOS? 【发布时间】:2014-04-08 07:50:26 【问题描述】:我想将视觉效果动态更改为正在运行的视频。我正在使用 GPUImage 框架来改变视觉效果。我从Here 下载了示例项目。在这个 GPUImage 中,我选择了 SimpleVideoFileFilter 示例。此示例使用一个过滤器运行,只是我修改了代码,目前它支持 10 个过滤器。我的问题是,视频文件正在 GPUImageView 中播放,现在我选择了另一个过滤器。突然间,视频效果也发生了变化。但是那个视频是从头开始的。我想为当前播放的视频动态更改过滤器。 我的代码是:
#pragma mark - Play Video with Effects
- (void)getVideo:(NSURL *)url
movieFile = [[GPUImageMovie alloc] initWithURL:url];
movieFile.runBenchmark = YES;
movieFile.playAtActualSpeed = YES;
// filter = [[GPUImagePixellateFilter alloc] init];
[movieFile addTarget:filter];
// Only rotate the video for display, leave orientation the same for recording
filterView = (GPUImageView *)self.view;
[filter addTarget:filterView];
// In addition to displaying to the screen, write out a processed version of the movie to disk
NSString *pathToMovie = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents/Movie.m4v"];
unlink([pathToMovie UTF8String]); // If a file already exists, AVAssetWriter won't let you record new frames, so delete the old movie
NSURL *movieURL1 = [NSURL fileURLWithPath:pathToMovie];
movieWriter = [[GPUImageMovieWriter alloc] initWithMovieURL:movieURL1 size:CGSizeMake(640.0, 480.0)];
[filter addTarget:movieWriter];
// Configure this for video from the movie file, where we want to preserve all video frames and audio samples
movieWriter.shouldPassthroughAudio = YES;
movieFile.audioEncodingTarget = movieWriter;
[movieFile enableSynchronizedEncodingUsingMovieWriter:movieWriter];
[movieWriter startRecording];
[movieFile startProcessing];
[movieWriter setCompletionBlock:^
[filter removeTarget:movieWriter];
[movieWriter finishRecording];
UISaveVideoAtPathToSavedPhotosAlbum(pathToMovie, nil, nil, nil);
];
- (void)event:(UIButton*)sender
[filter removeTarget:filterView];
UIButton *selectedBtn = sender;
[movieFile removeTarget:filter];
switch (selectedBtn.tag)
case 0:
filter = [[GPUImageBrightnessFilter alloc] init];
break;
case 1:
filter = [[GPUImageGrayscaleFilter alloc] init];
break;
case 2:
filter = [[GPUImageSketchFilter alloc] init];
break;
case 3:
filter = [[GPUImageToonFilter alloc] init];
break;
case 4:
filter = [[GPUImageMonochromeFilter alloc] init];
break;
case 5:
filter = [[GPUImagePixellateFilter alloc] init];
break;
case 6:
filter = [[GPUImageCrosshatchFilter alloc] init];
break;
case 7:
filter = [[GPUImageVignetteFilter alloc] init];
break;
case 8:
filter = [[GPUImageColorInvertFilter alloc] init];
break;
case 9:
filter = [[GPUImageLevelsFilter alloc] init];
[(GPUImageLevelsFilter *)filter setRedMin:1.0 gamma:1.0 max:0.0 minOut:0.5 maxOut:0.5];
break;
default:
break;
[self getVideo:movieURL];
请帮我解决这个问题。
【问题讨论】:
为什么每次更改过滤器设置时都重新运行[self getVideo:movieURL];
?当然,这会重新启动您的视频。只需更改过滤器属性或更换过滤器,无需重新生成您的电影实例。您可以轻松地暂停电影、更改滤镜并重新启动电影以动态更改这些效果。
嗨 @BradLarson,首先感谢您提供宝贵的 GPUImage 框架。实际上对这个问题感到震惊。请帮我解决这个问题。我不知道如何动态更换过滤器。请您编辑上述代码并作为答案发布。
@BradLarson 如何暂停正在播放的电影?
我也面临同样的问题。请发布解决方案。
@QUserS - 发布解决方案。
【参考方案1】:
我自己找到了答案。解决办法是,
- (void)event:(UIButton*)sender
// isMoviePlayCompleted = NO;
if (btnTag != sender.tag)
btnTag = (int)sender.tag;
NSLog(@"tag:%d",btnTag);
[self applyFilter:sender.tag];
应用过滤器
-(void) applyFilter:(NSInteger) tag
[[NSFileManager defaultManager] removeItemAtURL:saveTempUrl error:nil];
recording = NO;
switch (tag)
case 0:
filter =nil;
filter = [[GPUImagePixellateFilter alloc] init];
[(GPUImagePixellateFilter *)filter setFractionalWidthOfAPixel:0.0];
break;
case 1:
filter =nil;
filter = [[GPUImageGrayscaleFilter alloc] init];
break;
case 2:
filter =nil;
filter = [[GPUImageSketchFilter alloc] init];
break;
case 3:
filter =nil;
filter = [[GPUImageToonFilter alloc] init];
break;
case 4:
filter =nil;
filter = [[GPUImageMonochromeFilter alloc] init];
break;
case 5:
filter =nil;
filter = [[GPUImageVignetteFilter alloc] init];
break;
default:
break;
[self getVideo:movieURL];
使用效果播放视频
- (void)getVideo:(NSURL *)url
[filter removeAllTargets];
movieFile.audioEncodingTarget = nil;
[movieWriter cancelRecording];
[movieFile cancelProcessing];
[movieWriter finishRecording];
movieWriter = nil;
movieFile = nil;
filterView = nil;
recording = YES;
anAsset = [[AVURLAsset alloc] initWithURL:url options:nil];
movieFile = [[GPUImageMovie alloc] initWithURL:url];
movieFile.delegate = self;
movieFile.runBenchmark = NO;
movieFile.playAtActualSpeed = YES;
[movieFile addTarget:filter];
// Only rotate the video for display, leave orientation the same for recording
filterView = (GPUImageView *)self.view;
[filter addTarget:filterView];
NSString *pathName = [NSString stringWithFormat:@"Doc.MOV"];
// In addition to displaying to the screen, write out a processed version of the movie to disk
NSString *pathToMovie = [NSTemporaryDirectory() stringByAppendingPathComponent:pathName];
NSFileManager *fileTmp = [[NSFileManager alloc] init];
if ([fileTmp fileExistsAtPath:pathToMovie])
[fileTmp removeItemAtPath:pathToMovie error:nil];
unlink([pathToMovie UTF8String]); // If a file already exists, AVAssetWriter won't let you record new frames, so delete the old movie
saveTempUrl = [NSURL fileURLWithPath:pathToMovie];
movieWriter = [[GPUImageMovieWriter alloc] initWithMovieURL:saveTempUrl size:size];
[filter addTarget:movieWriter];
[movieFile enableSynchronizedEncodingUsingMovieWriter:movieWriter];
[movieWriter startRecording];
[movieFile startProcessing];
__unsafe_unretained typeof(self) weakSelf = self;
[weakSelf->movieWriter setCompletionBlock:^
NSLog(@"write completed");
[filter removeTarget:movieWriter];
[movieWriter finishRecording];
movieWriter = nil;
movieFile = nil;
filterView = nil;
recording = NO;
if (saveFilter)
saveFilter = NO;
UISaveVideoAtPathToSavedPhotosAlbum([saveTempUrl path], self, @selector(video:didFinishSavingWithError:contextInfo:), nil);
shareFilter = YES;
];
就是这样。现在,当我选择任何过滤器时,它都会重新填充。所以内存问题解决了。现在它适用于我的应用程序。
【讨论】:
抱歉回复晚了,感谢您的解决方案。我刚刚试用了您的代码,但没有得到预期的结果。每当更改过滤器时,我都需要恢复视频。目前它正在从应用每个过滤器的起点开始播放。请提出建议。【参考方案2】:// Use this code
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(movieFinished) name:MPMoviePlayerPlaybackDidFinishNotification object:videoPlayer];
[videoPlayer play];
-(void)movieFinished
[videoPlayer play];
-(void) playTheVideo:(NSURL *)videoURL
NSTimeInterval time= videoPlayer.currentPlaybackTime;
UIView *parentView = imageViewFiltered; // adjust as needed
CGRect bounds = parentView.bounds; // get bounds of parent view
CGRect subviewFrame = CGRectInset(bounds, 0, 0);
videoPlayer.view.frame = subviewFrame;
videoPlayer.view.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
[parentView addSubview:videoPlayer.view];
videoPlayer.contentURL = videoURL;
[videoPlayer setCurrentPlaybackTime:time];
[videoPlayer stop];
NSLog(@"Videoplayer stop or play in this view ");
[videoPlayer play];
self.showLoading = NO;
self.showLoading =NO;
【讨论】:
以上是关于如何在 iOS 中为正在运行的视频添加动态视觉效果?的主要内容,如果未能解决你的问题,请参考以下文章