pyqt 槽任意参数_PyQt+moviepy音视频剪辑实战1:多个音视频合成顺序播放或同屏播放的视频文件实现详解...

本文详细介绍了如何使用PyQt和moviepy库开发一个音视频合成的GUI应用。内容涵盖合成界面设计、参数配置、输出信息窗的实现以及代码实现,包括主界面构造、输入内容校验和视频合成处理方法。文章还展示了不同合成方式的运行界面截图,并提供了打包成exe的指南以及下载链接。
摘要由CSDN通过智能技术生成

- 专栏:Python基础教程目录

- 专栏:使用PyQt开发图形界面Python应用

- 专栏:PyQt+moviepy音视频剪辑实战

- 专栏:PyQt入门学习

- 老猿Python博文目录

- 老猿学5G博文目录

## 一、引言

在《moviepy音视频剪辑:音视频的加载和输出》、《moviepy音视频剪辑:多个视频合成一个视频》、《moviepy音视频剪辑:使用VideoFileClip、AudioFileClip和write_videofile、write_audiofile进行音视频的加载和输出》和《moviepy音视频剪辑:使用concatenate_videoclips和clips_array将多个视频合成一个顺序播放或同屏播放的视频》介绍了音视频文件加载和输出以及多视频合成一个视频的方法,本节将使用PyQt和moviepy结合开发一个音视频合成的GUI应用。

## 二、功能及界面设计

#### 2.1、主界面

3cf402ab6532f1ca34f3b1eef66ad5d3.png

以mainwindow为基础设计窗口主界面,包含一个菜单和对应工具条,用于选择要合成的文件、去除选中的文件、合成参数配置和执行合成操作等功能。

本次对该界面的信号处理没有使用UI界面来定义信号和槽的关联,因为线条太多会不好修改,相关信号和槽的连接主要通过代码实现。

#### 2.2、参数配置界面

82b1cc550653565983150a5969a9fdc5.png

根据选择的不同合成类型,可选配置不同的参数,也可以不配置,关于这些参数的说明请参考引言中提到的博文介绍。

#### 2.3、输出信息窗

老猿为准备开发的视频工具提供了一个统一的输出信息窗,moviepy本身的输出信息将全部被接管到该输出信息窗显示。界面设计如图:

82b1cc550653565983150a5969a9fdc5.png

关于输出信息截获请参考《在Python实现print标准输出sys.stdout、stderr重定向及捕获的简单办法》以及《PyQt(Python+Qt)学习随笔:print标准输出sys.stdout以及stderr重定向QTextBrowser等图形界面对象》。

## 三、代码实现

#### 3.1、主界面构造方法

```python

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、界面输入内容校验方法

```python

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、合成处理方法

该方法包含了三种合成方式处理的完整代码,有点长。

```python

def processFiles(self):

print("nn合成处理开始......")

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、加入合成文件后的主界面

54194650f301b86b21dffcefeb572892.png

可以看到支持重复加入视频,本案例就是将《笑看风云》这个视频重复四次进行合成。如果是拼接就是四个接连播放,如果是同屏播放则一个界面上播放四个视频。

#### 4.2、设置为统一分辨率拼接合成

由于padding这个参数不能用于chain模式的拼接,因此为了展示效果,设置了padding参数为-1,表示前后两段视频有1秒的重叠。参数设置界面如下:

fd260182826aff9875e95b99d9117c1c.png

执行合成处理,下图为合成处理过程的一个截图:

317df03af4fcd4e038891ca9a30d58c1.png

合成处理挺快,但输出比较耗时间。

播放就是顺序播放,截图不能体现什么,但可以与同屏播放合成对比一下:

31714db5839739ac1e0fb354bbda7859.png

不好意思免费做广告了。

#### 4.3、设置为同屏播放方式合成

主界面和运行界面与拼接没有什么区别,参数配置界面如下:

77dce8011549c69273d6dff473bc6784.png

合成后的视频截图:

48c0cdba40a3b13df85e3c6ef514525b.png

## 五、打包成exe

使用《PyQt(Python+Qt)学习随笔:windows下使用pyinstaller将PyQt文件打包成exe可执行文件》介绍的方法进行打包。

老猿在win7上最终打包的可执行程序包已经上传到百度云,大家可以下载下来长期免费使用。具体下载地址为百度网盘。

##### 链接:https://pan.baidu.com/s/1UNaA2UqQBoxx-v8rCIPDhA

**提取码:yh2d**

选择该链接下的:**视频合成工具.rar** 即可。

## 广告

老猿关于PyQt的付费专栏《使用PyQt开发图形界面Python应用》只需要9.9元,本专栏《PyQt+moviepy音视频剪辑实战》文档的同样内容在付费专栏上也有相应内容,总体来说付费专栏介绍更详细或案例更多。本节内容对应付费专栏的《PyQt+moviepy音视频剪辑实战1:多视频合成顺序播放或同屏播放的视频文件》。如果有兴趣也愿意支持老猿的读者,欢迎购买付费专栏。

5030e6dc1dbddd5a513b3442bb46b774.png

745af53e7f49490e8c5537e2dc6384aa.png

## 跟老猿学Python、学5G!

- 专栏:Python基础教程目录

- 专栏:使用PyQt开发图形界面Python应用

- 专栏:PyQt+moviepy音视频剪辑实战

- 专栏:PyQt入门学习

- 老猿Python博文目录

- 老猿学5G博文目录

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值