< Summary

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

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
GifWebRequestException(...)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    {
 618        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
 30                colors = gifImage.colors.Clone() as Color32[];
 31                delay = gifImage.SafeDelaySeconds;
 32            }
 33        }
 34
 35        private bool isRunningInternal;
 36        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
 43        public GifDecoderProcessor(string url, IWebRequestController webRequestController)
 44        {
 45            this.url = url;
 46            this.webRequestController = webRequestController;
 47        }
 48
 49        public GifDecoderProcessor(Stream stream) { this.stream = stream; }
 50
 51        public void DisposeGif()
 52        {
 53            gifFrameData = null;
 54            webRequestController.Dispose();
 55            stream?.Dispose();
 56        }
 57
 58        public async UniTask Load(Action<GifFrameData[]> loadSuccsess, Action<Exception> fail, CancellationToken token)
 59        {
 60            try
 61            {
 62                await StartDecoding(loadSuccsess, fail, token);
 63            }
 64            catch (Exception e) when (!(e is OperationCanceledException))
 65            {
 66                fail(e);
 67            }
 68        }
 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
 79                var stopwatch = new Stopwatch();
 80                stopwatch.Start();
 81
 82                GifStream gifStream;
 83
 84                if (stream != null)
 85                {
 86                    gifStream = new GifStream(stream);
 87                }
 88                else
 89                {
 90                    gifStream = new GifStream( await DownloadGifAndReadStream(token));
 91                }
 92
 93                var images = await ReadStream(gifStream, token);
 94
 95                token.ThrowIfCancellationRequested();
 96
 97                await TaskUtils.RunThrottledCoroutine(ProcessGifData(images, gifStream.Header.adjustedWidth, gifStream.H
 98                               .AttachExternalCancellation(token);
 99
 100                loadSuccsess(gifFrameData);
 101
 102                stopwatch.Stop();
 103            }
 104            catch (Exception e) when (!(e is OperationCanceledException))
 105            {
 106                throw;
 107            }
 108        }
 109
 110        private IEnumerator ProcessGifData(List<RawImage> rawImages, int width, int height)
 111        {
 112            gifFrameData = new GifFrameData[rawImages.Count];
 113            SkipFrameIfDepletedTimeBudget skipFrameIfDepletedTimeBudget = new SkipFrameIfDepletedTimeBudget();
 114
 115            for (var i = 0; i < rawImages.Count; i++)
 116            {
 117                var frame = new Texture2D(
 118                    width,
 119                    height,
 120                    TextureFormat.ARGB32, false);
 121
 122                frame.SetPixels32(rawImages[i].colors);
 123                frame.Compress(false);
 124                frame.Apply();
 125
 126                gifFrameData[i] = new GifFrameData()
 127                {
 128                    texture = frame,
 129                    delay = rawImages[i].delay
 130                };
 131
 132                yield return skipFrameIfDepletedTimeBudget;
 133            }
 134        }
 135
 136        private async UniTask<byte[]> DownloadGifAndReadStream(CancellationToken token)
 137        {
 138            var operation = webRequestController.Get(url, timeout: 15, disposeOnCompleted: false);
 139            await operation.WithCancellation(token);
 140
 141            if (!operation.isSucceeded)
 142            {
 143                throw new GifWebRequestException(url);
 144            }
 145
 146            return operation.webRequest.downloadHandler.data;
 147        }
 148
 149        private static UniTask<List<RawImage>> ReadStream(GifStream gifStream, CancellationToken token)
 150        {
 151            return TaskUtils.Run( () =>
 152            {
 153                var rawImages = new List<RawImage>();
 154
 155                while (gifStream.HasMoreData)
 156                {
 157                    if (gifStream.CurrentToken == GifStream.Token.Image)
 158                    {
 159                        GifImage gifImage = gifStream.ReadImage();
 160                        rawImages.Add(new RawImage(gifImage));
 161                    }
 162                    else
 163                    {
 164                        gifStream.SkipToken();
 165                    }
 166                }
 167
 168                return rawImages;
 169            }, token);
 170        }
 171    }
 172}