/// <summary>
        /// Loads movie with audio. It will be ready for playback
        /// </summary>
        /// <param name="source">Source</param>
        /// <param name="targetFramebuffer">Target framebuffer</param>
        /// <param name="targetAudioBuffer">Target audio buffer</param>
        /// <param name="loadOptions">Load options</param>
        public static Movie Load(MovieSource source, out Texture2D targetFramebuffer, out AudioClip targetAudioBuffer, LoadOptions loadOptions = null)
        {
            if (loadOptions == null)
                loadOptions = LoadOptions.Default;

            if (source.stream == null && source.url == null) {
                throw new MpException ("Either source.stream or source.url must be provided");
            }

            targetFramebuffer = null;
            targetAudioBuffer = null;

            var movie = new Movie ();
            movie.sourceStream = source.stream; // can be NULL

            // create and initialize demux for the source data
            if (source.url != null) {
                movie.demux = loadOptions.demuxOverride != null ? loadOptions.demuxOverride : Streamer.forUrl (source.url);
                ((Streamer)movie.demux).Connect (source.url, loadOptions);
            } else {
                movie.demux = loadOptions.demuxOverride != null ? loadOptions.demuxOverride : Demux.forSource (source.stream);
                movie.demux.Init (source.stream, loadOptions);
            }

            if (movie.demux.hasVideo && !loadOptions.skipVideo) {
                var vsi = movie.demux.videoStreamInfo;
                movie.videoDecoder = VideoDecoder.CreateFor (vsi);
                movie.videoDecoder.Init (out targetFramebuffer, movie.demux, loadOptions);

                if(loadOptions.preloadVideo) {
                    movie.frameUV = UnpackFramesToAtlas(movie.videoDecoder, ref targetFramebuffer, vsi.frameCount);
                } else {
                    movie.frameUV = new Rect[1] { new Rect(0, 0, 1, 1) };
                }
            }
            if (movie.demux.hasAudio && !loadOptions.skipAudio) {
                movie.audioDecoder = AudioDecoder.CreateFor (movie.demux.audioStreamInfo);
                movie.audioDecoder.Init (out targetAudioBuffer, movie.demux, loadOptions);
            }
            return movie;
        }
 /// <summary>
 /// Unloads the movie and releases all resources like file handlers associated with it.
 /// It's a good idea to stop the playback before unloading the movie.
 /// </summary>
 public static void Unload(Movie movie)
 {
     if (movie != null) {
         if (movie.sourceStream != null) {
             movie.sourceStream.Dispose ();
             movie.sourceStream = null;
         }
         if (movie.videoDecoder != null) {
             movie.videoDecoder.Shutdown ();
             movie.videoDecoder = null;
         }
         if (movie.audioDecoder != null) {
             movie.audioDecoder.Shutdown ();
             movie.audioDecoder = null;
         }
         if (movie.demux != null) {
             movie.demux.Shutdown ();
             movie.demux = null;
         }
     }
 }
        /// <summary>
        /// Starts the processing.
        /// </summary>
        void StartProcessing()
        {
            movie = new Movie ();
            movie.sourceStream = File.OpenRead (srcPath);

            dstStream = File.OpenWrite (dstPath);
            remux = new AviRemux ();

            // create and initialize demux for the source data
            movie.demux = Demux.forSource (movie.sourceStream);
            movie.demux.Init (movie.sourceStream);

            // create video stream and decoder too. without a decoder we can't access pixels to compare
            if (!movie.demux.hasVideo) {
                throw new MpException ("Remux needs video stream inside an AVI");
            }
            movie.videoDecoder = VideoDecoder.CreateFor (movie.demux.videoStreamInfo);
            movie.videoDecoder.Init (out framebuffer, movie.demux);

            // create a remux. this will write into dstStream
            bool outputHasAudio = movie.demux.hasAudio && !discardAudio;
            remux.Init (dstStream, movie.demux.videoStreamInfo, outputHasAudio ? movie.demux.audioStreamInfo : null);

            // create a duplicate finder. most of the options control how the frames are actually compared
            options.otherStreamsAvailable = outputHasAudio;
            dupFinder = new DuplicateFrameFinder (movie.videoDecoder, framebuffer, 0, movie.demux.videoStreamInfo.frameCount, options);

            // if we want a to log the duplicate indexes into a file, then clear the file first
            if (!string.IsNullOrEmpty (logDuplicatesPath)) {
                File.WriteAllText (logDuplicatesPath, "# Duplicate frame index for " + srcPath + "\n");
            }
        }