当代技术让我们能够创建各种有趣和实用的应用程序。在本篇博客中,我们将探索一个基于wxPython和OpenCV的四路视频播放器应用程序。这个应用程序可以同时播放四个视频文件,并将它们显示在一个GUI界面中。
C:\pythoncode\new\smetimeplaymp4.py
准备工作
在开始之前,我们需要安装一些必要的库。确保你已经安装了Python和以下库:
- wxPython:用于创建图形用户界面。
- OpenCV:用于视频处理和播放。
- moviepy:用于视频剪辑。
你可以使用pip来安装这些库。在命令行中运行以下命令:
pip install wxPython opencv-python moviepy
安装完成后,我们就可以开始编写代码了。
导入库
首先,让我们导入所需的库:
import os
import wx
import cv2
from moviepy.editor import VideoFileClip
os
库用于文件和文件夹操作。wx
库用于创建GUI界面。cv2
库用于视频处理。moviepy
库用于视频剪辑。
创建文件列表窗口
我们将创建一个名为FileListFrame
的wx.Frame子类,用于显示文件列表和选择文件夹。
class FileListFrame(wx.Frame):
def __init__(self):
super().__init__(None, title="选择MP4文件", size=(400, 300))
self.folder_path = "" # 添加实例变量来存储文件夹路径
panel = wx.Panel(self)
# 创建选择文件夹的按钮
select_button = wx.Button(panel, label="选择文件夹")
select_button.Bind(wx.EVT_BUTTON, self.on_select_folder)
# 创建列表框,用于显示文件列表
self.list_box = wx.ListBox(panel, style=wx.LB_MULTIPLE | wx.LB_HSCROLL)
# 创建播放按钮
play_button = wx.Button(panel, label="播放")
play_button.Bind(wx.EVT_BUTTON, self.on_play)
# 设置布局管理器
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(select_button, proportion=0, flag=wx.ALIGN_CENTER | wx.ALL, border=10)
sizer.Add(self.list_box, proportion=1, flag=wx.EXPAND | wx.ALL, border=10)
sizer.Add(play_button, proportion=0, flag=wx.ALIGN_CENTER | wx.ALL, border=10)
panel.SetSizer(sizer)
在__init__
方法中,我们设置了窗口的标题和大小,并初始化了一个实例变量folder_path
来存储文件夹路径。
接下来,我们创建一个wx.Panel,并在其中添加了一个选择文件夹的按钮、一个文件列表框和一个播放按钮。按钮的点击事件分别绑定到了on_select_folder
和on_play
方法。
最后,我们使用布局管理器(wx.BoxSizer)来设置控件的布局。
处理选择文件夹事件
我们需要实现on_select_folder
方法,以处理选择文件夹的事件。
def on_select_folder(self, event):
dialog = wx.DirDialog(self, message="选择文件夹")
if dialog.ShowModal() == wx.ID_OK:
self.folder_path = dialog.GetPath() # 存储选择的文件夹路径
self.update_file_list(self.folder_path)
dialog.Destroy()
在该方法中,我们创建了一个文件夹选择对话框(wx.DirDialog)。当对话框显示并用户选择了文件夹后,我们将选定的文件夹路径存储在folder_path
实例变量中,并调用update_file_list
方法更新文件列表框中显示的文件列表。
最后,我们销毁对话框。
更新文件列表
接下来,我们需要实现update_file_list
方法,用于更新文件列表框中显示的文件列表。
def update_file_list(self, folder_path):
self.list_box.Clear()
if folder_path:
video_files = [f for f in os.listdir(folder_path) if f.endswith(".mp4")]
for file in video_files:
self.list_box.Append(file)
在该方法中,我们首先清空文件列表框中的内容,然后检查folder_path
是否为空。如果不为空,我们使用os.listdir
函数获取文件夹中所有的文件,并筛选出以".mp4"为扩展名的视频文件。然后,我们将这些视频文件添加到文件列表框中显示出来。
处理播放按钮事件
现在,让我们实现on_play
方法,以处理播放按钮的点击事件。
def on_play(self, event):
selected_files = self.list_box.GetSelections() # 获取选择的文件索引
if selected_files:
video_paths = [os.path.join(self.folder_path, self.list_box.GetString(file_index)) for file_index in selected_files]
if len(video_paths) == 4:
player_frame = VideoPlayerFrame(video_paths)
player_frame.Show()
else:
wx.MessageBox("请选择四个视频文件!", "错误", wx.OK | wx.ICON_ERROR)
else:
wx.MessageBox("请选择视频文件!", "错误", wx.OK | wx.ICON_ERROR)
在该方法中,我们首先获取文件列表框中选中的文件索引。然后,我们使用这些索引来获取选中的视频文件的路径。
接下来,我们检查选中的视频文件数量是否为4。如果是4个视频文件,我们创建一个VideoPlayerFrame
实例,并将视频文件路径作为参数传递给它。最后,我们显示VideoPlayerFrame
窗口。
如果选中的视频文件数量不是4,或者没有选择任何视频文件,我们将显示一个错误消息框,提示用户选择正确的视频文件。
创建视频播放器窗口
我们将创建一个名为VideoPlayerFrame
的wx.Frame子类,用于显示四路视频播放器的窗口。
class VideoPlayerFrame(wx.Frame):
def __init__(self, video_paths):
super().__init__(None, title="四路视频播放器", size=(800, 600))
self.video_players = []
panel = wx.Panel(self)
grid = wx.GridSizer(rows=2, cols=2, hgap=10, vgap=10)
for path in video_paths:
video_player = VideoPlayer(panel, path)
grid.Add(video_player, proportion=1, flag=wx.EXPAND)
self.video_players.append(video_player)
panel.SetSizer(grid)
self.Bind(wx.EVT_CLOSE, self.on_close)
在__init__
方法中,我们设置了窗口的标题和大小,并初始化了一个实例变量video_players
,用于存储四个视频播放器的实例。
接下来,我们创建一个wx.Panel,并使用网格布局(wx.GridSizer)将四个视频播放器放置在窗口中。对于每个视频文件路径,我们创建一个VideoPlayer
实例,并将其添加到网格布局中和video_players
列表中。
最后,我们将网格布局设置为面板的布局管理器,并绑定窗口关闭事件到on_close
方法。
创建视频播放器
现在,我们将创建一个名为VideoPlayer
的wx.Panel子类,用于显示单个视频播放器。
class VideoPlayer(wx.Panel):
def __init__(self, parent, video_path):
super().__init__(parent)
self.video_path = video_path
self.video_capture = cv2.VideoCapture(video_path)
self.timer = wx.Timer(self)
self.Bind(wx.EVT_TIMER, self.on_timer, self.timer)
self.static_bitmap = wx.StaticBitmap(self)
self.update_frame()
self.timer.Start(30) # 每30毫秒更新一帧
def update_frame(self):
ret, frame = self.video_capture.read()
if ret:
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
bitmap = wx.Bitmap.FromBuffer(frame.shape[1], frame.shape[0], frame)
self.static_bitmap.SetBitmap(bitmap)
def on_timer(self, event):
self.update_frame()
在__init__
方法中,我们初始化了一些实例变量,包括视频文件路径、OpenCV的视频捕获对象(cv2.VideoCapture
)、定时器(wx.Timer
)和一个静态位图控件(wx.StaticBitmap
)。
我们在update_frame
方法中读取视频的下一帧,并将其转换为RGB格式。然后,我们将帧数据转换为wx.Bitmap
对象,并将其设置为静态位图控件的位图。这样可以实现视频的实时播放。
在on_timer
方法中,我们在定时器事件触发时调用update_frame
方法,以更新视频帧。
运行应用程序
现在我们已经完成了所有必要的类和方法,让我们在main
函数中实例化FileListFrame
窗口,并运行应用程序的主事件循环。
def main():
app = wx.App()
frame = FileListFrame()
frame.Show()
app.MainLoop()
if __name__ == "__main__":
main()
在main
函数中,我们创建了一个wx.App
实例,并实例化了FileListFrame
窗口。然后,我们显示窗口并启动应用程序的主事件循环。
##完整代码
import os
import wx
import cv2
from moviepy.editor import VideoFileClip
class FileListFrame(wx.Frame):
def __init__(self):
super().__init__(None, title="选择MP4文件", size=(400, 300))
self.folder_path = "" # 添加实例变量来存储文件夹路径
panel = wx.Panel(self)
# 创建选择文件夹的按钮
select_button = wx.Button(panel, label="选择文件夹")
select_button.Bind(wx.EVT_BUTTON, self.on_select_folder)
# 创建列表框,用于显示文件列表
self.list_box = wx.ListBox(panel, style=wx.LB_MULTIPLE | wx.LB_HSCROLL)
# 创建播放按钮
play_button = wx.Button(panel, label="播放")
play_button.Bind(wx.EVT_BUTTON, self.on_play)
# 设置布局管理器
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(select_button, proportion=0, flag=wx.ALIGN_CENTER | wx.ALL, border=10)
sizer.Add(self.list_box, proportion=1, flag=wx.EXPAND | wx.ALL, border=10)
sizer.Add(play_button, proportion=0, flag=wx.ALIGN_CENTER | wx.ALL, border=10)
panel.SetSizer(sizer)
def on_select_folder(self, event):
dialog = wx.DirDialog(self, message="选择文件夹")
if dialog.ShowModal() == wx.ID_OK:
self.folder_path = dialog.GetPath() # 存储选择的文件夹路径
self.update_file_list(self.folder_path)
dialog.Destroy()
def update_file_list(self, folder_path):
self.list_box.Clear()
if folder_path:
video_files = [f for f in os.listdir(folder_path) if f.endswith(".mp4")]
for file in video_files:
self.list_box.Append(file)
def on_play(self, event):
selected_indices = self.list_box.GetSelections()
if len(selected_indices) != 4:
wx.MessageBox("请选择四个MP4文件!", "提示", wx.OK | wx.ICON_INFORMATION)
return
selected_files = [self.list_box.GetString(index) for index in selected_indices]
video_paths = [os.path.join(self.folder_path, file) for file in selected_files] # 使用实例变量
video_player_frame = VideoPlayerFrame(video_paths)
video_player_frame.Show()
class VideoPlayerFrame(wx.Frame):
def __init__(self, video_paths):
super().__init__(None, title="四路视频播放器", size=(800, 600))
panel = wx.Panel(self)
grid = wx.GridSizer(rows=2, cols=2, hgap=5, vgap=5)
self.video_players = []
for path in video_paths:
video_player = VideoPlayer(panel, path)
self.video_players.append(video_player)
grid.Add(video_player, 0, wx.EXPAND)
panel.SetSizer(grid)
self.Bind(wx.EVT_CLOSE, self.on_close)
def on_close(self, event):
for video_player in self.video_players:
video_player.release()
event.Skip()
class VideoPlayer(wx.Panel):
def __init__(self, parent, video_path):
super().__init__(parent)
self.video_path = video_path
self.cap = cv2.VideoCapture(self.video_path)
self.width = int(self.cap.get(cv2.CAP_PROP_FRAME_WIDTH))
self.height = int(self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
self.video_window = wx.StaticBitmap(self, size=(self.width, self.height))
self.timer = wx.Timer(self)
self.Bind(wx.EVT_TIMER, self.update_frame, self.timer)
self.timer.Start(30)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.video_window, 0, wx.ALL, 5)
self.SetSizer(sizer)
def update_frame(self, event):
ret, frame = self.cap.read()
if ret:
img = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
bitmap = wx.Bitmap.FromBuffer(self.width, self.height, img)
self.video_window.SetBitmap(bitmap)
def release(self):
self.cap.release()
if __name__ == '__main__':
app = wx.App()
frame = FileListFrame()
frame.Show()
app.MainLoop()
总结
通过使用wxPython和OpenCV,我们成功创建了一个四路视频播放器应用程序。该应用程序允许用户选择一个包含四个MP4视频文件的文件夹,并在一个GUI界面中同时播放这四个视频文件。我们使用了wxPython来创建图形用户界面,OpenCV来处理和播放视频,以及moviepy来进行视频剪辑。