commit 185632063bbb48aafe2fa4226c67dbd4a39f7f3c Author: Jack Date: Fri Sep 13 12:22:04 2024 -0400 Initial commit diff --git a/ffmpeg.exe b/ffmpeg.exe new file mode 100644 index 0000000..a912fb1 Binary files /dev/null and b/ffmpeg.exe differ diff --git a/tinyblast.py b/tinyblast.py new file mode 100644 index 0000000..934aed6 --- /dev/null +++ b/tinyblast.py @@ -0,0 +1,170 @@ +import maya.OpenMaya as om +import maya.OpenMayaMPx as ompx +import maya.cmds as cmds +import os +import subprocess +import sys + +# Global variable to store the scriptJob ID +playblast_job_id = None +original_playblast = cmds.playblast + +def get_plugin_directory(): + # Get the path of the currently loaded plugin + plugin_name = "tinyblast" + plugin_path = cmds.pluginInfo(plugin_name, query=True, path=True) + return os.path.dirname(plugin_path) + +def custom_playblast(*args, **kwargs): + print("Running playblast...") + + kwargs['format'] = 'avi' + kwargs['percent'] = 100 + kwargs['quality'] = 100 + kwargs['widthHeight'] = (1920, 1080) + + result = original_playblast(*args, **kwargs) + print(f"{result}") + + if result: + try: + ffmpeg_path = os.path.join(get_plugin_directory(), 'ffmpeg.exe') + print(f"ffmpeg path: {ffmpeg_path}") + if not os.path.exists(ffmpeg_path): + raise FileNotFoundError(f"FFmpeg binary not found at {ffmpeg_path}") + + input_file = result # The file output by playblast + #output_directory = os.path.dirname(result) # Get the directory path + output_directory = os.path.dirname(cmds.file(query=True, sceneName=True)) + input_filename = os.path.basename(result) # Get the filename with extension + + # Change the extension to .mp4 + output_filename = os.path.splitext(input_filename)[0] + ".mp4" + + # Define the full path for the converted output file + output_file = os.path.join(output_directory, output_filename) + + # Run FFmpeg conversion + subprocess.run([ffmpeg_path, + '-i', input_file, + '-vcodec', 'libx264', + '-pix_fmt', 'yuv420p', + '-strict', 'experimental', + '-b:v', '1m', + output_file, + '-y'], check=True, shell=True) + print(f"Video conversion to {output_file} successful!") + # os.remove(input_file) # Running into permission issues trying to delete from AppData + # print(f"Original playblast deleted: {input_file}") + except subprocess.CalledProcessError as e: + print(f"Error during FFmpeg conversion: {e}") + +class WindowWatcher: + """ A class to watch for a particular window in Maya """ + + def __init__(self, window_title, on_open_callback, on_close_callback=None): + self.window_title = window_title + self.on_open_callback = on_open_callback + self.on_close_callback = on_close_callback + self.window_opened = False + + def check_for_window_open(self): + if not self.window_opened: + window = self.get_window_by_title(self.window_title) + if window: + self.on_open_callback() + self.window_opened = True + else: + window = self.get_window_by_title(self.window_title) + if not window: + self.window_opened = False + if self.on_close_callback: + self.on_close_callback() + + def get_window_by_title(self, title): + # Check all open windows and return the one that matches the title + windows = cmds.lsUI(windows=True) + for window in windows: + if cmds.window(window, query=True, title=True) == title: + return window + return None + + +def add_custom_button_to_playblast(): + # Get the Playblast Options window + window = get_playblast_options_window() + + if window: + # Find the layout of the Playblast Options window + layout = cmds.columnLayout(adjustableColumn=True) + if layout: + # Add a custom button below existing UI + cmds.setParent(layout) # Set the parent to the top-level layout + cmds.columnLayout(adjustableColumn=True) + cmds.button(label="Tinyblast", command=custom_button_action) + else: + print("Couldn't find the layout for the Playblast Options window.") + else: + print("Playblast Options window not found.") + + +def custom_button_action(*args): + cmds.playblast() + + +def get_playblast_options_window(): + # Check if the Playblast Options window is open + windows = cmds.lsUI(windows=True) + for window in windows: + if cmds.window(window, query=True, title=True) == "Playblast Options": # Exact title match + return window + return None + +def setup_script_job(): + global playblast_job_id + + # Kill any previously running scriptJob + if playblast_job_id is not None and cmds.scriptJob(exists=playblast_job_id): + cmds.scriptJob(kill=playblast_job_id, force=True) + print(f"Killed previous scriptJob with ID: {playblast_job_id}") + + # Watch for the Playblast Options window by title + playblast_watcher = WindowWatcher( + window_title="Playblast Options", # Exact window title to look for + on_open_callback=add_custom_button_to_playblast + ) + + # Set up a new scriptJob + playblast_job_id = cmds.scriptJob(event=["idle", playblast_watcher.check_for_window_open]) + +class Tinyblast(ompx.MPxCommand): + def __init__(self): + ompx.MPxCommand.__init__(self) + + def doIt(selfself, args): + print("Executing custom playblast command.") + cmds.playblast() + + @staticmethod + def cmdCreator(): + return ompx.asMPxPtr(Tinyblast()) + +def initializePlugin(mobject): + try: + mplugin = ompx.MFnPlugin(mobject, "Jack Christensen", "1.0.0", "Any") + mplugin.registerCommand("tinyblast", Tinyblast.cmdCreator) + om.MGlobal.displayInfo("Tinyblast plugin loaded.") + setup_script_job() + cmds.playblast = custom_playblast + except Exception as e: + om.MGlobal.displayError(f"Failed to initialize plugin: {str(e)}") + raise + +def uninitializePlugin(mobject): + try: + mplugin = ompx.MFnPlugin(mobject) + mplugin.deregisterCommand("tinyblast") + om.MGlobal.displayInfo("Tinyblast plugin unloaded.") + except Exception as e: + om.MGlobal.displayError(f"Failed to uninitialize plugin: {str(e)}") + raise \ No newline at end of file