Skip to content
This repository was archived by the owner on Nov 27, 2024. It is now read-only.

Commit 8993731

Browse files
committed
Remove FFMpegCore dependency
1 parent 5eb45d8 commit 8993731

File tree

5 files changed

+133
-19
lines changed

5 files changed

+133
-19
lines changed

OnnxStack.Core/Image/OnnxImage.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using SixLabors.ImageSharp.Processing;
66
using System;
77
using System.IO;
8+
using System.Threading;
89
using System.Threading.Tasks;
910
using ImageSharp = SixLabors.ImageSharp.Image;
1011

@@ -209,9 +210,9 @@ public void CopyToStream(Stream destination)
209210
/// </summary>
210211
/// <param name="destination">The destination.</param>
211212
/// <returns></returns>
212-
public Task CopyToStreamAsync(Stream destination)
213+
public Task CopyToStreamAsync(Stream destination, CancellationToken cancellationToken)
213214
{
214-
return _imageData.SaveAsPngAsync(destination);
215+
return _imageData.SaveAsPngAsync(destination, cancellationToken);
215216
}
216217

217218

OnnxStack.Core/OnnxStack.Core.csproj

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
4-
<Version>0.31.0</Version>
4+
<Version>0.31.10</Version>
55
<TargetFramework>net7.0</TargetFramework>
66
<ImplicitUsings>disable</ImplicitUsings>
77
<Nullable>disable</Nullable>
@@ -37,7 +37,6 @@
3737
</ItemGroup>
3838

3939
<ItemGroup>
40-
<PackageReference Include="FFMpegCore" Version="5.1.0" />
4140
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.1" />
4241
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="8.0.0" />
4342
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.1" />

OnnxStack.Core/Video/OnnxVideo.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ public void Dispose()
164164
public static async Task<OnnxVideo> FromFileAsync(string filename, float? frameRate = default, CancellationToken cancellationToken = default)
165165
{
166166
var videoBytes = await File.ReadAllBytesAsync(filename, cancellationToken);
167-
var videoInfo = await VideoHelper.ReadVideoInfoAsync(videoBytes);
167+
var videoInfo = await VideoHelper.ReadVideoInfoAsync(videoBytes, cancellationToken);
168168
if (frameRate.HasValue)
169169
videoInfo = videoInfo with { FrameRate = Math.Min(videoInfo.FrameRate, frameRate.Value) };
170170

OnnxStack.Core/Video/VideoHelper.cs

Lines changed: 54 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
using FFMpegCore;
2-
using OnnxStack.Core.Config;
1+
using OnnxStack.Core.Config;
32
using OnnxStack.Core.Image;
43
using System;
54
using System.Collections.Generic;
65
using System.Diagnostics;
76
using System.IO;
87
using System.Linq;
98
using System.Runtime.CompilerServices;
9+
using System.Text.Json;
1010
using System.Threading;
1111
using System.Threading.Tasks;
1212

@@ -73,7 +73,7 @@ private static async Task WriteVideoFramesAsync(IEnumerable<OnnxImage> onnxImage
7373
foreach (var image in onnxImages)
7474
{
7575
// Write each frame to the input stream of FFMPEG
76-
await videoWriter.StandardInput.BaseStream.WriteAsync(image.GetImageBytes(), cancellationToken);
76+
await image.CopyToStreamAsync(videoWriter.StandardInput.BaseStream, cancellationToken);
7777
}
7878

7979
// Done close stream and wait for app to process
@@ -103,7 +103,7 @@ public static async Task WriteVideoStreamAsync(VideoInfo videoInfo, IAsyncEnumer
103103
await foreach (var frame in videoStream)
104104
{
105105
// Write each frame to the input stream of FFMPEG
106-
await frame.CopyToStreamAsync(videoWriter.StandardInput.BaseStream);
106+
await frame.CopyToStreamAsync(videoWriter.StandardInput.BaseStream, cancellationToken);
107107
}
108108

109109
// Done close stream and wait for app to process
@@ -118,12 +118,17 @@ public static async Task WriteVideoStreamAsync(VideoInfo videoInfo, IAsyncEnumer
118118
/// </summary>
119119
/// <param name="videoBytes">The video bytes.</param>
120120
/// <returns></returns>
121-
public static async Task<VideoInfo> ReadVideoInfoAsync(byte[] videoBytes)
121+
public static async Task<VideoInfo> ReadVideoInfoAsync(byte[] videoBytes, CancellationToken cancellationToken = default)
122122
{
123-
using (var memoryStream = new MemoryStream(videoBytes))
123+
string tempVideoPath = GetTempFilename();
124+
try
125+
{
126+
await File.WriteAllBytesAsync(tempVideoPath, videoBytes, cancellationToken);
127+
return await ReadVideoInfoAsync(tempVideoPath, cancellationToken);
128+
}
129+
finally
124130
{
125-
var result = await FFProbe.AnalyseAsync(memoryStream).ConfigureAwait(false);
126-
return new VideoInfo(result.PrimaryVideoStream.Width, result.PrimaryVideoStream.Height, result.Duration, (int)result.PrimaryVideoStream.FrameRate);
131+
DeleteTempFile(tempVideoPath);
127132
}
128133
}
129134

@@ -133,10 +138,29 @@ public static async Task<VideoInfo> ReadVideoInfoAsync(byte[] videoBytes)
133138
/// </summary>
134139
/// <param name="filename">The filename.</param>
135140
/// <returns></returns>
136-
public static async Task<VideoInfo> ReadVideoInfoAsync(string filename)
141+
public static async Task<VideoInfo> ReadVideoInfoAsync(string filename, CancellationToken cancellationToken = default)
137142
{
138-
var result = await FFProbe.AnalyseAsync(filename).ConfigureAwait(false);
139-
return new VideoInfo(result.PrimaryVideoStream.Width, result.PrimaryVideoStream.Height, result.Duration, (int)result.PrimaryVideoStream.FrameRate);
143+
144+
using (var metadataReader = CreateMetadataReader(filename))
145+
{
146+
// Start FFMPEG
147+
metadataReader.Start();
148+
149+
var videoInfo = default(VideoInfo);
150+
using (StreamReader reader = metadataReader.StandardOutput)
151+
{
152+
string result = await reader.ReadToEndAsync();
153+
var videoMetadata = JsonSerializer.Deserialize<VideoMetadata>(result);
154+
var videoStream = videoMetadata.Streams.FirstOrDefault();
155+
if (videoStream is null)
156+
throw new Exception("Failed to parse video stream metadata");
157+
158+
videoInfo = new VideoInfo(videoStream.Height, videoStream.Width, videoStream.Duration, videoStream.FramesPerSecond);
159+
}
160+
161+
await metadataReader.WaitForExitAsync(cancellationToken);
162+
return videoInfo;
163+
}
140164
}
141165

142166

@@ -308,7 +332,7 @@ private static Process CreateReader(string inputFile, float fps)
308332
{
309333
var ffmpegProcess = new Process();
310334
ffmpegProcess.StartInfo.FileName = _configuration.FFmpegPath;
311-
ffmpegProcess.StartInfo.Arguments = $"-hide_banner -loglevel error -i \"{inputFile}\" -c:v png -r {fps} -f image2pipe -";
335+
ffmpegProcess.StartInfo.Arguments = $"-hide_banner -loglevel error -hwaccel:v auto -i \"{inputFile}\" -c:v png -r {fps} -f image2pipe -";
312336
ffmpegProcess.StartInfo.RedirectStandardOutput = true;
313337
ffmpegProcess.StartInfo.UseShellExecute = false;
314338
ffmpegProcess.StartInfo.CreateNoWindow = true;
@@ -329,14 +353,31 @@ private static Process CreateWriter(string outputFile, float fps, double aspectR
329353
var codec = preserveTransparency ? "png" : "libx264";
330354
var format = preserveTransparency ? "yuva420p" : "yuv420p";
331355
ffmpegProcess.StartInfo.FileName = _configuration.FFmpegPath;
332-
ffmpegProcess.StartInfo.Arguments = $"-hide_banner -loglevel error -framerate {fps:F4} -i - -c:v {codec} -movflags +faststart -vf format={format} -aspect {aspectRatio} {outputFile}";
356+
ffmpegProcess.StartInfo.Arguments = $"-hide_banner -loglevel error -framerate {fps:F4} -hwaccel:v auto -i - -c:v {codec} -movflags +faststart -vf format={format} -aspect {aspectRatio} {outputFile}";
333357
ffmpegProcess.StartInfo.RedirectStandardInput = true;
334358
ffmpegProcess.StartInfo.UseShellExecute = false;
335359
ffmpegProcess.StartInfo.CreateNoWindow = true;
336360
return ffmpegProcess;
337361
}
338362

339363

364+
/// <summary>
365+
/// Creates the metadata reader.
366+
/// </summary>
367+
/// <param name="inputFile">The input file.</param>
368+
/// <returns></returns>
369+
private static Process CreateMetadataReader(string inputFile)
370+
{
371+
var ffprobeProcess = new Process();
372+
ffprobeProcess.StartInfo.FileName = _configuration.FFprobePath;
373+
ffprobeProcess.StartInfo.Arguments = $"-v quiet -print_format json -show_format -show_streams {inputFile}";
374+
ffprobeProcess.StartInfo.RedirectStandardOutput = true;
375+
ffprobeProcess.StartInfo.UseShellExecute = false;
376+
ffprobeProcess.StartInfo.CreateNoWindow = true;
377+
return ffprobeProcess;
378+
}
379+
380+
340381
/// <summary>
341382
/// Determines whether we are at the start of a PNG image in the specified buffer.
342383
/// </summary>

OnnxStack.Core/Video/VideoInfo.cs

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
using System;
2+
using System.Collections.Generic;
3+
using System.Text.Json.Serialization;
24

35
namespace OnnxStack.Core.Video
46
{
@@ -12,6 +14,77 @@ public VideoInfo(int height, int width, TimeSpan duration, float frameRate) : th
1214
public int Height { get; set; }
1315
public int Width { get; set; }
1416

15-
public double AspectRatio => (double)Height / Width;
17+
public double AspectRatio => (double)Width / Height;
18+
}
19+
20+
public record VideoMetadata
21+
{
22+
[JsonPropertyName("format")]
23+
public VideoFormat Format { get; set; }
24+
25+
[JsonPropertyName("streams")]
26+
public List<VideoStream> Streams { get; set; }
27+
}
28+
29+
[JsonNumberHandling(JsonNumberHandling.AllowReadingFromString)]
30+
public record VideoFormat
31+
{
32+
[JsonPropertyName("filename")]
33+
public string FileName { get; set; }
34+
35+
[JsonPropertyName("nb_streams")]
36+
public int StreamCount { get; set; }
37+
38+
[JsonPropertyName("format_name")]
39+
public string FormatName { get; set; }
40+
41+
[JsonPropertyName("format_long_name")]
42+
public string FormatLongName { get; set; }
43+
44+
[JsonPropertyName("size")]
45+
public long Size { get; set; }
46+
47+
[JsonPropertyName("bit_rate")]
48+
public long BitRate { get; set; }
49+
}
50+
51+
[JsonNumberHandling(JsonNumberHandling.AllowReadingFromString)]
52+
public record VideoStream
53+
{
54+
[JsonPropertyName("codec_type")]
55+
public string Type { get; set; }
56+
57+
[JsonPropertyName("codec_name")]
58+
public string CodecName { get; set; }
59+
60+
[JsonPropertyName("codec_long_name")]
61+
public string CodecLongName { get; set; }
62+
63+
[JsonPropertyName("pix_fmt")]
64+
public string PixelFormat { get; set; }
65+
66+
[JsonPropertyName("width")]
67+
public int Width { get; set; }
68+
69+
[JsonPropertyName("height")]
70+
public int Height { get; set; }
71+
72+
[JsonPropertyName("nb_frames")]
73+
public int FrameCount { get; set; }
74+
75+
[JsonPropertyName("duration")]
76+
public float DurationSeconds { get; set; }
77+
78+
public float FramesPerSecond => GetFramesPerSecond();
79+
80+
public TimeSpan Duration => TimeSpan.FromSeconds(DurationSeconds);
81+
82+
private float GetFramesPerSecond()
83+
{
84+
if (FrameCount == 0 || DurationSeconds == 0)
85+
return 0;
86+
87+
return FrameCount / DurationSeconds;
88+
}
1689
}
1790
}

0 commit comments

Comments
 (0)