视频万能转换器(源码)

news/2025/2/11 17:51:37/文章来源:https://www.cnblogs.com/lyt263/p/18709571
import os
import sys
import tkinter as tk
from tkinter import filedialog, ttk
import subprocess
import threading
import datetimeclass VideoConverterApp:def __init__(self, root):self.root = rootself.root.title("万能高清转换器-三松礼品-强哥出品必属精品")# 转换参数预设self.presets = {'高清1080p': '-c:v libx264 -crf 23 -preset medium -vf scale=1920:1080 -c:a aac -b:a 192k','高清720p': '-c:v libx264 -crf 23 -preset fast -vf scale=1280:720 -c:a aac -b:a 128k','原画质': '-c:v libx264 -crf 18 -preset slow -c:a aac -b:a 256k'}# 获取 `ffmpeg` 相关文件的路径self.ffmpeg_path = self.get_ffmpeg_path()self.ffplay_path = self.get_ffplay_path()self.ffprobe_path = self.get_ffprobe_path()# 创建 GUI 界面
        self.create_widgets()# 当前转换进程self.current_process = Nonedef get_ffmpeg_path(self):""" 获取 ffmpeg.exe 的路径 """if getattr(sys, 'frozen', False):return os.path.join(sys._MEIPASS, "ffmpeg.exe")return os.path.join(os.path.dirname(os.path.abspath(__file__)), "ffmpeg.exe")def get_ffplay_path(self):""" 获取 ffplay.exe 的路径 """if getattr(sys, 'frozen', False):return os.path.join(sys._MEIPASS, "ffplay.exe")return os.path.join(os.path.dirname(os.path.abspath(__file__)), "ffplay.exe")def get_ffprobe_path(self):""" 获取 ffprobe.exe 的路径 """if getattr(sys, 'frozen', False):return os.path.join(sys._MEIPASS, "ffprobe.exe")return os.path.join(os.path.dirname(os.path.abspath(__file__)), "ffprobe.exe")def create_widgets(self):# 文件选择tk.Label(self.root, text="选择文件或文件夹:").grid(row=0, column=0, padx=5, pady=5, sticky="w")self.input_entry = tk.Entry(self.root, width=50)self.input_entry.grid(row=0, column=1, padx=5, pady=5)tk.Button(self.root, text="浏览", command=self.select_input_file_or_folder).grid(row=0, column=2, padx=5, pady=5)# 输出目录tk.Label(self.root, text="输出目录:").grid(row=1, column=0, padx=5, pady=5, sticky="w")self.output_entry = tk.Entry(self.root, width=50)self.output_entry.grid(row=1, column=1, padx=5, pady=5)self.output_entry.insert(0, os.getcwd())  # 默认当前目录tk.Button(self.root, text="浏览", command=self.select_output_dir).grid(row=1, column=2, padx=5, pady=5)# 预设选择tk.Label(self.root, text="转换预设:").grid(row=2, column=0, padx=5, pady=5, sticky="w")self.preset_var = tk.StringVar()self.preset_combobox = ttk.Combobox(self.root, textvariable=self.preset_var, values=list(self.presets.keys()))self.preset_combobox.current(0)self.preset_combobox.grid(row=2, column=1, padx=5, pady=5, sticky="w")# 输出格式选择tk.Label(self.root, text="选择输出格式:").grid(row=3, column=0, padx=5, pady=5, sticky="w")self.format_var = tk.StringVar()self.format_combobox = ttk.Combobox(self.root, textvariable=self.format_var,values=[".mp4", ".avi", ".mkv", ".mov", ".flv"])self.format_combobox.current(0)self.format_combobox.grid(row=3, column=1, padx=5, pady=5, sticky="w")# 进度条self.progress = ttk.Progressbar(self.root, orient="horizontal", length=400, mode="determinate")self.progress.grid(row=4, column=0, columnspan=3, padx=5, pady=5)# 日志框self.log_text = tk.Text(self.root, height=10, width=60)self.log_text.grid(row=5, column=0, columnspan=3, padx=5, pady=5)# 转换按钮self.start_conversion_button = tk.Button(self.root, text="开始转换", command=self.start_conversion)self.start_conversion_button.grid(row=6, column=2, padx=5, pady=10)# 取消按钮tk.Button(self.root, text="取消转换", command=self.cancel_conversion).grid(row=6, column=0, padx=5, pady=5)def select_input_file_or_folder(self):input_path = filedialog.askopenfilename(filetypes=[("视频文件", "*.ts;*.mp4;*.avi;*.mkv;*.mov;*.flv")])if not input_path:input_path = filedialog.askdirectory()self.input_entry.delete(0, tk.END)self.input_entry.insert(0, input_path)def select_output_dir(self):dir_path = filedialog.askdirectory()self.output_entry.delete(0, tk.END)self.output_entry.insert(0, dir_path)def log_message(self, message):self.log_text.insert(tk.END, message + "\n")self.log_text.see(tk.END)def start_conversion(self):""" 开始转换时禁用按钮,防止重复点击 """self.start_conversion_button.config(state=tk.DISABLED)input_file = self.input_entry.get()output_dir = self.output_entry.get()output_format = self.format_var.get()preset = self.presets[self.preset_var.get()]output_file = os.path.join(output_dir,os.path.splitext(os.path.basename(input_file))[0] + "_converted" + output_format)ffmpeg_cmd = [self.ffmpeg_path, "-i", input_file, "-y"] + preset.split() + [output_file]self.log_message(f"执行命令: {' '.join(ffmpeg_cmd)}")threading.Thread(target=self.run_ffmpeg_silently, args=(ffmpeg_cmd, output_file)).start()def run_ffmpeg_silently(self, cmd, output_file):""" 运行 ffmpeg 并隐藏窗口,同时在转换结束后恢复按钮 """startupinfo = subprocess.STARTUPINFO()startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOWprocess = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, startupinfo=startupinfo)out, err = process.communicate()  # 获取输出和错误信息
        process.wait()if process.returncode == 0:self.log_message(f"转换完成,文件保存在: {output_file}")else:self.log_message(f"错误: {err.decode()}")# 转换完成后恢复按钮self.start_conversion_button.config(state=tk.NORMAL)def cancel_conversion(self):if self.current_process:self.current_process.terminate()self.log_message("转换已取消")self.start_conversion_button.config(state=tk.NORMAL)  # 恢复按钮状态if __name__ == "__main__":root = tk.Tk()app = VideoConverterApp(root)root.mainloop()"""
pyinstaller --onefile --add-data "ffmpeg.exe;." --add-data "ffplay.exe;." --add-data "ffprobe.exe;." --noconsole 222.py"""

 带日期限制的代码:

import os
import sys
import tkinter as tk
from tkinter import filedialog, ttk
import subprocess
import threading
import datetime
import requestsclass VideoConverterApp:def __init__(self, root):self.root = rootself.root.title("万能高清转换器-三松礼品-强哥出品必属精品")# 设置程序的时间限制(比如:2025年2月12日 18:00)self.restricted_time = datetime.datetime(2025, 12, 30, 18, 0, 0)# 获取当前互联网时间并比较if not self.check_time_allowed():self.show_restricted_message()return# 转换参数预设self.presets = {'高清1080p': '-c:v libx264 -crf 23 -preset medium -vf scale=1920:1080 -c:a aac -b:a 192k','高清720p': '-c:v libx264 -crf 23 -preset fast -vf scale=1280:720 -c:a aac -b:a 128k','原画质': '-c:v libx264 -crf 18 -preset slow -c:a aac -b:a 256k'}# 获取 `ffmpeg` 相关文件的路径self.ffmpeg_path = self.get_ffmpeg_path()self.ffplay_path = self.get_ffplay_path()self.ffprobe_path = self.get_ffprobe_path()# 创建 GUI 界面
        self.create_widgets()# 当前转换进程self.current_process = Nonedef get_ffmpeg_path(self):""" 获取 ffmpeg.exe 的路径 """if getattr(sys, 'frozen', False):return os.path.join(sys._MEIPASS, "ffmpeg.exe")return os.path.join(os.path.dirname(os.path.abspath(__file__)), "ffmpeg.exe")def get_ffplay_path(self):""" 获取 ffplay.exe 的路径 """if getattr(sys, 'frozen', False):return os.path.join(sys._MEIPASS, "ffplay.exe")return os.path.join(os.path.dirname(os.path.abspath(__file__)), "ffplay.exe")def get_ffprobe_path(self):""" 获取 ffprobe.exe 的路径 """if getattr(sys, 'frozen', False):return os.path.join(sys._MEIPASS, "ffprobe.exe")return os.path.join(os.path.dirname(os.path.abspath(__file__)), "ffprobe.exe")def check_time_allowed(self):""" 获取当前互联网时间,并与限制时间进行比较 """try:response = requests.get('http://worldtimeapi.org/api/timezone/Etc/UTC')data = response.json()current_time = datetime.datetime.fromisoformat(data['datetime'].replace('Z', '+00:00'))if current_time > self.restricted_time:return False  # 超过限制时间,禁止使用return Trueexcept requests.RequestException:# 如果无法获取互联网时间,默认允许使用return Truedef show_restricted_message(self):""" 显示程序禁止使用的消息 """tk.Label(self.root, text="程序禁止使用:超过限制时间", font=("Arial", 16)).pack(padx=5, pady=5)self.root.after(5000, self.root.quit)  # 5秒后自动关闭程序def create_widgets(self):# 文件选择tk.Label(self.root, text="选择文件或文件夹:").grid(row=0, column=0, padx=5, pady=5, sticky="w")self.input_entry = tk.Entry(self.root, width=50)self.input_entry.grid(row=0, column=1, padx=5, pady=5)tk.Button(self.root, text="浏览", command=self.select_input_file_or_folder).grid(row=0, column=2, padx=5, pady=5)# 输出目录tk.Label(self.root, text="输出目录:").grid(row=1, column=0, padx=5, pady=5, sticky="w")self.output_entry = tk.Entry(self.root, width=50)self.output_entry.grid(row=1, column=1, padx=5, pady=5)self.output_entry.insert(0, os.getcwd())  # 默认当前目录tk.Button(self.root, text="浏览", command=self.select_output_dir).grid(row=1, column=2, padx=5, pady=5)# 预设选择tk.Label(self.root, text="转换预设:").grid(row=2, column=0, padx=5, pady=5, sticky="w")self.preset_var = tk.StringVar()self.preset_combobox = ttk.Combobox(self.root, textvariable=self.preset_var, values=list(self.presets.keys()))self.preset_combobox.current(0)self.preset_combobox.grid(row=2, column=1, padx=5, pady=5, sticky="w")# 输出格式选择tk.Label(self.root, text="选择输出格式:").grid(row=3, column=0, padx=5, pady=5, sticky="w")self.format_var = tk.StringVar()self.format_combobox = ttk.Combobox(self.root, textvariable=self.format_var,values=[".mp4", ".avi", ".mkv", ".mov", ".flv"])self.format_combobox.current(0)self.format_combobox.grid(row=3, column=1, padx=5, pady=5, sticky="w")# 进度条self.progress = ttk.Progressbar(self.root, orient="horizontal", length=400, mode="determinate")self.progress.grid(row=4, column=0, columnspan=3, padx=5, pady=5)# 日志框self.log_text = tk.Text(self.root, height=10, width=60)self.log_text.grid(row=5, column=0, columnspan=3, padx=5, pady=5)# 转换按钮self.start_conversion_button = tk.Button(self.root, text="开始转换", command=self.start_conversion)self.start_conversion_button.grid(row=6, column=2, padx=5, pady=10)# 取消按钮tk.Button(self.root, text="取消转换", command=self.cancel_conversion).grid(row=6, column=0, padx=5, pady=5)def select_input_file_or_folder(self):input_path = filedialog.askopenfilename(filetypes=[("视频文件", "*.ts;*.mp4;*.avi;*.mkv;*.mov;*.flv")])if not input_path:input_path = filedialog.askdirectory()self.input_entry.delete(0, tk.END)self.input_entry.insert(0, input_path)def select_output_dir(self):dir_path = filedialog.askdirectory()self.output_entry.delete(0, tk.END)self.output_entry.insert(0, dir_path)def log_message(self, message):self.log_text.insert(tk.END, message + "\n")self.log_text.see(tk.END)def start_conversion(self):""" 开始转换时禁用按钮,防止重复点击 """self.start_conversion_button.config(state=tk.DISABLED)input_file = self.input_entry.get()output_dir = self.output_entry.get()output_format = self.format_var.get()preset = self.presets[self.preset_var.get()]output_file = os.path.join(output_dir,os.path.splitext(os.path.basename(input_file))[0] + "_converted" + output_format)ffmpeg_cmd = [self.ffmpeg_path, "-i", input_file, "-y"] + preset.split() + [output_file]self.log_message(f"执行命令: {' '.join(ffmpeg_cmd)}")threading.Thread(target=self.run_ffmpeg_silently, args=(ffmpeg_cmd, output_file)).start()def run_ffmpeg_silently(self, cmd, output_file):""" 运行 ffmpeg 并隐藏窗口,同时在转换结束后恢复按钮 """startupinfo = subprocess.STARTUPINFO()startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOWprocess = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, startupinfo=startupinfo)out, err = process.communicate()  # 获取输出和错误信息
        process.wait()if process.returncode == 0:self.log_message(f"转换完成,文件保存在: {output_file}")else:self.log_message(f"错误: {err.decode()}")# 转换完成后恢复按钮self.start_conversion_button.config(state=tk.NORMAL)def cancel_conversion(self):if self.current_process:self.current_process.terminate()self.log_message("转换已取消")self.start_conversion_button.config(state=tk.NORMAL)  # 恢复按钮状态if __name__ == "__main__":root = tk.Tk()app = VideoConverterApp(root)root.mainloop()"""
pyinstaller --onefile --add-data "ffmpeg.exe;." --add-data "ffplay.exe;." --add-data "ffprobe.exe;." --noconsole 222.py"""

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/882179.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【触想智能】工控一体机在机械臂上应用的四大优势

随着工业自动化的发展,机械臂已成为现代制造业中不可或缺的一部分。为了使机械臂能够高效、精确地执行各种任务,工控一体机的应用变得越来越广泛。触想工控一体机在机械臂上的应用工控一体机是一种集计算、控制和通信于一体的高性能工业计算机,它不仅具备强大的计算能力,还…

CTFShow-Web167:

CTFShow-Web167:.htaccess利用 <button type="button" class="layui-btn" id="upload" lay-data="{url: upload.php, accept: images,exts:jpg}"> 限制上传类型为jpg文件 题目提示httpd,并且404页面返回Apache/2.4.25 (Debian…

对极几何(Epipolar Geometry)总结

为什么stereo很有用? 当我们需要从单一视角恢复结构时,我们的信息来源有以下几种: \(\bullet\) 从标定架可以获取标定架的位置 / 姿态以及相机内参 K。 \(\bullet\) 从无穷远点和线,加上正交的线和平面等信息,可以获取场景的结构和相机内参 K 。 但是由于内在歧义性,从单…

P10451 做题随笔

Solution 题意 原题链接 对每组数据,给定两颗用 01 序列描述的树,描述规则如下:按照 \(\text{DFS}\) 序进行遍历; 若序列中某位为 0,表示除根节点外的节点进栈;为 1 则表示出栈。要求判断一树是否可以通过交换子树的方式变换成另一子树(对于本题,即两树同构)。 分析 1…

堆排序--代码实现

本文主要说明代码编写思路和具体代码,下面的博文讲的比较全面 参考文章:https://www.cnblogs.com/jingmoxukong/p/4303826.html代码思路(以大根堆为例) 堆排一共分2个阶段:1. 创建一个大根堆 2.交换堆顶和堆尾元素,获取到堆顶元素,并重新维护大根堆 第一个阶段的思路: 从…

贪心tricks总结

贪心题一般没有什么技巧,多做题积累经验。 对于结论或策略,大胆猜想,小心求证,注意使用数据结构优化/结合其他算法。 一般类贪心 主要是证明贪心的正确性。 H. Fight Against Monsters 先用二分求出每个怪需要打的次数。 问题转化为一个排列的答案是 \[\sum_{i=1}^{n} \sum…

dp优化之斜率优化小结

这或许是这几天的济南云斗集训之旅最大的收获吧,若是最后一天的模拟赛文件不会交错也许结局会更好,但在这残酷的现实中却从不会有“如果”一词,母亲以不想让我学了,或许考完今年的 CSP 就可能不学了吧。 本文将效仿《李煜东算法进阶指南》的思路,按照例题层层深入。 P2365…

P3406 海底高铁(差分)

这道题要用到差分,因为反复经过一条路时只需要买一张对应的卡就行了,不用买多张,所以我们可以用差分,算出经过每条路的次数,要注意假设从1到3城市,只经过了道路1和道路2,应该让cha【1】++,cha【3】--; 还有算结果时应该从1到n-1列举每一条路,我最开始就搞错了,还要注…

JPlag:开源的代码抄袭检测工具

一、基本信息•项目地址: https://gitcode.com/gh_mirrors/jp/JPlaghttps://github.com/jplag/JPlag•编程语言:基于Java开发•主要特性:跨平台运行、支持多种文件格式、提供图形用户界面(GUI)和命令行接口、可扩展性强 二、技术特点 •多语言支持:JPlag支持包括Java、C、…

重构谷粒商城01:为何重构谷粒商城

前言:这个系列将使用最前沿的cursor作为辅助编程工具,来快速开发一些基础的编程项目。目的是为了在真实项目中,帮助初级程序员快速进阶,以最快的速度,效率,快速进阶到中高阶程序员。 本项目将基于谷粒商城项目,并且对谷粒商城项目进行二次重构,使其满足最新的主流技术栈…

div设置四个角边框

示例实现 .top-header {background-image:url(../../assets/slider/topHeaderTopLeft.svg), /* 左上角图像 */url(../../assets/slider/topHeaderTopRight.svg), /* 右上角图像 */url(../../assets/slider/topHeaderBottomLeft.svg), /* 左下角图像 */url(../../assets/slider/…