Skip to content

Commit bc60c67

Browse files
authored
Add support for HEVC, use ffmpeg-static (#1021)
1 parent 45a7a52 commit bc60c67

File tree

18 files changed

+168
-82
lines changed

18 files changed

+168
-82
lines changed

main/common/constants.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@ import {Format} from './types';
33
export const supportedVideoExtensions = ['mp4', 'mov', 'm4v'];
44

55
const formatExtensions = new Map([
6-
['av1', 'mp4']
6+
['av1', 'mp4'],
7+
['hevc', 'mp4']
78
]);
89

9-
export const formats = [Format.mp4, Format.av1, Format.gif, Format.apng, Format.webm];
10+
export const formats = [Format.mp4, Format.hevc, Format.av1, Format.gif, Format.apng, Format.webm];
1011

1112
export const getFormatExtension = (format: Format) => formatExtensions.get(format) ?? format;
1213

1314
export const defaultInputDeviceId = 'SYSTEM_DEFAULT';
14-

main/common/types/base.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import {Rectangle} from 'electron';
22

33
export enum Format {
44
gif = 'gif',
5+
hevc = 'hevc',
56
mp4 = 'mp4',
67
webm = 'webm',
78
apng = 'apng',

main/converters/h264.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,38 @@ const convertToAv1 = (options: ConvertOptions) => convert(options.outputPath, {
204204
options.outputPath
205205
));
206206

207+
// eslint-disable-next-line @typescript-eslint/promise-function-async
208+
const convertToHevc = (options: ConvertOptions) => convert(options.outputPath, {
209+
onProgress: (progress, estimate) => {
210+
options.onProgress('Converting', progress, estimate);
211+
},
212+
startTime: options.startTime,
213+
endTime: options.endTime
214+
}, conditionalArgs(
215+
'-i', options.inputPath,
216+
'-r', options.fps.toString(),
217+
'-c:v', 'libx265',
218+
'-c:a', 'libopus',
219+
'-preset', 'medium',
220+
'-tag:v', 'hvc1', // Metadata for macOS
221+
{
222+
args: ['-an'],
223+
if: options.shouldMute
224+
},
225+
{
226+
args: [
227+
'-s',
228+
`${makeEven(options.width)}x${makeEven(options.height)}`,
229+
'-ss',
230+
options.startTime.toString(),
231+
'-to',
232+
options.endTime.toString()
233+
],
234+
if: options.shouldCrop || !areDimensionsEven(options)
235+
},
236+
options.outputPath
237+
));
238+
207239
// eslint-disable-next-line @typescript-eslint/promise-function-async
208240
const convertToApng = (options: ConvertOptions) => convert(options.outputPath, {
209241
onProgress: (progress, estimate) => {
@@ -250,6 +282,7 @@ export const crop = (options: ConvertOptions) => convert(options.outputPath, {
250282
export default new Map([
251283
[Format.gif, convertToGif],
252284
[Format.mp4, convertToMp4],
285+
[Format.hevc, convertToHevc],
253286
[Format.webm, convertToWebm],
254287
[Format.apng, convertToApng],
255288
[Format.av1, convertToAv1]

main/converters/process.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,9 @@ import {track} from '../common/analytics';
99
import {conditionalArgs, extractProgressFromStderr} from './utils';
1010
import {settings} from '../common/settings';
1111

12-
const ffmpeg = require('@ffmpeg-installer/ffmpeg');
13-
const gifsicle = require('gifsicle');
12+
import ffmpegPath from '../utils/ffmpeg-path';
1413

15-
const ffmpegPath = util.fixPathForAsarUnpack(ffmpeg.path);
14+
const gifsicle = require('gifsicle');
1615
const gifsiclePath = util.fixPathForAsarUnpack(gifsicle);
1716

1817
enum Mode {

main/plugins/built-in/open-with-plugin.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ const getAppsForFormat = (format: Format) => {
3030
});
3131
};
3232

33-
const appsForFormat = (['mp4', 'gif', 'apng', 'webm', 'av1'] as Format[])
33+
const appsForFormat = (['mp4', 'gif', 'apng', 'webm', 'av1', 'hevc'] as Format[])
3434
.map(format => ({
3535
format,
3636
apps: getAppsForFormat(format)
@@ -44,4 +44,3 @@ export const shareServices = [{
4444
formats: [...apps.keys()],
4545
action
4646
}];
47-

main/plugins/built-in/save-file-plugin.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ const saveFile = {
4141
'mp4',
4242
'webm',
4343
'apng',
44-
'av1'
44+
'av1',
45+
'hevc'
4546
],
4647
action
4748
};
@@ -53,7 +54,8 @@ const filterMap = new Map([
5354
[Format.webm, [{name: 'Movies', extensions: ['webm']}]],
5455
[Format.gif, [{name: 'Images', extensions: ['gif']}]],
5556
[Format.apng, [{name: 'Images', extensions: ['apng']}]],
56-
[Format.av1, [{name: 'Movies', extensions: ['mp4']}]]
57+
[Format.av1, [{name: 'Movies', extensions: ['mp4']}]],
58+
[Format.hevc, [{name: 'Movies', extensions: ['mp4']}]]
5759
]);
5860

5961
let lastSavedDirectory: string;
@@ -83,4 +85,3 @@ export const askForTargetFilePath = async (
8385

8486
return undefined;
8587
};
86-

main/recording-history.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import {shell, clipboard} from 'electron';
55
import fs from 'fs';
66
import Store from 'electron-store';
7-
import util from 'electron-util';
87
import execa from 'execa';
98
import tempy from 'tempy';
109
import {SetOptional} from 'type-fest';
@@ -16,8 +15,7 @@ import {Video} from './video';
1615
import {ApertureOptions} from './common/types';
1716
import Sentry, {isSentryEnabled} from './utils/sentry';
1817

19-
const ffmpeg = require('@ffmpeg-installer/ffmpeg');
20-
const ffmpegPath = util.fixPathForAsarUnpack(ffmpeg.path);
18+
import ffmpegPath from './utils/ffmpeg-path';
2119

2220
export interface PastRecording {
2321
filePath: string;

main/remote-states/editor-options.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,10 @@ import {prettifyFormat} from '../utils/formats';
99
const exportUsageHistory = new Store<{[key in Format]: {lastUsed: number; plugins: Record<string, number>}}>({
1010
name: 'export-usage-history',
1111
defaults: {
12-
gif: {lastUsed: 5, plugins: {default: 1}},
13-
mp4: {lastUsed: 4, plugins: {default: 1}},
14-
webm: {lastUsed: 3, plugins: {default: 1}},
12+
gif: {lastUsed: 6, plugins: {default: 1}},
13+
mp4: {lastUsed: 5, plugins: {default: 1}},
14+
webm: {lastUsed: 4, plugins: {default: 1}},
15+
hevc: {lastUsed: 3, plugins: {default: 1}},
1516
av1: {lastUsed: 2, plugins: {default: 1}},
1617
apng: {lastUsed: 1, plugins: {default: 1}}
1718
}
@@ -44,6 +45,11 @@ const fpsUsageHistory = new Store<{[key in Format]: number}>({
4445
type: 'number',
4546
minimum: 0,
4647
default: 60
48+
},
49+
hevc: {
50+
type: 'number',
51+
minimum: 0,
52+
default: 60
4753
}
4854
}
4955
});

main/utils/encoding.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
11
/* eslint-disable array-element-newline */
22

33
import path from 'path';
4-
import util from 'electron-util';
54
import execa from 'execa';
65
import tempy from 'tempy';
76
import {track} from '../common/analytics';
8-
9-
const ffmpeg = require('@ffmpeg-installer/ffmpeg');
10-
const ffmpegPath = util.fixPathForAsarUnpack(ffmpeg.path);
7+
import ffmpegPath from './ffmpeg-path';
118

129
export const getEncoding = async (filePath: string) => {
1310
try {

main/utils/ffmpeg-path.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import ffmpeg from 'ffmpeg-static';
2+
import util from 'electron-util';
3+
4+
const ffmpegPath = util.fixPathForAsarUnpack(ffmpeg);
5+
6+
export default ffmpegPath;

0 commit comments

Comments
 (0)