Resources for visualizing data using C# and the .NET platform
How to draw graphics for each frame and use ffmpeg to save the result as a video file

This page describes how to create video files using System.Drawing and ffmpeg. The method described here uses System.Drawing.Common which is no longer supported on non-Windows platforms. Check out the rendering video with SkiaSharp page for a cross-platform solution.

1. Get FFMpegCore

Create a new project:

dotnet new console

Add the necessary packages to your project:

dotnet add package System.Drawing.Common
dotnet add package FFMpegCore
dotnet add package FFMpegCore.Extensions.System.Drawing.Common

2. Add Using Statements

using FFMpegCore;
using FFMpegCore.Pipes;
using FFMpegCore.Extensions.System.Drawing.Common;

3. Create a Frame Generator

Create a function to yield frames by creating and returning Bitmap images one at a time. This is where the logic goes that determines what will be drawn in each frame. This example draws a green rectangle that moves and grows as a function of frame number, and also displays frame information as text at the top of the image.

IEnumerable<BitmapVideoFrameWrapper> CreateFramesSD(int count, int width, int height)
{
    for (int i = 0; i < count; i++)
    {
        // create a Bitmap
        using Bitmap bmp = new(width, height, PixelFormat.Format24bppRgb);
        using Graphics gfx = Graphics.FromImage(bmp);

        // draw a blue background
        gfx.Clear(Color.Navy);

        // draw a growing green square
        Point pt = new(i, i);
        Size sz = new(i, i);
        Rectangle rect = new(pt, sz);
        gfx.FillRectangle(Brushes.Green, rect);

        // draw some text
        using Font fnt = new("consolas", 24);
        gfx.DrawString($"Frame: {i + 1:N0}", fnt, Brushes.Yellow, 2, 2);

        // yield the wrapped Bitmap
        using BitmapVideoFrameWrapper wrappedBitmap = new(bmp);
        yield return wrappedBitmap;
    }
}

4. Encode a Video File

This step cycles through your frame generator and encodes the video one frame at a time.

var frames = CreateFramesSD(count: 200, width: 400, height: 300);
RawVideoPipeSource source = new(frames) { FrameRate = 30 };
bool success = FFMpegArguments
    .FromPipeInput(source)
    .OutputToFile("output.webm", overwrite: true, options => options.WithVideoCodec("libvpx-vp9"))
    .ProcessSynchronously();

Additional Configuration

  • codec mpeg4 created output.mp4 that worked in media player but not my browser
  • codec libx264 created output.mp4 that worked in my browser not in media player
  • codec libvpx-vp9 created output.webm that worked everywhere
  • See the FFMpegCore GitHub page for more options

Resources