From dd2cc9001529fd7c2ef85aa8e38ee14c4855fa9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Beno=C3=AEt?= Date: Sun, 5 May 2024 22:07:19 +0300 Subject: [PATCH 1/5] feat: add "loop" video option --- cli.js | 0 index.d.ts | 2 ++ parseConfig.js | 12 ++++++++---- sources/videoFrameSource.js | 6 ++++-- 4 files changed, 14 insertions(+), 6 deletions(-) mode change 100644 => 100755 cli.js diff --git a/cli.js b/cli.js old mode 100644 new mode 100755 diff --git a/index.d.ts b/index.d.ts index 6895c815..d24cd25a 100644 --- a/index.d.ts +++ b/index.d.ts @@ -321,6 +321,8 @@ declare namespace Editly { */ cutFrom?: number; + loop?: boolean; + /** * Time value to cut to (in seconds). * Defaults to *end of video*. diff --git a/parseConfig.js b/parseConfig.js index cbdf5811..41b34dde 100644 --- a/parseConfig.js +++ b/parseConfig.js @@ -135,9 +135,10 @@ export default async function parseConfig({ defaults: defaultsIn = {}, clips, ar const thisLayerDefaults = (defaults.layerType || {})[layerIn.type]; const layer = { ...globalLayerDefaults, ...thisLayerDefaults, ...layerIn }; - const { type, path } = layer; + const { type, path, loop } = layer; if (type === 'video') { + const { duration: fileDuration, width: widthIn, height: heightIn, framerateStr, rotation } = await readVideoFileInfo(ffprobePath, path); let { cutFrom, cutTo } = layer; if (!cutFrom) cutFrom = 0; @@ -155,7 +156,7 @@ export default async function parseConfig({ defaults: defaultsIn = {}, clips, ar const inputWidth = isRotated ? heightIn : widthIn; const inputHeight = isRotated ? widthIn : heightIn; - return { ...layer, cutFrom, cutTo, inputDuration, framerateStr, inputWidth, inputHeight }; + return { ...layer, cutFrom, cutTo, inputDuration, framerateStr, inputWidth, inputHeight, loop }; } // Audio is handled later @@ -205,12 +206,15 @@ export default async function parseConfig({ defaults: defaultsIn = {}, clips, ar } if (type === 'video') { - const { inputDuration } = layer; + const { inputDuration, loop } = layer; + console.log('loop: ', loop); let speedFactor; // If user explicitly specified duration for clip, it means that should be the output duration of the video - if (userClipDuration) { + if (loop){ + speedFactor = 1; + } else if (userClipDuration) { // Later we will speed up or slow down video using this factor speedFactor = userClipDuration / inputDuration; } else { diff --git a/sources/videoFrameSource.js b/sources/videoFrameSource.js index d3a55e41..0a6e51e6 100644 --- a/sources/videoFrameSource.js +++ b/sources/videoFrameSource.js @@ -10,7 +10,7 @@ import { } from './fabric.js'; export default async ({ width: canvasWidth, height: canvasHeight, channels, framerateStr, verbose, logTimes, ffmpegPath, ffprobePath, enableFfmpegLog, params }) => { - const { path, cutFrom, cutTo, resizeMode = 'contain-blur', speedFactor, inputWidth, inputHeight, width: requestedWidthRel, height: requestedHeightRel, left: leftRel = 0, top: topRel = 0, originX = 'left', originY = 'top', fabricImagePostProcessing = null } = params; + const { path, cutFrom, cutTo, resizeMode = 'contain-blur', speedFactor, inputWidth, inputHeight, width: requestedWidthRel, height: requestedHeightRel, left: leftRel = 0, top: topRel = 0, originX = 'left', originY = 'top', fabricImagePostProcessing = null, loop } = params; const requestedWidth = requestedWidthRel ? Math.round(requestedWidthRel * canvasWidth) : canvasWidth; const requestedHeight = requestedHeightRel ? Math.round(requestedHeightRel * canvasHeight) : canvasHeight; @@ -83,12 +83,14 @@ export default async ({ width: canvasWidth, height: canvasHeight, channels, fram // http://zulko.github.io/blog/2013/09/27/read-and-write-video-frames-in-python-using-ffmpeg/ // Testing: ffmpeg -i 'vid.mov' -t 1 -vcodec rawvideo -pix_fmt rgba -f image2pipe - | ffmpeg -f rawvideo -vcodec rawvideo -pix_fmt rgba -s 2166x1650 -i - -vf format=yuv420p -vcodec libx264 -y out.mp4 // https://trac.ffmpeg.org/wiki/ChangingFrameRate + const args = [ ...getFfmpegCommonArgs({ enableFfmpegLog }), ...(inputCodec ? ['-vcodec', inputCodec] : []), ...(cutFrom ? ['-ss', cutFrom] : []), + ...(loop ? ['-stream_loop','-1'] : []), '-i', path, - ...(cutTo ? ['-t', (cutTo - cutFrom) * speedFactor] : []), + ...(cutTo && !loop ? ['-t', (cutTo - cutFrom) * speedFactor] : []), '-vf', `${ptsFilter}fps=${framerateStr},${scaleFilter}`, '-map', 'v:0', '-vcodec', 'rawvideo', From cd7422ffe485437e0bfb587e8cd2cb744e4ee8d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Beno=C3=AEt?= Date: Tue, 7 May 2024 13:44:46 +0300 Subject: [PATCH 2/5] fix: stream close ended --- sources/videoFrameSource.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/sources/videoFrameSource.js b/sources/videoFrameSource.js index 0a6e51e6..72b8dd62 100644 --- a/sources/videoFrameSource.js +++ b/sources/videoFrameSource.js @@ -9,8 +9,8 @@ import { blurImage, } from './fabric.js'; -export default async ({ width: canvasWidth, height: canvasHeight, channels, framerateStr, verbose, logTimes, ffmpegPath, ffprobePath, enableFfmpegLog, params }) => { - const { path, cutFrom, cutTo, resizeMode = 'contain-blur', speedFactor, inputWidth, inputHeight, width: requestedWidthRel, height: requestedHeightRel, left: leftRel = 0, top: topRel = 0, originX = 'left', originY = 'top', fabricImagePostProcessing = null, loop } = params; +export default async ({ width: canvasWidth, height: canvasHeight, channels, framerateStr, duration, verbose, logTimes, ffmpegPath, ffprobePath, enableFfmpegLog, params }) => { + const { path, cutFrom, cutTo, resizeMode = 'contain-blur', speedFactor, inputWidth, inputHeight, width: requestedWidthRel, height: requestedHeightRel, left: leftRel = 0, top: topRel = 0, originX = 'left', originY = 'top', fabricImagePostProcessing = null, loop = false } = params; const requestedWidth = requestedWidthRel ? Math.round(requestedWidthRel * canvasWidth) : canvasWidth; const requestedHeight = requestedHeightRel ? Math.round(requestedHeightRel * canvasHeight) : canvasHeight; @@ -84,13 +84,14 @@ export default async ({ width: canvasWidth, height: canvasHeight, channels, fram // Testing: ffmpeg -i 'vid.mov' -t 1 -vcodec rawvideo -pix_fmt rgba -f image2pipe - | ffmpeg -f rawvideo -vcodec rawvideo -pix_fmt rgba -s 2166x1650 -i - -vf format=yuv420p -vcodec libx264 -y out.mp4 // https://trac.ffmpeg.org/wiki/ChangingFrameRate + // TODO: maybe change to -vf loop=loop=XXXXX const args = [ ...getFfmpegCommonArgs({ enableFfmpegLog }), ...(inputCodec ? ['-vcodec', inputCodec] : []), ...(cutFrom ? ['-ss', cutFrom] : []), ...(loop ? ['-stream_loop','-1'] : []), '-i', path, - ...(cutTo && !loop ? ['-t', (cutTo - cutFrom) * speedFactor] : []), + ...(loop ? ['-t',duration] : cutTo ? ['-t', (cutTo - cutFrom) * speedFactor] : []), '-vf', `${ptsFilter}fps=${framerateStr},${scaleFilter}`, '-map', 'v:0', '-vcodec', 'rawvideo', @@ -123,6 +124,10 @@ export default async ({ width: canvasWidth, height: canvasHeight, channels, fram length -= frameByteSize; return frameBuffer; } + if(length == 0){ + console.log('No more frames') + } + // TODO: is this is here to get the end of the video? return null; } From 74539bfb5ef28b4d4cf1eccbb3ea43e22ba0c7db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Beno=C3=AEt?= Date: Tue, 7 May 2024 14:46:33 +0300 Subject: [PATCH 3/5] fix: remove logs --- sources/videoFrameSource.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/sources/videoFrameSource.js b/sources/videoFrameSource.js index 72b8dd62..4f45263a 100644 --- a/sources/videoFrameSource.js +++ b/sources/videoFrameSource.js @@ -124,9 +124,6 @@ export default async ({ width: canvasWidth, height: canvasHeight, channels, fram length -= frameByteSize; return frameBuffer; } - if(length == 0){ - console.log('No more frames') - } // TODO: is this is here to get the end of the video? return null; } From d9979433a2dbe0e3cc02f8885c0be4a7cdbf35e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Beno=C3=AEt?= Date: Fri, 10 May 2024 16:12:04 +0300 Subject: [PATCH 4/5] fix: load font by default --- parseConfig.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/parseConfig.js b/parseConfig.js index 41b34dde..f8c288fb 100644 --- a/parseConfig.js +++ b/parseConfig.js @@ -12,6 +12,7 @@ import { } from './util.js'; import { registerFont } from './sources/fabric.js'; import { calcTransition } from './transitions.js'; +import fabric from 'fabric'; const dirname = fileURLToPath(new URL('.', import.meta.url)); @@ -47,6 +48,13 @@ export default async function parseConfig({ defaults: defaultsIn = {}, clips, ar }, }; + // register default font + if(defaultsIn?.layer?.fontPath && defaultsIn.layer.fontFamily){ + registerFont(defaultsIn.layer.fontPath, { family: defaultsIn.layer.fontFamily, weight: 'regular', style: 'normal' }); + loadedFonts.push(defaultsIn.layer.fontFamily); + console.log('Default font registered'); + } + async function handleLayer(layer) { const { type, ...restLayer } = layer; From 436e9513948d24fe1ff17fc5ac78f9c9b683806b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Beno=C3=AEt?= Date: Fri, 10 May 2024 17:07:33 +0300 Subject: [PATCH 5/5] fix: loading font --- parseConfig.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/parseConfig.js b/parseConfig.js index f8c288fb..9ec316fa 100644 --- a/parseConfig.js +++ b/parseConfig.js @@ -49,9 +49,11 @@ export default async function parseConfig({ defaults: defaultsIn = {}, clips, ar }; // register default font - if(defaultsIn?.layer?.fontPath && defaultsIn.layer.fontFamily){ - registerFont(defaultsIn.layer.fontPath, { family: defaultsIn.layer.fontFamily, weight: 'regular', style: 'normal' }); - loadedFonts.push(defaultsIn.layer.fontFamily); + // console.log(defaultsIn); + const { layer } = defaultsIn; + if(layer !== undefined && layer.fontPath !== undefined && layer.fontFamilly !== undefined){ + registerFont(layer.fontPath, { family: layer.fontFamilly, weight: 'regular', style: 'normal' }); + loadedFonts.push(layer.fontFamilly); console.log('Default font registered'); }