Permalink
Browse files

Added support for Windows 64bit. Also fixed a few issues with signals…

…, including adding a new StopSignal, which kills the video preview thread on exit... which seems to make the exit much cleaner. Adding support for Inno Setup installer (for 64bit Windows installer), which is much improved over the old MSI system. Also updating build server to support new installer.
  • Loading branch information...
jonoomph committed Aug 13, 2016
1 parent 579cf34 commit fde27d52d3f3a36f4903eb49f5090384bf60b342
View
@@ -44,6 +44,7 @@
# b) bash installer/build-mac-dmg.sh
#
# Windows Syntax to Build MSI Installer
# NOTE: Python3.5 requires custom build of cx_Freeze (https://github.com/sekrause/cx_Freeze-wheels). Download, python setup.py build, python setup.py install
# 1) python3 freeze.py bdist_msi
# NOTE: Requires a tweak to cx_freeze: http://stackoverflow.com/questions/24195311/how-to-set-shortcut-working-directory-in-cx-freeze-msi-bundle
# 2) Sign MSI with private code signing key (optional)
@@ -115,72 +116,15 @@ def find_files(directory, patterns):
if sys.platform == "win32":
base = "Win32GUI"
external_so_files = []
build_exe_options["include_msvcr"] = True
# Copy required ZMQ files
external_so_files.append(("C:\\Python34\\Lib\\site-packages\\zmq\\libzmq.pyd", "libzmq.pyd"))
# Copy missing SVG dll
# TODO: Determine why cx_Freeze misses this DLL when freezing. Without it, libopenshot cannot open SVG files
external_so_files.append(("C:\\Qt\\Qt5.4.2\\5.4\\mingw491_32\\bin\\Qt5Svgd.dll", "Qt5Svgd.dll"))
# Append Windows ICON file
iconFile += ".ico"
src_files.append((os.path.join(PATH, "xdg", iconFile), iconFile))
# Append some additional files for Windows (this is a debug launcher)
src_files.append((os.path.join(PATH, "installer", "launch-win.bat"), "launch-win.bat"))
# Create environment variable for ImageMagick (on install)
environment_table = [
("MAGICK_CONFIGURE_PATH",
"*=MAGICK_CONFIGURE_PATH",
"[TARGETDIR]ImageMagick\\etc\\configuration",
"OpenShot"
),
# TODO: Find a better way to load the qt_plugin_path for libopenshot, which can be imported in
# different directories from the .exe, causing the plugins (i.e. svg) to not load in some cases.
("QT_PLUGIN_PATH",
"*=QT_PLUGIN_PATH",
"[TARGETDIR]",
"OpenShot"
)
]
# Create custom action table
# TODO: Revisit this idea, to force the environment variables to be updated after the installer runs.
# ImageMagick needs an environment variable or it will crash. Forcing a reboot is currently the only
# option I can get to work correctly.
# custom_action = [
# ("SetVar",
# "242",
# "[SystemFolder]setx.exe",
# "OSVE 1")
# ]
# Install an action into the MSI install sequence (schedule a reboot)
execute_sequence = [
("ScheduleReboot",
"NOT REMOVE",
"8000")
]
# Set some properties on the MSI
properties = [
("REINSTALLMODE", "amus") # Force overwrite of all files during install
]
# Now create the table dictionary
msi_data = {"Environment": environment_table,
"InstallExecuteSequence" : execute_sequence,
"InstallUISequence" : execute_sequence,
"Property" : properties }
# Change some default MSI options and specify the use of the above defined tables
bdist_msi_options = {"data": msi_data}
build_options["bdist_msi"] = bdist_msi_options
elif sys.platform == "linux":
# Find all related SO files
for filename in find_files("/usr/local/lib/", ["*openshot*.so*"]):
View
@@ -76,7 +76,7 @@
elif platform.system() == "Windows":
make_command = "mingw32-make"
freeze_command = "python C:\\Users\\Jonathan\\apps\\openshot-qt-git\\freeze.py bdist_msi"
freeze_command = "python3 C:\\Users\\Jonathan\\apps\\openshot-qt-git\\freeze.py build"
project_paths = [("C:\\Users\\Jonathan\\apps\\libopenshot-audio-git", '-G "MinGW Makefiles" ../ -D"CMAKE_BUILD_TYPE:STRING=Release"'),
("C:\\Users\\Jonathan\\apps\\libopenshot-git", '-G "MinGW Makefiles" ../ -D"CMAKE_BUILD_TYPE:STRING=Release"'),
("C:\\Users\\Jonathan\\apps\\openshot-qt-git", "")]
@@ -297,7 +297,7 @@ def upload(file_path, s3_bucket):
app_name += "-x86_64.dmg"
app_upload_bucket = "releases.openshot.org/mac"
elif platform.system() == "Windows":
app_name += "-x86_32.msi"
app_name += "-x86_64.exe"
app_upload_bucket = "releases.openshot.org/windows"
app_build_path = os.path.join(builds_path, app_name)
app_upload_path = os.path.join(upload_path, app_name)
@@ -416,23 +416,62 @@ def upload(file_path, s3_bucket):
if platform.system() == "Windows":
# Create MSI (OpenShot-%s-x86_32.MSI)
app_image_success = True
# Rename MSI (to be consistent with other OS installers)
os.rename(os.path.join(project_path, "dist", "OpenShot Video Editor-%s-win32.msi" % version), app_build_path)
# Move python3.5 folder structure, since Cx_Freeze doesn't put it in the correct place
exe_dir = os.path.join(PATH, 'build', 'exe.mingw-3.5')
python35_dir = os.path.join(exe_dir, 'lib', 'python3.5')
if not os.path.exists(python35_dir):
os.mkdir(python35_dir)
# Copy all non-zip files from /lib/ into /python3.5/
for lib_file in os.listdir(os.path.join(exe_dir, 'lib')):
if not ".zip" in lib_file:
lib_src_path = os.path.join(os.path.join(exe_dir, 'lib'), lib_file)
lib_dst_path = os.path.join(os.path.join(python35_dir), lib_file)
if not os.path.isdir(lib_src_path):
shutil.move(lib_src_path, lib_dst_path)
# Delete debug Qt libraries (since they are not needed, and cx_Freeze grabs them)
for debug_qt_lib in os.listdir(exe_dir):
if debug_qt_lib.endswith("d.dll"):
# Delete the debug dll
os.remove(os.path.join(exe_dir, debug_qt_lib))
# Create Installer (OpenShot-%s-x86_64.exe)
inno_success = True
inno_command = '"C:\Program Files (x86)\Inno Setup 5\iscc.exe" /Q /DVERSION=%s "%s"' % (version, os.path.join(PATH, 'installer', 'windows-installer.iss'))
inno_output = ""
# Compile Inno installer
for line in run_command(inno_command):
output(line)
if line:
inno_success = False
inno_output = line
# Was the Inno Installer successful
inno_output_exe = os.path.join(project_path, "installer", "Output", "OpenShot-x86_64.exe")
if not inno_success or not os.path.exists(inno_output_exe):
# Installer failed
error("Inno Compiler Error: Had output when none was expected (%s)" % inno_output)
needs_upload = False
else:
# Rename exe to correct name / path
os.rename(inno_output_exe, app_build_path)
# Clean-up empty folder created by Inno compiler
os.rmdir(os.path.join(PATH, 'installer', 'Output'))
# Sign the installer
key_sign_success = True
key_sign_command = '"C:\\Program Files (x86)\\kSign\\kSignCMD.exe" /f "%s" /p "%s" /d "OpenShot Video Editor" /du "http://www.openshot.org" "%s"' % (windows_key, windows_key_password, app_build_path)
key_sign_output = ""
# Sign MSI
for line in run_command(key_sign_command):
output(line)
if line:
app_image_success = False
key_sign_success = False
key_sign_output = line
# Was the MSI creation successful
if not app_image_success:
if not key_sign_success:
# MSI failed
error("Key Sign Error: Had output when none was expected (%s)" % key_sign_output)
needs_upload = False
Binary file not shown.
@@ -0,0 +1,97 @@
; Script generated by the Inno Setup Script Wizard.
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
#ifndef VERSION
#define VERSION "0.0.0"
#endif
#define MyAppName "OpenShot Video Editor"
#define MyAppPublisher "OpenShot Studios, LLC"
#define MyAppURL "http://www.openshot.org/"
#define MyAppExeName "launch.exe"
[Setup]
; NOTE: The value of AppId uniquely identifies this application.
; Do not use the same AppId value in installers for other applications.
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
AppId={{4BB0DCDC-BC24-49EC-8937-72956C33A470}
AppName={#MyAppName}
AppVersion={#VERSION}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
AppCopyright=Copyright (c) 2008-2016 {#MyAppPublisher}
DefaultDirName={pf}\{#MyAppName}
DisableProgramGroupPage=yes
LicenseFile=C:\Users\jonathan\Apps\openshot-qt-git\COPYING
OutputBaseFilename=OpenShot-x86_64
ArchitecturesInstallIn64BitMode=x64
ArchitecturesAllowed=x64
ChangesEnvironment=yes
Compression=lzma
SolidCompression=yes
WizardSmallImageFile=installer-logo.bmp
UninstallDisplayIcon={app}\{#MyAppExeName}
SignedUninstaller=yes
SignedUninstallerDir=..\s3-builds\
[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"
Name: "armenian"; MessagesFile: "compiler:Languages\Armenian.islu"
Name: "brazilianportuguese"; MessagesFile: "compiler:Languages\BrazilianPortuguese.isl"
Name: "catalan"; MessagesFile: "compiler:Languages\Catalan.isl"
Name: "corsican"; MessagesFile: "compiler:Languages\Corsican.isl"
Name: "czech"; MessagesFile: "compiler:Languages\Czech.isl"
Name: "danish"; MessagesFile: "compiler:Languages\Danish.isl"
Name: "dutch"; MessagesFile: "compiler:Languages\Dutch.isl"
Name: "finnish"; MessagesFile: "compiler:Languages\Finnish.isl"
Name: "french"; MessagesFile: "compiler:Languages\French.isl"
Name: "german"; MessagesFile: "compiler:Languages\German.isl"
Name: "greek"; MessagesFile: "compiler:Languages\Greek.isl"
Name: "hebrew"; MessagesFile: "compiler:Languages\Hebrew.isl"
Name: "hungarian"; MessagesFile: "compiler:Languages\Hungarian.isl"
Name: "italian"; MessagesFile: "compiler:Languages\Italian.isl"
Name: "japanese"; MessagesFile: "compiler:Languages\Japanese.isl"
Name: "nepali"; MessagesFile: "compiler:Languages\Nepali.islu"
Name: "norwegian"; MessagesFile: "compiler:Languages\Norwegian.isl"
Name: "polish"; MessagesFile: "compiler:Languages\Polish.isl"
Name: "portuguese"; MessagesFile: "compiler:Languages\Portuguese.isl"
Name: "russian"; MessagesFile: "compiler:Languages\Russian.isl"
Name: "scottishgaelic"; MessagesFile: "compiler:Languages\ScottishGaelic.isl"
Name: "serbiancyrillic"; MessagesFile: "compiler:Languages\SerbianCyrillic.isl"
Name: "serbianlatin"; MessagesFile: "compiler:Languages\SerbianLatin.isl"
Name: "slovenian"; MessagesFile: "compiler:Languages\Slovenian.isl"
Name: "spanish"; MessagesFile: "compiler:Languages\Spanish.isl"
Name: "turkish"; MessagesFile: "compiler:Languages\Turkish.isl"
Name: "ukrainian"; MessagesFile: "compiler:Languages\Ukrainian.isl"
[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
[InstallDelete]
; Remove previous installed versions of OpenShot
Type: filesandordirs; Name: "{app}\*"
Type: filesandordirs; Name: "{pf32}\OpenShot Video Editor\*"
Type: filesandordirs; Name: "{pf64}\OpenShot Video Editor\*"
Type: dirifempty; Name: "{app}\*"
Type: dirifempty; Name: "{pf32}\OpenShot Video Editor\"
Type: dirifempty; Name: "{pf64}\OpenShot Video Editor\"
Type: files; Name: "{group}\OpenShot Video Editor"
[Registry]
; Remove previously installed registry keys (no longer needed)
Root: HKLM; Subkey: "System\CurrentControlSet\Control\Session Manager\Environment"; ValueName:"QT_PLUGIN_PATH"; ValueType: none; Flags: deletevalue;
Root: HKLM; Subkey: "System\CurrentControlSet\Control\Session Manager\Environment"; ValueName:"MAGICK_CONFIGURE_PATH"; ValueType: none; Flags: deletevalue;
[Files]
; Add all frozen files from cx_Freeze build
Source: "..\build\exe.mingw-3.5\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs
[Icons]
Name: "{commonprograms}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
Name: "{commondesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
[Run]
; Launch after installation
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent
@@ -70,6 +70,7 @@ class MainWindow(QMainWindow, updates.UpdateWatcher, updates.UpdateInterface):
LoadFileSignal = pyqtSignal(str)
PlaySignal = pyqtSignal(int)
PauseSignal = pyqtSignal()
StopSignal = pyqtSignal()
SeekSignal = pyqtSignal(int)
SpeedSignal = pyqtSignal(float)
RecoverBackup = pyqtSignal()
@@ -106,14 +107,15 @@ def closeEvent(self, event):
track_metric_session(False)
# Stop threads
self.StopSignal.emit()
self.preview_thread.kill()
# Close & Stop libopenshot logger
openshot.ZmqLogger.Instance().Close()
get_app().logger_libopenshot.kill()
# Wait for thread
self.preview_parent.background.wait(250)
self.preview_parent.background.wait(500)
# Destroy lock file
self.destroy_lock_file()
@@ -85,6 +85,7 @@ def Init(self, parent, timeline, video_widget):
self.parent.PauseSignal.connect(self.worker.Pause)
self.parent.SeekSignal.connect(self.worker.Seek)
self.parent.SpeedSignal.connect(self.worker.Speed)
self.parent.StopSignal.connect(self.worker.Stop)
# Move Worker to new thread, and Start
self.worker.moveToThread(self.background)
@@ -163,7 +164,7 @@ def initPlayer(self):
# Get the address of the player's renderer (a QObject that emits signals when frames are ready)
self.renderer_address = self.player.GetRendererQObject()
self.player.SetQWidget(int(sip.unwrapinstance(self.videoPreview)))
self.player.SetQWidget(sip.unwrapinstance(self.videoPreview))
self.renderer = sip.wrapinstance(self.renderer_address, QObject)
self.videoPreview.connectSignals(self.renderer)
@@ -294,19 +295,25 @@ def Play(self, timeline_length):
self.player.Play()
def Pause(self):
""" Start playing the video player """
""" Pause the video player """
# Start playback
# Pause playback
self.player.Pause()
def Stop(self):
""" Stop the video player and terminate the playback threads """
# Stop playback
self.player.Stop()
def Seek(self, number):
""" Seek to a specific frame """
# Start playback
# Seek to frame
self.player.Seek(number)
def Speed(self, new_speed):
""" Set the speed of the video player """
# Start playback
# Set speed
self.player.Speed(new_speed)
@@ -2076,7 +2076,7 @@ def PreviewClipFrame(self, clip_id, frame_number):
def PlayheadMoved(self, position_seconds, position_frames, time_code):
# Load the timeline into the Player (ignored if this has already happened)
self.window.LoadFileSignal.emit(None)
self.window.LoadFileSignal.emit('')
if self.last_position_frames != position_frames:
# Update time code (to prevent duplicate previews)

0 comments on commit fde27d5

Please sign in to comment.