-
Notifications
You must be signed in to change notification settings - Fork 1
/
ffmpeg_converter.py
151 lines (123 loc) · 5.96 KB
/
ffmpeg_converter.py
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
import sys
import os
import glob
from PyQt5 import QtWidgets, QtGui, QtCore
import subprocess
class FFmpegConverter(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.sequenceFiles = []
self.inputDirectory = ''
self.initUI()
def initUI(self):
# Set window properties
self.setWindowTitle('FFmpeg EXR Converter')
self.setGeometry(100, 100, 600, 400)
# Apply dark theme
self.setStyleSheet('background-color: #2e2e2e; color: #ffffff;')
# Create layout
layout = QtWidgets.QVBoxLayout()
# Input file selection
self.inputButton = QtWidgets.QPushButton('Select Input EXR Sequence')
self.inputButton.clicked.connect(self.selectInputSequence)
layout.addWidget(self.inputButton)
# Codec selection
self.codecLabel = QtWidgets.QLabel('Select Codec:')
self.codecCombo = QtWidgets.QComboBox()
self.codecCombo.addItems(['mp4', 'ProRes', 'Animation', 'H.265'])
layout.addWidget(self.codecLabel)
layout.addWidget(self.codecCombo)
# Frame rate selection
self.fpsLabel = QtWidgets.QLabel('Frame Rate (FPS):')
self.fpsInput = QtWidgets.QLineEdit('24')
layout.addWidget(self.fpsLabel)
layout.addWidget(self.fpsInput)
# Bitrate selection (optional)
self.bitrateLabel = QtWidgets.QLabel('Bitrate (optional, e.g., 5M):')
self.bitrateInput = QtWidgets.QLineEdit() # Keep it optional
layout.addWidget(self.bitrateLabel)
layout.addWidget(self.bitrateInput)
# Resolution selection
self.resLabel = QtWidgets.QLabel('Output Resolution (e.g., 1920x1080):')
self.resInput = QtWidgets.QLineEdit()
layout.addWidget(self.resLabel)
layout.addWidget(self.resInput)
# Output file selection
self.outputButton = QtWidgets.QPushButton('Select Output Location')
self.outputButton.clicked.connect(self.selectOutputLocation)
layout.addWidget(self.outputButton)
self.outputPath = QtWidgets.QLineEdit()
self.outputPath.setPlaceholderText('Output file path (optional)')
layout.addWidget(self.outputPath)
# Convert button
self.convertButton = QtWidgets.QPushButton('Convert')
self.convertButton.clicked.connect(self.convertSequence)
layout.addWidget(self.convertButton)
self.setLayout(layout)
self.show()
def selectInputSequence(self):
options = QtWidgets.QFileDialog.Options()
fileName, _ = QtWidgets.QFileDialog.getOpenFileName(self, 'Select First EXR File', '', 'EXR Files (*.exr)', options=options)
if fileName:
self.inputDirectory = os.path.dirname(fileName)
baseName = os.path.basename(fileName)
prefix = ''.join(filter(lambda x: not x.isdigit(), baseName))
pattern = prefix + '*[0-9]*.exr'
self.sequenceFiles = sorted(glob.glob(os.path.join(self.inputDirectory, pattern)))
QtWidgets.QMessageBox.information(self, 'Sequence Selected', f'Found {len(self.sequenceFiles)} files in sequence.')
def selectOutputLocation(self):
options = QtWidgets.QFileDialog.Options()
fileName, _ = QtWidgets.QFileDialog.getSaveFileName(self, 'Select Output Location', '', 'All Files (*)', options=options)
if fileName:
self.outputPath.setText(fileName)
def convertSequence(self):
if not self.sequenceFiles:
QtWidgets.QMessageBox.warning(self, 'No Sequence', 'Please select an input EXR sequence.')
return
outputCodec = self.codecCombo.currentText()
fps = self.fpsInput.text()
bitrate = self.bitrateInput.text() if self.bitrateInput.text() else None
resolution = self.resInput.text().strip()
# Validate FPS
if not fps.isdigit():
QtWidgets.QMessageBox.warning(self, 'Invalid FPS', 'Please enter a valid frame rate (FPS).')
return
# Validate Resolution Format if provided
if resolution and 'x' not in resolution:
QtWidgets.QMessageBox.warning(self, 'Invalid Resolution', 'Please enter resolution in WIDTHxHEIGHT format (e.g., 1920x1080).')
return
# Determine output file path
if self.outputPath.text():
outputFile = self.outputPath.text()
else:
outputFile = os.path.join(self.inputDirectory, f'output.{outputCodec.lower()}')
# Ensure the output file has the correct extension
if not outputFile.lower().endswith(f'.{outputCodec.lower()}'):
outputFile += f'.{outputCodec.lower()}'
# Build FFmpeg command
inputPath = os.path.join(self.inputDirectory, '%*.exr')
cmd = ['ffmpeg', '-framerate', fps, '-i', inputPath]
if resolution:
cmd.extend(['-s', resolution])
if bitrate:
cmd.extend(['-b:v', bitrate])
# Codec-specific settings
if outputCodec == 'mp4':
cmd.extend(['-c:v', 'libx264', '-pix_fmt', 'yuv420p'])
elif outputCodec == 'ProRes':
cmd.extend(['-c:v', 'prores_ks'])
elif outputCodec == 'Animation':
cmd.extend(['-c:v', 'qtrle'])
elif outputCodec == 'H.265':
cmd.extend(['-c:v', 'libx265'])
cmd.append(outputFile)
try:
# Execute FFmpeg command
subprocess.run(cmd, check=True)
QtWidgets.QMessageBox.information(self, 'Conversion Complete', f'Output file saved as {outputFile}.')
except subprocess.CalledProcessError as e:
QtWidgets.QMessageBox.critical(self, 'Conversion Failed', f'An error occurred during conversion:\n{e}')
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
converter = FFmpegConverter()
sys.exit(app.exec_())