Skip to content

Commit e13e8d2

Browse files
save file
1 parent 5aa915f commit e13e8d2

File tree

1 file changed

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

1 file changed

+199
-0
lines changed
Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
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.js</span>
23+
<input value=run type=button>
24+
</div>
25+
<div id=ffmpeg-all-codecs class=type>
26+
<span>ffmpeg-all-codecs.js</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+
function worker(){
47+
48+
var mode = {mode};
49+
50+
(async()=>{
51+
log('worker',mode);
52+
var {zip} = await import('https://cdn.jsdelivr.net/gh/javascript-2020/libs/js/io/tiny-unzip/tiny-unzip.m.js');
53+
54+
var log = (...args)=>self.postMessage({type:'log',args});
55+
var get = url=>fetch(url).then(res=>res.blob());
56+
var dtype = v=>Object.prototype.toString.call(v).slice(8,-1).toLowerCase();
57+
var _uint8 = async v=>dtype(v)=='blob' ? new Uint8Array(await v.arrayBuffer()) : new Uint8Array(v);
58+
59+
log('loading',mode);
60+
var blob;
61+
switch(mode){
62+
63+
case 'ffmpeg' : blob=await get('https://cdn.jsdelivr.net/gh/javascript-2020/external/ffmpeg/videoconverter/ffmpeg.zip'); break;
64+
case 'ffmpeg-all-codecs' : blob=await get('https://cdn.jsdelivr.net/gh/javascript-2020/external/ffmpeg/videoconverter/ffmpeg-all-codecs.zip'); break;
65+
66+
}//switch
67+
var files = await zip.rd(blob);
68+
// now i kno y'all gon shout at me if i just use eval
69+
// var js = await files[0].blob.text();
70+
// var {ffmpeg_run} = eval(`${js};({ffmpeg_run})`);
71+
72+
var url = self.URL.createObjectURL(files[0].blob);
73+
importScripts(url);
74+
var {ffmpeg_run} = self;
75+
console.log(ffmpeg_run);
76+
log('loading','buck.webm');
77+
var buck = await get('https://cdn.jsdelivr.net/gh/javascript-2020/external/video/buck.webm');
78+
79+
80+
var cmd = 'ffmpeg -t 20 -nostdin -i buck.webm -strict experimental output.mp4';
81+
var args = cmd.split(' ').slice(1);
82+
var uint8 = await _uint8(buck);
83+
var print = log;
84+
var printErr = log;
85+
log(cmd);
86+
var start = Date.now();
87+
var result = ffmpeg_run({
88+
files : [{name:'buck.webm',data:uint8}],
89+
arguments : args,
90+
TOTAL_MEMORY : 250_000_000,
91+
print,printErr
92+
});
93+
var time = Date.now()-start;
94+
var {data:output} = result[0];
95+
console.log(output);
96+
97+
var cmd = `ffmpeg -nostdin -ss 00:00:03.00 -i output.mp4 -vframes 1 -vf scale=-1:50 output.jpg`;
98+
var args = cmd.split(' ').slice(1);
99+
var uint8 = await _uint8(output);
100+
log(cmd);
101+
var result = ffmpeg_run({
102+
files : [{name:'output.mp4',data:uint8}],
103+
arguments : args,
104+
print,printErr
105+
});
106+
107+
var {data:thumbnail} = result[0];
108+
109+
self.postMessage({type:'done',output,thumbnail,time},[output,thumbnail]);
110+
self.close();
111+
112+
function log(...args){self.postMessage({type:'log',args})}
113+
114+
})();
115+
116+
}//worker
117+
118+
worker.js = function(mode){
119+
120+
var js = fnstr(worker);
121+
js = js.replace('{mode}',`'${mode}'`);
122+
var blob = new Blob([js]);
123+
return blob;
124+
125+
}//js
126+
127+
worker.create = function(e){
128+
129+
var mode = e.target.parentNode.id;
130+
var node=log.create(mode);
131+
var blob = worker.js(mode);
132+
var url = window.URL.createObjectURL(blob);
133+
var thread = new Worker(url);
134+
thread.onmessage = ({data})=>onmsg(mode,node,data);
135+
136+
}//create
137+
138+
139+
140+
var $ = (root,sel)=>(!sel && (sel=root,root=document),root.querySelector(sel));
141+
var log = (node,args)=>{var div=document.createElement('div');div.textContent=args.join(' ');node.append(div);$('#log').scrollTop=9999999;console.log.apply(console,args);return node}
142+
log.create = (...args)=>{var div=document.createElement('div');div.className='log-item';$('#log').append(div);log(div,args);return div}
143+
var log2 = (...args)=>{var div=document.createElement('div');div.textContent=args.join(' ');$('#log').append(div);$('#log').scrollTop=9999999;console.log.apply(console,args);return div}
144+
var _blob = v=>new Blob([new Uint8Array(v)]);
145+
var fnstr = (fn,_,js,i1,i2)=>(js=fn+'',i1=js.indexOf('{'),i2=js.lastIndexOf('}'),js.slice(i1+1,i2));
146+
147+
148+
$('#ffmpeg [type]').onclick = worker.create;
149+
$('#ffmpeg-all-codecs [type]').onclick = worker.create;
150+
151+
var item = $('#item');
152+
item.remove();
153+
log2('ready');
154+
155+
function onmsg(mode,node,data){
156+
157+
switch(data.type){
158+
159+
case 'log' : log(node,data.args); break;
160+
case 'done' : onmsg.done(mode,data); break;
161+
162+
}//switch
163+
164+
}//onmsg
165+
166+
167+
onmsg.done = function(mode,data){
168+
169+
var {output,thumbnail,time} = data;
170+
171+
var fn = `${mode}.mp4`;
172+
173+
var nitem = item.cloneNode(true);
174+
175+
output = _blob(output);
176+
var url = window.URL.createObjectURL(output);
177+
nitem.download = fn;
178+
nitem.href = url;
179+
180+
thumbnail = _blob(thumbnail);
181+
var url = window.URL.createObjectURL(thumbnail);
182+
$(nitem,'img').src = url;
183+
184+
$(nitem,'#mode').textContent = fn;
185+
$(nitem,'#time').textContent = (time/1000).toFixed(1)+' s';
186+
187+
$('#list').append(nitem);
188+
$('#list').scrollTop = 9999999;
189+
190+
}//done
191+
192+
193+
194+
</script>
195+
196+
197+
198+
199+

0 commit comments

Comments
 (0)