/
BasicFactoryExample.razor
225 lines (213 loc) · 8.95 KB
/
BasicFactoryExample.razor
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
@page "/"
@using System.Text
@using SpawnDev.BlazorJS
@using SpawnDev.BlazorJS.FFmpegWasm
@implements IDisposable
<h3>Basic Demo of ffmpeg.wasm in Blazor</h3>
<p>A simple demo of ffmpeg.wasm in Blazor WASM using SpawnDev.BlazorJS.FFmpegWASM packages</p>
<p><a href="https://github.com/LostBeard/SpawnDev.BlazorJS.FFmpegWasm/blob/main/SpawnDev.BlazorJS.FFmpegWasmDemo/Pages/BasicFactoryExample.razor">Page source code</a></p>
<video @ref=videoResult autoplay muted id="video-result" controls style="border: 1px solid black;"></video>
<br />
<div>
<button @onclick=Load disabled="@(loaded || busy)" id="load-button">Load ffmpeg-core (~31 MB)</button>
<br />
<br />
</div>
<div>
Select file to test transcoding to mp4.<br />
<input @ref=fileInputRef accept="video/*" type="file" disabled="@(!loaded || busy)" style="width: 100%;" /><br />
<br />
<input type="checkbox" @bind="@useWorkerFS" disabled="@(!loaded || busy)" name="useWorkerFS" /><label for="useWorkerFS">Use WorkerFS</label><br />
<br />
<button @onclick=Transcode disabled="@(!loaded || busy || sourceFile == null)" id="transcode-button">Transcode to mp4</button><br />
Multithreading will be used: @FFmpegFactory.MultiThreadSupported<br />
<br />
<div style="width: 100%; background-color: grey; position: relative;">
<div style="width: @(percentComplete)%; background-color: cadetblue; height: 36px;">
</div>
<div style="padding-top: 0; top: 0; left: 0; position: absolute; height: 100%; width: 100%; background-color: transparent; font-weight: bold; text-align: center; font-size: 24px;">
@(Math.Round(percentComplete, 3)) %
</div>
</div>
</div>
<p>@logMessage</p>
<p>@progressMessage</p>
<p>Open Developer Tools (Ctrl+Shift+I) to View Logs</p>
<table>
<thead>
<tr>
<th>Package</th>
<th>Description</th>
<th>Includes</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<strong>SpawnDev.BlazorJS.FFmpegWasm</strong> <br>
<a href="https://www.nuget.org/packages/SpawnDev.BlazorJS.FFmpegWasm" rel="nofollow">
<img src="https://camo.githubusercontent.com/912d8f52e6e91dcb14e1ec293cc99ad9b7fa6599b3a9f85ae60a1980594468ea/68747470733a2f2f62616467652e667572792e696f2f6e752f537061776e4465762e426c617a6f724a532e46466d7065675761736d2e737667" alt="NuGet version" data-canonical-src="https://badge.fury.io/nu/SpawnDev.BlazorJS.FFmpegWasm.svg" style="max-width: 100%;">
</a>
</td>
<td>ffmpeg.wasm for Blazor WASM</td>
<td>ffmpeg/*<br>ffmpeg.js<br>814.ffmpeg.js</td>
</tr>
<tr>
<td>
<strong>SpawnDev.BlazorJS.FFmpegWasm.Core</strong> <br>
<a href="https://www.nuget.org/packages/SpawnDev.BlazorJS.FFmpegWasm.Core" rel="nofollow">
<img src="https://camo.githubusercontent.com/3d5a593e7aef769123997cc9860cdce8a50026d5abada5f1b21b87a8555683ca/68747470733a2f2f62616467652e667572792e696f2f6e752f537061776e4465762e426c617a6f724a532e46466d7065675761736d2e436f72652e737667" alt="NuGet version" data-canonical-src="https://badge.fury.io/nu/SpawnDev.BlazorJS.FFmpegWasm.Core.svg" style="max-width: 100%;">
</a>
</td>
<td>Includes SpawnDev.BlazorJS.FFmpegWasm and ffmpeg.wasm core resources</td>
<td>core/*<br>ffmpeg-core.js<br>ffmpeg-core.wasm</td>
</tr>
<tr>
<td>
<strong>SpawnDev.BlazorJS.FFmpegWasm.CoreMT</strong> <br>
<a href="https://www.nuget.org/packages/SpawnDev.BlazorJS.FFmpegWasm.CoreMT" rel="nofollow">
<img src="https://camo.githubusercontent.com/9c5195371a9d889c7f874899e68ea2e9a45dea972bead8b97702f57d53b514fa/68747470733a2f2f62616467652e667572792e696f2f6e752f537061776e4465762e426c617a6f724a532e46466d7065675761736d2e436f72654d542e737667" alt="NuGet version" data-canonical-src="https://badge.fury.io/nu/SpawnDev.BlazorJS.FFmpegWasm.CoreMT.svg" style="max-width: 100%;">
</a>
</td>
<td>Includes SpawnDev.BlazorJS.FFmpegWasm and ffmpeg.wasm core-mt resources</td>
<td>core-mt/*<br>ffmpeg-core.js<br>ffmpeg-core.wasm<br>ffmpeg-core.worker.js</td>
</tr>
</tbody>
</table>
@code {
[Inject]
BlazorJSRuntime JS { get; set; }
[Inject]
FFmpegFactory FFmpegFactory { get; set; }
ElementReference videoResult;
HTMLVideoElement? videoEl;
bool loaded = false;
bool busy = false;
string logMessage = "";
string progressMessage = "";
FFmpeg? ffmpeg = null;
ElementReference fileInputRef;
HTMLInputElement? fileInput;
bool beenInit = false;
double percentComplete = 0;
bool useWorkerFS = true;
File? sourceFile = null;
protected override void OnAfterRender(bool firstRender)
{
if (!beenInit)
{
beenInit = true;
videoEl = new HTMLVideoElement(videoResult);
fileInput = new HTMLInputElement(JS.ToJSRef(fileInputRef));
fileInput.OnChange += FileInput_OnChange;
}
}
public void Dispose()
{
if (beenInit)
{
beenInit = false;
videoEl!.Dispose();
fileInput!.OnChange -= FileInput_OnChange;
fileInput.Dispose();
}
if (ffmpeg != null)
{
ffmpeg.Terminate();
ffmpeg.Dispose();
ffmpeg = null;
}
sourceFile?.Dispose();
sourceFile = null;
}
void FileInput_OnChange(Event ev)
{
using var files = fileInput!.Files;
sourceFile = files!.Length > 0 ? files[0] : null;
StateHasChanged();
}
async Task Load()
{
busy = true;
StateHasChanged();
await FFmpegFactory.Init();
ffmpeg = new FFmpeg();
ffmpeg.OnLog += FFmpeg_OnLog;
ffmpeg.OnProgress += FFmpeg_OnProgress;
// Use FFmpegFactory extension methods supplied by the Nuget packages
// SpawnDev.BlazorJS.FFmpegWasm.Core
// SpawnDev.BlazorJS.FFmpegWasm.CoreMT
//
// From SpawnDev.BlazorJS.FFmpegWasm.Core
// - Contains the ffmpeg.wasm core for single thread files
// - Adds CreateLoadCoreConfig to FFmpegFactory
// From SpawnDev.BlazorJS.FFmpegWasm.CoreMT
// - Contains the ffmpeg.wasm core for multi thread files
// - Adds CreateLoadCoreMTConfig to FFmpegFactory
// Single thread and multi thread versions acn be used independently of each other to lower resource packaging.
var loadConfig = FFmpegFactory.MultiThreadSupported ? FFmpegFactory.CreateLoadCoreMTConfig() : FFmpegFactory.CreateLoadCoreConfig();
await ffmpeg.Load(loadConfig);
busy = false;
loaded = true;
StateHasChanged();
}
async Task Transcode()
{
if (sourceFile == null) return;
busy = true;
StateHasChanged();
var inputDir = "/input";
var inputFile = $"/input/{sourceFile.Name}";
await ffmpeg.CreateDir(inputDir);
if (useWorkerFS)
{
// using WORKERFS. the file handle will be shared with the main worker
await ffmpeg.MountWorkerFS(inputDir, new FSMountWorkerFSOptions { Files = new[] { sourceFile } });
}
else
{
// not using WORKERFS. the entire file will be read into memory and transferred to the main worker
using var arrayBuffer = await sourceFile.ArrayBuffer();
using var uint8Array = new Uint8Array(arrayBuffer);
await ffmpeg.WriteFile(inputFile, uint8Array);
}
//var ls = await ffmpeg.ListDir(inputDir);
logMessage = "Transcoding source video";
StateHasChanged();
var ret = await ffmpeg.Exec(new string[] { "-i", inputFile, "output.mp4" });
logMessage = "Source video transcoded";
StateHasChanged();
// empty the input folder
if (useWorkerFS)
{
await ffmpeg.Unmount(inputDir);
}
else
{
await ffmpeg.DeleteFile(inputFile);
}
// delete the input folder
await ffmpeg.DeleteDir(inputDir);
using var data = await ffmpeg.ReadFileUint8Array("output.mp4");
using var blob = new Blob(new Uint8Array[] { data }, new BlobOptions { Type = "video/mp4" });
var objSrc = URL.CreateObjectURL(blob);
videoEl!.Src = objSrc;
busy = false;
StateHasChanged();
}
void FFmpeg_OnLog(FFmpegLogEvent ev)
{
logMessage = ev.Message;
JS.Log("FFmpeg_OnLog", ev.Message);
StateHasChanged();
}
void FFmpeg_OnProgress(FFmpegProgressEvent ev)
{
var progress = ev.Progress;
var time = ev.Time;
progressMessage = $"{progress * 100} % (transcoded time: {time / 1000000} s)";
JS.Log("FFmpeg_OnProgress", ev.Time, ev.Progress);
percentComplete = ev.Progress * 100d;
StateHasChanged();
}
}