BradLarson / GPUImage

An open source iOS framework for GPU-based image and video processing
http://www.sunsetlakesoftware.com/2012/02/12/introducing-gpuimage-framework
BSD 3-Clause "New" or "Revised" License
20.25k stars 4.61k forks source link

GPUImageMovieWriter setCompletionBlock not always running #1321

Open EfeAcikgoz opened 10 years ago

EfeAcikgoz commented 10 years ago

Hi, I am trying to filter a video and save it again but the completionBlock of GPUImageMovieWriter does not get called half the time when I try to filter. Filtering function is connected to a UIButton and right now it does not do anything but call filter function. All variables are stored in interface in header file

- (void)addFilterToMovieAtURL:(NSURL *)movieURL withCompletionBlock:(void (^)(NSURL *finalMovieURL, NSError *error))completionBlock
{
    filter = [[GPUImagePixellateFilter alloc] init];
    [(GPUImagePixellateFilter *)filter setFractionalWidthOfAPixel:0.2f];

    finalMoviePath = [NSString stringWithFormat:@"%@%s", NSTemporaryDirectory(), filteredVideoFileName];
    unlink([finalMoviePath UTF8String]);
    finalMovieURL = [NSURL fileURLWithPath:finalMoviePath];

    movieFile = [[GPUImageMovie alloc] initWithURL:movieURL];
    movieFile.runBenchmark = NO;
    movieFile.playAtActualSpeed = NO;

    [movieFile addTarget:filter];

    movieWriter = [[GPUImageMovieWriter alloc] initWithMovieURL:finalMovieURL size:CGSizeMake(320, 320)];
    [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];
    [movieFile prepareForImageCapture];

    [movieWriter startRecording];
    [movieFile startProcessing];

    [movieWriter setCompletionBlock:^{
        NSLog(@"Movie writing complete");
        [filter removeTarget:movieWriter];
        [movieWriter finishRecording];

        completionBlock(movieURL, nil);
    }];
}

I searched for a solution in stackoverflow and in github but could not find what I am doing wrong

EfeAcikgoz commented 10 years ago

After changing things around a bit more I noticed that the issue happens when I add audio track to the video with

movieFile.audioEncodingTarget = movieWriter;

which also got mentioned here [https://github.com/BradLarson/GPUImage/issues/576]

plenilune commented 10 years ago

this happens to me even when I'm not encoding audio. It appears to work without filters, just not with filters. It appears that when GPUImageMovie endProcessing is called, the last filter in the chain no longer has the writer in the targets array. This only happens with some filters i.e. look up filter.

Edit: Apparently targets added to a GPUImageFilterGroup are added not to itself but to the _terminalFilter's targets, so endProcessing was never called on the writer. I fixed this by modifying endProcessing:

atishay commented 10 years ago

I also faced the same issue with a Filter Group. Thanks @plenilune. Your solution seems to work for me.

geek-paulwong commented 8 years ago

@efesus Did you eventually come up with any solution on this one? It's 2016, with GPUImage 0.1.7, and the problem still exists. The setCompletionBlock not always running... :( Please help!

canpoyrazoglu commented 7 years ago

@geek-paulwong I am having the same issue, the completion handler is not called. Have you ever solved it?

geek-paulwong commented 7 years ago

@canpoyrazoglu Yes. Don't use CocoaPods. Install GPUImage the static way, and then it shall be fine. It took me many many days to figure that out.

gmfxch commented 7 years ago

@geek-paulwong I met the same problem,but i using your methods it still not work ,can you help me ?

geek-paulwong commented 7 years ago

@gmfxch It should... Seriously, that totally solved my problem, give it one more try...

szdkkk commented 6 years ago

I met the same issue with GPUImage 0.1.7. In my case, I found the problem comes from this method: `- (void)endProcessing { if (!isEndProcessing) { isEndProcessing = YES;

    for (id<GPUImageInput> currentTarget in _initialFilters)
    {
        [currentTarget endProcessing];
    }
}

}`

The property "isEndProcessing" would be changed to YES once this method is called. So if you re-use filters to export video and "isEndProcessing" has been changed, the movie writer would never be notified to call - (void)endProcessing. You may fix this by modifying - (void)endProcessing or create new filters to export video.

jianshek commented 6 years ago

@szdkkk I create a new filtergroup,but it dose not work.Could you show me any codes ,thanks