< Summary

Class:DCL.GifDecoderProcessor
Assembly:GifProcessor
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/AssetManager/Gif/GifProcessor/GifDecoderProcessor.cs
Covered lines:54
Uncovered lines:3
Coverable lines:57
Total lines:172
Line coverage:94.7% (54 of 57)
Covered branches:0
Total branches:0
Covered methods:9
Total methods:9
Method coverage:100% (9 of 9)

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
RawImage(...)0%110100%
GifDecoderProcessor(...)0%110100%
GifDecoderProcessor(...)0%2100%
DisposeGif()0%2.062075%
Load()0%550100%
StartDecoding()0%10.3410085%
ProcessGifData()0%440100%
DownloadGifAndReadStream()0%440100%
ReadStream(...)0%110100%

File(s)

/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/AssetManager/Gif/GifProcessor/GifDecoderProcessor.cs

#LineLine coverage
 1using System;
 2using System.Collections;
 3using System.Collections.Generic;
 4using System.Diagnostics;
 5using System.IO;
 6using System.Threading;
 7using Cysharp.Threading.Tasks;
 8using DCL.Helpers;
 9using ThreeDISevenZeroR.UnityGifDecoder;
 10using ThreeDISevenZeroR.UnityGifDecoder.Model;
 11using UnityEngine;
 12using Debug = UnityEngine.Debug;
 13
 14namespace DCL
 15{
 16    public class GifWebRequestException : Exception
 17    {
 18        public GifWebRequestException(string message) : base(message) { }
 19    }
 20
 21    public class GifDecoderProcessor : IGifProcessor
 22    {
 23        private struct RawImage
 24        {
 25            public readonly Color32[] colors;
 26            public readonly float delay;
 27            public RawImage(GifImage gifImage)
 28            {
 29                //(Kinerius): We have to clone the colors as the pointer gets modifier as we read the gif
 27030                colors = gifImage.colors.Clone() as Color32[];
 27031                delay = gifImage.SafeDelaySeconds;
 27032            }
 33        }
 34
 35        private bool isRunningInternal;
 1236        private readonly ThrottlingCounter throttlingCounter = new ThrottlingCounter();
 37
 38        private readonly string url;
 39        private readonly Stream stream;
 40        private readonly IWebRequestController webRequestController;
 41        private GifFrameData[] gifFrameData;
 42
 1243        public GifDecoderProcessor(string url, IWebRequestController webRequestController)
 44        {
 1245            this.url = url;
 1246            this.webRequestController = webRequestController;
 1247        }
 48
 049        public GifDecoderProcessor(Stream stream) { this.stream = stream; }
 50
 51        public void DisposeGif()
 52        {
 1253            gifFrameData = null;
 1254            webRequestController.Dispose();
 1255            stream?.Dispose();
 056        }
 57
 58        public async UniTask Load(Action<GifFrameData[]> loadSuccsess, Action<Exception> fail, CancellationToken token)
 59        {
 60            try
 61            {
 3662                await StartDecoding(loadSuccsess, fail, token);
 663            }
 664            catch (Exception e) when (!(e is OperationCanceledException))
 65            {
 366                fail(e);
 367            }
 968        }
 69
 70        private async UniTask StartDecoding(Action<GifFrameData[]> loadSuccsess, Action<Exception> fail, CancellationTok
 71        {
 72            try
 73            {
 74                // (Kinerius): I noticed that overall the loading of multiple gifs at the same time is faster when only
 75                //          one is loading, this also avoids the "burst" of gifs loading at the same time, overall
 76                //          improving the smoothness and the experience, this could be further improved by prioritizing
 77                //          the processing of gifs whether im close or looking at them like GLFTs
 78
 1279                var stopwatch = new Stopwatch();
 1280                stopwatch.Start();
 81
 82                GifStream gifStream;
 83
 1284                if (stream != null)
 85                {
 086                    gifStream = new GifStream(stream);
 87                }
 88                else
 89                {
 3690                    gifStream = new GifStream( await DownloadGifAndReadStream(token));
 91                }
 92
 693                var images = await ReadStream(gifStream, token);
 94
 695                token.ThrowIfCancellationRequested();
 96
 1897                await TaskUtils.RunThrottledCoroutine(ProcessGifData(images, gifStream.Header.adjustedWidth, gifStream.H
 98                               .AttachExternalCancellation(token);
 99
 6100                loadSuccsess(gifFrameData);
 101
 6102                stopwatch.Stop();
 6103            }
 6104            catch (Exception e) when (!(e is OperationCanceledException))
 105            {
 3106                throw;
 107            }
 6108        }
 109
 110        private IEnumerator ProcessGifData(List<RawImage> rawImages, int width, int height)
 111        {
 6112            gifFrameData = new GifFrameData[rawImages.Count];
 6113            SkipFrameIfDepletedTimeBudget skipFrameIfDepletedTimeBudget = new SkipFrameIfDepletedTimeBudget();
 114
 552115            for (var i = 0; i < rawImages.Count; i++)
 116            {
 270117                var frame = new Texture2D(
 118                    width,
 119                    height,
 120                    TextureFormat.ARGB32, false);
 121
 270122                frame.SetPixels32(rawImages[i].colors);
 270123                frame.Compress(false);
 270124                frame.Apply();
 125
 270126                gifFrameData[i] = new GifFrameData()
 127                {
 128                    texture = frame,
 129                    delay = rawImages[i].delay
 130                };
 131
 270132                yield return skipFrameIfDepletedTimeBudget;
 133            }
 6134        }
 135
 136        private async UniTask<byte[]> DownloadGifAndReadStream(CancellationToken token)
 137        {
 12138            var operation = webRequestController.Get(url, timeout: 15, disposeOnCompleted: false);
 36139            await operation.WithCancellation(token);
 140
 9141            if (!operation.isSucceeded)
 142            {
 3143                throw new GifWebRequestException(url);
 144            }
 145
 6146            return operation.webRequest.downloadHandler.data;
 6147        }
 148
 149        private static UniTask<List<RawImage>> ReadStream(GifStream gifStream, CancellationToken token)
 150        {
 6151            return TaskUtils.Run( () =>
 152            {
 6153                var rawImages = new List<RawImage>();
 154
 840155                while (gifStream.HasMoreData)
 156                {
 834157                    if (gifStream.CurrentToken == GifStream.Token.Image)
 158                    {
 270159                        GifImage gifImage = gifStream.ReadImage();
 270160                        rawImages.Add(new RawImage(gifImage));
 161                    }
 162                    else
 163                    {
 564164                        gifStream.SkipToken();
 165                    }
 166                }
 167
 6168                return rawImages;
 169            }, token);
 170        }
 171    }
 172}