pwebm 0.1.0-alpha.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -5
- package/package.json +1 -1
- package/src/args.ts +5 -5
- package/src/ffmpeg.ts +8 -16
- package/src/schema/args.ts +1 -1
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ Utility to encode size restricted webm files with ffmpeg.
|
|
|
4
4
|
|
|
5
5
|
When executed multiple times, the additional encoding requests will be put inside a queue that will be handled in the first instance that was executed.
|
|
6
6
|
|
|
7
|
-
When not specified, the output file name will be the current unix timestamp (with 13 digits plus 3 random additional ones, e.g.: `1741140729397902.webm`), and saved in `~/Movies/pwebm/` (
|
|
7
|
+
When not specified, the output file name will be the current unix timestamp (with 13 digits plus 3 random additional ones, e.g.: `1741140729397902.webm`), and saved in `~/Movies/pwebm/` (macOS) or `~/Videos/pwebm/` (all others).
|
|
8
8
|
|
|
9
9
|
# Installation
|
|
10
10
|
|
|
@@ -29,7 +29,7 @@ bun i -g git+https://github.com/4ndrs/pwebm.git
|
|
|
29
29
|
|
|
30
30
|
In 2022, I wrote a script for the mpv media player called [PureMPV](https://github.com/4ndrs/PureMPV) that would help extracting the currently watched video's information, like the timestamps at certain points, and the cropping coordinates, which would then later be used for encoding videos with ffmpeg with specific parameters.
|
|
31
31
|
|
|
32
|
-
Up to that point, I mostly spent the time encoding short webm files to keep and share on some imageboards, as well as encoding some mkv files with streams and attachments copied, so I wanted to integrate this functionality in some way with PureMPV. I didn't like the idea of having PureMPV to do the encoding itself, I wanted a
|
|
32
|
+
Up to that point, I mostly spent the time encoding short webm files to keep and share on some imageboards, as well as encoding some mkv files with streams and attachments copied, so I wanted to integrate this functionality in some way with PureMPV. I didn't like the idea of having PureMPV to do the encoding itself, I wanted a separate process to handle this independently, so I could stop or start another mpv window without affecting the encoding process. I wrote down some of the initial requirements at the time, which were the following:
|
|
33
33
|
|
|
34
34
|
- Encoding webm files with size limits (first crf mode, then bitrate mode on retries)
|
|
35
35
|
- Having a queue for handling multiple encodings
|
|
@@ -63,7 +63,7 @@ The script has different arguments that can be used to customize the encoding pr
|
|
|
63
63
|
|-to| The end time of the segment to encode|
|
|
64
64
|
|-c:v| The video codec to use. Default is **libvpx-vp9**|
|
|
65
65
|
|-crf| The Constant Rate Factor to use. Default is **24**|
|
|
66
|
-
|-
|
|
66
|
+
|-vf| The set of video filters to pass to ffmpeg|
|
|
67
67
|
|-deadline| The deadline passed to ffmpeg for libvpx-vp9. Default is **good**|
|
|
68
68
|
|-cpu-used|The cpu-used passed to ffmpeg for libvpx-vp9. Default is **0**|
|
|
69
69
|
|-subs| Burn the subtitles|
|
|
@@ -71,9 +71,9 @@ The script has different arguments that can be used to customize the encoding pr
|
|
|
71
71
|
|--video-path| The path to save the video files. Default is **~/Movies/pwebm/** on macOs, and **~/Videos/pwebm/** on everything else|
|
|
72
72
|
|-ep, --extra-params| Extra parameters to pass to ffmpeg|
|
|
73
73
|
|
|
74
|
-
If the codec option `c:v` is set to `libvpx` for v8 webms, or `libvpx-vp9` for vp9 webms, the script will generate a webm with the
|
|
74
|
+
If the codec option `c:v` is set to `libvpx` for v8 webms, or `libvpx-vp9` for vp9 webms, the script will generate a webm with the chosen options and size limit in MiB. If the codec is set to anything else, the script will generate an mkv file with all streams copied, including the attachments, and re-encode the video stream with the chosen crf; no size limitations will be applied here.
|
|
75
75
|
|
|
76
|
-
The `subs` option will only trigger on webms, burning the subtitles onto the video stream. The internal implementation of this option is just picking the first input file's subtitles, and applying the subtitle filter to the resulting output. If you need to pick subtitles in a different file, you can use the `-
|
|
76
|
+
The `subs` option will only trigger on webms, burning the subtitles onto the video stream. The internal implementation of this option is just picking the first input file's subtitles, and applying the subtitle filter to the resulting output. If you need to pick subtitles in a different file, you can use the `-vf` option to pass the subtitles filter manually for now.
|
|
77
77
|
|
|
78
78
|
>[!NOTE]
|
|
79
79
|
>The `subs` option doesn't work with input seeking. If you need to seek, make sure you are using output seeking, otherwise the resulting webm will have the subtitles burned at the wrong time.
|
package/package.json
CHANGED
package/src/args.ts
CHANGED
|
@@ -22,7 +22,7 @@ const RECOGNIZED_ARGS = [
|
|
|
22
22
|
"-i",
|
|
23
23
|
"-ss",
|
|
24
24
|
"-to",
|
|
25
|
-
"-
|
|
25
|
+
"-vf",
|
|
26
26
|
"-c:v",
|
|
27
27
|
"-deadline",
|
|
28
28
|
"-crf",
|
|
@@ -53,7 +53,7 @@ Options:
|
|
|
53
53
|
-i <input> The input file to encode
|
|
54
54
|
-ss <start_time> The start time (same as ffmpeg's -ss)
|
|
55
55
|
-to <stop_time> The stop time (same as ffmpeg's -to)
|
|
56
|
-
-
|
|
56
|
+
-vf <filters> The set of video filters to pass to ffmpeg
|
|
57
57
|
-c:v <encoder> The video encoder to use (default is ${config.encoder})
|
|
58
58
|
-deadline {good,best} The deadline for libvpx-vp9; good is the recommended one, best has the best
|
|
59
59
|
compression efficiency but takes the most time (default is ${config.deadline})
|
|
@@ -62,7 +62,7 @@ Options:
|
|
|
62
62
|
the number the faster the encoding will be with a quality trade-off (default is ${config.cpuUsed})
|
|
63
63
|
-subs Burn the subtitles onto the output file; this flag will automatically use
|
|
64
64
|
the subtitles found in the first input file, to use a different file use
|
|
65
|
-
the -
|
|
65
|
+
the -vf flag with the subtitles filter directly
|
|
66
66
|
-sl, --size-limit <limit> The size limit of the output file in MiB, use 0 for no limit (default is ${config.sizeLimit})
|
|
67
67
|
--video-path <path> The video path where the video files are stored (default is ${config.videoPath})
|
|
68
68
|
this is overridden if the output file is specified
|
|
@@ -400,14 +400,14 @@ for (let index = 0; index < argv.length; index++) {
|
|
|
400
400
|
continue;
|
|
401
401
|
}
|
|
402
402
|
|
|
403
|
-
if (arg === "-
|
|
403
|
+
if (arg === "-vf") {
|
|
404
404
|
if (argv[index + 1] === undefined || argv[index + 1].startsWith("-")) {
|
|
405
405
|
logMissingArg(arg);
|
|
406
406
|
|
|
407
407
|
process.exit(1);
|
|
408
408
|
}
|
|
409
409
|
|
|
410
|
-
rawArgs.
|
|
410
|
+
rawArgs.vf = argv[index + 1];
|
|
411
411
|
|
|
412
412
|
skipNext();
|
|
413
413
|
|
package/src/ffmpeg.ts
CHANGED
|
@@ -48,7 +48,7 @@ const encode = async (args: ArgsSchema) => {
|
|
|
48
48
|
outputSeeking.push("-to", args.output.stopTime);
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
const
|
|
51
|
+
const vf = args.vf ? ["-vf", args.vf] : [];
|
|
52
52
|
const extraParams = args.extraParams || [];
|
|
53
53
|
|
|
54
54
|
const encoder = args.extraParams?.includes("-c:v")
|
|
@@ -90,7 +90,7 @@ const encode = async (args: ArgsSchema) => {
|
|
|
90
90
|
args.encoder,
|
|
91
91
|
"-crf",
|
|
92
92
|
args.crf.toString(),
|
|
93
|
-
...
|
|
93
|
+
...vf,
|
|
94
94
|
"-b:v",
|
|
95
95
|
"0",
|
|
96
96
|
"-preset",
|
|
@@ -194,10 +194,10 @@ const encode = async (args: ArgsSchema) => {
|
|
|
194
194
|
// this won't work with input seeking since they will be de-synced
|
|
195
195
|
const subtitles = `subtitles=${escapeSpecialCharacters(args.inputs[0].file)}`;
|
|
196
196
|
|
|
197
|
-
if (args.subs && args.
|
|
198
|
-
|
|
197
|
+
if (args.subs && args.vf) {
|
|
198
|
+
vf[1] += "," + subtitles;
|
|
199
199
|
} else if (args.subs) {
|
|
200
|
-
|
|
200
|
+
vf.push("-vf", subtitles);
|
|
201
201
|
}
|
|
202
202
|
|
|
203
203
|
// we don't want any of these
|
|
@@ -224,7 +224,7 @@ const encode = async (args: ArgsSchema) => {
|
|
|
224
224
|
args.deadline,
|
|
225
225
|
"-cpu-used",
|
|
226
226
|
args.cpuUsed.toString(),
|
|
227
|
-
...
|
|
227
|
+
...vf,
|
|
228
228
|
"-b:v",
|
|
229
229
|
"0",
|
|
230
230
|
"-row-mt",
|
|
@@ -613,18 +613,10 @@ const deduceDuration = async (args: ArgsSchema) => {
|
|
|
613
613
|
// the duration is only used for bitrate calculation for size limited
|
|
614
614
|
// webms and the percentage that is shown during the encoding process
|
|
615
615
|
|
|
616
|
-
// no output seeking, let's just pick the longest
|
|
617
|
-
// with the input seeking times or duration of the input metadata
|
|
618
|
-
if (!args.lavfi?.includes("concat")) {
|
|
619
|
-
const durations = getInputDurations(args.inputs, metadata);
|
|
620
|
-
|
|
621
|
-
return Math.max(...durations);
|
|
622
|
-
}
|
|
623
|
-
|
|
624
|
-
// if lavfi concat is used, let's sum the durations of the inputs
|
|
616
|
+
// no output seeking, let's just pick the longest
|
|
625
617
|
const durations = getInputDurations(args.inputs, metadata);
|
|
626
618
|
|
|
627
|
-
return
|
|
619
|
+
return Math.max(...durations);
|
|
628
620
|
};
|
|
629
621
|
|
|
630
622
|
const getInputDurations = (
|
package/src/schema/args.ts
CHANGED
|
@@ -19,7 +19,7 @@ export const ArgsSchema = ConfigSchema.merge(
|
|
|
19
19
|
startTime: z.string().optional(),
|
|
20
20
|
})
|
|
21
21
|
.optional(),
|
|
22
|
-
|
|
22
|
+
vf: z.string().optional(),
|
|
23
23
|
extraParams: z.array(z.string()).optional(),
|
|
24
24
|
// the next ones come from the config schema
|
|
25
25
|
// we are just replacing the defaults with the values loaded from the config file
|