Ejemplo n.º 1
0
    public async Task <bool> Render(
        ThumbnailsRenderContext ctx,
        ThumbnailsRenderFileInfo fileInfo,
        ThumbnailsRenderOption option)
    {
        await _fileService.ReadFileStream(fileInfo.FileHandle, videoStream =>
        {
            using var formatContext = new FormatContext(videoStream);

            var attachedPicStream = formatContext.FindAttachedPicStream();

            if (attachedPicStream != null)
            {
                DrawAttachedPicture(ctx, attachedPicStream);
            }
            else
            {
                var audioStream = formatContext.FindBestAudioStream();

                if (audioStream == null)
                {
                    throw new InvalidDataException("No audio stream found");
                }

                DrawWaves(ctx, audioStream);
            }

            return(ValueTask.FromResult(true));
        });

        return(true);
    }
Ejemplo n.º 2
0
 protected override Task <bool> Render(
     ThumbnailsRenderContext ctx,
     ThumbnailsRenderFileInfo fileInfo,
     ThumbnailsRenderOption option)
 {
     Assert.AreEqual(MimeType.image_png, fileInfo.MimeType);
     return(Task.FromResult(true));
 }
Ejemplo n.º 3
0
    public async Task <bool> Render(
        ThumbnailsRenderContext ctx,
        ThumbnailsRenderFileInfo fileInfo,
        ThumbnailsRenderOption option)
    {
        await _fileService.ReadFileStream(
            fileInfo.FileHandle,
            videoStream => ValueTask.FromResult(DrawVideo(videoStream, ctx)));

        return(true);
    }
Ejemplo n.º 4
0
    async Task <bool> IThumbnailsRenderer.Render(
        ThumbnailsRenderContext ctx,
        ThumbnailsRenderFileInfo fileInfo,
        ThumbnailsRenderOption option)
    {
        if (!IsSupported(fileInfo))
        {
            return(false);
        }

        return(await Render(ctx, fileInfo, option));
    }
Ejemplo n.º 5
0
    /// <inheritdoc />
    protected override async Task <bool> Render(
        ThumbnailsRenderContext ctx,
        ThumbnailsRenderFileInfo fileInfo,
        ThumbnailsRenderOption option)
    {
        // use the following code maybe faster. https://github.com/kleisauke/net-vips/issues/128
        // > sourceVipsImage = Image.Thumbnail(localPath, loadImageSize, loadImageSize, noRotate: false);
        return(await _fileService.ReadFileStream(
                   fileInfo.FileHandle,
                   stream =>
        {
            var sourceVipsImage = Image.ThumbnailStream(
                stream,
                (int)(ThumbnailUtils.DefaultMaxWidth * ctx.Density),
                height: (int)(ThumbnailUtils.DefaultMaxHeight * ctx.Density),
                noRotate: false);

            sourceVipsImage = sourceVipsImage.Colourspace(Enums.Interpretation.Srgb).Cast(Enums.BandFormat.Uchar);
            if (!sourceVipsImage.HasAlpha())
            {
                sourceVipsImage = sourceVipsImage.Bandjoin(255);
            }

            var imageWidth = sourceVipsImage.Width;
            var imageHeight = sourceVipsImage.Height;

            var sourceImageDataPtr = sourceVipsImage.WriteToMemory(out _);
            sourceVipsImage.Close();

            try
            {
                using var colorspace = SKColorSpace.CreateSrgb();
                var sourceImageInfo = new SKImageInfo(
                    imageWidth,
                    imageHeight,
                    SKColorType.Rgba8888,
                    SKAlphaType.Unpremul,
                    colorspace);

                using var image =
                          SKImage.FromPixels(sourceImageInfo, sourceImageDataPtr, sourceImageInfo.RowBytes);
                ThumbnailUtils.DrawShadowView(ctx, new SkImageView(image));
            }
            finally
            {
                NetVips.NetVips.Free(sourceImageDataPtr);
            }

            return ValueTask.FromResult(true);
        }));
    }
Ejemplo n.º 6
0
    public async Task Setup()
    {
        var services = new ServiceCollection();

        services.AddSingleton(typeof(ILogger <>), typeof(NullLogger <>));
        services.AddSingleton <ILogger, NullLogger>();
        services.AddSingleton <ILoggerFactory, NullLoggerFactory>();
        services.TryAddSingletonFileService(builder => builder.TryAddMemoryFileSystem("memory"));

        _serviceProvider = services.BuildServiceProvider();
        _fileService     = _serviceProvider.GetRequiredService <IFileService>();

        var root = await _fileService.CreateFileHandle(Url.Parse("file://memory/"));

        _exampleMp4FileHandle = await _fileService.CreateFile(
            root,
            "example.mp4",
            Resources.ReadEmbeddedFile(typeof(RendererBenchmark).Assembly, "/Resources/example.mp4"));

        _exampleMp4FileStats = await _fileService.Stat(_exampleMp4FileHandle);

        _exampleMp3FileHandle = await _fileService.CreateFile(
            root,
            "example.mp3",
            Resources.ReadEmbeddedFile(typeof(RendererBenchmark).Assembly, "/Resources/example.mp3"));

        _exampleMp3FileStats = await _fileService.Stat(_exampleMp3FileHandle);

        _exampleMp3WithCoverFileHandle = await _fileService.CreateFile(
            root,
            "example-with-cover.mp3",
            Resources.ReadEmbeddedFile(typeof(RendererBenchmark).Assembly, "/Resources/example-with-cover.mp3"));

        _exampleMp3WithCoverFileStats = await _fileService.Stat(_exampleMp3WithCoverFileHandle);

        _examplePngFileHandle = await _fileService.CreateFile(
            root,
            "example.png",
            Resources.ReadEmbeddedFile(typeof(RendererBenchmark).Assembly, "/Resources/example.png"));

        _examplePngFileStats = await _fileService.Stat(_examplePngFileHandle);

        _renderContext     = new ThumbnailsRenderContext();
        _audioFileRenderer = new AudioFileRenderer(_fileService);
        _videoFileRenderer = new VideoFileRenderer(_fileService);
        _renderOption      = new ThumbnailsRenderOption {
            Size = 512
        };
    }
Ejemplo n.º 7
0
    public async Task ImplementationTest()
    {
        IThumbnailsRenderer testRenderer = new TestRenderer();

        Assert.IsTrue(
            testRenderer.IsSupported(
                new ThumbnailsRenderFileInfo(
                    new FileHandle("test_file"),
                    new FileStats(DateTimeOffset.Now, DateTimeOffset.Now, 100, FileType.File, new FileHash("unavailable")),
                    MimeType.text_plain)));
        Assert.IsTrue(
            testRenderer.IsSupported(
                new ThumbnailsRenderFileInfo(
                    new FileHandle("test_file"),
                    new FileStats(DateTimeOffset.Now, DateTimeOffset.Now, 100, FileType.File, new FileHash("unavailable")),
                    MimeType.image_png)));
        Assert.IsFalse(
            testRenderer.IsSupported(
                new ThumbnailsRenderFileInfo(
                    new FileHandle("test_file"),
                    new FileStats(DateTimeOffset.Now, DateTimeOffset.Now, 1001, FileType.File, new FileHash("unavailable")),
                    MimeType.image_png)));
        Assert.IsFalse(
            testRenderer.IsSupported(
                new ThumbnailsRenderFileInfo(
                    new FileHandle("test_file"),
                    new FileStats(DateTimeOffset.Now, DateTimeOffset.Now, 100, FileType.File, new FileHash("unavailable")),
                    MimeType.image_jpeg)));

        using var testRenderContext = new ThumbnailsRenderContext();

        Assert.IsTrue(
            await testRenderer.Render(
                testRenderContext,
                new ThumbnailsRenderFileInfo(
                    new FileHandle("test_file"),
                    new FileStats(DateTimeOffset.Now, DateTimeOffset.Now, 100, FileType.File, new FileHash("unavailable")),
                    MimeType.image_png),
                new ThumbnailsRenderOption()));
        Assert.IsFalse(
            await testRenderer.Render(
                testRenderContext,
                new ThumbnailsRenderFileInfo(
                    new FileHandle("test_file"),
                    new FileStats(DateTimeOffset.Now, DateTimeOffset.Now, 100, FileType.File, new FileHash("unavailable")),
                    MimeType.image_jpeg),
                new ThumbnailsRenderOption()));
    }
Ejemplo n.º 8
0
    private static void DrawAttachedPicture(ThumbnailsRenderContext ctx, MediaStream attachedPicStream)
    {
        using var attachedPicture = attachedPicStream.ReadAttachedPicture();
        var attachedPictureVipsImage = Image.ThumbnailStream(
            attachedPicture,
            (int)(ThumbnailUtils.DefaultMaxWidth * ctx.Density),
            height: (int)(ThumbnailUtils.DefaultMaxHeight * ctx.Density),
            noRotate: false);

        attachedPictureVipsImage = attachedPictureVipsImage.Colourspace(Enums.Interpretation.Srgb).Cast(Enums.BandFormat.Uchar);
        if (!attachedPictureVipsImage.HasAlpha())
        {
            attachedPictureVipsImage = attachedPictureVipsImage.Bandjoin(255);
        }

        var imageWidth  = attachedPictureVipsImage.Width;
        var imageHeight = attachedPictureVipsImage.Height;

        var sourceImageDataPtr = attachedPictureVipsImage.WriteToMemory(out _);

        attachedPictureVipsImage.Close();

        try
        {
            using var colorspace = SKColorSpace.CreateSrgb();
            var sourceImageInfo = new SKImageInfo(
                imageWidth,
                imageHeight,
                SKColorType.Rgba8888,
                SKAlphaType.Unpremul,
                colorspace);

            using var image =
                      SKImage.FromPixels(sourceImageInfo, sourceImageDataPtr, sourceImageInfo.RowBytes);
            _cachedDecorationImage ??= SKImage.FromEncodedData(ReadDecorationImage());
            ThumbnailUtils.DrawShadowView(
                ctx,
                new SkImageView(image),
                _cachedDecorationImage,
                new SKColor(0, 0, 0),
                minSize: new SKSize(24, 24));
        }
        finally
        {
            NetVips.NetVips.Free(sourceImageDataPtr);
        }
    }
Ejemplo n.º 9
0
    private static unsafe void DrawWaves(ThumbnailsRenderContext ctx, MediaStream audioStream)
    {
        var height = 88;
        var width  = 88;

        using var recorder = new SKPictureRecorder();
        using var canvas   = recorder.BeginRecording(SKRect.Create(width, height));
        var columnCount = 88 * 2;
        var columnWidth = (float)width / columnCount;

        using var wavePaint = new SKPaint { Color = new SKColor(128, 128, 128, 76), StrokeWidth = columnWidth };
        var totalSample     = audioStream.SampleRate * audioStream.Duration;
        var columnMaxSample = (int)(totalSample / columnCount);
        var columns         = new short[columnCount];

        using var decoder = audioStream.CreateStreamDecoder();
        using var filter  = new AudioFormatFilter("sample_fmts=s16:channel_layouts=mono", audioStream, decoder);
        filter.Build();

        long sum = 0;
        var  n   = 0;
        var  c   = 0;

        while (filter.MoveNext())
        {
            var frame = filter.Current.Value;
            var p     = (short *)frame->data[0];

            for (var i = 0; i < frame->nb_samples; i++)
            {
                sum += SampleAbs(p[i]);

                n++;
                if (n == columnMaxSample && c < columnCount)
                {
                    columns[c] = (short)(sum / n);

                    n   = 0;
                    sum = 0;
                    c++;
                }
            }
        }

        for (var i = 0; i < columnCount; i++)
        {
            var h = Math.Max((float)columns[i] * height / short.MaxValue, 0.5f);
            var x = i * columnWidth;
            canvas.DrawLine(x, (height - h) / 2.0f, x, (height + h) / 2.0f, wavePaint);
        }

        _cachedWaveformDecorationImage ??= SKImage.FromEncodedData(ReadWaveformDecorationImage());
        canvas.DrawImage(_cachedWaveformDecorationImage, SKRect.Create((width - 28) / 2.0f, (height - 36) / 2.0f, 28, 36));

        using var picture = recorder.EndRecording();
        ThumbnailUtils.DrawShadowView(
            ctx,
            new SkPictureView(
                picture,
                new SKSize(88, 88)));
    }
Ejemplo n.º 10
0
 public Task <bool> Render(ThumbnailsRenderContext ctx, ThumbnailsRenderFileInfo fileInfo, ThumbnailsRenderOption option)
 {
     RenderCount++;
     return(_wrappedThumbnailsRenderer.Render(ctx, fileInfo, option));
 }
Ejemplo n.º 11
0
 protected abstract Task <bool> Render(ThumbnailsRenderContext ctx, ThumbnailsRenderFileInfo fileInfo, ThumbnailsRenderOption option);
Ejemplo n.º 12
0
    private static unsafe bool DrawVideo(Stream videoStream, ThumbnailsRenderContext ctx)
    {
        using var formatContext = new FormatContext(videoStream);
        var stream = formatContext.FindBestVideoStream();

        if (stream == null)
        {
            return(false);
        }

        using var videoStreamDecoder = stream.CreateStreamDecoder();

        try
        {
            if (videoStreamDecoder.Duration <= 0)
            {
                videoStreamDecoder.SeekFrame(10 * 1000000);
            }

            if (videoStreamDecoder.Duration > 3)
            {
                videoStreamDecoder.SeekFrame(videoStreamDecoder.Duration / 3);
            }
        }
        catch (FFmpegException err)
        {
            Console.WriteLine("Seek failed: " + err);
        }

        var destinationSize = ThumbnailUtils.ContainSize(
            new SKSize(videoStreamDecoder.FrameWidth, videoStreamDecoder.FrameHeight),
            new SKSize(ThumbnailUtils.DefaultMaxWidth * ctx.Density, ThumbnailUtils.DefaultMaxHeight * ctx.Density)).ToSizeI();

        var sourcePixelFormat = videoStreamDecoder.PixelFormat;

        if (!videoStreamDecoder.MoveNext())
        {
            throw new InvalidDataException("Can't decode the video.");
        }

        using var vfc =
                  new VideoFrameConverter(
                      videoStreamDecoder.FrameWidth,
                      videoStreamDecoder.FrameHeight,
                      sourcePixelFormat,
                      destinationSize.Width,
                      destinationSize.Height);

        var convertedFrame = vfc.Convert(videoStreamDecoder.Current.Value);

        using var colorspace = SKColorSpace.CreateSrgb();

        var sourceImageInfo = new SKImageInfo(
            convertedFrame.width,
            convertedFrame.height,
            SKColorType.Rgba8888,
            SKAlphaType.Unpremul,
            colorspace);

        using var image =
                  SKImage.FromPixels(sourceImageInfo, (IntPtr)convertedFrame.data[0], sourceImageInfo.RowBytes);

        _cachedDecorationImage ??= SKImage.FromEncodedData(ReadDecorationImage());
        ThumbnailUtils.DrawShadowView(
            ctx,
            new SkImageView(image),
            _cachedDecorationImage,
            new SKColor(0, 0, 0),
            minSize: new SKSize(24, 24));
        return(true);
    }
Ejemplo n.º 13
0
    public static void DrawShadowView(
        ThumbnailsRenderContext ctx,
        ISkView view,
        SKImage?decorationImage       = null,
        SKColor?backgroundColor       = null,
        SKSize?maxSize                = null,
        SKSize?minSize                = null,
        SKFilterQuality resizeQuality = SKFilterQuality.None)
    {
        // max width  = 128 - 12 - 12
        // max height = 128 - 20 - 20
        maxSize ??= new SKSize(DefaultMaxWidth, DefaultMaxHeight);

        minSize ??= new SKSize(0, 0);

        backgroundColor ??= new SKColor(0xff, 0xff, 0xff);

        var imageSize  = ContainSize(new SKSize(view.Size.Width, view.Size.Height), maxSize.Value);
        var imageRect  = CentralRect(imageSize);
        var borderSize = new SKSize(Math.Max(imageSize.Width, minSize.Value.Width), Math.Max(imageSize.Height, minSize.Value.Height));
        var borderRect = CentralRect(new SKSize(borderSize.Width + 1, borderSize.Height + 1));

        using (new SKAutoCanvasRestore(ctx.Canvas))
        {
            ctx.Canvas.Clear();

            using (var rectFillPaint = new SKPaint
            {
                Style = SKPaintStyle.Fill,
                Color = backgroundColor.Value,
                ImageFilter = SKImageFilter.CreateDropShadow(0, 1, 4, 4, new SKColor(136, 136, 136, 128))
            })
                using (var rectStrokePaint = new SKPaint
                {
                    Style = SKPaintStyle.Stroke, StrokeWidth = 1, Color = new SKColor(136, 136, 136, 64), BlendMode = SKBlendMode.Src
                })
                {
                    // draw border
                    using SKRoundRect roundRect = new(borderRect, 5);
                    ctx.Canvas.DrawRoundRect(roundRect, rectFillPaint);
                    ctx.Canvas.DrawRoundRect(roundRect, rectStrokePaint);
                }

            using (new SKAutoCanvasRestore(ctx.Canvas))
                using (var imagePaint = new SKPaint {
                    FilterQuality = resizeQuality
                })
                    using (var decorationImagePaint = new SKPaint {
                        FilterQuality = SKFilterQuality.Medium
                    })
                    {
                        using SKRoundRect roundRect = new(imageRect, 4.5f);

                        using (new SKAutoCanvasRestore(ctx.Canvas))
                        {
                            ctx.Canvas.ClipRoundRect(roundRect);

                            // draw image
                            view.Draw(ctx.Canvas, imageRect, imagePaint);
                        }

                        if (decorationImage != null)
                        {
                            var decorationRect = SKRect.Create(borderRect.Right - 24.5f, borderRect.Bottom - 22.5f, 36, 36);
                            ctx.Canvas.DrawImage(decorationImage, decorationRect, decorationImagePaint);
                        }
                    }
        }
    }