aboutsummaryrefslogtreecommitdiffhomepage
path: root/packages/ffmpeg/src/ffmpeg-images.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/ffmpeg/src/ffmpeg-images.ts')
-rw-r--r--packages/ffmpeg/src/ffmpeg-images.ts92
1 files changed, 92 insertions, 0 deletions
diff --git a/packages/ffmpeg/src/ffmpeg-images.ts b/packages/ffmpeg/src/ffmpeg-images.ts
new file mode 100644
index 000000000..4cd37aa80
--- /dev/null
+++ b/packages/ffmpeg/src/ffmpeg-images.ts
@@ -0,0 +1,92 @@
1import { FFmpegCommandWrapper, FFmpegCommandWrapperOptions } from './ffmpeg-command-wrapper.js'
2import { getVideoStreamDuration } from './ffprobe.js'
3
4export class FFmpegImage {
5 private readonly commandWrapper: FFmpegCommandWrapper
6
7 constructor (options: FFmpegCommandWrapperOptions) {
8 this.commandWrapper = new FFmpegCommandWrapper(options)
9 }
10
11 convertWebPToJPG (options: {
12 path: string
13 destination: string
14 }): Promise<void> {
15 const { path, destination } = options
16
17 this.commandWrapper.buildCommand(path)
18 .output(destination)
19
20 return this.commandWrapper.runCommand({ silent: true })
21 }
22
23 processGIF (options: {
24 path: string
25 destination: string
26 newSize: { width: number, height: number }
27 }): Promise<void> {
28 const { path, destination, newSize } = options
29
30 this.commandWrapper.buildCommand(path)
31 .fps(20)
32 .size(`${newSize.width}x${newSize.height}`)
33 .output(destination)
34
35 return this.commandWrapper.runCommand()
36 }
37
38 async generateThumbnailFromVideo (options: {
39 fromPath: string
40 output: string
41 }) {
42 const { fromPath, output } = options
43
44 let duration = await getVideoStreamDuration(fromPath)
45 if (isNaN(duration)) duration = 0
46
47 this.commandWrapper.buildCommand(fromPath)
48 .seekInput(duration / 2)
49 .videoFilter('thumbnail=500')
50 .outputOption('-frames:v 1')
51 .output(output)
52
53 return this.commandWrapper.runCommand()
54 }
55
56 async generateStoryboardFromVideo (options: {
57 path: string
58 destination: string
59
60 sprites: {
61 size: {
62 width: number
63 height: number
64 }
65
66 count: {
67 width: number
68 height: number
69 }
70
71 duration: number
72 }
73 }) {
74 const { path, destination, sprites } = options
75
76 const command = this.commandWrapper.buildCommand(path)
77
78 const filter = [
79 `setpts=N/round(FRAME_RATE)/TB`,
80 `select='not(mod(t,${options.sprites.duration}))'`,
81 `scale=${sprites.size.width}:${sprites.size.height}`,
82 `tile=layout=${sprites.count.width}x${sprites.count.height}`
83 ].join(',')
84
85 command.outputOption('-filter_complex', filter)
86 command.outputOption('-frames:v', '1')
87 command.outputOption('-q:v', '2')
88 command.output(destination)
89
90 return this.commandWrapper.runCommand()
91 }
92}