[Python] 纯文本查看 复制代码
# -*- coding:utf-8 -*-
import wx
import subprocess
import os
import sys
import re
#解决额外资源打包问题
def get_path(relative_path):
try:
base_path = sys._MEIPASS
except AttributeError:
base_path = os.path.abspath(".")
return os.path.normpath(os.path.join(base_path, relative_path))
ffmpeg_path =get_path("assets/ffmpeg.exe")#资源的路径
#弹窗消息
def show_message(message):
"""
显示消息框。
参数:
message (str): 要显示的消息。
"""
app = wx.App(False)
dlg = wx.MessageDialog(None, message, "提示", wx.OK | wx.ICON_INFORMATION)
dlg.ShowModal()
dlg.Destroy()
app.MainLoop()
#转mp4
def convert_to_mp4(input_video_path, output_directory):
"""
将输入的视频文件转换为 MP4 格式。
参数:
input_video_path (str): 输入视频文件的路径。
output_directory (str): 输出目录的路径。
"""
video_name = os.path.splitext(os.path.basename(input_video_path))[0]
output_mp4_path = os.path.join(output_directory, f"{video_name}.mp4")
if os.path.exists(output_mp4_path):
show_message(f"目录中存在同名文件 '{output_mp4_path}',请删除或重命名后重试。")
return
result=subprocess.run([ffmpeg_path, "-i", input_video_path, "-c:v", "libx264", "-preset", "slow", "-crf", "23", "-c:a", "aac", "-b:a", "192k", "-strict", "experimental", output_mp4_path])
if result.returncode == 0:
show_message("转码成功!")
else:
show_message(f"转码失败!错误代码:{result.returncode}")
#转mp3
def convert_to_mp3(input_video_path, output_directory):
"""
将输入的视频文件转换为 MP3 格式。
参数:
input_video_path (str): 输入视频文件的路径。
output_directory (str): 输出目录的路径。
"""
video_name = os.path.splitext(os.path.basename(input_video_path))[0]
output_mp3_path = os.path.join(output_directory, f"{video_name}.mp3")
if os.path.exists(output_mp3_path):
show_message(f"目录中存在同名文件 '{output_mp3_path}',请删除或重命名后重试。")
return
result=subprocess.run([ffmpeg_path, "-i", input_video_path, "-vn", "-acodec", "libmp3lame", output_mp3_path])
if result.returncode == 0:
show_message("转码成功!")
else:
show_message(f"转码失败!错误代码:{result.returncode}")
#转avi
def convert_to_avi(input_video_path, output_directory):
"""
将输入的视频文件转换为 AVI 格式。
参数:
input_video_path (str): 输入视频文件的路径。
output_directory (str): 输出目录的路径。
"""
video_name = os.path.splitext(os.path.basename(input_video_path))[0]
output_avi_path = os.path.join(output_directory, f"{video_name}.avi")
if os.path.exists(output_avi_path):
show_message(f"目录中存在同名文件 '{output_avi_path}',请删除或重命名后重试。")
return
result=subprocess.run([ffmpeg_path, "-i", input_video_path, "-c:v", "libx264", "-preset", "slow", "-crf", "23", "-c:a", "pcm_s16le", output_avi_path])
if result.returncode == 0:
show_message("转码成功!")
else:
show_message(f"转码失败!错误代码:{result.returncode}")
#转wmv
def convert_to_wmv(input_video_path, output_directory):
"""
将输入的视频文件转换为 WMV 格式。
参数:
input_video_path (str): 输入视频文件的路径。
output_directory (str): 输出目录的路径。
"""
video_name = os.path.splitext(os.path.basename(input_video_path))[0]
output_wmv_path = os.path.join(output_directory, f"{video_name}.wmv")
if os.path.exists(output_wmv_path):
show_message(f"目录中存在同名文件 '{output_wmv_path}',请删除或重命名后重试。")
return
result=subprocess.run([ffmpeg_path, "-i", input_video_path, "-c:v", "wmv2", "-b:v", "1024k", "-c:a", "wmav2", output_wmv_path])
if result.returncode == 0:
show_message("转码成功!")
else:
show_message(f"转码失败!错误代码:{result.returncode}")
#转gif
def convert_to_gif(input_video_path, output_directory, start_time, end_time, fps=10):
"""
将输入的视频文件转换为 GIF 格式。
参数:
input_video_path (str): 输入视频文件的路径。
output_directory (str): 输出目录的路径。
start_time (int): 视频开始时间(以秒为单位)。
end_time (int): 视频结束时间(以秒为单位)。
fps (int): GIF 的帧率,默认为 10。
"""
video_name = os.path.splitext(os.path.basename(input_video_path))[0]
output_gif_path = os.path.join(output_directory, f"{video_name}_segment.gif")
if os.path.exists(output_gif_path):
show_message(f"目录中存在同名文件 '{output_gif_path}',请删除或重命名后重试。")
return
result=subprocess.run([ffmpeg_path, "-ss", str(start_time), "-i", input_video_path, "-t", str(end_time - start_time), "-vf", f"fps={fps}", output_gif_path])
if result.returncode == 0:
show_message("转码成功!")
else:
show_message(f"转码失败!错误代码:{result.returncode}")
#转mov
def convert_to_mov(input_video_path, output_directory):
"""
将输入的视频文件转换为 MOV 格式。
参数:
input_video_path (str): 输入视频文件的路径。
output_directory (str): 输出目录的路径。
"""
video_name = os.path.splitext(os.path.basename(input_video_path))[0]
output_mov_path = os.path.join(output_directory, f"{video_name}.mov")
if os.path.exists(output_mov_path):
show_message(f"目录中存在同名文件 '{output_mov_path}',请删除或重命名后重试。")
return
result=subprocess.run([ffmpeg_path, "-i", input_video_path, "-c:v", "libx264", "-preset", "slow", "-crf", "23", output_mov_path])
if result.returncode == 0:
show_message("转码成功!")
else:
show_message(f"转码失败!错误代码:{result.returncode}")
# 函数集合
def function_dispatcher(number,input_video_path,output_directory,start_time,end_time):
"""
根据用户选择的数字执行相应的视频转换函数。
参数:
number (int): 用户选择的数字,代表要执行的转换函数。
input_video_path (str): 输入视频文件的路径。
output_directory (str): 输出目录的路径。
start_time (int): 视频开始时间(以秒为单位)。
end_time (int): 视频结束时间(以秒为单位)。
"""
functions = {
0: convert_to_mp4,
1: convert_to_avi,
2: convert_to_wmv,
3: convert_to_mp3,
4: convert_to_gif,
5: convert_to_mov,
}
if number in functions:
if number == 4: # 如果选中的是转换为 GIF
if start_time is not None and end_time is not None:
functions[number](input_video_path, output_directory, start_time, end_time)
else:
# 在这种情况下,可以选择不传递 start_time 和 end_time 参数,或者传递默认值
functions[number](input_video_path, output_directory, 0, None)
else:
functions[number](input_video_path, output_directory)
#gif所需视频长度格式
def convert_time_to_seconds(time_str):
"""
将时间字符串转换为秒数。
参数:
time_str (str): 表示时间的字符串,可以是 HH:MM:SS 格式或整数表示的秒数。
返回:
int: 转换后的秒数。
"""
if isinstance(time_str, int) or time_str.isdigit():
# 如果输入是整数或者全是数字,则直接解析为整数,代表秒数
return int(time_str)
elif ':' in time_str:
# 如果输入包含冒号,则尝试将其解析为时间格式
parts = time_str.split(':')
if len(parts) == 3:
try:
hours = int(parts[0])
minutes = int(parts[1])
seconds = int(parts[2])
# 计算总秒数
return hours * 3600 + minutes * 60 + seconds
except ValueError:
# 如果解析失败,则说明时间格式不正确
raise ValueError("Invalid time format")
else:
# 如果冒号数量不是三个,则抛出异常
raise ValueError("Invalid time format")
else:
# 如果既不是整数,也不是带冒号的时间格式,则抛出异常
raise ValueError("Invalid time format")
#转换时间字符串
def format_duration(duration):
"""
格式化视频持续时间为 HH:MM:SS 格式的字符串。
参数:
duration (float): 视频的持续时间(以秒为单位)。
返回:
str: 格式化后的时间字符串。
"""
hours = int(duration // 3600)
minutes = int((duration % 3600) // 60)
seconds = int(duration % 60)
return f'{hours:02d}:{minutes:02d}:{seconds:02d}'
#获取视频长度
def chixu_video(input_video_path):
"""
获取视频文件的持续时间,并将其格式化为 HH:MM:SS 的字符串。
参数:
input_video_path (str): 视频文件的路径。
返回:
str: 格式化后的视频持续时间字符串。
"""
if not input_video_path:
return "00:00:00"
# 运行 FFmpeg 命令获取视频时长信息
command = [ffmpeg_path, '-i', input_video_path]
result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
output = result.stderr
# 使用正则表达式从输出中提取视频时长信息
duration_match = re.search(r'Duration:\s*(\d+):(\d+):(\d+)', output)
if duration_match:
hours = int(duration_match.group(1))
minutes = int(duration_match.group(2))
seconds = int(duration_match.group(3))
formatted_duration = f"{hours:02d}:{minutes:02d}:{seconds:02d}"
return formatted_duration
else:
return "00:00:00"
class Frame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, title='原创:吾爱qianaonan', size=(430, 239), name='frame', style=541072384)
self.启动窗口 = wx.Panel(self)
self.Centre()
self.编辑框1 = wx.TextCtrl(self.启动窗口, size=(293, 29), pos=(8, 5), value='', name='text', style=16)
self.编辑框1.SetForegroundColour((128, 128, 128, 255))
self.按钮1 = wx.Button(self.启动窗口, size=(80, 32), pos=(315, 3), label='选择文件', name='button')
self.标签1 = wx.StaticText(self.启动窗口, size=(80, 24), pos=(10, 44), label='转换成', name='staticText',style=2321)
self.单选框2 = wx.RadioButton(self.启动窗口, size=(58, 24), pos=(8, 72), name='radioButton', label='MP4')
self.单选框3 = wx.RadioButton(self.启动窗口, size=(40, 24), pos=(73, 72), name='radioButton', label='AVI')
self.单选框4 = wx.RadioButton(self.启动窗口, size=(58, 24), pos=(136, 72), name='radioButton', label='WMV')
self.单选框5 = wx.RadioButton(self.启动窗口, size=(61, 24), pos=(209, 72), name='radioButton', label='MP3')
self.单选框6 = wx.RadioButton(self.启动窗口, size=(42, 24), pos=(275, 72), name='radioButton', label='GIF')
self.单选框7 = wx.RadioButton(self.启动窗口, size=(80, 24), pos=(327, 72), name='radioButton', label='MOV')
self.按钮2 = wx.Button(self.启动窗口, size=(80, 32), pos=(317, 107), label='保存目录', name='button')
self.编辑框2 = wx.TextCtrl(self.启动窗口, size=(293, 29), pos=(8, 107), value='未选择目录则是源文件相同目录', name='text', style=16)
self.编辑框2.SetForegroundColour((128, 128, 128, 255))
self.按钮3 = wx.Button(self.启动窗口, size=(80, 32), pos=(254, 156), label='开始转换', name='button')
self.Bind(wx.EVT_BUTTON, self.OnSelectFile, self.按钮1) # 绑定选择文件按钮的事件
self.Bind(wx.EVT_BUTTON, self.OnSelectFolder, self.按钮2)
self.按钮3.Bind(wx.EVT_BUTTON, self.按钮3_按钮被单击)
self.标签2 = wx.StaticText(self.启动窗口,size=(195, 36),pos=(15, 153),label='请谨慎使用gif转换,一般是视频过\n长会导致程序卡死',name='staticText',style=17)
self.标签2.SetForegroundColour((255, 0, 0, 255))
self.标签3 = wx.StaticText(self.启动窗口,size=(80, 17),pos=(254, 56),label='10帧/秒',name='staticText',style=2321)
self.标签4 = wx.StaticText(self.启动窗口,size=(80, 46),pos=(335, 151),label='视频越长\n花费时间越长',name='staticText',style=2321)
self.标签4.SetForegroundColour((255, 0, 0, 255))
self.编辑框3 = wx.TextCtrl(self.启动窗口, size=(80, 18), pos=(303, 35), value='', name='text',style=0)
self.编辑框3.SetForegroundColour((128, 128, 128, 255))
self.编辑框4 = wx.TextCtrl(self.启动窗口, size=(80, 18), pos=(304, 54), value='', name='text',style=0)
self.编辑框4.SetForegroundColour((128, 128, 128, 255))
self.编辑框4.Bind(wx.EVT_KILL_FOCUS, self.编辑框4_失去焦点)
self.编辑框4.Bind(wx.EVT_SET_FOCUS, self.onSetFocus)
self.标签5 = wx.StaticText(self.启动窗口, size=(26, 17), pos=(269, 38), label='开始', name='staticText',style=2321)
self.标签6 = wx.StaticText(self.启动窗口, size=(28, 14), pos=(268, 56), label='结束', name='staticText',style=2321)
self.编辑框3.Hide()
self.编辑框4.Hide()
self.标签5.Hide()
self.标签6.Hide()
self.单选框2.Bind(wx.EVT_RADIOBUTTON, self.onRadioButton)
self.单选框3.Bind(wx.EVT_RADIOBUTTON, self.onRadioButton)
self.单选框4.Bind(wx.EVT_RADIOBUTTON, self.onRadioButton)
self.单选框5.Bind(wx.EVT_RADIOBUTTON, self.onRadioButton)
self.单选框6.Bind(wx.EVT_RADIOBUTTON, self.onRadioButton)
self.单选框7.Bind(wx.EVT_RADIOBUTTON, self.onRadioButton)
def 编辑框4_失去焦点(self,event):
self.编辑框4.SetValue(str(chixu_video(self.编辑框1.GetValue())))
def onSetFocus(self, event):
self.编辑框4.SetValue("") # 清空文本框的值
self.编辑框4.SetForegroundColour(wx.BLACK) # 设置黑色
def onRadioButton(self, event):
selectedRadioButton = event.GetEventObject()
if selectedRadioButton in [self.单选框6] and selectedRadioButton.GetValue():
self.标签3.Hide()
self.编辑框3.Show()
self.编辑框4.Show()
self.编辑框3.SetValue('0')
self.编辑框4.SetValue(str(chixu_video(self.编辑框1.GetValue())))
self.标签5.Show()
self.标签6.Show()
else:
self.标签3.Show()
self.编辑框3.Hide()
self.编辑框4.Hide()
self.标签5.Hide()
self.标签6.Hide()
def GetSelectedRadioButtonIndex(self):
radio_buttons = [self.单选框2, self.单选框3, self.单选框4, self.单选框5, self.单选框6, self.单选框7]
for i, button in enumerate(radio_buttons):
if button.GetValue():
return i
return None
def OnSelectFile(self, event):
wildcard = "Video Files (*.mp4;*.avi;*.wmv;*.mov)|*.mp4;*.avi;*.wmv;*.mov|All Files (*.*)|*.*" # 文件类型过滤器
dialog = wx.FileDialog(self, "选择文件", wildcard=wildcard,
style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST | wx.FD_MULTIPLE)
if dialog.ShowModal() == wx.ID_CANCEL:
return
paths = dialog.GetPaths()
directories = paths # 提取文件路径
self.编辑框1.SetValue("\n".join(directories)) # 在编辑框中显示目录,使用换行分隔多个目录
if self.单选框6.GetValue():
self.编辑框4.SetValue(str(chixu_video(self.编辑框1.GetValue())))
dialog.Destroy()
def OnSelectFolder(self, event):
dialog = wx.DirDialog(self, "选择文件夹", style=wx.DD_DEFAULT_STYLE | wx.DD_DIR_MUST_EXIST)
if dialog.ShowModal() == wx.ID_CANCEL:
return
folder_path = dialog.GetPath()
self.编辑框2.SetValue(folder_path) # 在编辑框2中显示所选文件夹路径
dialog.Destroy()
def 按钮3_按钮被单击(self, event):
if self.编辑框1.GetValue().strip() == '' :
wx.MessageBox('你有东西没选中,请重新设置', '警告', wx.OK | wx.ICON_WARNING)
return
if self.GetSelectedRadioButtonIndex() is None:
wx.MessageBox('你有东西没选中,请重新设置', '警告', wx.OK | wx.ICON_WARNING)
return
selected_index = self.GetSelectedRadioButtonIndex() # 输出单选项位置位置
input_path1 = self.编辑框1.GetValue()
if self.编辑框2.GetValue().strip()=='未选择目录则是源文件相同目录':
output_directory1=os.path.dirname(self.编辑框1.GetValue())
else:
output_directory1 = self.编辑框2.GetValue()
start_time_str = self.编辑框3.GetValue()
end_time_str = self.编辑框4.GetValue()
if start_time_str.strip() == '' or end_time_str.strip() == '':
start_time = None
end_time = None
else:
start_time = convert_time_to_seconds(start_time_str)
end_time = convert_time_to_seconds(end_time_str)
function_dispatcher(selected_index, input_path1, output_directory1, start_time, end_time)
class myApp(wx.App):
def OnInit(self):
self.frame = Frame()
self.frame.Show(True)
return True
if __name__ == '__main__':
app = myApp()
app.MainLoop()