当前位置: 代码网 > it编程>前端脚本>Python > 使用Python创建一个视频管理器并实现视频截图功能

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

2024年08月20日 Python 我要评论
项目概述本项目的目标是创建一个视频文件管理器应用,它能够:列出视频文件:用户可以选择一个文件夹,应用会显示该文件夹中的所有视频文件。显示视频时长:用户点击视频文件后,可以查看视频的时长信息。播放视频:

项目概述

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

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

所有代码

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="视频文件列表", 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_activated, 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.startswith('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="视频文件管理器", 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, "待获取")
            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()

效果如下

总结

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

以上就是使用python创建一个视频管理器并实现视频截图功能的详细内容,更多关于python视频截图的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com