mirror of
https://github.com/rosenbjerg/FFMpegCore.git
synced 2024-11-10 08:34:12 +01:00
Merge branch 'main' into feat/cut-video
This commit is contained in:
commit
98fdaf424b
9 changed files with 89 additions and 89 deletions
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
|
@ -10,7 +10,7 @@ on:
|
||||||
- FFMpegCore.Test/**
|
- FFMpegCore.Test/**
|
||||||
pull_request:
|
pull_request:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- main
|
||||||
- release
|
- release
|
||||||
paths:
|
paths:
|
||||||
- .github/workflows/ci.yml
|
- .github/workflows/ci.yml
|
||||||
|
|
4
.github/workflows/release.yml
vendored
4
.github/workflows/release.yml
vendored
|
@ -16,8 +16,8 @@ jobs:
|
||||||
dotnet-version: '7.0.x'
|
dotnet-version: '7.0.x'
|
||||||
|
|
||||||
- name: Build solution
|
- name: Build solution
|
||||||
run: dotnet pack FFMpegCore.sln --output build -c Release
|
run: dotnet pack FFMpegCore.sln -c Release
|
||||||
|
|
||||||
- name: Publish NuGet package
|
- name: Publish NuGet package
|
||||||
run: dotnet nuget push build/*.nupkg --source nuget.org --api-key ${{ secrets.NUGET_TOKEN }}
|
run: dotnet nuget push nupkg/*.nupkg --skip-duplicate --source nuget.org --api-key ${{ secrets.NUGET_TOKEN }}
|
||||||
|
|
||||||
|
|
|
@ -7,8 +7,8 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\FFMpegCore.Extensions.System.Drawing.Common\FFMpegCore.Extensions.System.Drawing.Common.csproj" />
|
<ProjectReference Include="..\FFMpegCore.Extensions.System.Drawing.Common\FFMpegCore.Extensions.System.Drawing.Common.csproj"/>
|
||||||
<ProjectReference Include="..\FFMpegCore\FFMpegCore.csproj" />
|
<ProjectReference Include="..\FFMpegCore\FFMpegCore.csproj"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
<IsPackable>true</IsPackable>
|
<IsPackable>true</IsPackable>
|
||||||
<Description>Image extension for FFMpegCore using System.Common.Drawing</Description>
|
<Description>Image extension for FFMpegCore using System.Common.Drawing</Description>
|
||||||
<PackageVersion>5.0.0</PackageVersion>
|
<PackageVersion>5.0.0</PackageVersion>
|
||||||
|
<PackageOutputPath>../nupkg</PackageOutputPath>
|
||||||
<PackageReleaseNotes>
|
<PackageReleaseNotes>
|
||||||
</PackageReleaseNotes>
|
</PackageReleaseNotes>
|
||||||
<PackageTags>ffmpeg ffprobe convert video audio mediafile resize analyze muxing</PackageTags>
|
<PackageTags>ffmpeg ffprobe convert video audio mediafile resize analyze muxing</PackageTags>
|
||||||
|
@ -11,11 +12,11 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="System.Drawing.Common" Version="7.0.0" />
|
<PackageReference Include="System.Drawing.Common" Version="7.0.0"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\FFMpegCore\FFMpegCore.csproj" />
|
<ProjectReference Include="..\FFMpegCore\FFMpegCore.csproj"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
@ -12,19 +12,19 @@
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="FluentAssertions" Version="6.9.0" />
|
<PackageReference Include="FluentAssertions" Version="6.9.0"/>
|
||||||
<PackageReference Include="GitHubActionsTestLogger" Version="2.0.1">
|
<PackageReference Include="GitHubActionsTestLogger" Version="2.0.1">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.4.1" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.4.1"/>
|
||||||
<PackageReference Include="MSTest.TestAdapter" Version="3.0.2" />
|
<PackageReference Include="MSTest.TestAdapter" Version="3.0.2"/>
|
||||||
<PackageReference Include="MSTest.TestFramework" Version="3.0.2" />
|
<PackageReference Include="MSTest.TestFramework" Version="3.0.2"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\FFMpegCore.Extensions.System.Drawing.Common\FFMpegCore.Extensions.System.Drawing.Common.csproj" />
|
<ProjectReference Include="..\FFMpegCore.Extensions.System.Drawing.Common\FFMpegCore.Extensions.System.Drawing.Common.csproj"/>
|
||||||
<ProjectReference Include="..\FFMpegCore\FFMpegCore.csproj" />
|
<ProjectReference Include="..\FFMpegCore\FFMpegCore.csproj"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
@ -1,15 +1,5 @@
|
||||||
namespace FFMpegCore.Test.Resources
|
namespace FFMpegCore.Test.Resources
|
||||||
{
|
{
|
||||||
public enum AudioType
|
|
||||||
{
|
|
||||||
Mp3
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum ImageType
|
|
||||||
{
|
|
||||||
Png
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class TestResources
|
public static class TestResources
|
||||||
{
|
{
|
||||||
public static readonly string Mp4Video = "./Resources/input_3sec.mp4";
|
public static readonly string Mp4Video = "./Resources/input_3sec.mp4";
|
||||||
|
|
|
@ -413,7 +413,7 @@ public void Video_Snapshot_InMemory()
|
||||||
[TestMethod, Timeout(10000)]
|
[TestMethod, Timeout(10000)]
|
||||||
public void Video_Snapshot_PersistSnapshot()
|
public void Video_Snapshot_PersistSnapshot()
|
||||||
{
|
{
|
||||||
var outputPath = new TemporaryFile("out.png");
|
using var outputPath = new TemporaryFile("out.png");
|
||||||
var input = FFProbe.Analyse(TestResources.Mp4Video);
|
var input = FFProbe.Analyse(TestResources.Mp4Video);
|
||||||
|
|
||||||
FFMpeg.Snapshot(TestResources.Mp4Video, outputPath);
|
FFMpeg.Snapshot(TestResources.Mp4Video, outputPath);
|
||||||
|
@ -427,10 +427,10 @@ public void Video_Snapshot_PersistSnapshot()
|
||||||
[TestMethod, Timeout(10000)]
|
[TestMethod, Timeout(10000)]
|
||||||
public void Video_Join()
|
public void Video_Join()
|
||||||
{
|
{
|
||||||
var inputCopy = new TemporaryFile("copy-input.mp4");
|
using var inputCopy = new TemporaryFile("copy-input.mp4");
|
||||||
File.Copy(TestResources.Mp4Video, inputCopy);
|
File.Copy(TestResources.Mp4Video, inputCopy);
|
||||||
|
|
||||||
var outputPath = new TemporaryFile("out.mp4");
|
using var outputPath = new TemporaryFile("out.mp4");
|
||||||
var input = FFProbe.Analyse(TestResources.Mp4Video);
|
var input = FFProbe.Analyse(TestResources.Mp4Video);
|
||||||
var success = FFMpeg.Join(outputPath, TestResources.Mp4Video, inputCopy);
|
var success = FFMpeg.Join(outputPath, TestResources.Mp4Video, inputCopy);
|
||||||
Assert.IsTrue(success);
|
Assert.IsTrue(success);
|
||||||
|
@ -461,7 +461,7 @@ public void Video_Join_Image_Sequence()
|
||||||
});
|
});
|
||||||
var imageAnalysis = FFProbe.Analyse(imageSet.First());
|
var imageAnalysis = FFProbe.Analyse(imageSet.First());
|
||||||
|
|
||||||
var outputFile = new TemporaryFile("out.mp4");
|
using var outputFile = new TemporaryFile("out.mp4");
|
||||||
var success = FFMpeg.JoinImageSequence(outputFile, frameRate: 10, images: imageSet.ToArray());
|
var success = FFMpeg.JoinImageSequence(outputFile, frameRate: 10, images: imageSet.ToArray());
|
||||||
Assert.IsTrue(success);
|
Assert.IsTrue(success);
|
||||||
var result = FFProbe.Analyse(outputFile);
|
var result = FFProbe.Analyse(outputFile);
|
||||||
|
@ -484,7 +484,7 @@ public void Video_With_Only_Audio_Should_Extract_Metadata()
|
||||||
public void Video_Duration()
|
public void Video_Duration()
|
||||||
{
|
{
|
||||||
var video = FFProbe.Analyse(TestResources.Mp4Video);
|
var video = FFProbe.Analyse(TestResources.Mp4Video);
|
||||||
var outputFile = new TemporaryFile("out.mp4");
|
using var outputFile = new TemporaryFile("out.mp4");
|
||||||
|
|
||||||
FFMpegArguments
|
FFMpegArguments
|
||||||
.FromFileInput(TestResources.Mp4Video)
|
.FromFileInput(TestResources.Mp4Video)
|
||||||
|
@ -503,7 +503,7 @@ public void Video_Duration()
|
||||||
[TestMethod, Timeout(10000)]
|
[TestMethod, Timeout(10000)]
|
||||||
public void Video_UpdatesProgress()
|
public void Video_UpdatesProgress()
|
||||||
{
|
{
|
||||||
var outputFile = new TemporaryFile("out.mp4");
|
using var outputFile = new TemporaryFile("out.mp4");
|
||||||
|
|
||||||
var percentageDone = 0.0;
|
var percentageDone = 0.0;
|
||||||
var timeDone = TimeSpan.Zero;
|
var timeDone = TimeSpan.Zero;
|
||||||
|
@ -544,7 +544,7 @@ void OnTimeProgess(TimeSpan time)
|
||||||
[TestMethod, Timeout(10000)]
|
[TestMethod, Timeout(10000)]
|
||||||
public void Video_OutputsData()
|
public void Video_OutputsData()
|
||||||
{
|
{
|
||||||
var outputFile = new TemporaryFile("out.mp4");
|
using var outputFile = new TemporaryFile("out.mp4");
|
||||||
var dataReceived = false;
|
var dataReceived = false;
|
||||||
|
|
||||||
GlobalFFOptions.Configure(opt => opt.Encoding = Encoding.UTF8);
|
GlobalFFOptions.Configure(opt => opt.Encoding = Encoding.UTF8);
|
||||||
|
@ -604,7 +604,7 @@ public void Video_TranscodeToMemory()
|
||||||
[TestMethod, Timeout(10000)]
|
[TestMethod, Timeout(10000)]
|
||||||
public async Task Video_Cancel_Async()
|
public async Task Video_Cancel_Async()
|
||||||
{
|
{
|
||||||
var outputFile = new TemporaryFile("out.mp4");
|
using var outputFile = new TemporaryFile("out.mp4");
|
||||||
|
|
||||||
var task = FFMpegArguments
|
var task = FFMpegArguments
|
||||||
.FromFileInput("testsrc2=size=320x240[out0]; sine[out1]", false, args => args
|
.FromFileInput("testsrc2=size=320x240[out0]; sine[out1]", false, args => args
|
||||||
|
@ -628,7 +628,7 @@ public async Task Video_Cancel_Async()
|
||||||
[TestMethod, Timeout(10000)]
|
[TestMethod, Timeout(10000)]
|
||||||
public void Video_Cancel()
|
public void Video_Cancel()
|
||||||
{
|
{
|
||||||
var outputFile = new TemporaryFile("out.mp4");
|
using var outputFile = new TemporaryFile("out.mp4");
|
||||||
var task = FFMpegArguments
|
var task = FFMpegArguments
|
||||||
.FromFileInput("testsrc2=size=320x240[out0]; sine[out1]", false, args => args
|
.FromFileInput("testsrc2=size=320x240[out0]; sine[out1]", false, args => args
|
||||||
.WithCustomArgument("-re")
|
.WithCustomArgument("-re")
|
||||||
|
@ -649,7 +649,7 @@ public void Video_Cancel()
|
||||||
[TestMethod, Timeout(10000)]
|
[TestMethod, Timeout(10000)]
|
||||||
public async Task Video_Cancel_Async_With_Timeout()
|
public async Task Video_Cancel_Async_With_Timeout()
|
||||||
{
|
{
|
||||||
var outputFile = new TemporaryFile("out.mp4");
|
using var outputFile = new TemporaryFile("out.mp4");
|
||||||
|
|
||||||
var task = FFMpegArguments
|
var task = FFMpegArguments
|
||||||
.FromFileInput("testsrc2=size=320x240[out0]; sine[out1]", false, args => args
|
.FromFileInput("testsrc2=size=320x240[out0]; sine[out1]", false, args => args
|
||||||
|
@ -679,7 +679,7 @@ public async Task Video_Cancel_Async_With_Timeout()
|
||||||
[TestMethod, Timeout(10000)]
|
[TestMethod, Timeout(10000)]
|
||||||
public async Task Video_Cancel_CancellationToken_Async()
|
public async Task Video_Cancel_CancellationToken_Async()
|
||||||
{
|
{
|
||||||
var outputFile = new TemporaryFile("out.mp4");
|
using var outputFile = new TemporaryFile("out.mp4");
|
||||||
|
|
||||||
var cts = new CancellationTokenSource();
|
var cts = new CancellationTokenSource();
|
||||||
|
|
||||||
|
@ -704,7 +704,7 @@ public async Task Video_Cancel_CancellationToken_Async()
|
||||||
[TestMethod, Timeout(10000)]
|
[TestMethod, Timeout(10000)]
|
||||||
public async Task Video_Cancel_CancellationToken_Async_Throws()
|
public async Task Video_Cancel_CancellationToken_Async_Throws()
|
||||||
{
|
{
|
||||||
var outputFile = new TemporaryFile("out.mp4");
|
using var outputFile = new TemporaryFile("out.mp4");
|
||||||
|
|
||||||
var cts = new CancellationTokenSource();
|
var cts = new CancellationTokenSource();
|
||||||
|
|
||||||
|
@ -727,7 +727,7 @@ public async Task Video_Cancel_CancellationToken_Async_Throws()
|
||||||
[TestMethod, Timeout(10000)]
|
[TestMethod, Timeout(10000)]
|
||||||
public void Video_Cancel_CancellationToken_Throws()
|
public void Video_Cancel_CancellationToken_Throws()
|
||||||
{
|
{
|
||||||
var outputFile = new TemporaryFile("out.mp4");
|
using var outputFile = new TemporaryFile("out.mp4");
|
||||||
|
|
||||||
var cts = new CancellationTokenSource();
|
var cts = new CancellationTokenSource();
|
||||||
|
|
||||||
|
@ -749,7 +749,7 @@ public void Video_Cancel_CancellationToken_Throws()
|
||||||
[TestMethod, Timeout(10000)]
|
[TestMethod, Timeout(10000)]
|
||||||
public async Task Video_Cancel_CancellationToken_Async_With_Timeout()
|
public async Task Video_Cancel_CancellationToken_Async_With_Timeout()
|
||||||
{
|
{
|
||||||
var outputFile = new TemporaryFile("out.mp4");
|
using var outputFile = new TemporaryFile("out.mp4");
|
||||||
|
|
||||||
var cts = new CancellationTokenSource();
|
var cts = new CancellationTokenSource();
|
||||||
|
|
||||||
|
|
|
@ -66,25 +66,34 @@ public static async Task<bool> SnapshotAsync(string input, string output, Size?
|
||||||
/// <returns>Output video information.</returns>
|
/// <returns>Output video information.</returns>
|
||||||
public static bool JoinImageSequence(string output, double frameRate = 30, params string[] images)
|
public static bool JoinImageSequence(string output, double frameRate = 30, params string[] images)
|
||||||
{
|
{
|
||||||
|
var fileExtensions = images.Select(Path.GetExtension).Distinct().ToArray();
|
||||||
|
if (fileExtensions.Length != 1)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("All images must have the same extension", nameof(images));
|
||||||
|
}
|
||||||
|
|
||||||
|
var fileExtension = fileExtensions[0].ToLowerInvariant();
|
||||||
int? width = null, height = null;
|
int? width = null, height = null;
|
||||||
|
|
||||||
var tempFolderName = Path.Combine(GlobalFFOptions.Current.TemporaryFilesFolder, Guid.NewGuid().ToString());
|
var tempFolderName = Path.Combine(GlobalFFOptions.Current.TemporaryFilesFolder, Guid.NewGuid().ToString());
|
||||||
var temporaryImageFiles = images.Select((imagePath, index) =>
|
Directory.CreateDirectory(tempFolderName);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var index = 0;
|
||||||
|
foreach (var imagePath in images)
|
||||||
{
|
{
|
||||||
var analysis = FFProbe.Analyse(imagePath);
|
var analysis = FFProbe.Analyse(imagePath);
|
||||||
FFMpegHelper.ConversionSizeExceptionCheck(analysis.PrimaryVideoStream!.Width, analysis.PrimaryVideoStream!.Height);
|
FFMpegHelper.ConversionSizeExceptionCheck(analysis.PrimaryVideoStream!.Width, analysis.PrimaryVideoStream!.Height);
|
||||||
width ??= analysis.PrimaryVideoStream.Width;
|
width ??= analysis.PrimaryVideoStream.Width;
|
||||||
height ??= analysis.PrimaryVideoStream.Height;
|
height ??= analysis.PrimaryVideoStream.Height;
|
||||||
|
|
||||||
var destinationPath = Path.Combine(tempFolderName, $"{index.ToString().PadLeft(9, '0')}{Path.GetExtension(imagePath)}");
|
var destinationPath = Path.Combine(tempFolderName, $"{index++.ToString().PadLeft(9, '0')}{fileExtension}");
|
||||||
Directory.CreateDirectory(tempFolderName);
|
|
||||||
File.Copy(imagePath, destinationPath);
|
File.Copy(imagePath, destinationPath);
|
||||||
return destinationPath;
|
}
|
||||||
}).ToArray();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return FFMpegArguments
|
return FFMpegArguments
|
||||||
.FromFileInput(Path.Combine(tempFolderName, "%09d.png"), false)
|
.FromFileInput(Path.Combine(tempFolderName, $"%09d{fileExtension}"), false)
|
||||||
.OutputToFile(output, true, options => options
|
.OutputToFile(output, true, options => options
|
||||||
.ForcePixelFormat("yuv420p")
|
.ForcePixelFormat("yuv420p")
|
||||||
.Resize(width!.Value, height!.Value)
|
.Resize(width!.Value, height!.Value)
|
||||||
|
@ -93,8 +102,7 @@ public static bool JoinImageSequence(string output, double frameRate = 30, param
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
Cleanup(temporaryImageFiles);
|
Directory.Delete(tempFolderName, true);
|
||||||
Directory.Delete(tempFolderName);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,8 @@
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<IsPackable>true</IsPackable>
|
<IsPackable>true</IsPackable>
|
||||||
<Description>A .NET Standard FFMpeg/FFProbe wrapper for easily integrating media analysis and conversion into your .NET applications</Description>
|
<Description>A .NET Standard FFMpeg/FFProbe wrapper for easily integrating media analysis and conversion into your .NET applications</Description>
|
||||||
<PackageVersion>5.0.0</PackageVersion>
|
<PackageVersion>5.0.1</PackageVersion>
|
||||||
|
<PackageOutputPath>../nupkg</PackageOutputPath>
|
||||||
<PackageReleaseNotes>
|
<PackageReleaseNotes>
|
||||||
</PackageReleaseNotes>
|
</PackageReleaseNotes>
|
||||||
<PackageTags>ffmpeg ffprobe convert video audio mediafile resize analyze muxing</PackageTags>
|
<PackageTags>ffmpeg ffprobe convert video audio mediafile resize analyze muxing</PackageTags>
|
||||||
|
@ -12,12 +13,12 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="..\README.md" Pack="true" PackagePath="\" />
|
<None Include="..\README.md" Pack="true" PackagePath="\"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Instances" Version="3.0.0" />
|
<PackageReference Include="Instances" Version="3.0.0"/>
|
||||||
<PackageReference Include="System.Text.Json" Version="7.0.1" />
|
<PackageReference Include="System.Text.Json" Version="7.0.1"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
Loading…
Reference in a new issue