-
Notifications
You must be signed in to change notification settings - Fork 982
Closed
Labels
Description
Here's some code to get things started
using FFMpegCore;
using FFMpegCore.Pipes;
using SkiaSharp;
// prepare data representing 10 seconds of a 1000 Hz recording
double sampleRate = 1000;
double samplePeriod = 1.0 / sampleRate;
double[] values = ScottPlot.Generate.Sin(10_000, oscillations: 10);
ScottPlot.Generate.AddNoiseInPlace(values, 0.1);
double frameRate = 30;
int frameCount = (int)(values.Length / sampleRate * frameRate) + 1;
IEnumerable<IVideoFrame> frames = FrameMaker(640, 480, frameCount, frameRate, values, samplePeriod);
RawVideoPipeSource videoFramesSource = new(frames) { FrameRate = 30 };
bool success = FFMpegArguments
.FromPipeInput(videoFramesSource)
.OutputToFile("output.webm", overwrite: true, options => options.WithVideoCodec("libvpx-vp9"))
.ProcessSynchronously();
static IEnumerable<IVideoFrame> FrameMaker(int width, int height,
int frameCount, double frameRate, double[] values, double samplePeriod)
{
ScottPlot.Plot plot = new();
plot.Add.Signal(values, samplePeriod);
double framePeriod = 1.0 / frameRate;
double horizontalSpan = 1;
for (int i = 0; i < frameCount; i++)
{
Console.WriteLine($"\rRendering frame {i + 1} of {frameCount}");
double xMin = i / frameRate;
plot.Title($"{xMin:0.000}");
plot.Axes.SetLimitsX(xMin, xMin + horizontalSpan);
using SKBitmap bmp = new(width, height);
using SKCanvas canvas = new(bmp);
using SKBitmapFrame frame = new(bmp);
plot.Render(canvas, width, height);
yield return frame;
}
}
class SKBitmapFrame(SKBitmap bmp) : IVideoFrame, IDisposable
{
public int Width => Source.Width;
public int Height => Source.Height;
public string Format => "bgra";
private readonly SKBitmap Source = (bmp.ColorType == SKColorType.Bgra8888) ? bmp
: throw new ArgumentException("Bitmap ColorType must be Bgra8888");
public void Dispose() =>
Source.Dispose();
public void Serialize(Stream pipe) =>
pipe.Write(Source.Bytes, 0, Source.Bytes.Length);
public Task SerializeAsync(Stream pipe, CancellationToken token) =>
pipe.WriteAsync(Source.Bytes, 0, Source.Bytes.Length, token);
}output.webm
Reactions are currently unavailable