/// <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"); } }
/// <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> /// Initializes a duplicate frame finder. /// </summary> /// <param name="videoDecoder">Video decoder is used to access frame pixel info for comparison</param> /// <param name="framebuffer">Provide the same framebuffer here that was returned by video decoder init</param> /// <param name="frameOffset">Frame offset. Usually 0</param> /// <param name="frameCount">Frame count. Since the decoder doesn't know the frame count, provide it here</param> /// <param name="options">Options.</param> public DuplicateFrameFinder (VideoDecoder videoDecoder, Texture2D framebuffer, int frameOffset, int frameCount, Options options = null) { if (options == null) options = Options.Default; this.options = options; this.videoDecoder = videoDecoder; this.framebuffer = framebuffer; this.frameOffset = frameOffset; this.frameCount = frameCount; Reset (); }
/// <summary> /// Initializes a duplicate frame finder. /// </summary> /// <param name="videoDecoder">Video decoder is used to access frame pixel info for comparison</param> /// <param name="framebuffer">Provide the same framebuffer here that was returned by video decoder init</param> /// <param name="frameOffset">Frame offset. Usually 0</param> /// <param name="frameCount">Frame count. Since the decoder doesn't know the frame count, provide it here</param> /// <param name="options">Options.</param> public DuplicateFrameFinder(VideoDecoder videoDecoder, Texture2D framebuffer, int frameOffset, int frameCount, Options options = null) { if (options == null) { options = Options.Default; } this.options = options; this.videoDecoder = videoDecoder; this.framebuffer = framebuffer; this.frameOffset = frameOffset; this.frameCount = frameCount; Reset(); }
static Rect[] UnpackFramesToAtlas(VideoDecoder videoDecoder, ref Texture2D framebuffer, int frameCount) { if(frameCount < 1) { throw new MpException("Expecting at least 1 video frame"); } #if MP_DEBUG var watch = new System.Diagnostics.Stopwatch (); watch.Start (); #endif // TODO don't use PackTexture? Measure performance with alternative implementation #if UNITY_STANDALONE || UNITY_WEBPLAYER || UNITY_WEBGL int maxWH = MAX_DESKTOP_ATLAS_WH; #else int maxWH = MAX_MOBILE_ATLAS_WH; #endif // Seek to the beginning and decode first frame. // If it reveals that all the frames won't fit into an atlas, stop. videoDecoder.Position = 0; videoDecoder.DecodeNext(); int singleFrameWidth = framebuffer.width; int singleFrameHeight = framebuffer.height; int maxTilesX = maxWH / singleFrameWidth; int maxTilesY = maxWH / singleFrameHeight; if(frameCount > maxTilesX * maxTilesY) { throw new MpException(frameCount + " " + singleFrameWidth + "x" + singleFrameHeight + " video frames can't fit into " + maxWH + "x" + maxWH + " atlas texture. Consider lowering frame count or resolution, or disable video preloading"); } // Create and fill an array of frame textures that are needed for Unity's PackTextures. // Then create an atlas var frameTextures = new Texture2D[frameCount]; frameTextures[0] = CloneTexture(framebuffer); for(int i = 1; i < frameCount; i++) { videoDecoder.DecodeNext(); frameTextures[i] = CloneTexture(framebuffer); } Rect[] uvs = framebuffer.PackTextures(frameTextures, 0, maxWH); // Free temporarily allocated textures for(int i = 0; i < frameCount; i++) { #if UNITY_EDITOR Texture2D.DestroyImmediate(frameTextures[i]); #else Texture2D.Destroy(frameTextures[i]); #endif } #if MP_DEBUG watch.Stop (); Debug.Log ("Packed " + frameCount + " " + singleFrameWidth + "x" + singleFrameHeight + " video frames into an atlas (" + framebuffer.width + "x" + framebuffer.height + ")" + " in " + (watch.Elapsed.TotalMilliseconds * 0.001f) + " seconds"); #endif return uvs; }
static Rect[] UnpackFramesToAtlas(VideoDecoder videoDecoder, ref Texture2D framebuffer, int frameCount) { if (frameCount < 1) { throw new MpException("Expecting at least 1 video frame"); } #if MP_DEBUG var watch = new System.Diagnostics.Stopwatch(); watch.Start(); #endif // TODO don't use PackTexture? Measure performance with alternative implementation #if UNITY_STANDALONE || UNITY_WEBPLAYER || UNITY_WEBGL int maxWH = MAX_DESKTOP_ATLAS_WH; #else int maxWH = MAX_MOBILE_ATLAS_WH; #endif // Seek to the beginning and decode first frame. // If it reveals that all the frames won't fit into an atlas, stop. videoDecoder.Position = 0; videoDecoder.DecodeNext(); int singleFrameWidth = framebuffer.width; int singleFrameHeight = framebuffer.height; int maxTilesX = maxWH / singleFrameWidth; int maxTilesY = maxWH / singleFrameHeight; if (frameCount > maxTilesX * maxTilesY) { throw new MpException(frameCount + " " + singleFrameWidth + "x" + singleFrameHeight + " video frames can't fit into " + maxWH + "x" + maxWH + " atlas texture. Consider lowering frame count or resolution, or disable video preloading"); } // Create and fill an array of frame textures that are needed for Unity's PackTextures. // Then create an atlas var frameTextures = new Texture2D[frameCount]; frameTextures[0] = CloneTexture(framebuffer); for (int i = 1; i < frameCount; i++) { videoDecoder.DecodeNext(); frameTextures[i] = CloneTexture(framebuffer); } Rect[] uvs = framebuffer.PackTextures(frameTextures, 0, maxWH); // Free temporarily allocated textures for (int i = 0; i < frameCount; i++) { #if UNITY_EDITOR Texture2D.DestroyImmediate(frameTextures[i]); #else Texture2D.Destroy(frameTextures[i]); #endif } #if MP_DEBUG watch.Stop(); Debug.Log("Packed " + frameCount + " " + singleFrameWidth + "x" + singleFrameHeight + " video frames into an atlas (" + framebuffer.width + "x" + framebuffer.height + ")" + " in " + (watch.Elapsed.TotalMilliseconds * 0.001f) + " seconds"); #endif return(uvs); }