-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.htm
301 lines (262 loc) · 11.6 KB
/
index.htm
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
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
<html>
<head>
<meta charset="utf-8">
<title>FFmpeg command line wizard</title>
<style type="text/css">
body, td {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 14px;
}
body {
line-height: 1.5;
}
h1 {
font-size: 17px;
}
div {
margin-bottom: 5px;
}
.commandline span {
border-radius: 3px;
padding: 1px;
}
.commandline span:hover {
background-color: #aaa;
}
[v-cloak] { opacity: .1; }
</style>
<style type="text/css">
.tooltip .tooltip-inner {
background: black;
color: white;
border-radius: 5px;
padding: 3px 5px;
font-size: 12px;
margin-left: 7px;
}
.tooltip .tooltip-arrow {
display: none;
}
.tooltip[aria-hidden='true'] {
visibility: hidden;
opacity: 0;
transition: opacity .15s, visibility .15s;
}
.tooltip[aria-hidden='false'] {
visibility: visible;
opacity: 1;
transition: opacity .15s;
}
</style>
</head>
<body>
<h1>FFmpeg command line wizard</h1>
<b>Settings:</b>
<div id="mountpoint" v-cloak>
<div>
Input:
<label><input type="radio" v-model="input" value="video">Video</label> <label><input type="checkbox" v-model="audio" v-bind:disabled="input != 'video' || output == 'gif'">with audio</label>
<label><input type="radio" v-model="input" value="images">Images</label>
</div>
<div>
Output:
<label><input type="radio" v-model="output" value="h264">H.264</label>
<label><input type="radio" v-model="output" value="gif">GIF</label>
</div>
<div v-if="output == 'h264'">
<div v-if="input=='video' && audio">
Audio bitrate: <input v-model="audio_bitrate" style="width: 50px">
</div>
<div v-if="input=='images'">
<label>Frame rate: <input v-model="framerate" style="width: 50px"></label><br>
<label><input type="checkbox" v-model="concatenate"> I will concatenate this file with other video material</label> <span style="color: blue; font-weight: bold; cursor: default;" v-tooltip.right-start="'When concatenating several files, differing frame rates will lead to errors with FFmpeg.<br>My recommendation is in these cases to encode all files to the same, quite high, frame rate.<br>Doing so won\'t increase the file size because repeated frames don\'t take up any space.'">ⓘ</span><br>
<label v-if="concatenate">Output frame rate: <input v-model="output_framerate" style="width: 50px"></label>
</div>
<div>
How to set the quality: <span style="color: blue; font-weight: bold; cursor: default;" v-tooltip.right-start="'FFmpeg always encodes according to a Rate Factor that specifies the quality of the result.<br>Instead of directly specifying the Rate Factor, an average bit rate can be specified. FFmpeg will then determine the optimal Rate Factor in a first pass.<br>In fact the first pass is only used for determining the Rate Factor, no other data is carried over into the second pass.<br>Specifying an average bitrate but running only one pass is possible, but not recommended. FFmpeg would then encode the beginning of the video with a random Rate Factor and then change it near the end of the video to eventually reach the target bitrate.'">ⓘ</span><br>
<label><input type="radio" v-model="mode" value="CRF"> Manual rate factor</label><br>
<label><input type="radio" v-model="mode" value="ABR" disabled> Determine from target bitrate (2-Pass)</label>
</div>
<div v-if="mode == 'CRF'">
<label for="rf_slider">
Rate factor:
</label>
<span style="display: inline-block; width: 30px;" v-bind:style="{ color: rf != 0 && rf < 18 || rf > 28 ? 'orange' : ( rf == 23 ? 'blue' : 'green' ) }">{{ rf }}</span>
<table style="display: inline-table; vertical-align: middle;">
<tr>
<td style="font-size: 11px;">Lossless</td>
<td rowspan="2"><input id="rf_slider" v-model="rf" type="range" min="0" max="51" step="1"></td>
<td style="font-size: 11px;">Bad quality</td>
</tr>
<tr>
<td style="font-size: 11px;">Large file</td>
<td style="font-size: 11px;">Small file</td>
</tr>
</table>
</div>
<div>
<label>
Patience preset:
<select v-model="preset">
<option value="ultrafast">ultrafast</option>
<option value="superfast">superfast</option>
<option value="veryfast">veryfast</option>
<option value="faster">faster</option>
<option value="medium">medium</option>
<option value="slow">slow</option>
<option value="slower">slower</option>
<option value="veryslow">veryslow</option>
</select>
{{ presetinfo }}
</label>
</div>
<div>
Various optimizations:<br>
<label><input type="checkbox" v-model="seek"> Optimize for fast seeking (shorter keyframe interval, about 10% larger file)</label><br>
<label><input type="checkbox" v-model="tunings" value="film"> Input video is a high-quality movie</label><br>
<label><input type="checkbox" v-model="tunings" value="animation"> Input video is an animation movie</label><br>
<label><input type="checkbox" v-model="tunings" value="grain"> Input video contains film grain</label><br>
<label><input type="checkbox" v-model="tunings" value="stillimage"> Input video is an image slideshow</label><br>
<label><input type="checkbox" v-model="tunings" value="fastdecode"> Optimize for really weak CPU playback devices</label><br>
<label v-if="rf != 0"><input type="checkbox" v-model="profile"> Optimize for really old devices</label><br v-if="rf != 0">
<label><input type="checkbox" v-model="faststart"> Move headers to beginning of file (so it can play while still downloading)</label><br>
<label><input type="checkbox" v-model="limit"> Limit bitrate to <input v-model="limit_mbps" style="width: 50px" v-bind:disabled="!limit"> Mbit/s <span v-if="limit">(assuming a receiving buffer of <input v-model="limit_buffer" style="width: 50px" v-bind:disabled="!limit"> {{ limit_buffer == 1 ? 'second' : 'seconds' }})</span></label><br>
<label><input type="checkbox" v-model="tunings" value="zerolatency"> Fast encoding and low latency streaming</label><br>
</div>
<div>
Container:
<label><input type="radio" v-model="container" value="MP4">MP4</label>
<label><input type="radio" v-model="container" value="MKV">MKV</label>
</div>
<div v-if="mode=='ABR'">
The first pass creates a dummy file, what should it be called?
<label><input type="radio" v-model="dummyfile" value="output">use the output file</label>
<label><input type="radio" v-model="dummyfile" value="dummy"><code>"dummy"</code></label>
<label><input type="radio" v-model="dummyfile" value="/dev/null"><code>/dev/null</code> (Linux)</label>
<label><input type="radio" v-model="dummyfile" value="NUL"><code>NUL</code> (Windows)</label>
</div>
</div>
<div v-if="output == 'gif'">
<table><tr style="vertical-align: top;">
<td>Palette:</td>
<td><input type="radio" id="palette-faster" v-model="palette" value="faster"></td>
<td><label for="palette-faster">
Faster<br>
<span style="font-size: 12px;">Uses dithering to a standard palette provided by FFmpeg<br>
Can cause dithering artifacts and slight banding</span>
</label></td>
<td><input type="radio" id="palette-better" v-model="palette" value="better"></td>
<td><label for="palette-better">
Better<br>
<span style="font-size: 12px;">Determines an optimized palette for the video<br>
Uses two passes and a temporary file for the palette</span>
</label></td>
</tr></table>
</div>
<div>
<label><input type="checkbox" v-model="banner">Include FFmpeg build configuration in log output</label>
</div>
<br>
<b>Result:</b>
<pre style="margin: 0;"><code v-html="commandline" class="commandline"></code></pre>
<small v-if="input=='images'"><br>The example uses image filenames of the format <code>img001.jpg</code>.</small>
<small v-if="input=='video'"><br>The example uses <code>source.ext</code> as the imput video.</small>
</div>
<script src="https://unpkg.com/vue@2"></script>
<script src="https://unpkg.com/popper.js"></script>
<script src="https://unpkg.com/tooltip.js"></script>
<script src="https://unpkg.com/v-tooltip"></script>
<script type="text/javascript">
var app = new Vue({
el: '#mountpoint',
data: {
input: 'video',
output: 'h264',
framerate: 25,
mode: 'CRF',
rf: 23,
bitrate: 0,
preset: 'medium',
tunings: [],
container: 'MP4',
dummyfile: 'output',
profile: false,
limit: false,
limit_mbps: 1,
limit_buffer: 2,
audio: true,
audio_bitrate: 128,
banner: false,
faststart: true,
concatenate: false,
output_framerate: 25,
seek: true,
palette: 'faster'
},
computed: {
commandline: function() {
var opts = '';
if (this.input == 'video')
opts += '-i source.ext ';
if (this.input == 'images') {
opts += '-framerate ' + this.framerate + ' -i image%03d.jpg ';
if (this.concatenate && this.framerate != this.output_framerate) {
opts += '-r ' + this.output_framerate + ' ';
}
}
if (this.output == 'h264') {
opts += '<span title="Only necessary if the output filename does not end with .mp4">-c:v libx264</span> '; // necessary?
opts += '-preset ' + this.preset + ' ';
if (this.tunings.length) {
opts += '-tune ' + this.tunings.join(',') + ' ';
}
if (this.faststart)
opts += '-movflags faststart ';
if (this.input == 'video' && this.audio)
opts += '-c:a aac -b:a ' + this.audio_bitrate + 'k ';
if (this.profile && this.rf != 0)
opts += '-profile:v baseline -level 3.0 ';
if (this.limit)
opts += '-maxrate ' + this.limit_mbps + 'M -bufsize ' + (this.limit_mbps * this.limit_buffer) + 'M ';
if (this.seek)
opts += '<span title="Inserts an I-frame every 15 frames">-x264-params keyint=15</span> ';
opts += '<span title="Preserves the frame timestamps of VFR videos">-vsync 2 -enc_time_base -1</span> ';
if (this.mode == 'CRF') {
return 'ffmpeg ' + (!this.banner ? '-hide_banner ' : '') + opts + '-crf ' + this.rf + ' output.' + this.container.toLowerCase();
}
if (this.mode == 'ABR') {
var dummy = this.dummyfile;
if (this.dummyfile == 'output')
dummy = 'output.' + this.container.toLowerCase();
return 'ffmpeg ' + (!this.banner ? '-hide_banner ' : '') + '-y ' + opts + '-b:v ' + this.bitrate + ' -pass 1 -f mp4 ' + dummy + ' && ffmpeg ' + (!this.banner ? '-hide_banner ' : '') + opts + '-b:v ' + this.bitrate + ' -pass 2 output.' + this.container.toLowerCase();
}
}
if (this.output == 'gif') {
if (this.palette == 'faster') {
return 'ffmpeg ' + (!this.banner ? '-hide_banner ' : '') + opts + 'output.gif';
}
if (this.palette == 'better') {
return 'ffmpeg ' + (!this.banner ? '-hide_banner ' : '') + opts + '-vf palettegen palette.png && ffmpeg ' + (!this.banner ? '-hide_banner ' : '') + opts + '-i palette.png -filter_complex "[0:v][1:v] paletteuse" output.gif';
}
}
return "";
},
presetinfo: function() {
var mapping = {
ultrafast: '',
superfast: '',
veryfast: '',
faster: '',
fast: '',
medium: '(default)',
slow: '(about 5-10% smaller file than medium)',
slower: '(about 15% smaller file than medium)',
veryslow: '(about 17% smaller file than medium)'
};
return mapping[this.preset];
}
}
})
</script>
</body>
</html>