-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathffmpeg-repl.py
More file actions
172 lines (143 loc) · 6.22 KB
/
ffmpeg-repl.py
File metadata and controls
172 lines (143 loc) · 6.22 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
#!/bin/python3
import readline # Add this at the top
# ... rest of the code
from datetime import datetime
import subprocess
import sys
cmdConcat='ffmpeg -i video1.mp4 -i video2.mp4 -filter_complex "[0:v][1:v]concat=n=2:v=1:a=0[v]" -map "[v]" output.mp4'
#audio from first vid
cmdAudioFromFirst = 'ffmpeg -i video1.mp4 -i video2.mp4 -filter_complex "[0:v][1:v]hstack[v]" -map "[v]" -map 0:a -c:a copy output.mp4'
#resize videos to same height
cmdResizeToSameHeight = 'ffmpeg -i video1.mp4 -i video2.mp4 -filter_complex "[0:v]scale=-1:720[v0];[1:v]scale=-1:720[v1];[v0][v1]hstack[v]" -map "[v]" -map 0:a -c:a copy output.mp4'
#padding between vids
cmdPadding = 'ffmpeg -i video1.mp4 -i video2.mp4 -filter_complex "[0:v]pad=iw+10:ih[v0];[v0][1:v]hstack[v]" -map "[v]" -map 0:a output.mp4'
#shorter duration vid
cmdDurationShorter = 'ffmpeg -i video1.mp4 -i video2.mp4 -filter_complex "[0:v][1:v]hstack=shortest=1[v]" -map "[v]" -map 0:a output.mp4'
#mix audio from both
cmdAudioMix = 'ffmpeg -i video1.mp4 -i video2.mp4 -filter_complex "[0:v][1:v]hstack=shortest=1[v]" -map "[v]" -map 0:a output.mp4'
#force same dimensions
cmdForceSameDimension = 'ffmpeg -i video1.mp4 -i video2.mp4 -filter_complex "[0:v][1:v]hstack[v];[0:a][1:a]amix[a]" -map "[v]" -map "[a]" output.mp4'
#vertical stack
cmdStackVertical = 'ffmpeg -i video1.mp4 -i video2.mp4 -filter_complex "[0:v]scale=640:480[v0];[1:v]scale=640:480[v1];[v0][v1]hstack[v]" -map "[v]" -map 0:a output.mp4'
cmdStackHorizontal = 'ffmpeg -i video1.mp4 -i video2.mp4 -filter_complex hstack output.mp4'
#3 or more vids sidebyside
cmdMultiVids = 'ffmpeg -i video1.mp4 -i video2.mp4 -i video3.mp4 -filter_complex "[0:v][1:v][2:v]hstack=inputs=3[v]" -map "[v]" -map 0:a output.mp4'
class SimpleREPL:
def __init__(self):
self.prompt = ">> "
self.commands = {
"help": self._show_help,
"exit": self._exit_repl,
"quit": self._exit_repl, # Alias for exit
"echo": self._echo,
"stack": self.stack, #vertical or horizontal
}
def stack(self):
return
def _show_help(self, *args):
"""Displays available commands."""
print("Available commands:")
for cmd, func in self.commands.items():
docstring = func.__doc__ or "No description available."
print(f" {cmd:<15} - {docstring.strip().splitlines()[0]}") # Show first line of docstring
return None # No printable result for help
def _exit_repl(self, *args):
"""Exits the REPL."""
print("Exiting REPL. Goodbye!")
sys.exit(0)
def _echo(self, *args):
"""Echoes the input arguments back to the user.
Usage: echo <arg1> <arg2> ...
"""
if not args:
return "Echo: Nothing to echo!"
return "Echo: " + " ".join(args)
# --- Placeholder for your custom commands ---
# def _handle_my_command(self, arg1, arg2=None, *other_args):
# """
# Description of my_command.
# Usage: my_command <required_arg> [optional_arg] ...
# """
# # Your command logic here
# # Example:
# # self.app_state['something'] = arg1
# # return f"Processed {arg1} and {arg2}"
# pass
def evaluate(self, line):
"""Evaluates a single line of input."""
parts = line.strip().split()
if not parts:
return None # Empty line
command_name = parts[0].lower() # Case-insensitive command matching
args = parts[1:]
if command_name in self.commands:
command_func = self.commands[command_name]
try:
return command_func(*args)
except TypeError as e:
# Catch errors related to incorrect number of arguments
return f"Error: Invalid arguments for '{command_name}'. Usage: {command_func.__doc__ or ''}"
except Exception as e:
return f"Error executing '{command_name}': {e}"
else: #todo check for partial str match
return f"Unknown command: '{command_name}'. Type 'help' for available commands."
def run(self):
"""Runs the REPL main loop."""
print("Welcome to SimpleREPL! Type 'help' for commands or 'exit' to quit.")
while True:
try:
line = input(self.prompt)
if line.strip(): # Process only if line is not empty
result = self.evaluate(line)
if result is not None: # Print only if there's a result
print(result)
except EOFError: # Ctrl+D
print("\nExiting REPL (EOF).")
break
except KeyboardInterrupt: # Ctrl+C
print("\nInterrupted. Type 'exit' or 'quit' to exit.")
# Optionally, you might want to clear any partial input here
# or reset some state if an operation was interrupted.
except Exception as e:
print(f"An unexpected error occurred: {e}")
# Depending on severity, you might want to break or continue
if __name__ == "__main__":
repl_app = SimpleREPL()
repl_app.run()
#Common. functions that are frequently used by many utilities
#execute a command
'''def cmd(cmdStr):
return subprocess.run(cmdStr.join(' '), encoding='utf-8', stdout=subprocess.PIPE).stdout
'''
'''
execute a command using the python subprocess module
params:
cmdstr (str) : the command to run
return: stdout of command
'''
def cmd(cmdstr,v=False):
cmdarray = cmdstr.strip().split(' ')
log(f'runcmd: {cmdstr}')
'''if '|' in cmdarray: #TODO handling pipe not yet working
i = cmdarray.index('|')
proc0 = subprocess.check_output(cmdstr, shell=True)'''
proc = subprocess.run(cmdarray, stdout=subprocess.PIPE)
if proc.returncode == 0:
res = proc.stdout
else:
log(f'returncode = {proc.returncode}')
res = proc.stderr
return res
def log(msg, filename=None):
fn = filename
if fn == None:
fn = logfilenamedefault
t = tnow()
with open(filename, 'a') as lf:
lf.write(f'{t}: {msg}\n')
lf.close()
def tnow():
'''
return: current time, formatted as %Y%m%d-%H%M%S
'''
return datetime.now().strftime('%Y%m%d-%H%M%S')