PyQt+moviepy音视频剪辑实战1:多个音视频合成顺序播放或同屏播放的视频文件实现详解
一、引言
在《moviepy音视频剪辑:音视频的加载和输出》、《moviepy音视频剪辑:多个视频合成一个视频》、《moviepy音视频剪辑:使用VideoFileClip、AudioFileClip和write_videofile、write_audiofile进行音视频的加载和输出》和《moviepy音视频剪辑:使用concatenate_videoclips和clips_array将多个视频合成一个顺序播放或同屏播放的视频》介绍了音视频文件加载和输出以及多视频合成一个视频的方法,本节将使用PyQt和moviepy结合开发一个音视频合成的GUI应用。
二、功能及界面设计
2.1、主界面
以mainwindow为基础设计窗口主界面,包含一个菜单和对应工具条,用于选择要合成的文件、去除选中的文件、合成参数配置和执行合成操作等功能。
本次对该界面的信号处理没有使用UI界面来定义信号和槽的关联,因为线条太多会不好修改,相关信号和槽的连接主要通过代码实现。
2.2、参数配置界面
根据选择的不同合成类型,可选配置不同的参数,也可以不配置,关于这些参数的说明请参考引言中提到的博文介绍。
2.3、输出信息窗
老猿为准备开发的视频工具提供了一个统一的输出信息窗,moviepy本身的输出信息将全部被接管到该输出信息窗显示。界面设计如图:
关于输出信息截获请参考《在Python实现print标准输出sys.stdout、stderr重定向及捕获的简单办法》以及《PyQt(Python+Qt)学习随笔:print标准输出sys.stdout以及stderr重定向QTextBrowser等图形界面对象》。
三、代码实现
3.1、主界面构造方法
class mainWin(QtWidgets.QMainWindow,ui_mixClips.Ui_ui_mainWin):
def __init__(self):
super().__init__()
self.setupUi(self)
self.initValues() #完成初始化成员变量
self.initSignalAndSlots() #完成信号和槽的连接
self.initPublicFrame() #完成公共框架相关变量初始化
上面代码调用很简单,相关方法都好理解,只有initPublicFrame方法比较特殊,这是因为为了支持工具的开发只关注工具本身的功能,老猿单独开发了几个单独的模块用于所有工具都能使用,这些功能包括显示About窗口信息、截获标准输出、显示或关闭信息输出窗、信息输出窗与应用本身的QMainWindow对象关联(作为一个QDockWidget对象,关于QDockWidget请参考《第三十一章、containers容器类部件QDockWidget停靠窗功能介绍》或参考免费专栏《PyQt入门知识目录》相关章节的介绍)等功能,在此就不详细介绍了。
3.2、界面输入内容校验方法
def validateAllInput(self,isOutputMessage=False):
#效验所有文件是否都存在
ret = True
fileList = self.videoFileListModel.stringList()
if fileList:
count = len(fileList)
if count<2:
self.actionProcessVideos.setEnabled(False)
if isOutputMessage:print(f"输入视频文件数为{count},必须至少2个文件")
ret = False
else:
for fileName in fileList:
if len(fileName)==0:continue
if not os.path.exists(fileName):
if isOutputMessage:print(f"文件{fileName}不存在,请修订后再进行合成处理!")
ret = False
if ret:
if not self.outputFileNameManuChanged:
filePre = self.lastFileDir +"\\video_"+self.configW.composeType
self.outputFileName = filePre + time.strftime("%Y%m%d%H%M%S", time.localtime()) + ".mp4"
self.input_outputFile.setText(self.outputFileName)
self.outputDir = self.lastFileDir
else:
ret = False
if isOutputMessage:print(f"没有输入视频文件,必须至少2个文件")
#print(self.videoFileListModel.stringList())
if not self.outputDir:
ret = False
if isOutputMessage:print("输出文件没有指定")
elif not os.path.exists(self.outputDir):
ret = False
if isOutputMessage:print(f"输出文件对应目录:{self.outputDir} 不存在")
#self.btn_processVideoFiles.setEnabled(ret)
self.actionProcessVideos.setEnabled(ret)
if ret:
if isOutputMessage:print("所有输入数据检测正常!")
if self.configW.composeType!='stack' and self.configW.transitionFileName and len(self.configW.transitionFileName):
if not os.path.exists(self.configW.transitionFileName):
if isOutputMessage:print(f"转场文件{self.configW.transitionFileName}不存在,请修订后再进行合成处理!")
ret = False
return ret
该方法在所有界面内容输入发送变化后触发,用于检测输入内容是否完整、合法,如果返回False,则视频合成操作不能进行。该方法带的参数用于控制是否输出检测到的异常信息,当各组件正在输入时不应输出以免干扰,而最后要执行合成前会再校验一次,此次校验的异常则会输出。检测内容请见相关输出信息。
3.3、合成处理方法
该方法包含了三种合成方式处理的完整代码,有点长。
def processFiles(self):
print("\n\n合成处理开始......")
if self.loadWin: self.loadWin.openCaptureWin() #打开输出信息窗口
if not self.validateAllInput(True):return #检测有异常则终止合成
tmpClip = [] #用于保存所有需要参与合成视频文件的剪辑对象
try:
fileList = self.videoFileListModel.stringList() #取合成输入视频文件名列表
fileCount = len(fileList)
for fileName in fileList:
print(f"准备加载视频文件:{fileName} ")
clip = mpe.VideoFileClip(fileName,verbose=True)
print(f"加载视频文件:{fileName} 完成,时长为{clip.duration}秒,视频分辨率大小为:{clip.size} ")
tmpClip.append(clip)
print(f"视频文件:{fileName} 已经加载并缓存")
transitionClip = None
if self.configW.composeType != 'stack':#视频拼接可能需要转场文件
if self.configW.transitionFileName and len(self.configW.transitionFileName):
print(f"准备加载转场文件:{self.configW.transitionFileName}")
transitionClip = mpe.VideoFileClip(self.configW.transitionFileName)
print(f"转场文件加载成功,时长为{transitionClip.duration}")
print("进行内存视频合成...")
padding = 0
if self.configW.composeType=='compose': #将所有输入剪辑全部统一分辨率方式合成则获取对应参数配置
method = 'compose'
bgcolor = self.configW.bgColor
padding = self.configW.input_padding.value()
if padding==0.00:
padding = 0
print("padding=", padding, 'bgcolor=', bgcolor, 'method=', method)
destClip = mpe.concatenate_videoclips(tmpClip, method=method, padding=padding, bg_color=bgcolor,transition=transitionClip) #执行顺序拼接,统一分辨率
elif self.configW.composeType=='chain': #保持所有输入视频分辨率不变进行视频拼接则获取对应参数配置
padding = 0
bgcolor = None
method = 'chain'
print("padding=", padding, 'bgcolor=', bgcolor, 'method=', method)
destClip = mpe.concatenate_videoclips(tmpClip, method=method, padding=padding, bg_color=bgcolor,transition=transitionClip)#执行顺序拼接
elif self.configW.composeType=='stack':#进行同屏播放合成则获取对应参数配置
bgcolor = self.configW.bgColor
#下面代码用于设置屏幕上视频的行数和列数
if fileCount<=3:
lines = 1
columns = fileCount
elif fileCount<=10:
lines = 2
columns = int((fileCount+1)/2)
else:
lines = 3
columns = int((fileCount+2)/3)
print(f"视频将排列成{lines}行{columns}列")
clipArrays = []
tmpClipArray = []
lines = column= 0
for clip in tmpClip:#按行列将视频排列
tmpClipArray.append(clip)
column += 1
if column == columns:
clipArrays.append(tmpClipArray)
column = 0
tmpClipArray = []
destClip = mpe.clips_array(clipArrays) #进行同屏播放合成
print(f"内存视频合成完成,准备输出到文件:{self.outputFileName}.")
destClip.write_videofile(self.outputFileName)
print(f"输出到文件:{self.outputFileName} 成功!")
except Exception as e:
print(f"进行视频处理合成失败,请参考上面输出信息确认处理存在问题的文件,异常原因:\n{e}")
strinfo = str(e)
if strinfo.find("codec can't decode"):
print("该问题是由于视频文件解码导致的错误,请尝试将文件名或目录名改成纯ASCII字符集再尝试一下")
四、运行界面截图
4.1、加入合成文件后的主界面
可以看到支持重复加入视频,本案例就是将《笑看风云》这个视频重复四次进行合成。如果是拼接就是四个接连播放,如果是同屏播放则一个界面上播放四个视频。
4.2、设置为统一分辨率拼接合成
由于padding这个参数不能用于chain模式的拼接,因此为了展示效果,设置了padding参数为-1,表示前后两段视频有1秒的重叠。参数设置界面如下:
执行合成处理,下图为合成处理过程的一个截图:
合成处理挺快,但输出比较耗时间。
播放就是顺序播放,截图不能体现什么,但可以与同屏播放合成对比一下:
不好意思免费做广告了。
4.3、设置为同屏播放方式合成
主界面和运行界面与拼接没有什么区别,参数配置界面如下:
合成后的视频截图:
五、打包成exe
使用《PyQt(Python+Qt)学习随笔:windows下使用pyinstaller将PyQt文件打包成exe可执行文件》介绍的方法进行打包。
老猿在win7上最终打包的可执行程序包已经上传到百度云,大家可以下载下来长期免费使用。具体下载地址为百度网盘。
链接:https://pan.baidu.com/s/1UNaA2UqQBoxx-v8rCIPDhA
提取码:yh2d
选择该链接下的:视频合成工具.rar 即可。
更多moviepy的介绍请参考《PyQt+moviepy音视频剪辑实战文章目录》或《moviepy音视频开发专栏》。
关于收费专栏
老猿的付费专栏《使用PyQt开发图形界面Python应用》专门介绍基于Python的PyQt图形界面开发基础教程,付费专栏《moviepy音视频开发专栏》详细介绍moviepy音视频剪辑合成处理的类相关方法及使用相关方法进行相关剪辑合成场景的处理,两个专栏加起来只需要19.9元,都适合有一定Python基础但无相关专利知识的小白读者学习。这2个收费专栏都有对应免费专栏,只是收费专栏的文章介绍更具体、内容更深入、案例更多。
收费专栏文章目录:《moviepy音视频开发专栏文章目录》、《使用PyQt开发图形界面Python应用专栏目录》,本文收费专栏对应文章为《PyQt+moviepy音视频剪辑实战1:多视频合成顺序播放或同屏播放的视频文件》。
对于缺乏Python基础的同仁,可以通过老猿的免费专栏《专栏:Python基础教程目录》从零开始学习Python。
如果有兴趣也愿意支持老猿的读者,欢迎购买付费专栏。
跟老猿学Python、学5G!
PyQt+moviepy音视频剪辑实战1:多个音视频合成顺序播放或同屏播放的视频文件实现详解的更多相关文章
- PyQt+moviepy音视频剪辑实战文章目录
☞ ░ 前往老猿Python博文目录 ░ 本专栏为moviepy音视频剪辑合成相关内容介绍的免费专栏,对应的收费专栏为<moviepy音视频开发专栏>. 一.moviepy基础能力系统介绍 ...
- PyQt+moviepy音视频剪辑实战2:一个剪裁视频文件精华内容留存工具的实现
专栏:Python基础教程目录 专栏:使用PyQt开发图形界面Python应用 PyQt+moviepy音视频剪辑实战 专栏:PyQt入门学习 老猿Python博文目录 老猿学5G博文目录 一.引言 ...
- PyQt+moviepy音视频剪辑实战2:实现一个剪裁视频文件精华内容留存工具
专栏:Python基础教程目录 专栏:使用PyQt开发图形界面Python应用 PyQt+moviepy音视频剪辑实战 专栏:PyQt入门学习 老猿Python博文目录 老猿学5G博文目录 一.引言 ...
- moviepy音视频剪辑:使用concatenate_videoclips和clips_array将多个视频合成一个顺序播放或同屏播放的视频
专栏:Python基础教程目录 专栏:使用PyQt开发图形界面Python应用 专栏:PyQt入门学习 老猿Python博文目录 老猿学5G博文目录 一.视频合成概述 视频合成,也称为非线性编辑,实际 ...
- PyQt+moviepy音视频剪辑实战1:多视频合成顺序播放或同屏播放的视频文件
专栏:Python基础教程目录 专栏:使用PyQt开发图形界面Python应用 专栏:PyQt入门学习 老猿Python博文目录 老猿学5G博文目录 一.引言 在<moviepy音视频剪辑:音视 ...
- SVN与TortoiseSVN实战:文件加锁详解
硬广:<SVN与TortoiseSVN实战>系列已经写了八篇,本篇是完结篇,整个系列结合TortoiseSVN对SVN中容易被忽视的部分进行了详解,以技巧性为主. 本篇详解使用Tortoi ...
- moviepy音视频剪辑:与time时间线相关的变换函数freeze_region、make_loopable、speedx、time_mirror、time_symmetrize介绍
☞ ░ 前往老猿Python博文目录 ░ 一.引言 在<moviepy音视频剪辑:moviepy中的剪辑基类Clip详解>介绍了剪辑基类的fl.fl_time.fx方法,在<movi ...
- Python音视频剪辑库MoviePy1.0.3中文教程导览及可执行工具下载
☞ ░ 前往老猿Python博文目录 ░ 一.简介 MoviePy是一个用于视频编辑的Python模块,可用于进行视频的基本操作(如剪切.拼接.标题插入).视频合成(也称非线性编辑).视频处理或创建高 ...
- Python MoviePy中文教程导览及可执行音视频剪辑工具下载
☞ ░ 前往老猿Python博文目录 ░ <Python音视频剪辑库MoviePy1.0.3中文教程导览及可执行工具下载>是老猿两个关于moviepy的专栏<PyQt+moviepy ...
随机推荐
- bash中选择结构、循环结构与break、continue
if两种选择结构 if 测试条件; then 程序块 else 程序块 fi if 测试条件1; then 程序块 elif 测试条件2; then 程序块 ... elif 程序条件n; then ...
- SpringBoot入门最简单的一个项目示例
使用IDEA创建一个SpringBoot项目 1.1 打开IDEA,文件-New-Project 1.2下一步,选择版本8(根据自己安装的JDK版本来选择) 1.3 下一步后点击Web,勾选Sprin ...
- Python优点与缺点
优点 简单 -- Python 是一种代表简单主义思想的语言.阅读一个良好的 Python 程序就感觉像是在读英语一样,尽管这个英语的要求非常严格!Python 的这种伪代码本质是它最大的优点之一.它 ...
- Java编码和字符集(详解)
[1]什么是编码? [2]通过生活案例: [3]由权威机构形成的编码表才可以称之为:字符集 ASCII 英文字符集 用一个字节的7位表示 IOS8859-1 西欧字符集 用一个字节的8位表示 GB23 ...
- Python_俄罗斯方块
网上资料,仅供学习,希望以后自己也能看懂再改进下... """ 俄罗斯方块 author: wolfstar last edited: 2018年1月 "&qu ...
- [原题复现+审计][SUCTF 2019] WEB CheckIn(上传绕过、.user.ini)
简介 原题复现:https://github.com/team-su/SUCTF-2019/tree/master/Web/checkIn 考察知识点:上传绕过..user.ini 线上平台:h ...
- 应用程序-特定 权限设置并未向在应用程序容器不可用 SID (不可用)中运行的地址 LocalHost (使用 LRPC) 中的用户...的 COM 服务器应用程序的 本地 激活 权限。此安全权限可以使用组件服务管理工具进行修改。
很久以前发现我们的业务服务器上出现一个System的系统严重错误,查找很久都没有找到解决办法,今日再次查看服务器发现报错更频繁,于是就搜集各种资料进行查找解决办法,终于找到了一个解决办法. 错误截图介 ...
- web安全入门--入门条件
介绍:网络安全由习大大提出,是继海.陆.空.外太空的第五大作战领域,也是一个关系国家安全和主权.社会稳定.民族文化继承和发扬的重要问题.其重要性,正随着全球信息化步伐的加快越来越重要.接下来,我向大家 ...
- 使用Folx下载热门电影居然这么简单
在闲暇的时候,很多人会选择观看电影.电视剧来打发时间.对于一些热门的资源,可以通过网页搜索的方式,找到很多与之相对应的种子资源. 但有时候,一些不那么热门的资源就要花费较多时间搜索.有了Folx bt ...
- 自定义IDM的网页嗅探下载浮条样式
如果大家有用过IDM(Internet Download Manager)下载器的朋友应该会知道,我们在安装完IDM后,打开网页时,有时网页上会出现一个IDM的下载浮窗,这就是IDM的嗅探下载浮条. ...