From 78b74f3388955f403a2260bca23373caff3df5fe Mon Sep 17 00:00:00 2001 From: wil Date: Sat, 9 Nov 2024 19:31:27 -0500 Subject: [PATCH] feature / Preview Button (#65) * preview button done * error if there's no video * fix playing problem with chroma key * fix the problem of videonode unable to play after being processed --- src/KonvaApp/Engine.ts | 90 +++++++++++++++---- src/KonvaApp/Nodes/BaseNode.ts | 4 +- src/KonvaApp/Nodes/VideoNode/VideoNode.ts | 44 ++++----- .../RenderingPrimitives/RenderEngine.ts | 9 +- src/KonvaApp/constants.ts | 2 + .../ToolbarMain/ButtonPreviewAndRender.tsx | 76 ++++++++++++++++ .../features/ToolbarMain/ToolbarMain.tsx | 50 ++--------- src/components/features/ToolbarMain/enum.ts | 2 +- 8 files changed, 187 insertions(+), 90 deletions(-) create mode 100644 src/components/features/ToolbarMain/ButtonPreviewAndRender.tsx diff --git a/src/KonvaApp/Engine.ts b/src/KonvaApp/Engine.ts index 63e7560ce6..d68fc74414 100644 --- a/src/KonvaApp/Engine.ts +++ b/src/KonvaApp/Engine.ts @@ -272,6 +272,18 @@ export class Engine { document.body.style.cursor = "default"; return; } + case AppModes.PREVIEW: { + console.log("APPMODE: RENDER"); + this.selectorSquare.disable(); + this.selectionManager.disable(); + uiAccess.toolbarMain.disable(); + uiAccess.toolbarMain.changeButtonState(ToolbarMainButtonNames.SELECT, { + active: false, + }); + this.matteBox.enable(); + document.body.style.cursor = "not-allowed"; + return; + } case AppModes.RENDERING: { console.log("APPMODE: RENDER"); this.selectorSquare.disable(); @@ -426,8 +438,14 @@ export class Engine { uiEvents.toolbarMain.SAVE.onClick(async (/*event*/) => { this.sceneManager.saveScene(); }); + uiEvents.toolbarMain.PREVIEW.onClick(async () => { + console.log("Toolbar Main >> Preview"); + this.setAppMode(AppModes.PREVIEW); + await this.handlePreview(); + this.setAppMode(AppModes.SELECT); + }); uiEvents.toolbarMain.DOWNLOAD.onClick(async () => { - console.log("Toolbar Main Render and Download"); + console.log("Toolbar Main >> Render Download"); try { this.setAppMode(AppModes.RENDERING); await this.renderEngine.startProcessing(); @@ -558,30 +576,27 @@ export class Engine { } public async setupStage() { - var textNode = new Konva.Text({ - x: 0, - y: 0, + // Frame rate inicator + const textNode = new Konva.Text({ + x: 5, + y: 5, text: "", fontSize: 32, - fontFamily: "Calibri", + fontFamily: "Source Sans 3", fill: "black", }); - - var anim = new Konva.Animation((frame) => { - if (frame) { - if (import.meta.env.DEV) { - const timeDiff = frame.timeDiff; - const frameRate = frame.frameRate; - textNode.setText( - `FrameTime:${timeDiff.toFixed(0)} ms\nFrameRate:${frameRate.toFixed(0)} fps`, - ); - } + const anim = new Konva.Animation((frame) => { + if (frame && import.meta.env.DEV) { + const timeDiff = frame.timeDiff; + const frameRate = frame.frameRate; + textNode.setText( + `FrameTime: ${timeDiff.toFixed(0)} ms\nFrameRate: ${frameRate.toFixed(0)} fps`, + ); } }, this.mediaLayer); + anim.start(); - this.uiLayer.add(textNode); - this.addKeyboardShortcuts(); } @@ -638,6 +653,47 @@ export class Engine { } }); } + + private async handlePreview(): Promise { + return new Promise((resolve) => { + const allNodes = this.nodesManager.getAllNodes(); + let longestVideoNode: VideoNode | undefined; + allNodes.forEach((node) => { + if (node instanceof VideoNode) { + node.videoComponent.pause(); + node.videoComponent.currentTime = 0; + if ( + longestVideoNode === undefined || + node.videoComponent.duration > + longestVideoNode.videoComponent.duration + ) { + longestVideoNode = node; + } + } + }); + const timer = setTimeout(() => { + resolve(); + }, 7000); + if (longestVideoNode !== undefined) { + longestVideoNode.videoComponent.addEventListener("ended", () => { + clearTimeout(timer); + resolve(); + }); + } else { + // no videonode + uiAccess.dialogError.show({ + title: "No Video Node", + message: "You have not yet put a video on the board", + }); + resolve(); + } + allNodes.forEach((node) => { + if (node instanceof VideoNode) { + node.togglePlay(); + } + }); + }); + } } function downloadURI(uri: string, name: string) { diff --git a/src/KonvaApp/Nodes/BaseNode.ts b/src/KonvaApp/Nodes/BaseNode.ts index ed1ea2f983..3e2adfb806 100644 --- a/src/KonvaApp/Nodes/BaseNode.ts +++ b/src/KonvaApp/Nodes/BaseNode.ts @@ -41,8 +41,8 @@ export abstract class BaseNode { // Do any other clean up and delete the konva node. this.kNode.destroy(); } - protected async setProcessing() { - this.isProcessing = true; + public async setProcessing(val: boolean) { + this.isProcessing = val; } public isKEventRef() { return this._isKDragEventListening && this._isKTranformEventListening; diff --git a/src/KonvaApp/Nodes/VideoNode/VideoNode.ts b/src/KonvaApp/Nodes/VideoNode/VideoNode.ts index 2d8b8f4d2b..d30f80c000 100644 --- a/src/KonvaApp/Nodes/VideoNode/VideoNode.ts +++ b/src/KonvaApp/Nodes/VideoNode/VideoNode.ts @@ -152,26 +152,7 @@ export class VideoNode extends NetworkedNode { private listenToVideoPlayPause() { // TODO: for controling video playpause, can be improved with bette ui this.kNode.on("click", () => { - // console.log("click"); - // Shouldn't play if anything things are true - if (this.didFinishLoading == false) { - return; - } - if (this.isProcessing == true) { - return; - } - if (this.isSegmentationMode) { - // console.log("Not Playing because Segmenting"); - return; - } - if (this.videoComponent.paused) { - console.log("Playing", this.videoComponent.src); - this.videoComponent.play(); - this.chromaKeyRender(0); // For starting Chroma - } else { - console.log("Pause", this.videoComponent.src); - this.videoComponent.pause(); - } + this.togglePlay(); }); } private removeLisentoVideoPlayPause() { @@ -296,10 +277,29 @@ export class VideoNode extends NetworkedNode { // TODO: impolement retry } } + public togglePlay() { + // Shouldn't play in these situations + if (this.didFinishLoading == false) { + return; + } + if (this.isProcessing == true) { + return; + } + if (this.isSegmentationMode) { + // console.log("Not Playing because Segmenting"); + return; + } - async setProcessing() { - this.isProcessing = true; + if (this.videoComponent.paused) { + console.log("Playing", this.videoComponent.src); + this.videoComponent.play(); + this.chromaKeyRender(0); // For starting Chroma + } else { + console.log("Pause", this.videoComponent.src); + this.videoComponent.pause(); + } } + async reset() { this.videoComponent.pause(); await this.seek(0); diff --git a/src/KonvaApp/RenderingPrimitives/RenderEngine.ts b/src/KonvaApp/RenderingPrimitives/RenderEngine.ts index 841615a826..5e14ee269f 100644 --- a/src/KonvaApp/RenderingPrimitives/RenderEngine.ts +++ b/src/KonvaApp/RenderingPrimitives/RenderEngine.ts @@ -342,7 +342,7 @@ export class RenderEngine { setTimeout(this.startProcessing.bind(this), 1000); break; } - item.setProcessing(); + item.setProcessing(true); } // todo remove @@ -371,14 +371,15 @@ export class RenderEngine { if (!item.kNode) { return; } + item.setProcessing(false); item.kNode.listening(true); } } } - public stopProcessing() { - this.isProcessing = false; - } + // public stopProcessing() { + // this.isProcessing = false; + // } // find the frame time given the frame number private calculateFrameTime(frameNumber: number, frameRate: number): number { diff --git a/src/KonvaApp/constants.ts b/src/KonvaApp/constants.ts index 6b3778958d..e6e9720c01 100644 --- a/src/KonvaApp/constants.ts +++ b/src/KonvaApp/constants.ts @@ -1,11 +1,13 @@ export enum AppModes { INIT = "INIT", + PREVIEW = "PREVIEW", SELECT = "SELECT", RENDERING = "RENDERING", } export const VideoResolutions = { VERTICAL_720: { width: 720, height: 1280 }, + LANDSCAPE_720: { width: 1280, height: 720 }, }; export const Colors = { diff --git a/src/components/features/ToolbarMain/ButtonPreviewAndRender.tsx b/src/components/features/ToolbarMain/ButtonPreviewAndRender.tsx new file mode 100644 index 0000000000..29bc0271ef --- /dev/null +++ b/src/components/features/ToolbarMain/ButtonPreviewAndRender.tsx @@ -0,0 +1,76 @@ +import { faCameraMovie, faPlayCircle } from "@fortawesome/pro-solid-svg-icons"; +import { Button, Tooltip } from "~/components/ui"; +import { ToolbarButtonProps } from "../ToolbarButton"; + +export const ButtonPreviewAndRender = ({ + buttonPreviewProps, + buttonRenderProps, +}: { + buttonPreviewProps: ToolbarButtonProps; + buttonRenderProps: ToolbarButtonProps; +}) => { + return ( +
+ + +
+ ); +}; +const ButtonPreview = (buttonProps: ToolbarButtonProps) => { + const { + className: customButtonClassNames, + disabled, + active, + hidden, + onClick, + ...restButtonProps + } = buttonProps; + return ( + + + + ); +}; diff --git a/src/components/features/ToolbarMain/ToolbarMain.tsx b/src/components/features/ToolbarMain/ToolbarMain.tsx index 6d66fb3a14..c1f4611214 100644 --- a/src/components/features/ToolbarMain/ToolbarMain.tsx +++ b/src/components/features/ToolbarMain/ToolbarMain.tsx @@ -6,10 +6,6 @@ import { faArrowRotateLeft, faArrowRotateRight, faBars, - faCameraMovie, - // faCameraRotate, - // faDownload, - // faCloudArrowDown, faFilePlus, faFilm, faFloppyDisk, @@ -19,12 +15,12 @@ import { faText, } from "@fortawesome/pro-solid-svg-icons"; -import { ToolbarButton, ToolbarButtonProps } from "../ToolbarButton"; +import { ToolbarButton } from "../ToolbarButton"; // style and constants import { paperWrapperStyles, toolTipStyles } from "~/components/styles"; import { ToolbarMainButtonNames } from "./enum"; -import { Button, Tooltip } from "~/components/ui"; +import { ButtonPreviewAndRender } from "./ButtonPreviewAndRender"; export const ToolbarMain = ({ disabled = false, @@ -92,11 +88,6 @@ export const ToolbarMain = ({ - {/* */} - + ); }; - -const DownloadButton = (buttonProps: ToolbarButtonProps) => { - const { - className: customButtonClassNames, - disabled, - active, - hidden, - onClick, - ...restButtonProps - } = buttonProps; - - return ( - - - - ); -}; diff --git a/src/components/features/ToolbarMain/enum.ts b/src/components/features/ToolbarMain/enum.ts index f6387cab39..352c48cfe8 100644 --- a/src/components/features/ToolbarMain/enum.ts +++ b/src/components/features/ToolbarMain/enum.ts @@ -4,10 +4,10 @@ export enum ToolbarMainButtonNames { ADD_TEXT = "ADD_TEXT", ADD_IMAGE = "ADD_IMAGE", ADD_VIDEO = "ADD_VIDEO", - // CHANGE_CAMERA_ORIENTATION = "CHANGE_CAMERA_ORIENTATION", AI_STYLIZE = "AI_STYLIZE", UNDO = "UNDO", REDO = "REDO", SAVE = "SAVE", + PREVIEW = "PREVIEW", DOWNLOAD = "DOWNLOAD", }