From f27d44168a63eb57349f38562ecc7b6da15783b6 Mon Sep 17 00:00:00 2001 From: Mikael Finstad Date: Mon, 26 Oct 2020 21:50:50 +0100 Subject: [PATCH] fix resizeMode cover issue with on resolutions (do calculations in JS instead of ffmpeg) --- examples/pip.json5 | 4 ++-- sources/videoFrameSource.js | 44 +++++++++++++++++++++++++------------ 2 files changed, 32 insertions(+), 16 deletions(-) diff --git a/examples/pip.json5 b/examples/pip.json5 index 94ae112..9d0043a 100644 --- a/examples/pip.json5 +++ b/examples/pip.json5 @@ -1,14 +1,14 @@ { outPath: './pip.mp4', width: 1280, height: 720, fps: 30, - enableFfmpegLog: true, defaults: { layer: { fontPath: './assets/Patua_One/PatuaOne-Regular.ttf' }, }, clips: [ { duration: 4, layers: [ { type: 'rainbow-colors' }, - { type: 'video', path: './assets/tungestolen.mp4', resizeMode: 'contain', width: 0.4, height: 0.4, top: 0.05, left: 0.95, originY: 'top', originX: 'right' }, + { type: 'video', path: './assets/tungestolen.mp4', resizeMode: 'cover', width: 0.3, height: 0.4, top: 0.05, left: 0.95, originY: 'top', originX: 'right' }, + { type: 'video', path: './assets/tungestolen.mp4', resizeMode: 'cover', width: 0.4, height: 0.2, top: 0.05, left: 0.05, originY: 'top', originX: 'left' }, { type: 'title', position: 'bottom', text: 'Picture-in-Picture' } ] }, ], diff --git a/sources/videoFrameSource.js b/sources/videoFrameSource.js index 95ceb2f..b6bf76a 100644 --- a/sources/videoFrameSource.js +++ b/sources/videoFrameSource.js @@ -14,14 +14,15 @@ module.exports = async ({ width: canvasWidth, height: canvasHeight, channels, fr const left = leftRel * canvasWidth; const top = topRel * canvasHeight; + const ratioW = requestedWidth / inputWidth; + const ratioH = requestedHeight / inputHeight; + const inputAspectRatio = inputWidth / inputHeight; + let targetWidth = requestedWidth; let targetHeight = requestedHeight; + let scaleFilter; if (['contain', 'contain-blur'].includes(resizeMode)) { - const ratioW = requestedWidth / inputWidth; - const ratioH = requestedHeight / inputHeight; - const inputAspectRatio = inputWidth / inputHeight; - if (ratioW > ratioH) { targetHeight = requestedHeight; targetWidth = Math.round(requestedHeight * inputAspectRatio); @@ -29,15 +30,27 @@ module.exports = async ({ width: canvasWidth, height: canvasHeight, channels, fr targetWidth = requestedWidth; targetHeight = Math.round(requestedWidth / inputAspectRatio); } - } - const frameByteSize = targetWidth * targetHeight * channels; + scaleFilter = `scale=${targetWidth}:${targetHeight}`; + } else if (resizeMode === 'cover') { + let scaledWidth; + let scaledHeight; - // TODO assert that we have read the correct amount of frames + if (ratioW > ratioH) { + scaledWidth = requestedWidth; + scaledHeight = Math.round(requestedWidth / inputAspectRatio); + } else { + scaledHeight = requestedHeight; + scaledWidth = Math.round(requestedHeight * inputAspectRatio); + } - const buf = Buffer.allocUnsafe(frameByteSize); - let length = 0; - // let inFrameCount = 0; + // TODO improve performance by crop first, then scale? + scaleFilter = `scale=${scaledWidth}:${scaledHeight},crop=${targetWidth}:${targetHeight}`; + } else { // 'stretch' + scaleFilter = `scale=${targetWidth}:${targetHeight}`; + } + + if (verbose) console.log(scaleFilter); let ptsFilter = ''; if (speedFactor !== 1) { @@ -45,10 +58,13 @@ module.exports = async ({ width: canvasWidth, height: canvasHeight, channels, fr ptsFilter = `setpts=${speedFactor}*PTS,`; } - let scaleFilter; - if (['stretch', 'contain', 'contain-blur'].includes(resizeMode)) scaleFilter = `scale=${targetWidth}:${targetHeight}`; - // Cover: https://unix.stackexchange.com/a/192123 - else scaleFilter = `scale=(iw*sar)*max(${targetWidth}/(iw*sar)\\,${targetHeight}/ih):ih*max(${targetWidth}/(iw*sar)\\,${targetHeight}/ih),crop=${targetWidth}:${targetHeight}`; + const frameByteSize = targetWidth * targetHeight * channels; + + // TODO assert that we have read the correct amount of frames + + const buf = Buffer.allocUnsafe(frameByteSize); + let length = 0; + // let inFrameCount = 0; // https://forum.unity.com/threads/settings-for-importing-a-video-with-an-alpha-channel.457657/ const streams = await readFileStreams(ffprobePath, path);