-
Notifications
You must be signed in to change notification settings - Fork 4
/
video-thumb.js
92 lines (81 loc) · 3.4 KB
/
video-thumb.js
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
const ffmpeg = require("fluent-ffmpeg");
const ThumbnailSupplier = require("../thumb.js");
function ratioStringToParts(str) {
return str.split(":").map(n => parseInt(n, 10));
}
class VideoThumbnailSupplier extends ThumbnailSupplier {
constructor(options) {
super(options);
this.timestamp = options.timestamp || "10%";
}
createThumbnail(video) {
return new Promise((resolve, reject) => {
this.getVideoDimension(video)
.then(this.getOptimalThumbnailResolution.bind(this))
.then(res => {
ffmpeg(video)
.on("end", () => resolve(super.getThumbnailLocation(video)))
.on("error", reject)
.screenshots({
size: `${res.width}x${res.height}`,
timestamps: [this.timestamp],
filename: ThumbnailSupplier.getThumbnailFileName(video),
folder: this.cacheDir
});
})
.catch(err => {
ffmpeg(video)
.on("end", () => resolve(super.getThumbnailLocation(video)))
.on("error", reject)
.screenshots({
size: `${this.size.width}x${this.size.height}`,
timestamps: [this.timestamp],
filename: ThumbnailSupplier.getThumbnailFileName(video),
folder: this.cacheDir
});
});
});
}
getVideoDimension(video) {
return new Promise((resolve, reject) => {
ffmpeg.ffprobe(video, (err, metadata) => {
if (err) return reject(err);
const stream = metadata.streams.find(
stream => stream.codec_type === "video"
);
const darString = stream.display_aspect_ratio;
// ffprobe returns aspect ratios of "0:1" or `undefined` if they're not specified.
// https://trac.ffmpeg.org/ticket/3798
if (darString && darString !== "0:1") {
// The DAR is specified so use it directly
const [widthRatioPart, heightRatioPart] = ratioStringToParts(darString);
const inverseDar = heightRatioPart / widthRatioPart;
resolve({
width: stream.width,
height: stream.width * inverseDar
});
} else {
// DAR not specified so assume square pixels (use sample resolution as-is).
resolve({
width: stream.width,
height: stream.height
});
}
});
});
}
getOptimalThumbnailResolution(videoDimension) {
if(videoDimension.width > videoDimension.height) {
return {
width: this.size.width,
height: Math.round(this.size.width * videoDimension.height / videoDimension.width)
}
} else {
return {
width: Math.round(this.size.height * videoDimension.width / videoDimension.height),
height: this.size.height
}
}
}
}
module.exports = VideoThumbnailSupplier;