Skip to content

Commit 9455d5c

Browse files
save file
1 parent 0d480f7 commit 9455d5c

File tree

1 file changed

+195
-0
lines changed
  • blog/25-11-15/ffmpeg-in-the-browser/ex/ffmpeg-wasm

1 file changed

+195
-0
lines changed
Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
2+
3+
<style>
4+
html {height:100%}
5+
body {height:caclc(100% - 40px);margin:20px}
6+
#root {position:absolute;left:0;right:0;height:200px;border:1px solid gray;display:flex;gap:5px;font-family:arial}
7+
</style>
8+
9+
<style>
10+
#view {min-width:350px;display:flex;flex-direction:column;padding:10px;border-right:1px solid lightgray}
11+
.type {display:flex;justify-content:space-between;align-items:center;margin-bottom:10px}
12+
#list {flex:1;overflow:auto;border-top:1px solid lightblue}
13+
#item {display:flex;align-items:center;gap:30px;height:50px;margin:10px 0}
14+
#log {flex:1;font-family:monospace;color:gray;line-height:1.2;overflow:auto;flex:1;white-space:pre-wrap;font-size:16px;margin:0}
15+
.log-item {border:1px solid dimgray;padding:10px}
16+
input {font-size:16px;padding:2px 10px;cursor:pointer}
17+
</style>
18+
19+
<div id=root>
20+
<div id=view>
21+
<div id=ffmpeg class=type>
22+
<span>ffmpeg.wasm</span>
23+
<input value=run type=button>
24+
</div>
25+
<div id=ffmpeg-no-log class=type>
26+
<span>ffmpeg.wasm - no log</span>
27+
<input value=run type=button>
28+
</div>
29+
<div id=list>
30+
<a id=item>
31+
<img>
32+
<div>
33+
<div id=mode></div>
34+
<div id=time></div>
35+
</div>
36+
</a>
37+
</div>
38+
</div>
39+
<pre id=log></pre>
40+
</div>
41+
42+
43+
<script>
44+
console.clear();
45+
46+
(async()=>{
47+
48+
var $ = (root,sel)=>(!sel && (sel=root,root=document),root.querySelector(sel));
49+
var log = (...args)=>{log.add($('#log'),args)}
50+
log.add = (node,args)=>{var div=document.createElement('div');div.textContent=args.join(' ');node.append(div);$('#log').scrollTop=9999999;console.log.apply(console,args)}
51+
log.create = (...args)=>{var node=document.createElement('div');node.className='log-item';$('#log').append(node);var log2=(...args)=>{log2.enabled && log.add(node,args)};log2.enabled=true;return log2}
52+
var get = url=>fetch(url).then(res=>res.blob());
53+
var dtype = v=>Object.prototype.toString.call(v).slice(8,-1).toLowerCase();
54+
var _blob = v=>new Blob([v]);
55+
var _uint8 = async v=>dtype(v)=='blob' ? new Uint8Array(await v.arrayBuffer()) : new Uint8Array(v);
56+
var fnstr = (fn,_,js,i1,i2)=>(js=fn+'',i1=js.indexOf('{'),i2=js.lastIndexOf('}'),js.slice(i1+1,i2));
57+
58+
$('#ffmpeg [type]').onclick = e=>run(true);
59+
$('#ffmpeg-no-log [type]').onclick = e=>run(false);
60+
var item = $('#item');
61+
item.remove();
62+
63+
log('loading');
64+
var {zip} = await import('https://cdn.jsdelivr.net/gh/javascript-2020/libs/js/io/tiny-unzip/tiny-unzip.m.js');
65+
log('loading','ffmpeg.wasm');
66+
//var blob = await get('https://cdn.jsdelivr.net/gh/javascript-2020/external/ffmpeg/ffmeg-wasm/ffmpeg-wasm.zip');
67+
var blob = await get('https://raw.githubusercontent.com/javascript-2020/external/main/ffmpeg/ffmpeg-wasm/ffmpeg-wasm.zip');
68+
69+
var files = await zip.rd(blob);
70+
files.forEach(({name,blob})=>files[name]=blob);
71+
files['ffmpeg-core.wasm'] = window.URL.createObjectURL(files['ffmpeg-core.wasm']);
72+
var txt = ['ffmpeg-core.js','index.js','ffmpeg.js','814.ffmpeg.js'];
73+
await Promise.all(txt.map(async name=>files[name]=await files[name].text()));
74+
75+
var sandbox = {};
76+
77+
sandbox.worker = function(){
78+
79+
self.fetch = url=>new Promise(async res=>res(new Response('Not Found',{status:404})));
80+
self.onmessage = ({data:{lib,file}})=>{var importScripts=()=>self.eval(lib);eval(file)}
81+
82+
}//worker
83+
84+
sandbox.main = function(){
85+
86+
(()=>{
87+
88+
var globalThis = {document:{currentScript:{src:'https://null.com/'}}};
89+
function Worker(url){
90+
console.log('worker-sandbox',`${url}`);
91+
var js = fnstr(sandbox.worker);
92+
var blob = new Blob([js]);
93+
var url2 = window.URL.createObjectURL(blob);
94+
var worker = new window.Worker(url2);
95+
var lib = files['ffmpeg-core.js'];
96+
var name = url.pathname.split('/').at(-1);
97+
var file = files[name];
98+
worker.postMessage({lib,file});
99+
return worker;
100+
101+
}//worker
102+
103+
eval(files['ffmpeg.js']);
104+
105+
})();
106+
107+
}//main
108+
109+
110+
eval(fnstr(sandbox.main));
111+
eval(files['index.js']);
112+
113+
var {fetchFile} = FFmpegUtil;
114+
var {FFmpeg} = FFmpegWASM;
115+
116+
var ffmpeg = new FFmpeg();
117+
console.log(ffmpeg);
118+
await ffmpeg.load({coreURL:'ffmpeg-core.js',wasmURL:files['ffmpeg-core.wasm']});
119+
120+
log('loading','buck.webm');
121+
var buck = await get('https://cdn.jsdelivr.net/gh/javascript-2020/external/video/buck.webm');
122+
log('ready');
123+
124+
125+
async function run(logging){
126+
var log2=log.create();
127+
var cmd = 'ffmpeg -t 20 -nostdin -i buck.webm -strict experimental output.mp4';
128+
log2(cmd);
129+
var args = cmd.split(' ').slice(1);
130+
var uint8 = await _uint8(buck);
131+
132+
await ffmpeg.writeFile('buck.webm',uint8);
133+
134+
var on = {};
135+
on.log = ({message})=>log2(message);
136+
on.progress = ({progress,time})=>log2(`${progress*100}%,time:${time}`);
137+
138+
ffmpeg.on('log',on.log);
139+
ffmpeg.on('progress',on.progress);
140+
log2.enabled=!!logging;
141+
var start = Date.now();
142+
await ffmpeg.exec(args);
143+
var time = Date.now()-start;
144+
log2.enabled=true;
145+
var data = await ffmpeg.readFile('output.mp4');
146+
console.log(data);
147+
var output = _blob(data);
148+
149+
var cmd = `ffmpeg -nostdin -ss 00:00:03.00 -i output.mp4 -vframes 1 -vf scale=-1:50 output.jpg`;
150+
log2(cmd);
151+
var args = cmd.split(' ').slice(1);
152+
var uint8 = await _uint8(output);
153+
log2.enabled=!!logging;
154+
await ffmpeg.exec(args);
155+
log2.enabled=true;
156+
var data = await ffmpeg.readFile('output.jpg');
157+
var thumbnail = _blob(data);
158+
159+
ffmpeg.off('log',on.log);
160+
ffmpeg.off('progress',on.progress);
161+
162+
done(output,thumbnail,time);
163+
164+
}//run
165+
166+
function done(output,thumbnail,time){
167+
168+
var fn = `output.mp4`;
169+
170+
var nitem = item.cloneNode(true);
171+
172+
var url = window.URL.createObjectURL(output);
173+
nitem.download = fn;
174+
nitem.href = url;
175+
176+
var url = window.URL.createObjectURL(thumbnail);
177+
$(nitem,'img').src = url;
178+
179+
$(nitem,'#mode').textContent = fn;
180+
$(nitem,'#time').textContent = (time/1000).toFixed(1)+' s';
181+
182+
$('#list').append(nitem);
183+
$('#list').scrollTop = 9999999;
184+
185+
}//done
186+
187+
})();
188+
189+
190+
</script>
191+
192+
193+
194+
195+

0 commit comments

Comments
 (0)