I am trying to process a video by adding a filter between GPUImageMovie and GPUImageMovieWriter. However, I got a trouble before adding a custom filter.
Here is my testing code.
NSURL *sampleURL = [[NSBundle mainBundle] URLForResource:#"Documents/test" withExtension:#"mov"];
movieFile = [[GPUImageMovie alloc] initWithURL:sampleURL];
NSString *pathToMovie = [NSHomeDirectory() stringByAppendingPathComponent:#"Documents/output.mov"];
unlink([pathToMovie UTF8String]);
NSURL *movieURL = [NSURL fileURLWithPath:pathToMovie];
movieWriter = [[GPUImageMovieWriter alloc] initWithMovieURL:movieURL size:CGSizeMake(1280.0, 720.0)];
[movieFile addTarget:movieWriter];
[movieWriter startRecording];
[movieFile startProcessing];
[movieWriter setCompletionBlock:^{
[movieFile removeTarget:movieWriter];
[movieWriter finishRecording];
}];
I got a error message like this
uncaught exception 'NSInvalidArgumentException', reason: '*** -[AVAssetReader initWithAsset:error:] invalid parameter not satisfying: asset != ((void*)0)'
, and there is a file named output.mov created under Documents folder with size 0.
What can I do to fix this simple task?
Your problem appears to be here:
[pixellateFilter addTarget:movieWriter];
[movieFile addTarget:movieWriter];
You're adding both the filter and movie source to the movie writer. I think what you mean to do is this:
[movieFile addTarget:pixellateFilter];
[pixellateFilter addTarget:movieWriter];
This error means that the sample file is not found or it's size is zero.
I believe you are mixing up the bundle files with the sandbox files. Where is your test.mov file? If it is in the bundle (i.e. added to the project files) then you should use:
NSURL *sampleURL = [[NSBundle mainBundle] URLForResource:#"test" withExtension:#"mov"];
Even if it is under a folder named Documents.
But if it is in the sandbox files of the app, then you should use:
NSString *pathToSample = [NSHomeDirectory() stringByAppendingPathComponent:#"Documents/test.mov"];
NSURL *sampleURL = [NSURL fileURLWithPath:pathToSample];
Related
I use the MPMoviePlayerController for playing video. It works, but it displays unknown strings which I think it is related to its localization files:
The code for playing video is here:
NSString *videoPath = [[NSBundle mainBundle] pathForResource:#"test" ofType:#"m4v"];
NSURL *streamURL = [NSURL fileURLWithPath:videoPath];
MPMoviePlayerController *moviplayer =[[MPMoviePlayerController alloc] initWithContentURL: streamURL];
[moviplayer prepareToPlay];
[moviplayer.view setFrame: self.view.bounds];
[self.view addSubview: moviplayer.view];
moviplayer.fullscreen = YES;
moviplayer.shouldAutoplay = YES;
moviplayer.repeatMode = MPMovieRepeatModeNone;
moviplayer.movieSourceType = MPMovieSourceTypeFile;
[moviplayer play];
How to solve this problem?
After looking to all part of my project, I find that the below class (category) which is used to set the default language for the application, yields to this bug:
https://github.com/cmaftuleac/BundleLocalization
Use this forked class solved my problem by not use swizzling method for UIKit bundle:
https://github.com/jbolter/BundleLocalization
https://github.com/jbolter/BundleLocalization/commit/4eedcf45a315a4a5f3ddaf9521f3cadec6632bcc
I can't seem to get the GPUImageMovieWriter to work properly.
Despite the fact that the authors are always suggesting to look over their examples; none of them are able to properly build and run.
So here's my code sample:
ALAsset *asset = (ALAsset *)[self galleryImages][indexPath.row];
NSURL *fileURLForInput = [asset valueForProperty:ALAssetPropertyAssetURL];
GPUImageMovie *movieFile = [[GPUImageMovie alloc] initWithURL:fileURLForInput];
movieFile.runBenchmark = YES;
movieFile.playAtActualSpeed = NO;
NSURL *fileURLForOutput = [NSURL fileURLWithPath:[self getVideoLocalFilePathWithVideoID:videoID]];
GPUImageMovieWriter *movieWriter = [[GPUImageMovieWriter alloc] initWithMovieURL:fileURLForOutput size:CGSizeMake(640, 480)];
movieWriter.shouldPassthroughAudio = YES;
movieFile.audioEncodingTarget = movieWriter;
[movieFile enableSynchronizedEncodingUsingMovieWriter:movieWriter];
[movieWriter startRecording];
[movieFile startProcessing];
[movieWriter setCompletionBlock:^{
PSLog(#"DONE!");
}];
Running the code sample results in a "EXC_BAD_ACCESS" error.
And if I were to remove this line:
[movieFile enableSynchronizedEncodingUsingMovieWriter:movieWriter];
The app does not crash but the output file has a size of 0 bytes and the completion block is never called.
Any ideas? :(
You need to call [movieFile addTarget:movieWriter] before you start processing the movie.
I think you need to make the GPUImageMovie and GPUImageMovieWriter variable a strong property or an instance variable.
self.movie = [[GPUImageMovie alloc]initWithURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:#"merge_video" ofType:#"mp4"]]];
self.sketchFilter = [[GPUImageSketchFilter alloc]init];
[self.movie addTarget:self.sketchFilter];
self.movie.runBenchmark = YES;
self.movie.playAtActualSpeed = NO;
NSString *pathToMovie = [NSHomeDirectory() stringByAppendingPathComponent:#"Documents/MyMovie.m4v"];
unlink([pathToMovie UTF8String]);
NSURL *movieURL = [NSURL fileURLWithPath:pathToMovie];
self.writer = [[GPUImageMovieWriter alloc]initWithMovieURL:movieURL size:CGSizeMake(320, 320)];
[self.sketchFilter addTarget:self.writer];
[self.writer setShouldPassthroughAudio:YES];
[self.movie setAudioEncodingTarget: self.writer];
__weak GPUImageMovieWriter *weakSelf = writer;
[self.movie enableSynchronizedEncodingUsingMovieWriter: weakSelf];
[ weakSelf startRecording];
[self.movie startProcessing];
[weakSelf setCompletionBlock:^{
NSLog(#"Effecting Completed Succefully");
[self.sketchFilter removeTarget:weakSelf];
[weakSelf finishRecording];
}];
You don't show where you define the writer instance variable, but I bet you created that as an instance variable and then created a writer property which is instead backed by a generated _writer variable.
This means that writer is nil in the above and your movie never even starts processing. Use self.writer instead.
I've tried the examples from the GPUImage library.
I tried the 'SimpleVideoFileFilter' but all I see its black screen with the slider.
I tried to do the same by my self, I got the images working perfect.
but I can't really understand the videos process.
the examples taking the videos from the project itself ? folder from the mac ? or its from the iPhone's videos ?
I don't have Apple Developer account, so I can't really test it on my device.
I found way to put an random (.m4v) file in the iPhone Simulator, and tried to play/filter the video.
anyone had this issue ? I'm trying for now just to play the video from the iPhone Simulator or the resource files .. I don't really know where how its works.
I tried this link, no luck.
Here is part of the example that we can find in GPUImage:
- (void)viewDidLoad
{
[super viewDidLoad];
NSURL *sampleURL = [[NSBundle mainBundle] URLForResource:#"sample_iPod" withExtension:#"m4v"];
movieFile = [[GPUImageMovie alloc] initWithURL:sampleURL];
movieFile.runBenchmark = YES;
movieFile.playAtActualSpeed = YES;
filter = [[GPUImagePixellateFilter alloc] init];
// filter = [[GPUImageUnsharpMaskFilter alloc] init];
[movieFile addTarget:filter];
// Only rotate the video for display, leave orientation the same for recording
GPUImageView *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/TestMovie.m4v"];
unlink([pathToMovie UTF8String]); // If a file already exists, AVAssetWriter won't let you record new frames, so delete the old movie
NSURL *movieURL = [NSURL fileURLWithPath:pathToMovie];
movieWriter = [[GPUImageMovieWriter alloc] initWithMovieURL:movieURL 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];
}];
}
simple code that should filter the video ..
all I get from there is black screen with the slider ..
I'm talking about this project.
Movie playback does not currently work within the Simulator using GPUImage. You'll need to run this on an actual device to have this work.
I'm not sure why movie files don't output anything when run from the Simulator, but you're welcome to dig into the GPUImageMovie code and see what might be wrong. Since it runs fine when operated on actual hardware, it hasn't been a priority of mine to fix.
UPDATE: I know now that i'm sending messages to a deallocated instance, i think i've setup my project correct, but are starting to doubt this....
I've read brad's documentation and set up my project as no-arc, that will probably have something to do with the situation. I've added the linker flag -fobjc-arc and targeted GPUImage and my target to ios 4.3.
Any one out there with the same problem that discoverd what he/she was doing wrong????
I've been searching for an answer for days now, but I can't fix it and have run out of ideas.
Whenever I try to record a movie with the GPUImageMovieWriter my app crashes (EXC_BADACCESS) on:
CVPixelBufferPoolCreatePixelBuffer (NULL, [assetWriterPixelBufferInput pixelBufferPool], &renderTarget);
Full code:
NSString *pathToMovie = [NSHomeDirectory() stringByAppendingPathComponent:#"Documents/file.mov"];
unlink([pathToMovie UTF8String]); // If a file already exists, AVAssetWriter won't let you record new frames, so delete the old movie
NSURL *movieURL = [NSURL fileURLWithPath:pathToMovie];
GPUImageSepiaFilter *sepiaFilter = [[GPUImageSepiaFilter alloc] init];
[videoCamera addTarget:sepiaFilter];
movieWriter = [[GPUImageMovieWriter alloc] initWithMovieURL:movieURL size:CGSizeMake(640.0, 480.0)];
movieWriter.encodingLiveVideo = YES;
[sepiaFilter addTarget:movieWriter];
movieWriter.shouldPassthroughAudio = YES;
videoCamera.audioEncodingTarget = movieWriter;
[movieWriter startRecording];
Ant help or pointers welcome!