Skip to content

Commit

Permalink
Version 0.0.3
Browse files Browse the repository at this point in the history
Added:
- Output file format mov
- Explanation when codec/profile not supported.
- Explanation when wrong file format selected.

Fixed:
- Fixed changing bitrate, which was always 240MBps.
- Fixed file format for prores, for which mp4 is not allowed.

Changed:
- Force file format 'mov' for 'prores'.
- Force profile 'main' for 'h265' (baseline fails).
  • Loading branch information
xlvisuals committed Oct 29, 2022
1 parent e888f7f commit e54847c
Show file tree
Hide file tree
Showing 6 changed files with 198 additions and 138 deletions.
27 changes: 27 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@

# Editor directories and files
.idea
.idea/
../.idea
*.suo
*.ntvs*
*.njsproj
*.sln
.DS_Store*
__pycache__

# Python virtual env
env/
venv/

# Image files
*.img
*.img.zip
*.zip
*.dmg
*.pkg
*.exe

# pyinstaller folders
dist/*
build/*
14 changes: 0 additions & 14 deletions LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,7 @@
Version 2.1, February 1999

Copyright (C) 1991, 1999 Free Software Foundation, Inc.
<<<<<<< HEAD
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
=======
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
>>>>>>> 6898a473625f7e3b2de05cea2272404971d5331e
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.

Expand Down Expand Up @@ -489,12 +485,7 @@ convey the exclusion of warranty; and each file should have at least the

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
<<<<<<< HEAD
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
=======
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
USA
>>>>>>> 6898a473625f7e3b2de05cea2272404971d5331e

Also add information on how to contact you by electronic and paper mail.

Expand All @@ -503,12 +494,7 @@ school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:

Yoyodyne, Inc., hereby disclaims all copyright interest in the
<<<<<<< HEAD
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
=======
library `Frob' (a library for tweaking knobs) written by James Random
Hacker.
>>>>>>> 6898a473625f7e3b2de05cea2272404971d5331e

<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
Expand Down
15 changes: 8 additions & 7 deletions batchstitcher.ini
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,22 @@ bitrate = 251658240
min_recording_duration = 30
rename_after_stitching = 0
rename_prefix = _
trim_start = 10
trim_end = 12
trim_start = 5
trim_end = -5
blender_type = nvidia
output_format = mp4
zenith_optimisation = 0
flowstate_stabilisation = 1
original_offset = 1
smooth_stitch = 1
brightness = 0
contrast = 10
highlight = 3
shadow = 5
saturation = 5
contrast = 0
highlight = 0
shadow = 0
saturation = 0
temperature = 0
tint = 0
sharpness = 85
sharpness = 0
audio_type = pano
sampling_level = fast
encode_preset = superfast
Expand Down
172 changes: 103 additions & 69 deletions batchstitcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
__author__ = "Axel Busch"
__copyright__ = "Copyright 2022, Xlvisuals Limited"
__license__ = "GPL-2.1"
__version__ = "0.0.2"
__version__ = "0.0.3"
__email__ = "info@xlvisuals.com"

import shutil
Expand All @@ -24,7 +24,7 @@
from time import sleep


class BatchStitcher():
class BatchStitcher():

def __init__(self):
self.inifile_name = "batchstitcher.ini"
Expand Down Expand Up @@ -66,6 +66,8 @@ def init(self):

# Scripts running under py2exe do not have a __file__ global
default_inifile_path = os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), self.inifile_name)
if not os.path.exists(default_inifile_path):
default_inifile_path = self.inifile_name
try:
inifile_dir = os.path.join(Helpers.get_datadir(), "BatchStitcher")
self.inifile_path = os.path.join(inifile_dir, self.inifile_name)
Expand Down Expand Up @@ -120,9 +122,9 @@ def _init_gui(self):
self.settings_widgets[k] = None
self.settings_labels[k] = None
self.settings_buttons[k] = None
self.settings_stringvars["bitrate_mbps"] = tk.StringVar(value=str(int(int(self.settings["bitrate"])/1024/1024)))
for k in self.intvar_keys:
self.settings_intvars[k] = tk.IntVar(value=Helpers.parse_int(self.settings[k]))
self.settings_intvars["bitrate_mbps"] = tk.IntVar(value=int(Helpers.parse_int(self.settings["bitrate"])/1024/1024))

if platform == "darwin":
self.editor_width = 25
Expand Down Expand Up @@ -311,7 +313,7 @@ def _on_about(self):
title = 'About Batch Stitcher'
message = (
'Batch Stitcher for Insta360 Pro 2 by Axel Busch\n'
'Version 0.0.2\n'
'Version 0.0.3\n'
'\n'
'Provided by Mantis Sub underwater housing for Pro 2\n'
'Visit https://www.mantis-sub.com/'
Expand All @@ -332,25 +334,49 @@ def _on_quit(self):
sleep(0.1)
self.root.quit()

def _on_save(self, quiet=False):
def _on_save(self, to_file=False, quiet=False):
result = False
for k in self.settings_stringvars.keys():
self.settings[k] = self.settings_stringvars[k].get()
try:
self.settings[k] = self.settings_stringvars[k].get()
except Exception as e:
if not quiet:
messagebox.showwarning(title="Warning", message=f"Could not save setting {k}: {str(e)}")
else:
print(f"fCould not save setting {k}: {str(e)}")
for k in self.intvar_keys:
self.settings[k] = self.settings_intvars[k].get()
if self.settings.get("bitrate_mpbs"):
self.settings["bitrate"] = Helpers.parse_int(self.settings_intvars["bitrate_mpbs"]) * 1024 * 1024
# if platform == "darwin":
# if self.settings["blender_type"] == "cuda":
# # cuda not supported on mac
# self.settings["blender_type"] = "opencl"

if Helpers.write_config(self.inifile_path, self.settings):
if not quiet:
messagebox.showinfo(title="Info", message="Settings saved.")
return True
try:
self.settings[k] = self.settings_intvars[k].get()
except Exception as e:
if not quiet:
messagebox.showwarning(title="Warning", message=f"Could not save setting {k}: {str(e)}")
else:
print(f"fCould not save setting {k}:: {str(e)}")
if self.settings_intvars.get("bitrate_mbps"):
try:
self.settings["bitrate"] = Helpers.parse_int(self.settings_intvars["bitrate_mbps"].get()) * 1024 * 1024
except Exception as e:
if not quiet:
messagebox.showwarning(title="Warning", message=f"fCould not save setting bitrate_mbps: {str(e)}")
else:
print(f"fCould not save setting bitrate_mbps: {str(e)}")
if to_file:
# optional
try:
if Helpers.write_config(self.inifile_path, self.settings):
if not quiet:
messagebox.showinfo(title="Info", message="Settings saved.")
else:
if not quiet:
messagebox.showerror(title="Error", message="Could not save settings to file.")
except Exception as e:
if not quiet:
messagebox.showerror(title="Error", message=f"Error saving settings to file: {str(e)}")
else:
print("Error saving settings to file:", e)
else:
messagebox.showerror(title="Error", message="Could not save settings.")
return False
result = True
return result

def _clear_log(self):
self.text_area.configure(state=tk.NORMAL)
Expand All @@ -368,21 +394,21 @@ def start_stitcher():
self._clear_log()
self.button_start.config(state=tk.DISABLED)
self.button_cancel.config(state=tk.NORMAL)
if self._on_save(quiet=True):

if not os.path.isdir(self.settings.get('source_dir')):
messagebox.showwarning(title="Warning", message="No valid source folder selected.")
elif not os.path.isdir(self.settings.get('target_dir')):
messagebox.showwarning(title="Warning", message="No valid target folder selected.")
elif not os.path.isfile(self.settings.get('stitcher_path')):
messagebox.showwarning(title="Warning", message="No ProStitcher executable selected.")
elif not os.path.isfile(self.settings.get('ffprobe_path')):
messagebox.showwarning(title="Warning", message="No ffprobe executable selected.")
else:
self._stitching_thread = threading.Thread(target=start_stitcher)
if self._stitching_thread:
self._stitching_thread.start()
self._can_quit = False
self._on_save(to_file=True, quiet=True)

if not os.path.isdir(self.settings.get('source_dir')):
messagebox.showwarning(title="Warning", message="No valid source folder selected.")
elif not os.path.isdir(self.settings.get('target_dir')):
messagebox.showwarning(title="Warning", message="No valid target folder selected.")
elif not os.path.isfile(self.settings.get('stitcher_path')):
messagebox.showwarning(title="Warning", message="No ProStitcher executable selected.")
elif not os.path.isfile(self.settings.get('ffprobe_path')):
messagebox.showwarning(title="Warning", message="No ffprobe executable selected.")
else:
self._stitching_thread = threading.Thread(target=start_stitcher)
if self._stitching_thread:
self._stitching_thread.start()
self._can_quit = False
finally:
if not self._is_stitching_thread_alive():
self._stitcher = None
Expand Down Expand Up @@ -456,7 +482,6 @@ def _populate_scroll_frame(self):

row_s = 0
ttk.Label(self.scroll_frame, text="Setup", anchor='e').grid(row=row_s, column=0,padx=2, pady=8,sticky="e")
#ttk.Separator(self.scroll_frame, orient='horizontal').grid(row=row_s, column=1, columnspan=2, padx=2, pady=8, sticky="ew")

settings_with_buttons = [("source_dir", 'Source folder:',self._on_select_source_dir),
("target_dir", 'Output folder:', self._on_select_target_dir),
Expand Down Expand Up @@ -541,9 +566,9 @@ def _populate_scroll_frame(self):
k = "blender_type"
blender_type_values = ("auto", "cuda", "opencl", "cpu")
blender_type_label = "Cuda only on Nvidia cards"
# if platform == "darwin":
# blender_type_values = ("auto", "opencl", "cpu")
# blender_type_label = "opencl for best performance on macOS"
if platform == "darwin":
blender_type_values = ("auto", "opencl", "cpu")
blender_type_label = "opencl for best performance on macOS"
self.settings_labels[k] = ttk.Label(self.scroll_frame, text="Blender type:", anchor='e', width=25)
self.settings_labels[k].grid(row=row_s, column=0, padx=2, pady=2, sticky="e")
self.settings_widgets[k] = ttk.Combobox(self.scroll_frame,
Expand Down Expand Up @@ -652,7 +677,6 @@ def _populate_scroll_frame(self):
self.settings_widgets[k].grid(row=row_s, column=1, padx=2, pady=2, sticky="w")
ttk.Label(self.scroll_frame, text="-180 to 180 Degrees, default 0", anchor='w').grid(row=row_s, column=2, padx=2, pady=2, sticky="w")


row_s += 1
ttk.Label(self.scroll_frame, text="Color", anchor='e').grid(row=row_s, column=0, padx=2, pady=8, sticky="e")
color_settings = ["brightness", "contrast", "highlight", "shadow", "saturation", "temperature", "tint", "sharpness"]
Expand All @@ -670,8 +694,19 @@ def _populate_scroll_frame(self):
ttk.Label(self.scroll_frame, text="Output", anchor='e').grid(row=row_s, column=0, padx=2, pady=8, sticky="e")

row_s += 1
k = "codec"
self.settings_labels[k] = ttk.Label(self.scroll_frame, text="Codec:", anchor='e', width=25)
k = "output_format"
self.settings_labels[k] = ttk.Label(self.scroll_frame, text="File format:", anchor='e', width=25)
self.settings_labels[k].grid(row=row_s, column=0, padx=2, pady=2, sticky="e")
self.settings_widgets[k] = ttk.Combobox(self.scroll_frame,
textvariable=self.settings_stringvars[k],
values=("mp4", "mov",))
self.settings_widgets[k].config(width=self.editor_width-2, state="readonly")
self.settings_widgets[k].grid(row=row_s, column=1, padx=2, pady=2, sticky="w")
ttk.Label(self.scroll_frame, text="default is mp4, prores requires mov", anchor='w').grid(row=row_s, column=2, padx=2, pady=2,sticky="w")

row_s += 1
k = "output_codec"
self.settings_labels[k] = ttk.Label(self.scroll_frame, text="Codec type:", anchor='e', width=25)
self.settings_labels[k].grid(row=row_s, column=0, padx=2, pady=2, sticky="e")
self.settings_widgets[k] = ttk.Combobox(self.scroll_frame,
textvariable=self.settings_stringvars[k],
Expand All @@ -688,6 +723,28 @@ def _populate_scroll_frame(self):
self.settings_widgets[k].grid(row=row_s, column=1, padx=2, pady=2, sticky="w")
ttk.Label(self.scroll_frame, text="Not supported for all modes on all platforms", anchor='w').grid(row=row_s, column=2, padx=2, pady=2, sticky="w")

row_s += 1
k = "encode_profile"
self.settings_labels[k] = ttk.Label(self.scroll_frame, text="Encoding profile", anchor='e', width=25)
self.settings_labels[k].grid(row=row_s, column=0, padx=2, pady=2, sticky="e")
self.settings_widgets[k] = ttk.Combobox(self.scroll_frame,
textvariable=self.settings_stringvars[k],
values=("baseline", "main", "high"))
self.settings_widgets[k].config(width=self.editor_width-2, state="readonly")
self.settings_widgets[k].grid(row=row_s, column=1, padx=2, pady=2, sticky="w")
ttk.Label(self.scroll_frame, text="Default is baseline", anchor='w').grid(row=row_s, column=2, padx=2, pady=2, sticky="w")
row_s += 1

k = "encode_preset"
self.settings_labels[k] = ttk.Label(self.scroll_frame, text="Encoding speed", anchor='e', width=25)
self.settings_labels[k].grid(row=row_s, column=0, padx=2, pady=2, sticky="e")
self.settings_widgets[k] = ttk.Combobox(self.scroll_frame,
textvariable=self.settings_stringvars[k],
values=("superfast", "veryfast", "faster", "fast", "medium"))
self.settings_widgets[k].config(width=self.editor_width-2, state="readonly")
self.settings_widgets[k].grid(row=row_s, column=1, padx=2, pady=2, sticky="w")
ttk.Label(self.scroll_frame, text="Default is superfast", anchor='w').grid(row=row_s, column=2, padx=2, pady=2, sticky="w")

row_s += 1
k = "width"
self.settings_labels[k] = ttk.Label(self.scroll_frame, text="Width:", anchor='e', width=25)
Expand All @@ -700,15 +757,15 @@ def _populate_scroll_frame(self):
ttk.Label(self.scroll_frame, text="Height is set automatically", anchor='w').grid(row=row_s, column=2, padx=2, pady=2, sticky="w")

row_s += 1
k = "bitrate"
k = "bitrate_mbps"
self.settings_labels[k] = ttk.Label(self.scroll_frame, text="Bitrate:", anchor='e', width=25)
self.settings_labels[k].grid(row=row_s, column=0, padx=2, pady=2, sticky="e")
self.settings_widgets[k] = ttk.Combobox(self.scroll_frame,
textvariable=self.settings_stringvars["bitrate_mbps"],
textvariable=self.settings_intvars[k],
values=("60", "120", "240", "480", "960", "1920", "4090"))
self.settings_widgets[k].config(width=self.editor_width-2)
self.settings_widgets[k].grid(row=row_s, column=1, padx=2, pady=2, sticky="w")
ttk.Label(self.scroll_frame, text="Mbps", anchor='w').grid(row=row_s, column=2, padx=2, pady=2, sticky="w")
ttk.Label(self.scroll_frame, text="Mbps. Use 1920 or higher for prores.", anchor='w').grid(row=row_s, column=2, padx=2, pady=2, sticky="w")

row_s += 1
k = "output_fps"
Expand All @@ -721,27 +778,6 @@ def _populate_scroll_frame(self):
self.settings_widgets[k].grid(row=row_s, column=1, padx=2, pady=2, sticky="w")
ttk.Label(self.scroll_frame, text="Default is recording frame rate", anchor='w').grid(row=row_s, column=2, padx=2, pady=2, sticky="w")


row_s += 1
k = "encode_preset"
self.settings_labels[k] = ttk.Label(self.scroll_frame, text="Encoding speed", anchor='e', width=25)
self.settings_labels[k].grid(row=row_s, column=0, padx=2, pady=2, sticky="e")
self.settings_widgets[k] = ttk.Combobox(self.scroll_frame,
textvariable=self.settings_stringvars[k],
values=("superfast", "veryfast", "faster", "fast", "medium"))
self.settings_widgets[k].config(width=self.editor_width-2, state="readonly")
self.settings_widgets[k].grid(row=row_s, column=1, padx=2, pady=2, sticky="w")
ttk.Label(self.scroll_frame, text="Default is superfast", anchor='w').grid(row=row_s, column=2, padx=2, pady=2, sticky="w")
row_s += 1
k = "encode_profile"
self.settings_labels[k] = ttk.Label(self.scroll_frame, text="Encoding profile", anchor='e', width=25)
self.settings_labels[k].grid(row=row_s, column=0, padx=2, pady=2, sticky="e")
self.settings_widgets[k] = ttk.Combobox(self.scroll_frame,
textvariable=self.settings_stringvars[k],
values=("baseline", "main", "high"))
self.settings_widgets[k].config(width=self.editor_width-2, state="readonly")
self.settings_widgets[k].grid(row=row_s, column=1, padx=2, pady=2, sticky="w")
ttk.Label(self.scroll_frame, text="Default is baseline", anchor='w').grid(row=row_s, column=2, padx=2, pady=2, sticky="w")
row_s += 1
k = "audio_type"
self.settings_labels[k] = ttk.Label(self.scroll_frame, text="Audio type", anchor='e', width=25)
Expand All @@ -754,8 +790,6 @@ def _populate_scroll_frame(self):
ttk.Label(self.scroll_frame, text="Default is pano (= Spatial)", anchor='w').grid(row=row_s, column=2, padx=2, pady=2, sticky="w")




row_s += 1
ttk.Label(self.scroll_frame, text="Post processing", anchor='e').grid(row=row_s, column=0, padx=2, pady=8, sticky="e")

Expand Down Expand Up @@ -816,7 +850,7 @@ def show(self):


def run():
b = BatchStitcher()
b = BatchStitcher()
b.init()
b.show()

Expand Down

0 comments on commit e54847c

Please sign in to comment.