Skip to content

Commit 83f6e41

Browse files
committed
Added better integration with stabilizer effect
1 parent d4e88ec commit 83f6e41

File tree

5 files changed

+318
-8
lines changed

5 files changed

+318
-8
lines changed

src/effects/icons/stabilizer.png

3.83 KB
Loading

src/effects/icons/tracker.png

14.1 KB
Loading

src/example-effect-init.patch

+298
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,298 @@
1+
Index: src/windows/process_effect.py
2+
IDEA additional info:
3+
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
4+
<+>UTF-8
5+
===================================================================
6+
--- src/windows/process_effect.py (date 1594417794000)
7+
+++ src/windows/process_effect.py (date 1594417794000)
8+
@@ -0,0 +1,115 @@
9+
+"""
10+
+ @file
11+
+ @brief This file loads the Initialize Effects / Pre-process effects dialog
12+
+ @author Jonathan Thomas <[email protected]>
13+
+
14+
+ @section LICENSE
15+
+
16+
+ Copyright (c) 2008-2018 OpenShot Studios, LLC
17+
+ (http://www.openshotstudios.com). This file is part of
18+
+ OpenShot Video Editor (http://www.openshot.org), an open-source project
19+
+ dedicated to delivering high quality video editing and animation solutions
20+
+ to the world.
21+
+
22+
+ OpenShot Video Editor is free software: you can redistribute it and/or modify
23+
+ it under the terms of the GNU General Public License as published by
24+
+ the Free Software Foundation, either version 3 of the License, or
25+
+ (at your option) any later version.
26+
+
27+
+ OpenShot Video Editor is distributed in the hope that it will be useful,
28+
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
29+
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30+
+ GNU General Public License for more details.
31+
+
32+
+ You should have received a copy of the GNU General Public License
33+
+ along with OpenShot Library. If not, see <http://www.gnu.org/licenses/>.
34+
+ """
35+
+
36+
+import os
37+
+import sys
38+
+import time
39+
+
40+
+from PyQt5.QtCore import *
41+
+from PyQt5.QtGui import QIcon, QStandardItemModel, QStandardItem
42+
+from PyQt5.QtWidgets import *
43+
+from PyQt5 import uic
44+
+import openshot # Python module for libopenshot (required video editing module installed separately)
45+
+
46+
+from classes import info, ui_util, settings, qt_types, updates
47+
+from classes.app import get_app
48+
+from classes.logger import log
49+
+from classes.metrics import *
50+
+
51+
+
52+
+class ProcessEffect(QDialog):
53+
+ """ Choose Profile Dialog """
54+
+ progress = pyqtSignal(int)
55+
+
56+
+ # Path to ui file
57+
+ ui_path = os.path.join(info.PATH, 'windows', 'ui', 'process-effect.ui')
58+
+
59+
+ def __init__(self, clip_id, effect_name):
60+
+
61+
+ # Create dialog class
62+
+ QDialog.__init__(self)
63+
+
64+
+ # Load UI from designer & init
65+
+ ui_util.load_ui(self, self.ui_path)
66+
+ ui_util.init_ui(self)
67+
+
68+
+ # get translations
69+
+ _ = get_app()._tr
70+
+
71+
+ # Pause playback (to prevent crash since we are fixing to change the timeline's max size)
72+
+ get_app().window.actionPlay_trigger(None, force="pause")
73+
+
74+
+ # Track metrics
75+
+ track_metric_screen("process-effect-screen")
76+
+
77+
+ # Init form
78+
+ self.progressBar.setValue(0)
79+
+ self.txtAdvanced.setText("{}")
80+
+ self.setWindowTitle(_("%s: Initialize Effect") % effect_name)
81+
+ self.clip_id = clip_id
82+
+ self.effect_name = effect_name
83+
+
84+
+ # Add combo entries
85+
+ self.cboOptions.addItem("Option 1", 1)
86+
+ self.cboOptions.addItem("Option 2", 2)
87+
+ self.cboOptions.addItem("Option 3", 3)
88+
+
89+
+ # Add buttons
90+
+ self.cancel_button = QPushButton(_('Cancel'))
91+
+ self.process_button = QPushButton(_('Process Effect'))
92+
+ self.buttonBox.addButton(self.process_button, QDialogButtonBox.AcceptRole)
93+
+ self.buttonBox.addButton(self.cancel_button, QDialogButtonBox.RejectRole)
94+
+
95+
+ def accept(self):
96+
+ """ Start processing effect """
97+
+ # Disable UI
98+
+ self.cboOptions.setEnabled(False)
99+
+ self.txtAdvanced.setEnabled(False)
100+
+ self.process_button.setEnabled(False)
101+
+
102+
+ # DO WORK HERE, and periodically set progressBar value
103+
+ # Access C++ timeline and find the Clip instance which this effect should be applied to
104+
+ timeline_instance = get_app().window.timeline_sync.timeline
105+
+ for clip_instance in timeline_instance.Clips():
106+
+ if clip_instance.Id() == self.clip_id:
107+
+ print("Apply effect: %s to clip: %s" % (self.effect_name, clip_instance.Id()))
108+
+
109+
+ # EXAMPLE progress updates
110+
+ for value in range(1, 100, 4):
111+
+ self.progressBar.setValue(value)
112+
+ time.sleep(0.25)
113+
+
114+
+ # Process any queued events
115+
+ QCoreApplication.processEvents()
116+
+
117+
+ # Accept dialog
118+
+ super(ProcessEffect, self).accept()
119+
+
120+
+ def reject(self):
121+
+ # Cancel dialog
122+
+ self.exporting = False
123+
+ super(ProcessEffect, self).reject()
124+
Index: src/windows/ui/process-effect.ui
125+
IDEA additional info:
126+
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
127+
<+>UTF-8
128+
===================================================================
129+
--- src/windows/ui/process-effect.ui (date 1594417794000)
130+
+++ src/windows/ui/process-effect.ui (date 1594417794000)
131+
@@ -0,0 +1,105 @@
132+
+<?xml version="1.0" encoding="UTF-8"?>
133+
+<ui version="4.0">
134+
+ <class>Dialog</class>
135+
+ <widget class="QDialog" name="Dialog">
136+
+ <property name="geometry">
137+
+ <rect>
138+
+ <x>0</x>
139+
+ <y>0</y>
140+
+ <width>410</width>
141+
+ <height>193</height>
142+
+ </rect>
143+
+ </property>
144+
+ <property name="windowTitle">
145+
+ <string>%s: Initialize Effect</string>
146+
+ </property>
147+
+ <layout class="QFormLayout" name="formLayout">
148+
+ <item row="1" column="0">
149+
+ <widget class="QLabel" name="label">
150+
+ <property name="text">
151+
+ <string>Progress:</string>
152+
+ </property>
153+
+ </widget>
154+
+ </item>
155+
+ <item row="1" column="1">
156+
+ <widget class="QProgressBar" name="progressBar">
157+
+ <property name="value">
158+
+ <number>24</number>
159+
+ </property>
160+
+ </widget>
161+
+ </item>
162+
+ <item row="2" column="0">
163+
+ <widget class="QLabel" name="label_2">
164+
+ <property name="text">
165+
+ <string>Option:</string>
166+
+ </property>
167+
+ </widget>
168+
+ </item>
169+
+ <item row="2" column="1">
170+
+ <widget class="QComboBox" name="cboOptions"/>
171+
+ </item>
172+
+ <item row="3" column="0">
173+
+ <widget class="QLabel" name="label_3">
174+
+ <property name="text">
175+
+ <string>Advanced:</string>
176+
+ </property>
177+
+ </widget>
178+
+ </item>
179+
+ <item row="3" column="1">
180+
+ <widget class="QTextEdit" name="txtAdvanced">
181+
+ <property name="minimumSize">
182+
+ <size>
183+
+ <width>0</width>
184+
+ <height>75</height>
185+
+ </size>
186+
+ </property>
187+
+ </widget>
188+
+ </item>
189+
+ <item row="4" column="1">
190+
+ <widget class="QDialogButtonBox" name="buttonBox">
191+
+ <property name="orientation">
192+
+ <enum>Qt::Horizontal</enum>
193+
+ </property>
194+
+ <property name="standardButtons">
195+
+ <set>QDialogButtonBox::NoButton</set>
196+
+ </property>
197+
+ </widget>
198+
+ </item>
199+
+ </layout>
200+
+ </widget>
201+
+ <resources/>
202+
+ <connections>
203+
+ <connection>
204+
+ <sender>buttonBox</sender>
205+
+ <signal>accepted()</signal>
206+
+ <receiver>Dialog</receiver>
207+
+ <slot>accept()</slot>
208+
+ <hints>
209+
+ <hint type="sourcelabel">
210+
+ <x>248</x>
211+
+ <y>254</y>
212+
+ </hint>
213+
+ <hint type="destinationlabel">
214+
+ <x>157</x>
215+
+ <y>274</y>
216+
+ </hint>
217+
+ </hints>
218+
+ </connection>
219+
+ <connection>
220+
+ <sender>buttonBox</sender>
221+
+ <signal>rejected()</signal>
222+
+ <receiver>Dialog</receiver>
223+
+ <slot>reject()</slot>
224+
+ <hints>
225+
+ <hint type="sourcelabel">
226+
+ <x>316</x>
227+
+ <y>260</y>
228+
+ </hint>
229+
+ <hint type="destinationlabel">
230+
+ <x>286</x>
231+
+ <y>274</y>
232+
+ </hint>
233+
+ </hints>
234+
+ </connection>
235+
+ </connections>
236+
+</ui>
237+
Index: src/windows/views/timeline_webview.py
238+
IDEA additional info:
239+
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
240+
<+>UTF-8
241+
===================================================================
242+
--- src/windows/views/timeline_webview.py (date 1592265000000)
243+
+++ src/windows/views/timeline_webview.py (date 1594417794000)
244+
@@ -38,7 +38,7 @@
245+
from PyQt5.QtCore import QFileInfo, pyqtSlot, QUrl, Qt, QCoreApplication, QTimer
246+
from PyQt5.QtGui import QCursor, QKeySequence
247+
from PyQt5.QtWebKitWidgets import QWebView
248+
-from PyQt5.QtWidgets import QMenu
249+
+from PyQt5.QtWidgets import QMenu, QDialog
250+
251+
from classes import info, updates
252+
from classes import settings
253+
@@ -2939,6 +2939,9 @@
254+
# Add Effect
255+
def addEffect(self, effect_names, position):
256+
log.info("addEffect: %s at %s" % (effect_names, position))
257+
+ # Translation object
258+
+ _ = get_app()._tr
259+
+
260+
# Get name of effect
261+
name = effect_names[0]
262+
263+
@@ -2951,13 +2954,23 @@
264+
# Loop through clips on the closest layer
265+
possible_clips = Clip.filter(layer=closest_layer)
266+
for clip in possible_clips:
267+
- if js_position == 0 or (
268+
- clip.data["position"] <= js_position <= clip.data["position"]
269+
- + (clip.data["end"] - clip.data["start"])
270+
- ):
271+
+ if js_position == 0 or (clip.data["position"] <= js_position <= clip.data["position"] + (clip.data["end"] - clip.data["start"])):
272+
log.info("Applying effect to clip")
273+
log.info(clip)
274+
275+
+ # Handle custom effect dialogs
276+
+ if name in ["Bars", "Stabilize", "Tracker"]:
277+
+
278+
+ from windows.process_effect import ProcessEffect
279+
+ win = ProcessEffect(clip.id, name)
280+
+ # Run the dialog event loop - blocking interaction on this window during this time
281+
+ result = win.exec_()
282+
+ if result == QDialog.Accepted:
283+
+ log.info('Start processing')
284+
+ else:
285+
+ log.info('Cancel processing')
286+
+ return
287+
+
288+
# Create Effect
289+
effect = openshot.EffectInfo().CreateEffect(name)
290+
291+
@@ -2970,6 +2983,7 @@
292+
293+
# Update clip data for project
294+
self.update_clip_data(clip.data, only_basic_props=False, ignore_reader=True)
295+
+ break
296+
297+
# Without defining this method, the 'copy' action doesn't show with cursor
298+
def dragMoveEvent(self, event):

src/windows/process_effect.py

+11-5
Original file line numberDiff line numberDiff line change
@@ -96,15 +96,21 @@ def accept(self):
9696
timeline_instance = get_app().window.timeline_sync.timeline
9797
for clip_instance in timeline_instance.Clips():
9898
if clip_instance.Id() == self.clip_id:
99+
self.protobufPath = openshot.ClipProcessingJobs(self.effect_name, clip_instance).stabilizeVideo(clip_instance)
100+
self.effect = openshot.EffectInfo().CreateEffect(self.effect_name, "/media/brenno/Data/projects/openshot/stabilization.data")
101+
# self.effect.SetJson('{"Stabilizer":{"protobuf_data_path": "/home/gustavostahl/LabVisao/VideoEditor/openshot-qt/stabilization.data"}}')
102+
# clip_instance.AddEffect(self.effect)
103+
# return self.effect
99104
print("Apply effect: %s to clip: %s" % (self.effect_name, clip_instance.Id()))
105+
100106

101107
# EXAMPLE progress updates
102-
for value in range(1, 100, 4):
103-
self.progressBar.setValue(value)
104-
time.sleep(0.25)
108+
# for value in range(1, 100, 4):
109+
# self.progressBar.setValue(value)
110+
# time.sleep(0.25)
105111

106-
# Process any queued events
107-
QCoreApplication.processEvents()
112+
# # Process any queued events
113+
# QCoreApplication.processEvents()
108114

109115
# Accept dialog
110116
super(ProcessEffect, self).accept()

src/windows/views/timeline_webview.py

+9-3
Original file line numberDiff line numberDiff line change
@@ -2959,27 +2959,33 @@ def addEffect(self, effect_names, position):
29592959
log.info(clip)
29602960

29612961
# Handle custom effect dialogs
2962-
if name in ["Bars", "Stabilize", "Tracker"]:
2962+
if name in ["Bars", "Stabilizer", "Tracker"]:
29632963

29642964
from windows.process_effect import ProcessEffect
2965-
win = ProcessEffect(clip.id, name)
2965+
win = ProcessEffect(clip.id, "Stabilizer")
29662966
# Run the dialog event loop - blocking interaction on this window during this time
29672967
result = win.exec_()
2968+
29682969
if result == QDialog.Accepted:
29692970
log.info('Start processing')
29702971
else:
29712972
log.info('Cancel processing')
29722973
return
29732974

2975+
effect = win.effect
2976+
2977+
29742978
# Create Effect
2975-
effect = openshot.EffectInfo().CreateEffect(name)
2979+
else:
2980+
effect = openshot.EffectInfo().CreateEffect(name)
29762981

29772982
# Get Effect JSON
29782983
effect.Id(get_app().project.generate_id())
29792984
effect_json = json.loads(effect.Json())
29802985

29812986
# Append effect JSON to clip
29822987
clip.data["effects"].append(effect_json)
2988+
print(clip.data["effects"])
29832989

29842990
# Update clip data for project
29852991
self.update_clip_data(clip.data, only_basic_props=False, ignore_reader=True)

0 commit comments

Comments
 (0)