From ef54e1b29fabbaf6a628dc3e140a03abc001f64a Mon Sep 17 00:00:00 2001 From: Mikael Finstad Date: Mon, 21 May 2018 00:56:27 +0200 Subject: [PATCH] Allow pre-formatting or pre-encoding the video for more format support Will still cut in original file. --- src/ffmpeg.js | 22 ++++++++++++++++++++++ src/menu.js | 12 ++++++++++++ src/renderer.jsx | 37 +++++++++++++++++++++++++++++-------- 3 files changed, 63 insertions(+), 8 deletions(-) diff --git a/src/ffmpeg.js b/src/ffmpeg.js index f7ccfadf..025ae710 100644 --- a/src/ffmpeg.js +++ b/src/ffmpeg.js @@ -92,6 +92,27 @@ async function cut({ return util.transferTimestamps(filePath, outPath); } +async function html5ify(filePath, outPath, encodeVideo) { + console.log('Making HTML5 friendly version', { filePath, outPath, encodeVideo }); + + const videoArgs = encodeVideo + ? ['-vf', 'scale=-2:400,format=yuv420p', '-sws_flags', 'neighbor', '-vcodec', 'libx264', '-profile:v', 'baseline', '-x264opts', 'level=3.0', '-preset:v', 'ultrafast', '-crf', '28'] + : ['-vcodec', 'copy']; + + const ffmpegArgs = [ + '-i', filePath, ...videoArgs, '-an', + '-y', + outPath, + ]; + + console.log('ffmpeg', ffmpegArgs.join(' ')); + + const ffmpegPath = await getFfmpegPath(); + const process = execa(ffmpegPath, ffmpegArgs); + const result = await process; + console.log(result.stdout); +} + /** * ffmpeg only supports encoding certain formats, and some of the detected input * formats are not the same as the names used for encoding. @@ -145,4 +166,5 @@ module.exports = { cut, getFormat, showFfmpegFail, + html5ify, }; diff --git a/src/menu.js b/src/menu.js index 3fee38d1..cae239ac 100644 --- a/src/menu.js +++ b/src/menu.js @@ -25,6 +25,18 @@ module.exports = (app, mainWindow, newVersion) => { }); }, }, + { + label: 'Convert to friendly format (fast)', + click() { + mainWindow.webContents.send('html5ify', false); + }, + }, + { + label: 'Convert to friendly codec (slow)', + click() { + mainWindow.webContents.send('html5ify', true); + }, + }, ], }); diff --git a/src/renderer.jsx b/src/renderer.jsx index 7aeab987..33f8f708 100644 --- a/src/renderer.jsx +++ b/src/renderer.jsx @@ -85,6 +85,7 @@ class App extends React.Component { const defaultState = { working: false, filePath: '', // Setting video src="" prevents memory leak in chromium + html5FriendlyPath: undefined, playing: false, currentTime: undefined, duration: undefined, @@ -95,6 +96,7 @@ class App extends React.Component { fileFormat: undefined, captureFormat: 'jpeg', rotation: 360, + cutProgress: undefined, }; this.state = _.cloneDeep(defaultState); @@ -106,8 +108,8 @@ class App extends React.Component { this.setState(defaultState); }; - const load = (filePath) => { - console.log('Load', filePath); + const load = (filePath, html5FriendlyPath) => { + console.log('Load', { filePath, html5FriendlyPath }); if (this.state.working) return alert('I\'m busy'); resetState(); @@ -120,7 +122,7 @@ class App extends React.Component { .then((fileFormat) => { if (!fileFormat) return alert('Unsupported file'); setFileNameTitle(filePath); - return this.setState({ filePath, fileFormat }); + return this.setState({ filePath, html5FriendlyPath, fileFormat }); }) .catch((err) => { if (err.code === 1 || err.code === 'ENOENT') { @@ -137,6 +139,23 @@ class App extends React.Component { load(filePaths[0]); }); + electron.ipcRenderer.on('html5ify', async (event, encodeVideo) => { + const { filePath, customOutDir } = this.state; + if (!filePath) return; + + try { + this.setState({ working: true }); + const html5ifiedPath = util.getOutPath(customOutDir, filePath, 'html5ified.mp4'); + await ffmpeg.html5ify(filePath, html5ifiedPath, encodeVideo); + this.setState({ working: false }); + load(filePath, html5ifiedPath); + } catch (err) { + alert('Failed to html5ify file'); + console.error('Failed to html5ify file', err); + this.setState({ working: false }); + } + }); + document.ondragover = document.ondragend = ev => ev.preventDefault(); document.body.ondrop = (ev) => { @@ -194,7 +213,7 @@ class App extends React.Component { } getFileUri() { - return (this.state.filePath || '').replace(/#/g, '%23'); + return (this.state.html5FriendlyPath || this.state.filePath || '').replace(/#/g, '%23'); } getOutputDir() { @@ -275,7 +294,7 @@ class App extends React.Component { return video.play().catch((err) => { console.log(err); if (err.name === 'NotSupportedError') { - alert('This video format is not supported, maybe you can re-format the file first using ffmpeg'); + alert('This video format or codec is not supported. Try to convert it to a friendly format/codec in the player from the "File" menu.'); } }); } @@ -380,9 +399,11 @@ class App extends React.Component { {this.state.working && (
- - {Math.floor((this.state.cutProgress || 0) * 100)} % - + {this.state.cutProgress != null && + + {Math.floor(this.state.cutProgress * 100)} % + + }
)}