开发者

使用Python创建一个视频管理器并实现视频截图功能

目录
  • 项目概述编程客栈
  • 所有代码
    • 项目实现
      • 1. 环境准备
      • 2. 创建主窗口类
      • 3. 列出视频文件
      • 4. 显示视频时长
      • 5. 播放视频
      • 6. 截取视频截图
      • 7. 运行应用
  • 效果如下
    • 总结

      项目概述

      本项目的目标是创建一个视频文件管理器应用,它能够:

      • 列出视频文件:用户可以选择一个文件夹,应用会显示该文件夹中的所有视频文件。
      • 显示视频时长:用户点击视频文件后,可以查看视频的时长信息。
      • 播放视频:用户双击视频文件,应用将调用默认的媒体播放器播放视频。
      • 生成视频截图:用户可以选择视频并设定截图时间间隔,应用将生成视频截图,并将截图存放在以视频文件命名的文件夹中。
      • 自动打开截图文件夹:截图生成后,应用会自动打开截图文件夹以方便用户查看。

      所有代码

      import wx
      import os
      import datetime
      import subprocess
      import sys
      import cv2  # Ensure OpenCV is installed
      import threading
      
      class FileListFrame(wx.Frame):
          def __init__(self):
              wx.Frame.__init__(self, None, title编程客栈="使用python创建一个视频管理器并实现视频截图功能", size=(600, 400))
      
              self.panel = wx.Panel(self)
              self.current_path = ""
      
              self.file_list_ctrl = wx.ListCtrl(self.panel, style=wx.LC_REPORT | wx.LC_SINGLE_SEL)
              self.file_list_ctrl.InsertColumn(0, "文件名")
              self.file_list_ctrl.InsertColumn(1, "大小")
              self.file_list_ctrl.InsertColumn(2, "修改时间")
              self.file_list_ctrl.Bind(wx.EVT_LIST_ITEM_SELECTED, self.on_file_selected)
              self.file_list_ctrl.Bind(wx.EVT_LIST_ITEM_AphpCTIVATED, self.on_file_double_clicked)
      
              self.path_label = wx.StaticText(self.panel, label="路径:")
              self.path_textctrl = wx.TextCtrl(self.panel, style=wx.TE_READONLY)
              self.path_button = wx.Button(self.panel, label="选择路径")
              self.path_button.Bind(wx.EVT_BUTTON, self.on_select_path)
      
              self.interval_label = wx.StaticText(self.panel, label="截图间隔(秒):")
              self.interval_textctrl = wx.TextCtrl(self.panel, value="1")
              self.capture_button = wx.Button(self.panel, label="生成截图")
              self.capture_button.Bind(wx.EVT_BUTTON, self.on_capture)
      
              self.export_button = wx.Button(self.panel, label="导出为文本")
              self.export_button.Bind(wx.EVT_BUTTON, self.on_export)
      
              self.play_button = wx.Button(self.panel, label="播放")
              self.play_button.Bind(wx.EVT_BUTTON, self.on_play)
      
              sizer = wx.BoxSizer(wx.VERTICAL)
              sizer.Add(self.path_label, 0, wx.ALL, 5)
              sizer.Add(self.path_textctrl, 0, wx.EXPAND | wx.LEFT | wx.RIGHT, 5)
              sizer.Add(self.path_button, 0, wx.ALL, 5)
              sizer.Add(self.interval_label, 0, wx.ALL, 5)
              sizer.Add(self.interval_textctrl, 0, wx.EXPAND | wx.LEFT | wx.RIGHT, 5)
              sizer.Add(self.capture_button, 0, wx.ALL, 5)
              sizer.Add(self.file_list_ctrl, 1, wx.EXPAND | wx.ALL, 5)
              sizer.Add(self.export_button, 0, wx.ALL, 5)
              sizer.Add(self.play_button, 0, wx.ALL, 5)
              self.panel.SetSizer(sizer)
      
          def on_select_path(self, event):
              dlg = wx.DirDialog(self, "选择路径", style=wx.DD_DEFAULT_STYLE)
              if dlg.ShowModal() == wx.ID_OK:
                  self.current_path = dlg.GetPath()
                  self.path_textctrl.SetValue(self.current_path)
                  self.update_file_list()
              dlg.Destroy()
      
          def update_file_list(self):
              self.file_list_ctrl.DeleteAllItems()
      
              if not self.current_path:
                  return
      
              file_list = self.search_video_files(self.current_path)
              for filename, file_path, file_size, modified_time in file_list:
                  modified_time_str = datetime.datetime.fromtimestamp(modified_time).strftime("%Y-%m-%d %H:%M:%S")
      
                  index = self.file_list_ctrl.InsertItem(self.file_list_ctrl.GetItemCount(), filename)
                  self.file_list_ctrl.SetItem(index, 1, str(file_size))
                  self.file_list_ctrl.SetItem(index, 2, modified_time_str)
      
          def search_video_files(self, directory):
              video_extensions = ['.mp4', '.avi', '.mkv', '.mov', '.wmv', '.flv', '.webm']
              file_list = []
      
              for root, dirs, files in os.walk(directory):
                  for file in files:
                      if os.path.splitext(file)[1].lower() in video_extensions:
                          file_path = os.path.join(root, file)
                          file_size = os.path.getsize(file_path)
                          modified_time = os.path.getmtime(file_path)
                          file_list.append((file, file_path, file_size, modified_time))
      
              return file_list
      
          def on_file_selected(self, event):
              selected_item = event.GetItem()
              file_name = selected_item.GetText()
              file_path = os.path.join(self.current_path, file_name)
      
              video = cv2.VideoCapture(file_path)
              fps = video.get(cv2.CAP_PROP_FPS)
              frame_count = int(video.get(cv2.CAP_PROP_FRAME_COUNT))
              duration = frame_count / fps
              video.release()
      
              duration_str = str(datetime.timedelta(seconds=int(duration)))
      
              wx.MessageBox(
                  f"文件名: {file_name}\n时长: {duration_str}",
                  "视频信息", wx.OK | wx.ICON_INFORMATION)
      
          def on_file_double_clicked(self, event):
              self.on_play(event)
      
          def on_play(self, event):
              selected_item = self.file_list_ctrl.GetFirstSelected()
              if selected_item != -1:
                  file_name = self.file_list_ctrl.GetItemText(selected_item)
                  file_path = os.path.join(self.current_path, file_name)
                  if sys.platform.startswith('win'):
                      subprocess.Popen(['start', '', file_path], shell=True)
                  elif sys.platform.startswith('darwin'):
                      subprocess.Popen(['open', file_path])
                  elif sys.platform.startswith('linux'):
                      subprocess.Popen(['xdg-open', file_path])
              else:
                  wx.MessageBox("请先选择要播放的文件", "提示", wx.OK | wx.ICON_INFORMATION)
      
      
          def on_export(self, event):
              dlg = wx.FileDialog(self, "保存为文本文件", wildcard="Text files (*.txt)|*.txt",
                                  style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT)
      
              if dlg.ShowModal() == wx.ID_OK:
                  file_path = dlg.GetPath()
                  with open(file_path, 'w') as file:
                      for index in range(self.file_list_ctrl.GetItemCount()):
                          file.write(self.file_list_ctrl.GetItemText(index) + '\n')
      
          def on_capture(self, event):
              selected_item = self.file_list_ctrl.GetFirstSelected()
              if selected_item != -1:
                  file_name = self.file_list_ctrl.GetItemText(selected_item)
                  file_path = os.path.join(self.current_path, file_name)
                  try:
                      interval = int(self.interval_textctrl.GetValue())
                  except ValueError:
                      wx.MessageBox("请输入有效的时间间隔(秒)", "错误", wx.OK | wx.ICON_ERROR)
                      return
      
                  thread = threading.Thread(target=self.capture_screenshots, args=(file_path, interval))
                  thread.start()
              else:
                  wx.MessageBox("请先选择要生成截图的文件", "提示", wx.OK | wx.ICON_INFORMATION)
      
          def capture_screenshots(self, file_path, interval):
              # 生成以视频名称命名的文件夹
              output_dir = os.path.join(self.current_path, os.path.splitext(os.path.basename(file_path))[0])
              if not os.path.exists(output_dir):
                  os.makedirs(output_dir)
      
              # 构造 ffmpeg 命令
              cmd = [
                  'ffmpeg',
                  '-i', file_path,                 # 输入视频文件
                  '-vf', f'fps=1/{interval}',      # 每隔 {interval} 秒截取一帧
                  os.path.join(output_dir, 'screenshot_%03d.jpg')  # 输出截图路径及文件名格式
              ]
      
              # 执行命令
              subprocess.run(cmd, check=True)
      
              # 截图完成后,自动打开文件夹
              if sys.platform.startswith('win'):
                  subprocess.Popen(['explorer', output_dir])
              elif sys.platform.startswith('darwin'):
                  subprocess.Popen(['open', output_dir])
              elif sys.platform.startswith('linux'):
                  subprocess.Popen(['xdg-open', output_dir])
      
          # def capture_screenshots(self, file_path, interval):
          #     video = cv2.VideoCapture(file_path)
          #     fps = video.get(cv2.CAP_PROP_FPS)
          #     frame_count = int(video.get(cv2.CAP_PROP_FRAME_COUNT))
          #     duration = frame_count / fps
      
          #     output_dir = os.path.join(self.current_path, os.path.splitext(os.path.basename(file_path))[0])  
          #     if not os.path.exists(output_dir):
          #         os.makedirs(output_dir)
      
          #     for sec in range(0, int(duration), interval):
                  video.set(cv2.CAP_PROP_POS_MSEC, sec * 1000)
                  success, image = video.read()
                  if success:
                      cv2.imwrite(os.path.join(output_dir, f"{sec}.png"), image)
      
              video.release()
              wx.CallAfter(wx.MessageBox, "截图已生成", "完成", wx.OK | wx.ICON_INFORMATION)
              
              # Automatically open the folder containing screenshots
              if sys.platform.startswith('win'):
                  subprocess.Popen(['explorer', output_dir], shell=True)
              elif sys.platform.startswith('darwin'):
                  subprocess.Popen(['open', output_dir])
              elif sys.platform.startswwww.devze.comith('linux'):
                  subprocess.Popen(['xdg-open', output_dir])
      
      if __name__ == "__main__":
          app = wx.App()
          frame = FileListFrame()
          frame.Show()
          app.MainLoop()
      
      

      项目实现

      让我们一步一步实现这个项目。

      1. 环境准备

      首先,你需要确保系统中安装了以下工具:

      • Python 3.x:Python 是本项目的编程语言。
      • wxPython:用于创建图形用户界面。你可以使用以下命令安装它:
      pip install wxPython
      
      • ffmpeg:用于处理视频文件和生成截图。你可以从 ffmpeg 官网 下载并安装。

      2. 创建主窗口类

      首先,我们创建一个主窗口类 FileListFrame,用于展示视频文件列表并处理用户交互。

      import wx
      import os
      import datetime
      import subprocess
      import sys
      import threading
      
      class FileListFrame(wx.Frame):
          def __init__(self):
              wx.Frame.__init__(self, None, title="使用Python创建一个视频管理器并实现视频截图功能", size=(600, 400))
      
              self.panel = wx.Panel(self)
              self.current_path = ""
      
              # 创建文件列表控件
              self.file_list_ctrl = wx.ListCtrl(self.panel, style=wx.LC_REPORT | wx.LC_SINGLE_SEL)
              self.file_list_ctrl.InsertColumn(0, "文件名")
              self.file_list_ctrl.InsertColumn(1, "时长")
              self.file_list_ctrl.InsertColumn(2, "大小")
              self.file_list_ctrl.InsertColumn(3, "修改时间")
              self.file_list_ctrl.Bind(wx.EVT_LIST_ITEM_SELECTED, self.on_file_selected)
              self.file_list_ctrl.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.on_play)
      
              # 创建路径选择控件
              self.path_label = wx.StaticText(self.panel, label="路径:")
              self.path_textctrl = wx.TextCtrl(self.panel, style=wx.TE_READONLY)
              self.path_button = wx.Button(self.panel, label="选择路径")
              self.path_button.Bind(wx.EVT_BUTTON, self.on_select_path)
      
              # 创建导出和播放按钮
              self.capture_button = wx.Button(self.panel, label="截图")
              self.capture_button.Bind(wx.EVT_BUTTON, self.on_capture)
      
              # 创建截图时间间隔输入框
              self.interval_label = wx.StaticText(self.panel, label="截图时间间隔(秒):")
              self.interval_textctrl = wx.TextCtrl(self.panel)
      
              # 创建布局
              sizer = wx.BoxSizer(wx.VERTICAL)
              sizer.Add(self.path_label, 0, wx.ALL, 5)
              sizer.Add(self.path_textctrl, 0, wx.EXPAND | wx.LEFT | wx.RIGHT, 5)
              sizer.Add(self.path_button, 0, wx.ALL, 5)
              sizer.Add(self.file_list_ctrl, 1, wx.EXPAND | wx.ALL, 5)
              sizer.Add(self.interval_label, 0, wx.ALL, 5)
              sizer.Add(self.interval_textctrl, 0, wx.EXPAND | wx.ALL, 5)
              sizer.Add(self.capture_button, 0, wx.ALL, 5)
              self.panel.SetSizer(sizer)
      

      在 __init__ 方法中,我们初始化了主窗口,并创建了一个 ListCtrl 控件用于显示视频文件列表。还添加了用于选择路径的按钮和输入截图时间间隔的文本框。

      3. 列出视频文件

      接下来,我们实现选择路径和列出视频文件的功能:

          # 处理选择路径事件
          def on_select_path(self, event):
              dlg = wx.DirDialog(self, "选择路径", style=wx.DD_DEFAULT_STYLE)
              if dlg.ShowModal() == wx.ID_OK:
                  self.current_path = dlg.GetPath()
                  self.path_textctrl.SetValue(self.current_path)
                  self.update_file_list()
              dlg.Destroy()
      
          # 更新文件列表
          def update_file_list(self):
              self.file_list_ctrl.DeleteAllItems()
      
              if not self.current_path:
                  return
      
              file_list = self.search_video_files(self.current_path)
              for filename, file_path, file_size, modified_time in file_list:
                  modified_time_str = datetime.datetime.fromtimestamp(modified_time).strftime("%Y-%m-%d %H:%M:%S")
      
                  index = self.file_list_ctrl.InsertItem(self.file_list_ctrl.GetItemCount(), filename)
                  self.file_list_ctrl.SetItem(index, 1, "待获取")
                 lAKGTHf self.file_list_ctrl.SetItem(index, 2, str(file_size))
                  self.file_list_ctrl.SetItem(index, 3, modified_time_str)
      
          # 搜索视频文件
          def search_video_files(self, directory):
              video_extensions = ['.mp4', '.avi', '.mkv', '.mov', '.wmv', '.flv', '.webm']
              file_list = []
      
              for root, dirs, files in os.walk(directory):
                  for file in files:
                      if os.path.splitext(file)[1].lower() in video_extensions:
                          file_path = os.path.join(root, file)
                          file_size = os.path.getsize(file_path)
                          modified_time = os.path.getmtime(file_path)
                          file_list.append((file, file_path, file_size, modified_time))
      
              return file_list
      

      这里我们通过遍历用户选择的路径,查找所有视频文件,并将其添加到列表控件中。视频文件的时长将在用户点击时获取。

      4. 显示视频时长

      我们使用 ffmpeg 提供的功能来获取视频文件的时长。

          # 处理文件选择事件
          def on_file_selected(self, event):
              selected_item = event.GetItem()
              file_name = selected_item.GetText()
              file_path = os.path.join(self.current_path, file_name)
              duration = self.get_video_duration(file_path)
              self.file_list_ctrl.SetItem(selected_item.GetId(), 1, duration)
      
          # 获取视频时长
          def get_video_duration(self, file_path):
              cmd = [
                  'ffmpeg',
                  '-i', file_path,
                  '-hide_banner',
                  '-loglevel', 'error',
                  '-show_entries', 'format=duration',
                  '-of', 'default=noprint_wrappers=1:nokey=1'
              ]
              result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
              duration = float(result.stdout.strip())
              return str(datetime.timedelta(seconds=int(duration)))
      

      在用户选择视频文件时,on_file_selected 事件被触发,应用会调用 ffmpeg 命令获取视频时长并显示在列表中。

      5. 播放视频

      用户可以通过双击视频文件来播放视频。我们使用默认的媒体播放器来实现播放功能:

          # 处理播放事件
          def on_play(self, event):
              selected_item = self.file_list_ctrl.GetFirstSelected()
              if selected_item != -1:
                  file_name = self.file_list_ctrl.GetItemText(selected_item)
                  file_path = os.path.join(self.current_path, file_name)
                  if sys.platform.startswith('win'):
                      subprocess.Popen(['start', '', file_path], shell=True)
                  elif sys.platform.startswith('darwin'):
                      subprocess.Popen(['open', file_path])
                  elif sys.platform.startswith('linux'):
                      subprocess.Popen(['xdg-open', file_path])
              else:
                  wx.MessageBox("请先选择要播放的文件", "提示", wx.OK | wx.ICON_INFORMATION)
      

      通过调用系统命令,我们让视频文件可以使用系统默认的播放器进行播放。

      6. 截取视频截图

      用户可以设置时间间隔,并对视频进行截图。截图将保存到以视频文件名命名的文件夹中:

          # 处理截图事件
          def on_capture(self, event):
              selected_item = self.file_list_ctrl.GetFirstSelected()
              if selected_item != -1:
                  file_name = self.file_list_ctrl.GetItemText(selected_item)
                  file_path = os.path.join(self.current_path, file_name)
                  interval = int(self.interval_textctrl.GetValue())
                  thread = threading.Thread(target=self.capture_screenshots, args=(file_path, interval))
                  thread.start()
              else:
                  wx.MessageBox("请先选择要截图的视频文件", "提示", wx.OK | wx.ICON_INFORMATION)
      
          # 截取视频截图
          def capture_screenshots(self, file_path, interval):
              # 生成以视频名称命名的文件夹
              output_dir
      
       = os.path.join(self.current_path, os.path.splitext(os.path.basename(file_path))[0])
              if not os.path.exists(output_dir):
                  os.makedirs(output_dir)
      
              # 构造 ffmpeg 命令
              cmd = [
                  'ffmpeg',
                  '-i', file_path,
                  '-vf', f'fps=1/{interval}',
                  os.path.join(output_dir, 'screenshot_%03d.jpg')
              ]
      
              # 执行命令
              subprocess.run(cmd, check=True)
      
              # 截图完成后,自动打开文件夹
              if sys.platform.startswith('win'):
                  subprocess.Popen(['explorer', output_dir])
              elif sys.platform.startswith('darwin'):
                  subprocess.Popen(['open', output_dir])
              elif sys.platform.startswith('linux'):
                  subprocess.Popen(['xdg-open', output_dir])
      

      7. 运行应用

      最后,添加主函数以启动应用:

      if __name__ == "__main__":
          app = wx.App(False)
          frame = FileListFrame()
          frame.Show()
          app.MainLoop()
      

      效果如下

      使用Python创建一个视频管理器并实现视频截图功能

      总结

      在这篇博客中,我们使用 wxPython 和 ffmpeg 创建了一个视频文件管理器。它不仅能管理和播放视频,还能生成视频截图,并将截图存放到特定的文件夹中。你可以根据需要进一步扩展这个应用程序,例如增加视频剪辑、视频合并等功能。希望这篇博客能帮助你更好地理解 wxPython 和 ffmpeg 的使用方法,并激发你在项目中应用这些技术的兴趣。

      以上就是使用Python创建一个视频管理器并实现视频截图功能的详细内容,更多关于Python视频截图的资料请关注编程客栈(www.devze.com)其它相关文章!

      0

      上一篇:

      下一篇:

      精彩评论

      暂无评论...
      验证码 换一张
      取 消

      最新开发

      开发排行榜