Python实现批量视频竖屏转横屏工具实战

在当今数字化时代,视频内容已成为信息传播的重要载体。然而,不同设备和平台对视频显示格式的要求各不相同,尤其是竖屏与横屏之间的转换需求日益增多。为了满足这一需求,本文将介绍如何使用Python实现一个批

在当今数字化时代,视频内容已成为信息传播的重要载体。然而,不同设备和平台对视频显示格式的要求各不相同,尤其是竖屏与横屏之间的转换需求日益增多。为了满足这一需求,本文将介绍如何使用Python实现一个批量视频竖屏转横屏的工具。通过实战演练,我们将深入了解视频处理的基本原理,掌握利用Python进行视频格式转换的技巧,并借助强大的第三方库,轻松实现视频的批量处理。无论是对于个人用户还是专业视频处理人员,本文都将提供一份宝贵的参考指南,助你在视频处理领域更上一层楼。

1. 简介

这是一款基于Python和Tkinter框架开发的视频处理器应用。该应用集成了FFmpeg,用于批量横屏转竖屏视频处理,支持多种视频格式和编码选择,并提供多线程支持以提升处理效率。用户可以通过简洁直观的图形界面导入、删除视频文件,并且对每个文件设置处理参数,如输出格式、视频编码器、音频编码器及高斯模糊效果。应用还支持暂停/继续和多线程并发处理,确保在长时间处理时能保持灵活性和高效性。

2.功能说明

Python实现批量视频竖屏转横屏工具实战

Python实现批量视频竖屏转横屏工具实战

2.1 文件管理

  • 支持通过拖放或文件选择对话框导入视频文件。

  • 支持删除已导入的文件。

  • 显示导入文件的基本信息,包括文件名和处理状态。

2.2 FFmpeg配置

  • 用户可以选择视频输出格式(MP4、AVI、MOV等)。

  • 提供不同的视频和音频编码器选项(如libx264、aac)。

  • 支持设置处理线程数,允许用户根据系统性能调整并发处理数量。

  • 可选应用高斯模糊效果以实现视频特效。

2.3 多线程处理

  • 使用ThreadPoolExecutor实现多线程并发处理多个视频文件。

  • 支持暂停和继续处理,用户可以在处理过程中暂停视频文件的转换,稍后继续。

2.4 输出文件管理

  • 用户可以设置输出文件夹,处理完成的视频会保存至该目录。

  • 支持在处理完成后直接打开输出文件夹。

2.5 进度监控与日志

  • 在文件列表中显示每个视频的处理进度。

  • 提供日志框,实时显示处理过程中的信息。

2.6 拖放支持

支持通过拖拽文件到窗口的方式导入视频文件,提升用户体验。

2.7 错误处理与反馈

针对文件已存在、格式不支持等情况提供相应的错误提示。

3. 运行效果

Python实现批量视频竖屏转横屏工具实战

Python实现批量视频竖屏转横屏工具实战

视频处理转换前(横屏状态):

Python实现批量视频竖屏转横屏工具实战

视频处理转换后(竖屏状态):

Python实现批量视频竖屏转横屏工具实战

4. 相关源码

importosimportttkbootstrapasttkfromttkbootstrap.constantsimport*fromtkinterimportfiledialog,messagebox,END,Text,StringVar,IntVar,BooleanVar,Menufromconcurrent.futuresimportThreadPoolExecutor,as_completedimportsubprocessimportthreadingimportpsutilimportreimportsysfromtkinterdnd2importTkinterDnD,DND_FILESdefresource_path(relative_path):\"\"\"Getabsolutepathtoresource,worksfordevandforPyInstaller\"\"\"try:#PyInstallercreatesatempfolderandstorespathin_MEIPASSbase_path=sys._MEIPASSexceptException:base_path=os.path.abspath(\".\")returnos.path.join(base_path,relative_path)classVideoProcessor:def__init__(self,master):self.master=masterself.master.title(\"视频处理器吾爱作者:是谁的大海(是貔貅呀)版本:1.3\")self.input_files=[]self.output_folder=\"\"self.process_thread=Noneself.pause_event=threading.Event()self.pause_event.set()#Startintheunpausedstateself.ffmpeg_processes=[]#Listtokeeptrackofallffmpegprocessesself.is_closing=Falseself.output_format=StringVar(value=\"mp4\")self.video_codec=StringVar(value=\"libx264\")self.audio_codec=StringVar(value=\"aac\")self.thread_count=IntVar(value=1)#Defaultto1threadsself.apply_blur=BooleanVar(value=False)#Booleantocheckifblurshouldbeappliedself.create_widgets()self.create_menu()self.master.protocol(\"WM_DELETE_WINDOW\",self.on_closing)defcreate_widgets(self):frame=ttk.Frame(self.master,padding=10)frame.pack(fill=BOTH,expand=YES)self.file_list_frame=ttk.Frame(frame)self.file_list_frame.pack(fill=BOTH,expand=YES,pady=5)columns=(\'序号\',\'文件夹名字\',\'进度\')self.file_tree=ttk.Treeview(self.file_list_frame,columns=columns,show=\'headings\')self.file_tree.heading(\'序号\',text=\'序号\')self.file_tree.heading(\'文件夹名字\',text=\'文件夹名字\')self.file_tree.heading(\'进度\',text=\'进度\')self.file_tree.column(\'序号\',width=100,anchor=\'center\')self.file_tree.column(\'文件夹名字\',width=400,anchor=\'w\')self.file_tree.column(\'进度\',width=100,anchor=\'center\')self.file_tree.pack(side=LEFT,fill=BOTH,expand=YES)scrollbar=ttk.Scrollbar(self.file_list_frame,orient=\"vertical\",command=self.file_tree.yview)self.file_tree.configure(yscrollcommand=scrollbar.set)scrollbar.pack(side=RIGHT,fill=Y)self.log_text=Text(frame,height=5,state=\'disabled\')self.log_text.pack(fill=BOTH,expand=YES,pady=5)button_frame=ttk.Frame(frame)button_frame.pack(fill=BOTH,expand=YES)self.add_files_button=ttk.Button(button_frame,text=\"导入文件\",command=self.add_files,bootstyle=PRIMARY)self.add_files_button.pack(side=LEFT,padx=5,pady=5)self.remove_files_button=ttk.Button(button_frame,text=\"删除文件\",command=self.remove_files,bootstyle=DANGER)self.remove_files_button.pack(side=LEFT,padx=5,pady=5)self.pause_button=ttk.Button(button_frame,text=\"暂停/继续\",command=self.toggle_pause,bootstyle=WARNING)self.pause_button.pack(side=LEFT,padx=5,pady=5)self.open_output_folder_button=ttk.Button(button_frame,text=\"打开文件\",command=self.open_output_folder,bootstyle=SUCCESS)self.open_output_folder_button.pack(side=LEFT,padx=5,pady=5)self.set_output_folder_button=ttk.Button(button_frame,text=\"导出文件\",command=self.set_output_folder,bootstyle=SUCCESS)self.set_output_folder_button.pack(side=LEFT,padx=5,pady=5)self.process_button=ttk.Button(button_frame,text=\"开始处理文件\",command=self.start_processing,bootstyle=INFO)self.process_button.pack(side=RIGHT,padx=5,pady=5)config_frame=ttk.LabelFrame(frame,text=\"FFmpeg配置\")config_frame.pack(fill=BOTH,expand=YES,pady=5)ttk.Label(config_frame,text=\"输出格式:\").pack(side=LEFT,padx=5,pady=5)ttk.OptionMenu(config_frame,self.output_format,\"mp4\",\"mp4\",\"avi\",\"mov\").pack(side=LEFT,padx=5,pady=5)ttk.Label(config_frame,text=\"视频编码器:\").pack(side=LEFT,padx=5,pady=5)ttk.OptionMenu(config_frame,self.video_codec,\"libx264\",\"libx264\",\"libx265\",\"mpeg4\").pack(side=LEFT,padx=5,pady=5)ttk.Label(config_frame,text=\"音频编码器:\").pack(side=LEFT,padx=5,pady=5)ttk.OptionMenu(config_frame,self.audio_codec,\"aac\",\"aac\",\"mp3\",\"ac3\").pack(side=LEFT,padx=5,pady=5)ttk.Label(config_frame,text=\"线程数:\").pack(side=LEFT,padx=5,pady=5)ttk.Entry(config_frame,textvariable=self.thread_count).pack(side=LEFT,padx=5,pady=5)self.blur_checkbox=ttk.Checkbutton(config_frame,text=\"应用高斯模糊效果\",variable=self.apply_blur)self.blur_checkbox.pack(side=LEFT,padx=5,pady=5)#Setupdraganddropself.master.drop_target_register(DND_FILES)self.master.dnd_bind(\'<>\',self.drop_files)defcreate_menu(self):menu_bar=Menu(self.master)self.master.config(menu=menu_bar)help_menu=Menu(menu_bar,tearoff=0)menu_bar.add_cascade(label=\"帮助\",menu=help_menu)help_menu.add_command(label=\"使用说明\",command=self.show_usage_instructions)help_menu.add_command(label=\"软件具体说明\",command=self.show_software_details)defshow_usage_instructions(self):instructions=(\"使用说明:\\n\"\"1.导入文件:点击“导入文件”按钮,选择需要处理的视频文件,或将视频文件拖拽到软件窗口中。\\n\"\"2.设置输出文件夹:点击“导出文件”按钮,选择一个文件夹作为输出文件夹。\\n\"\"3.配置FFmpeg参数:在“FFmpeg配置”区域,选择输出格式、视频编码器、音频编码器、线程数,并可选择是否应用高斯模糊效果。\\n\"\"4.开始处理:点击“开始处理文件”按钮,开始批量处理视频文件。处理过程中可以查看处理进度和日志信息。\\n\"\"5.查看输出文件:点击“打开文件”按钮,打开输出文件夹查看处理完成的视频文件。\\n\"\"6.删除文件:选择文件列表中的文件,点击“删除文件”按钮删除不需要处理的文件。\\n\")messagebox.showinfo(\"使用说明\",instructions)defshow_software_details(self):details=(\"仅供学习,切勿使用到其他用途\\n\"\"1.输出格式:支持MP4、AVI和MOV等常见格式,用户可自定义选择。\\n\"\"2.视频压缩:默认使用libx264视频编码器和aac音频编码器,支持高效视频压缩,用户可自定义选择其他编码器。\\n\"\"3.视频裁剪:适用于将1920x1080横屏视频裁剪成9:16竖屏视频,不会变形。\\n\"\"4.高斯模糊:可选应用高斯模糊效果,适用于特殊视频效果需求。\\n\"\"5.多线程处理:支持多线程并发处理,用户可自定义线程数,提高处理效率。\\n\")messagebox.showinfo(\"软件具体说明\",details)defdrop_files(self,event):files=self.master.tk.splitlist(event.data)forfileinfiles:iffilenotinself.input_filesandfile.lower().endswith((\'.mp4\',\'.avi\',\'.mov\')):self.input_files.append(file)self.file_tree.insert(\'\',END,values=(len(self.input_files),os.path.basename(file),\"未处理\"))self.log(f\"导入文件:{file}\")else:messagebox.showwarning(\"警告\",f\"文件已存在或不支持的文件类型:{os.path.basename(file)}\")defadd_files(self):files=filedialog.askopenfilenames(title=\"选择视频文件\",filetypes=[(\"视频文件\",\"*.mp4*.avi*.mov\")])forfileinfiles:iffilenotinself.input_files:self.input_files.append(file)self.file_tree.insert(\'\',END,values=(len(self.input_files),os.path.basename(file),\"未处理\"))self.log(f\"导入文件:{file}\")else:messagebox.showwarning(\"警告\",f\"文件已存在:{os.path.basename(file)}\")defremove_files(self):selected_items=self.file_tree.selection()indices_to_remove=[]foriteminselected_items:values=self.file_tree.item(item,\'values\')ifvalues:index=int(values[0])-1indices_to_remove.append(index)self.file_tree.delete(item)#删除索引列表中的元素(倒序删除避免索引问题)forindexinsorted(indices_to_remove,reverse=True):delself.input_files[index]self.log(\"删除选中文件\")self.refresh_file_list()defrefresh_file_list(self):foriteminself.file_tree.get_children():self.file_tree.delete(item)forindex,fileinenumerate(self.input_files):self.file_tree.insert(\'\',END,values=(index+1,os.path.basename(file),\"未处理\"))defset_output_folder(self):self.output_folder=filedialog.askdirectory(title=\"选择输出文件夹\")self.log(f\"设置输出文件夹:{self.output_folder}\")defstart_processing(self):ifnotself.input_filesornotself.output_folder:messagebox.showerror(\"错误\",\"请添加文件并设置输出文件夹。\")returnself.process_thread=threading.Thread(target=self.process_videos_concurrently)self.process_thread.start()deftoggle_pause(self):ifself.pause_event.is_set():self.pause_event.clear()self.log(\"处理暂停\")forprocessinself.ffmpeg_processes:proc=psutil.Process(process.pid)proc.suspend()else:self.pause_event.set()self.log(\"处理继续\")forprocessinself.ffmpeg_processes:proc=psutil.Process(process.pid)proc.resume()defopen_output_folder(self):ifself.output_folder:os.startfile(self.output_folder)self.log(f\"打开输出文件夹:{self.output_folder}\")else:messagebox.showerror(\"错误\",\"请先设置输出文件夹。\")deflog(self,message):ifnotself.is_closing:self.master.after(0,self._log,message)def_log(self,message):ifnotself.is_closing:self.log_text.configure(state=\'normal\')self.log_text.insert(END,message+\'\\n\')self.log_text.configure(state=\'disabled\')self.log_text.yview(END)defupdate_tree_status(self,index,status):ifnotself.is_closing:self.master.after(0,self._update_tree_status,index,status)def_update_tree_status(self,index,status):ifnotself.is_closing:self.file_tree.item(self.file_tree.get_children()[index],values=(index+1,os.path.basename(self.input_files[index]),status))defprocess_videos_concurrently(self):max_workers=self.thread_count.get()withThreadPoolExecutor(max_workers=max_workers)asexecutor:futures=[executor.submit(self.process_video,index,input_file)forindex,input_fileinenumerate(self.input_files)]forfutureinas_completed(futures):future.result()defprocess_video(self,index,input_file):ffmpeg_path=resource_path(os.path.join(\"ffmpeg_folder\",\"ffmpeg\"))filename=os.path.basename(input_file)output_file=os.path.join(self.output_folder,f\"processed_{filename}.{self.output_format.get()}\")ifos.path.exists(output_file):overwrite=messagebox.askyesno(\"文件已存在\",f\"{output_file}已存在,是否覆盖?\")ifnotoverwrite:self.update_tree_status(index,\"跳过\")returnifself.apply_blur.get():cmd=[ffmpeg_path,\"-y\",#自动覆盖输出文件\"-i\",input_file,\"-vf\",\"split[a][b];[a]scale=1080:1920,boxblur=10:5[1];[b]scale=1080:ih*1080/iw[2];[1][2]overlay=0:(H-h)/2\",\"-c:v\",self.video_codec.get(),\"-crf\",\"18\",\"-preset\",\"veryfast\",\"-aspect\",\"9:16\",\"-c:a\",self.audio_codec.get(),output_file]else:cmd=[ffmpeg_path,\"-y\",#自动覆盖输出文件\"-i\",input_file,\"-vf\",\"scale=\'if(gt(iw/ih,9/16),1080,-2)\':\'if(gt(iw/ih,9/16),-2,1920)\',pad=1080:1920:(1080-iw)/2:(1920-ih)/2\",\"-c:v\",self.video_codec.get(),\"-crf\",\"18\",\"-preset\",\"veryfast\",\"-c:a\",self.audio_codec.get(),output_file]self.log(f\"开始处理:{filename}\")self.update_tree_status(index,\"处理中\")try:startupinfo=subprocess.STARTUPINFO()startupinfo.dwFlags|=subprocess.STARTF_USESHOWWINDOWprocess=subprocess.Popen(cmd,stderr=subprocess.PIPE,universal_newlines=True,encoding=\'utf-8\',startupinfo=startupinfo)self.ffmpeg_processes.append(process)forlineinprocess.stderr:ifself.is_closing:breakprogress=self.parse_progress(line)ifprogress:self.update_tree_status(index,progress)process.wait()exceptExceptionase:self.log(f\"处理文件时出错:{filename}-{str(e)}\")self.update_tree_status(index,\"处理失败\")returnifself.is_closing:self.update_tree_status(index,\"未完成\")else:self.log(f\"完成处理:{filename}\")self.update_tree_status(index,\"已完成\")self.ffmpeg_processes.remove(process)defparse_progress(self,line):match=re.search(r\'time=(\\d+:\\d+:\\d+\\.\\d+)\',line)ifmatch:returnf\"进度:{match.group(1)}\"returnNonedefon_closing(self):self.is_closing=Trueforprocessinself.ffmpeg_processes:proc=psutil.Process(process.pid)proc.terminate()self.master.destroy()if__name__==\"__main__\":root=TkinterDnD.Tk()root.title(\"视频处理器\")root.geometry(\"870x520\")#Setthewindowsizeto870x520root.resizable(False,False)#Makethewindownon-resizableapp=VideoProcessor(master=root)root.mainloop()

5.总结

该视频处理器应用通过Python与Tkinter提供了一个强大而简洁的图形界面,允许用户批量处理视频文件。借助FFmpeg,用户不仅可以自由选择输出格式和编码器,还可以根据需求应用视频特效,如高斯模糊。多线程的支持使得处理多个视频文件更加高效,确保了在处理过程中能够灵活控制暂停、继续和取消操作。通过增强的文件管理和进度监控,用户能够轻松掌控整个视频处理过程。此工具对于需要批量转换视频格式或应用特效的用户非常实用,尤其适合需要高效处理大量视频文件的场景。

通过本次实战演练,我们成功实现了一个基于Python的批量视频竖屏转横屏工具。从视频处理的基础知识出发,我们逐步掌握了利用Python进行视频格式转换的关键技术。通过引入第三方库,我们实现了视频的批量读取、处理与保存,大大提高了工作效率。同时,我们也见证了Python在视频处理领域的强大潜力和广泛应用前景。无论是对于个人日常的视频编辑需求,还是对于专业视频处理人员的工作要求,本工具都展现出了出色的性能和稳定性。希望本文能够为你提供一份有价值的参考,助你在视频处理的道路上越走越远。

本站部分文章来自网络或用户投稿,如无特殊说明或标注,均为本站原创发布。涉及资源下载的,本站旨在共享仅供大家学习与参考,如您想商用请获取官网版权,如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。
后端

DeepSeek-Coder:跨文件代码补全实战与性能解析

2025-2-28 13:25:57

后端

使用Python+Deepseek轻松编写一个PDF转Word工具

2025-2-28 13:26:01

搜索