예제 #1
0
        private async Task CreateGifAsync(TextureArray2D left, TextureArray2D right, Config cfg, IProgress progress)
        {
            // delay in milliseconds
            var numFrames = cfg.FramesPerSecond * cfg.NumSeconds;

            try
            {
                progressModel.EnableDllProgress = false;
                var leftView  = left.GetSrView(LayerMipmapSlice.Mip0);
                var rightView = right.GetSrView(LayerMipmapSlice.Mip0);

                var curProg = progress.CreateSubProgress(0.9f);
                // create frames
                using (var dst = IO.CreateImage(new ImageFormat(Format.R8G8B8A8_UNorm_SRgb), left.Size, LayerMipmapCount.One))
                {
                    var dstMip  = dst.GetMipmap(LayerMipmapSlice.Mip0);
                    var dstPtr  = dstMip.Bytes;
                    var dstSize = dstMip.ByteSize;

                    // render frames into texture
                    using (var frame = new TextureArray2D(LayerMipmapCount.One, left.Size,
                                                          Format.R8G8B8A8_UNorm_SRgb, false))
                    {
                        var frameView = frame.GetRtView(LayerMipmapSlice.Mip0);

                        for (int i = 0; i < numFrames; ++i)
                        {
                            float t         = (float)i / (numFrames);
                            int   borderPos = (int)(t * frame.Size.Width);

                            // render frame
                            shader.Run(leftView, rightView, frameView, cfg.SliderWidth, borderPos,
                                       frame.Size.Width, frame.Size.Height);

                            // save frame as png
                            frame.CopyPixels(LayerMipmapSlice.Mip0, dstPtr, dstSize);
                            var filename = $"{cfg.TmpFilename}{i:D4}";
                            await Task.Run(() => IO.SaveImage(dst, filename, "png", GliFormat.RGBA8_SRGB), progress.Token);

                            curProg.Progress = i / (float)numFrames;
                            curProg.What     = "creating frames";
                        }
                    }
                }

                // convert video
                await FFMpeg.ConvertAsync(cfg, progress.CreateSubProgress(1.0f));
            }
            finally
            {
                progressModel.EnableDllProgress = true;
            }
        }
예제 #2
0
        private async Task CreateGifAsync(Config cfg, IProgress progress, SharedModel shared)
        {
            // delay in milliseconds
            var numFrames = cfg.FramesPerSecond * cfg.NumSeconds;
            var left      = cfg.Left;
            var right     = cfg.Right;
            var overlay   = cfg.Overlay;

            // size compatible?
            bool disposeImages = false;

            if ((left.Size.Width % 2) != 0 || (left.Size.Height % 2) != 0)
            {
                disposeImages = true;
                var pad = Size3.Zero;
                pad.X = left.Size.Width % 2;
                pad.Y = left.Size.Height % 2;
                left  = (TextureArray2D)shared.Padding.Run(left, Size3.Zero, pad, PaddingShader.FillMode.Clamp, null, shared, false);
                right = (TextureArray2D)shared.Padding.Run(right, Size3.Zero, pad, PaddingShader.FillMode.Clamp, null, shared, false);
                if (overlay != null)
                {
                    overlay = (TextureArray2D)shared.Padding.Run(overlay, Size3.Zero, pad,
                                                                 PaddingShader.FillMode.Transparent, null, shared, false);
                }

                Debug.Assert(left.Size.Width % 2 == 0 && left.Size.Height % 2 == 0);
            }

            try
            {
                progressModel.EnableDllProgress = false;
                var leftView    = left.GetSrView(LayerMipmapSlice.Mip0);
                var rightView   = right.GetSrView(LayerMipmapSlice.Mip0);
                var overlayView = overlay?.GetSrView(LayerMipmapSlice.Mip0);

                var curProg = progress.CreateSubProgress(0.9f);

                // prepare parallel processing
                var numTasks = Environment.ProcessorCount;
                var tasks    = new Task[numTasks];
                var images   = new DllImageData[numTasks];
                for (int i = 0; i < numTasks; ++i)
                {
                    images[i] = IO.CreateImage(new ImageFormat(Format.R8G8B8A8_UNorm_SRgb), left.Size,
                                               LayerMipmapCount.One);
                }
                int   textSize = left.Size.Y / 18;
                float padding  = textSize / 4.0f;

                // render frames into texture
                using (var frame = new TextureArray2D(LayerMipmapCount.One, left.Size,
                                                      Format.R8G8B8A8_UNorm_SRgb, false))
                {
                    var frameView = frame.GetRtView(LayerMipmapSlice.Mip0);
                    using (var d2d = new Direct2D(frame))
                    {
                        for (int i = 0; i < numFrames; ++i)
                        {
                            float t         = (float)i / (numFrames - 1);
                            int   borderPos = (int)(t * (frame.Size.Width - 1));
                            int   idx       = i % numTasks;

                            // render frame
                            shader.Run(leftView, rightView, overlayView, frameView, cfg.SliderWidth, borderPos,
                                       frame.Size.Width, frame.Size.Height, shared.QuadShader, shared.Upload);

                            // add text
                            using (var c = d2d.Begin())
                            {
                                c.Text(new Float2(padding), new Float2(left.Size.X - padding, left.Size.Y - padding),
                                       textSize, Colors.White, cfg.Label1, TextAlignment.Leading);

                                c.Text(new Float2(padding), new Float2(left.Size.X - padding, left.Size.Y - padding), textSize,
                                       Colors.White, cfg.Label2, TextAlignment.Trailing);
                            }

                            // copy frame from gpu to cpu
                            var dstMip  = images[idx].GetMipmap(LayerMipmapSlice.Mip0);
                            var dstPtr  = dstMip.Bytes;
                            var dstSize = dstMip.ByteSize;

                            // wait for previous task to finish before writing it to the file
                            if (tasks[idx] != null)
                            {
                                await tasks[idx];
                            }

                            frame.CopyPixels(LayerMipmapSlice.Mip0, dstPtr, dstSize);
                            var filename = $"{cfg.TmpFilename}{i:D4}";

                            // write to file
                            tasks[idx] = Task.Run(() =>
                            {
                                try
                                {
                                    IO.SaveImage(images[idx], filename, "png", GliFormat.RGBA8_SRGB);
                                }
                                catch (Exception)
                                {
                                    // ignored (probably cancelled by user)
                                }
                            }, progress.Token);

                            curProg.Progress = i / (float)numFrames;
                            curProg.What     = "creating frames";

                            progress.Token.ThrowIfCancellationRequested();
                        }
                    }
                }

                // wait for tasks to finish
                for (var i = 0; i < tasks.Length; i++)
                {
                    if (tasks[i] != null)
                    {
                        await tasks[i];
                    }
                    tasks[i] = null;
                }

                // convert video
                await FFMpeg.ConvertAsync(cfg, progress.CreateSubProgress(1.0f));
            }
            finally
            {
                progressModel.EnableDllProgress = true;

                if (disposeImages)
                {
                    left.Dispose();
                    right.Dispose();
                    overlay?.Dispose();
                }
            }
        }