BradLarson / GPUImage2

GPUImage 2 is a BSD-licensed Swift framework for GPU-accelerated video and image processing.
BSD 3-Clause "New" or "Revised" License
4.87k stars 609 forks source link

unable to save video using MovieOutput applying filter #151

Open dhavalagile opened 7 years ago

dhavalagile commented 7 years ago

i am create videofilter demo, i am apply video filter sucessfully while video is play but i am unable to save video to local path.

let finalpath = "(FileManager.default.finalCompositions)/composition(getTimeStamp).mp4" let finalUrl = URL(fileURLWithPath: finalpath) print("Final url :: (finalUrl)")

    let movieURL = Bundle.main.url(forResource: "test", withExtension: "mp4")

    let asset: AVURLAsset = AVURLAsset(url: movieURL!)
    let asetTrack: AVAssetTrack = asset.tracks(withMediaType: AVMediaTypeVideo)[0]

    let exportedMovieFile = try! MovieInput(url: movieURL!, playAtActualSpeed: false)
    exportedMovieFile.runBenchmark = true

    let exportfilter = BrightnessAdjustment()
    exportfilter.brightness = 0.5
    exportedMovieFile.addTarget(exportfilter)

    let exportedMovieWritter = try! MovieOutput(URL: finalUrl, size: Size(width: Float(asetTrack.naturalSize.width), height: Float(asetTrack.naturalSize.height)))

    exportfilter.addTarget(exportedMovieWritter)

    //Configure this for video from the movie file, where we want to preserve all video frames and audio samples

    exportedMovieWritter.startRecording()
    exportedMovieFile.start()

    exportedMovieWritter.finishRecording {
        exportfilter.removeAllTargets()
        exportedMovieFile.removeAllTargets()
    }
BradLarson commented 7 years ago

What happens when you try to record? What errors do you get?

dhavalagile commented 7 years ago

Using above code finishRecording successfully but when i check file the file contain only gray scale 0 sec video it don't process video .

Hassan-Davis commented 7 years ago

Hello. I ran into the same problem and got it working with the following code changes.

Firstly, the problem was that while the MovieOutput instance needs to have its finishRecording() method called in order to close the file, calling .finishRecording() immediately after the asynchronous invocation of the MovieInput start method would result in the output being closed prior to the full data set being completed (hence the zero length file).

Also, there was no way to tell when that process chain had completed.

So, I added a completion callback as a parameter in the MovieInput start method.

MovieInput now invokes this callback when all input has been processed (or in case of failure, etc.).

The MovieOutput finishRecording() method can now be called at the correct time, e.g.:

            let videoOutput = try EVGPUImage2.MovieOutput( URL: destinationUrl, size: movieSize )

            let movieInput = try EVGPUImage2.MovieInput( url: videoUrl, playAtActualSpeed: false )

            // let's test the chain by running a good old desaturation filter
            let filter = EVGPUImage2.SaturationAdjustment()
            filter.saturation = 0.1

            // build the process chain
            movieInput --> filter --> videoOutput

            videoOutput.startRecording()

            movieInput.start( completionCallback: {
                videoOutput.finishRecording( completionCallback: { 
                    cleanup()
                })
            })

Please find my diff for the MovieInput class attached. Thx!

screen shot 2017-08-05 at 12 41 44 am
zhulmin commented 6 years ago

The method does not render in sync