Quantcast
Channel: Martin Dráb – Goshoom.NET Dev Blog
Viewing all articles
Browse latest Browse all 48

Animated GIF thumbnails from a video

$
0
0

This blog post isn’t about Dynamics AX / Dynamics 365, although it may occasionally be useful for some AX/D365 developers as well.

Let’s say I have a 30 minutes long movie that I want to share on a website and I want to give people an idea about the content of the video. Therefore I want to create a slideshow of screenshots taken from the movie at regular intervals. An animated GIF is an obvious choice.

I spent quite some time trying to figure out how to do it, because I had little idea. After some research, I came to a conclusion that a reasonable approach is extracting screenshots with FFmpeg and then combining them to a GIF file with ImageMagick.

Because installing those console applications and dealing with them directly would be quite cumbersome, I also looked for some wrapper libraries available via NuGet. I chose these:

Now let’s build a simple application to show the code. Create a console application for .NET Framework and add those two NuGet packages.

Add using statements for namespaces that we’ll need in a moment:

using System.IO;
using ImageMagick;
using MediaToolkit;
using MediaToolkit.Model;
using MediaToolkit.Options;

The structure of your program will be following:

class Program
{
    static void Main(string[] args)
    {
        new Program().Run();
    }
 
    void Run()
    {
        string videoFilePath = @"c:\temp\input.mp4";
 
        List<string> thumbnails = ExtractThumbnails(videoFilePath, 10);
 
        if (thumbnails?.Any() == true)
        {
            string gifFilePath = Path.Combine(
                Path.GetDirectoryName(videoFilePath),
                $"{Path.GetFileName(videoFilePath)}.gif");
 
            CombineThumbnails(gifFilePath, thumbnails);
 
            // Delete temporary files
            thumbnails.ForEach(file => File.Delete(file));
        }
    }
}

ExtractThumbnails() takes screenshots from the video as JPG files.

CombineThumbnails() then take these files and put them into an animated GIF.

Finally we delete JPG files, because they aren’t needed anymore.

Here is the implementation of ExtractThumbnails(). The key part is the call of engine.GetThumbnail() at the end.

List<string> ExtractThumbnails(string inputFilePath, int numOfPics)
{
    MediaFile inputFile = new MediaFile { Filename = inputFilePath };
    List<string> thumbnails = new List<string>(numOfPics);
 
    using (var engine = new Engine())
    {
        engine.GetMetadata(inputFile);
        if (inputFile.Metadata == null)
        {
            throw new InvalidOperationException("Invalid file");
        }
 
        int duration = (int)inputFile.Metadata.Duration.TotalSeconds;
        int picDistance = duration / (numOfPics + 1);
 
        for (int i = 1; i <= numOfPics; i++)
        {
            var options = new ConversionOptions { Seek = TimeSpan.FromSeconds(i * picDistance) };
 
            string outputFilePath = $"{inputFilePath}{i}.jpg";
 
            var outputFile = new MediaFile { Filename = outputFilePath };
            engine.GetThumbnail(inputFile, outputFile, options);
            thumbnails.Add(outputFilePath);
        }
    }
 
    return thumbnails;
}

The last missing piece is the method creating the animated GIF. It’s straightforward, thanks to Magick.NET:

void CombineThumbnails(string gifFilePath, List<string> thumbnails)
{
    using (var collection = new MagickImageCollection())
    {
        for (int i = 0; i < thumbnails.Count; i++)
        {
            collection.Add(thumbnails[i]);
            collection[i].AnimationDelay = 70;
            collection[i].Resize(800, 600);
        }
 
        collection.Write(gifFilePath);
    }
}


Viewing all articles
Browse latest Browse all 48

Trending Articles


Re: Prosím o určení autora - google nepomáhá


Nelze se přihlásit na Facebook přes PC


Prodám Flexi pass - 3 200


Markéta Reinischová: Chceme s Filipem Jankovičem dítě!


Od: Martina


Podzemlje - epizoda 62


Defender


Plynový kotel DAKON DS 22G - 2 500


Gymnastické řemínky na hrazdu zn. Reisport, vel. č. 2: 590


P: NooK Soundelirium THE 12.6


Qube SP26 ( XTA DP226 ) signal processor - 12 000


Narovnání,vylisování bankovek


Javorina Holubyho chata


Tinylab: Tlačítka


Levasan Maxx není gel na klouby, nýbrž hnus


RNS315 couvací kamera


Kde najdu GameInput Service ve win 10?


Redmi Note 11 Pro+ 5G (PISSARO)


MV3 Vermona, Klingenthal, NDR


Hradcany 30h fialova razena 11 1/2 11 3/4