From e8913e31411f0f308464d0961cdeb03e39aafb60 Mon Sep 17 00:00:00 2001 From: peteruithoven Date: Wed, 19 Jun 2013 00:42:43 +0200 Subject: [PATCH 1/3] Adding settings for webcam flipX and flipY --- octoprint/server.py | 6 +++++- octoprint/settings.py | 2 ++ octoprint/static/js/ui.js | 8 +++++++- octoprint/templates/settings.jinja2 | 12 ++++++++++++ 4 files changed, 26 insertions(+), 2 deletions(-) diff --git a/octoprint/server.py b/octoprint/server.py index 4ede4ed..3a619a8 100644 --- a/octoprint/server.py +++ b/octoprint/server.py @@ -432,7 +432,9 @@ def getSettings(): "snapshotUrl": s.get(["webcam", "snapshot"]), "ffmpegPath": s.get(["webcam", "ffmpeg"]), "bitrate": s.get(["webcam", "bitrate"]), - "watermark": s.getBoolean(["webcam", "watermark"]) + "watermark": s.getBoolean(["webcam", "watermark"]), + "flipX": s.getBoolean(["webcam", "flipX"]), + "flipY": s.getBoolean(["webcam", "flipY"]) }, "feature": { "gcodeViewer": s.getBoolean(["feature", "gCodeVisualizer"]), @@ -479,6 +481,8 @@ def setSettings(): if "ffmpegPath" in data["webcam"].keys(): s.set(["webcam", "ffmpeg"], data["webcam"]["ffmpegPath"]) if "bitrate" in data["webcam"].keys(): s.set(["webcam", "bitrate"], data["webcam"]["bitrate"]) if "watermark" in data["webcam"].keys(): s.setBoolean(["webcam", "watermark"], data["webcam"]["watermark"]) + if "flipX" in data["webcam"].keys(): s.setBoolean(["webcam", "flipX"], data["webcam"]["flipX"]) + if "flipY" in data["webcam"].keys(): s.setBoolean(["webcam", "flipY"], data["webcam"]["flipY"]) if "feature" in data.keys(): if "gcodeViewer" in data["feature"].keys(): s.setBoolean(["feature", "gCodeVisualizer"], data["feature"]["gcodeViewer"]) diff --git a/octoprint/settings.py b/octoprint/settings.py index 71251b4..aa7f33f 100644 --- a/octoprint/settings.py +++ b/octoprint/settings.py @@ -36,6 +36,8 @@ default_settings = { "ffmpeg": None, "bitrate": "5000k", "watermark": True + "flipX": False, + "flipY": False }, "feature": { "gCodeVisualizer": True, diff --git a/octoprint/static/js/ui.js b/octoprint/static/js/ui.js index 8ade8a1..c924305 100644 --- a/octoprint/static/js/ui.js +++ b/octoprint/static/js/ui.js @@ -1328,6 +1328,8 @@ function SettingsViewModel(loginStateViewModel, usersViewModel) { self.webcam_ffmpegPath = ko.observable(undefined); self.webcam_bitrate = ko.observable(undefined); self.webcam_watermark = ko.observable(undefined); + self.webcam_flipX = ko.observable(undefined); + self.webcam_flipY = ko.observable(undefined); self.feature_gcodeViewer = ko.observable(undefined); self.feature_waitForStart = ko.observable(undefined); @@ -1375,6 +1377,8 @@ function SettingsViewModel(loginStateViewModel, usersViewModel) { self.webcam_ffmpegPath(response.webcam.ffmpegPath); self.webcam_bitrate(response.webcam.bitrate); self.webcam_watermark(response.webcam.watermark); + self.webcam_flipX(response.webcam.flipX); + self.webcam_flipY(response.webcam.flipY); self.feature_gcodeViewer(response.feature.gcodeViewer); self.feature_waitForStart(response.feature.waitForStart); @@ -1409,7 +1413,9 @@ function SettingsViewModel(loginStateViewModel, usersViewModel) { "snapshotUrl": self.webcam_snapshotUrl(), "ffmpegPath": self.webcam_ffmpegPath(), "bitrate": self.webcam_bitrate(), - "watermark": self.webcam_watermark() + "watermark": self.webcam_watermark(), + "flipX": self.webcam_flipX(), + "flipY": self.webcam_flipY() }, "feature": { "gcodeViewer": self.feature_gcodeViewer(), diff --git a/octoprint/templates/settings.jinja2 b/octoprint/templates/settings.jinja2 index c6a3652..4e55cd2 100644 --- a/octoprint/templates/settings.jinja2 +++ b/octoprint/templates/settings.jinja2 @@ -89,6 +89,18 @@ +
+
+ +
+
+ +
+
From ecfdb37f936b425dc8871337c31229dc383a2af4 Mon Sep 17 00:00:00 2001 From: peteruithoven Date: Wed, 19 Jun 2013 02:39:49 +0200 Subject: [PATCH 2/3] Adding classes according to flipX, flipY settings and flipping using css --- octoprint/server.py | 4 +++- octoprint/settings.py | 2 +- octoprint/static/css/octoprint.less | 12 ++++++++++++ octoprint/templates/index.jinja2 | 2 +- 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/octoprint/server.py b/octoprint/server.py index 3a619a8..f4d9aca 100644 --- a/octoprint/server.py +++ b/octoprint/server.py @@ -119,7 +119,9 @@ def index(): enableGCodeVisualizer=settings().get(["feature", "gCodeVisualizer"]), enableSystemMenu=settings().get(["system"]) is not None and settings().get(["system", "actions"]) is not None and len(settings().get(["system", "actions"])) > 0, enableAccessControl=userManager is not None, - enableSdSupport=settings().get(["feature", "sdSupport"]) + enableSdSupport=settings().get(["feature", "sdSupport"]), + webcamFlipX=settings().get(["webcam", "flipX"]), + webcamFlipY=settings().get(["webcam", "flipY"]) ) #~~ Printer control diff --git a/octoprint/settings.py b/octoprint/settings.py index aa7f33f..58da843 100644 --- a/octoprint/settings.py +++ b/octoprint/settings.py @@ -35,7 +35,7 @@ default_settings = { "snapshot": None, "ffmpeg": None, "bitrate": "5000k", - "watermark": True + "watermark": True, "flipX": False, "flipY": False }, diff --git a/octoprint/static/css/octoprint.less b/octoprint/static/css/octoprint.less index 1251ae0..5629f47 100644 --- a/octoprint/static/css/octoprint.less +++ b/octoprint/static/css/octoprint.less @@ -359,6 +359,18 @@ ul.dropdown-menu li a { #webcam_container { width: 100%; } +#webcam_container.flipX { + -webkit-transform: scaleX(-1); + -moz-transform: scaleX(-1); +} +#webcam_container.flipY { + -webkit-transform: scaleY(-1); + -moz-transform: scaleY(-1); +} +#webcam_container.flipX.flipY { + -webkit-transform: scaleX(-1) scaleY(-1); + -moz-transform: scaleX(-1) scaleY(-1); +} /** GCODE file manager */ diff --git a/octoprint/templates/index.jinja2 b/octoprint/templates/index.jinja2 index d6d4336..74e025d 100644 --- a/octoprint/templates/index.jinja2 +++ b/octoprint/templates/index.jinja2 @@ -310,7 +310,7 @@
{% if webcamStream %} -
+
{% endif %} From 329656837af731cfef4ddde19db2d48537043cd8 Mon Sep 17 00:00:00 2001 From: Bryan Mayland Date: Thu, 20 Jun 2013 17:41:10 +0200 Subject: [PATCH 3/3] Renamed flipX, flipY to flipH, flipV, made update upon change instant, also made timelapse video reflect flipped webcam --- octoprint/server.py | 12 +++++------- octoprint/settings.py | 4 ++-- octoprint/static/css/octoprint.less | 27 +++++++++++++++------------ octoprint/static/js/ui.js | 18 +++++++++--------- octoprint/templates/index.jinja2 | 4 ++-- octoprint/templates/settings.jinja2 | 4 ++-- octoprint/timelapse.py | 27 +++++++++++++++++++++++++-- 7 files changed, 60 insertions(+), 36 deletions(-) diff --git a/octoprint/server.py b/octoprint/server.py index f4d9aca..c840ad7 100644 --- a/octoprint/server.py +++ b/octoprint/server.py @@ -119,9 +119,7 @@ def index(): enableGCodeVisualizer=settings().get(["feature", "gCodeVisualizer"]), enableSystemMenu=settings().get(["system"]) is not None and settings().get(["system", "actions"]) is not None and len(settings().get(["system", "actions"])) > 0, enableAccessControl=userManager is not None, - enableSdSupport=settings().get(["feature", "sdSupport"]), - webcamFlipX=settings().get(["webcam", "flipX"]), - webcamFlipY=settings().get(["webcam", "flipY"]) + enableSdSupport=settings().get(["feature", "sdSupport"]) ) #~~ Printer control @@ -435,8 +433,8 @@ def getSettings(): "ffmpegPath": s.get(["webcam", "ffmpeg"]), "bitrate": s.get(["webcam", "bitrate"]), "watermark": s.getBoolean(["webcam", "watermark"]), - "flipX": s.getBoolean(["webcam", "flipX"]), - "flipY": s.getBoolean(["webcam", "flipY"]) + "flipH": s.getBoolean(["webcam", "flipH"]), + "flipV": s.getBoolean(["webcam", "flipV"]) }, "feature": { "gcodeViewer": s.getBoolean(["feature", "gCodeVisualizer"]), @@ -483,8 +481,8 @@ def setSettings(): if "ffmpegPath" in data["webcam"].keys(): s.set(["webcam", "ffmpeg"], data["webcam"]["ffmpegPath"]) if "bitrate" in data["webcam"].keys(): s.set(["webcam", "bitrate"], data["webcam"]["bitrate"]) if "watermark" in data["webcam"].keys(): s.setBoolean(["webcam", "watermark"], data["webcam"]["watermark"]) - if "flipX" in data["webcam"].keys(): s.setBoolean(["webcam", "flipX"], data["webcam"]["flipX"]) - if "flipY" in data["webcam"].keys(): s.setBoolean(["webcam", "flipY"], data["webcam"]["flipY"]) + if "flipH" in data["webcam"].keys(): s.setBoolean(["webcam", "flipH"], data["webcam"]["flipH"]) + if "flipV" in data["webcam"].keys(): s.setBoolean(["webcam", "flipV"], data["webcam"]["flipV"]) if "feature" in data.keys(): if "gcodeViewer" in data["feature"].keys(): s.setBoolean(["feature", "gCodeVisualizer"], data["feature"]["gcodeViewer"]) diff --git a/octoprint/settings.py b/octoprint/settings.py index 58da843..f1ca051 100644 --- a/octoprint/settings.py +++ b/octoprint/settings.py @@ -36,8 +36,8 @@ default_settings = { "ffmpeg": None, "bitrate": "5000k", "watermark": True, - "flipX": False, - "flipY": False + "flipH": False, + "flipV": False }, "feature": { "gCodeVisualizer": True, diff --git a/octoprint/static/css/octoprint.less b/octoprint/static/css/octoprint.less index 5629f47..85a90ce 100644 --- a/octoprint/static/css/octoprint.less +++ b/octoprint/static/css/octoprint.less @@ -358,18 +358,21 @@ ul.dropdown-menu li a { #webcam_container { width: 100%; -} -#webcam_container.flipX { - -webkit-transform: scaleX(-1); - -moz-transform: scaleX(-1); -} -#webcam_container.flipY { - -webkit-transform: scaleY(-1); - -moz-transform: scaleY(-1); -} -#webcam_container.flipX.flipY { - -webkit-transform: scaleX(-1) scaleY(-1); - -moz-transform: scaleX(-1) scaleY(-1); + + .flipH { + -webkit-transform: scaleX(-1); + -moz-transform: scaleX(-1); + } + + .flipV { + -webkit-transform: scaleY(-1); + -moz-transform: scaleY(-1); + } + + .flipH.flipV { + -webkit-transform: scaleX(-1) scaleY(-1); + -moz-transform: scaleX(-1) scaleY(-1); + } } /** GCODE file manager */ diff --git a/octoprint/static/js/ui.js b/octoprint/static/js/ui.js index c924305..e1c1a4a 100644 --- a/octoprint/static/js/ui.js +++ b/octoprint/static/js/ui.js @@ -526,10 +526,11 @@ function TemperatureViewModel(loginStateViewModel, settingsViewModel) { } } -function ControlViewModel(loginStateViewModel) { +function ControlViewModel(loginStateViewModel, settingsViewModel) { var self = this; self.loginState = loginStateViewModel; + self.settings = settingsViewModel; self.isErrorOrClosed = ko.observable(undefined); self.isOperational = ko.observable(undefined); @@ -1328,8 +1329,8 @@ function SettingsViewModel(loginStateViewModel, usersViewModel) { self.webcam_ffmpegPath = ko.observable(undefined); self.webcam_bitrate = ko.observable(undefined); self.webcam_watermark = ko.observable(undefined); - self.webcam_flipX = ko.observable(undefined); - self.webcam_flipY = ko.observable(undefined); + self.webcam_flipH = ko.observable(undefined); + self.webcam_flipV = ko.observable(undefined); self.feature_gcodeViewer = ko.observable(undefined); self.feature_waitForStart = ko.observable(undefined); @@ -1377,8 +1378,8 @@ function SettingsViewModel(loginStateViewModel, usersViewModel) { self.webcam_ffmpegPath(response.webcam.ffmpegPath); self.webcam_bitrate(response.webcam.bitrate); self.webcam_watermark(response.webcam.watermark); - self.webcam_flipX(response.webcam.flipX); - self.webcam_flipY(response.webcam.flipY); + self.webcam_flipH(response.webcam.flipH); + self.webcam_flipV(response.webcam.flipV); self.feature_gcodeViewer(response.feature.gcodeViewer); self.feature_waitForStart(response.feature.waitForStart); @@ -1414,15 +1415,14 @@ function SettingsViewModel(loginStateViewModel, usersViewModel) { "ffmpegPath": self.webcam_ffmpegPath(), "bitrate": self.webcam_bitrate(), "watermark": self.webcam_watermark(), - "flipX": self.webcam_flipX(), - "flipY": self.webcam_flipY() + "flipH": self.webcam_flipH(), + "flipV": self.webcam_flipV() }, "feature": { "gcodeViewer": self.feature_gcodeViewer(), "waitForStart": self.feature_waitForStart(), "alwaysSendChecksum": self.feature_alwaysSendChecksum(), "resetLineNumbersWithPrefixedN": self.feature_resetLineNumbersWithPrefixedN(), - "waitForStart": self.feature_waitForStart(), "sdSupport": self.feature_sdSupport() }, "folder": { @@ -1837,7 +1837,7 @@ $(function() { var settingsViewModel = new SettingsViewModel(loginStateViewModel, usersViewModel); var appearanceViewModel = new AppearanceViewModel(settingsViewModel); var temperatureViewModel = new TemperatureViewModel(loginStateViewModel, settingsViewModel); - var controlViewModel = new ControlViewModel(loginStateViewModel); + var controlViewModel = new ControlViewModel(loginStateViewModel, settingsViewModel); var terminalViewModel = new TerminalViewModel(loginStateViewModel); var gcodeFilesViewModel = new GcodeFilesViewModel(loginStateViewModel); var timelapseViewModel = new TimelapseViewModel(loginStateViewModel); diff --git a/octoprint/templates/index.jinja2 b/octoprint/templates/index.jinja2 index 74e025d..46d52ac 100644 --- a/octoprint/templates/index.jinja2 +++ b/octoprint/templates/index.jinja2 @@ -310,8 +310,8 @@
{% if webcamStream %} -
- +
+
{% endif %} diff --git a/octoprint/templates/settings.jinja2 b/octoprint/templates/settings.jinja2 index 4e55cd2..b247cdf 100644 --- a/octoprint/templates/settings.jinja2 +++ b/octoprint/templates/settings.jinja2 @@ -92,12 +92,12 @@
diff --git a/octoprint/timelapse.py b/octoprint/timelapse.py index 3f2c1d6..1f5a302 100644 --- a/octoprint/timelapse.py +++ b/octoprint/timelapse.py @@ -106,19 +106,42 @@ class Timelapse(object): ffmpeg, '-i', input, '-vcodec', 'mpeg2video', '-pix_fmt', 'yuv420p', '-r', '25', '-y', '-b:v', bitrate, '-f', 'vob'] + filters = [] + + # flip video if configured + if settings().getBoolean(["webcam", "flipX"]): + filters.append('hflip') + if settings().getBoolean(["webcam", "flipY"]): + filters.append('vflip') + # add watermark if configured + watermarkFilter = None if settings().getBoolean(["webcam", "watermark"]): watermark = os.path.join(os.path.dirname(__file__), "static", "img", "watermark.png") if sys.platform == "win32": # Because ffmpeg hiccups on windows' drive letters and backslashes we have to give the watermark # path a special treatment. Yeah, I couldn't believe it either... watermark = watermark.replace("\\", "/").replace(":", "\\\\:") - command.extend(['-vf', 'movie=%s [wm]; [in][wm] overlay=10:main_h-overlay_h-10 [out]' % watermark]) + + watermarkFilter = "movie=%s [wm]; [%%(inputName)s][wm] overlay=10:main_h-overlay_h-10" % watermark + + filterstring = None + if len(filters) > 0: + if watermarkFilter is not None: + filterstring = "[in] %s [postprocessed]; %s [out]" % (",".join(filters), watermarkFilter % {"inputName": "postprocessed"}) + else: + filterstring = "[in] %s [out]" % ",".join(filters) + elif watermarkFilter is not None: + filterstring = watermarkFilter % {"inputName": "in"} + " [out]" + + if filterstring is not None: + self._logger.debug("Applying videofilter chain: %s" % filterstring) + command.extend(["-vf", filterstring]) # finalize command with output file command.append(output) - subprocess.call(command) self._logger.debug("Rendering movie to %s" % output) + subprocess.call(command) def cleanCaptureDir(self): if not os.path.isdir(self._captureDir):