音频/视频提取器:Python和moviepy实现

在这篇博客中,我们将深入探讨一个使用Python和wxPython构建的音频/视频提取器应用程序。这个应用程序允许用户从视频文件中提取音频,或者从音频文件中截取特定时间段。让我们逐步分析这个程序的功能和实现。
C:\pythoncode\new\MP3towav.py

全部代码

import wx
import os
import subprocess
from datetime import datetime
import json
from moviepy.editor import VideoFileClip, AudioFileClip

class AudioVideoExtractor(wx.Frame):
    def __init__(self):
        super().__init__(parent=None, title='Audio/Video Extractor')
        self.panel = wx.Panel(self)
        self.create_widgets()
        self.load_settings()

    def create_widgets(self):
        # File selection
        self.file_picker = wx.FilePickerCtrl(self.panel, message="Choose an audio or video file")
        
        # Time range
        self.start_time = wx.TextCtrl(self.panel, value="00:00:00")
        self.end_time = wx.TextCtrl(self.panel, value="00:00:00")
        
        # Output format
        self.formats = ['mp3', 'wav', 'aac']
        self.format_choice = wx.Choice(self.panel, choices=self.formats)
        
        # Output directory
        self.dir_picker = wx.DirPickerCtrl(self.panel, message="Choose output directory")
        
        # Export button
        self.export_btn = wx.Button(self.panel, label="Export")
        self.export_btn.Bind(wx.EVT_BUTTON, self.on_export)
        
        # Open button
        self.open_btn = wx.Button(self.panel, label="Open in PotPlayer")
        self.open_btn.Bind(wx.EVT_BUTTON, self.on_open)
        
        # Layout
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(wx.StaticText(self.panel, label="Select Audio or Video File:"), 0, wx.ALL, 5)
        sizer.Add(self.file_picker, 0, wx.EXPAND|wx.ALL, 5)
        sizer.Add(wx.StaticText(self.panel, label="Start Time (HH:MM:SS):"), 0, wx.ALL, 5)
        sizer.Add(self.start_time, 0, wx.EXPAND|wx.ALL, 5)
        sizer.Add(wx.StaticText(self.panel, label="End Time (HH:MM:SS):"), 0, wx.ALL, 5)
        sizer.Add(self.end_time, 0, wx.EXPAND|wx.ALL, 5)
        sizer.Add(wx.StaticText(self.panel, label="Output Format:"), 0, wx.ALL, 5)
        sizer.Add(self.format_choice, 0, wx.EXPAND|wx.ALL, 5)
        sizer.Add(wx.StaticText(self.panel, label="Output Directory:"), 0, wx.ALL, 5)
        sizer.Add(self.dir_picker, 0, wx.EXPAND|wx.ALL, 5)
        sizer.Add(self.export_btn, 0, wx.ALL|wx.CENTER, 5)
        sizer.Add(self.open_btn, 0, wx.ALL|wx.CENTER, 5)
        
        self.panel.SetSizer(sizer)
        
    def on_export(self, event):
        input_path = self.file_picker.GetPath()
        start_time = self.start_time.GetValue()
        end_time = self.end_time.GetValue()
        output_format = self.formats[self.format_choice.GetSelection()]
        output_dir = self.dir_picker.GetPath()
        
        if not all([input_path, start_time, end_time, output_format, output_dir]):
            wx.MessageBox("Please fill in all fields", "Error", wx.OK | wx.ICON_ERROR)
            return
        
        try:
            # Check if the input file is video or audio
            file_extension = os.path.splitext(input_path)[1].lower()
            if file_extension in ['.mp4', '.avi', '.mov', '.flv']:  # Add more video extensions if needed
                clip = VideoFileClip(input_path).audio
            elif file_extension in ['.mp3', '.wav', '.aac', '.flac']:  # Add more audio extensions if needed
                clip = AudioFileClip(input_path)
            else:
                raise ValueError("Unsupported file format")

            start = self.time_to_seconds(start_time)
            end = self.time_to_seconds(end_time)
            
            clip = clip.subclip(start, end)
            
            timestamp = datetime.now().strftime("%Y%m%d")
            counter = 1
            while True:
                output_filename = f"{timestamp}_{counter:03d}.{output_format}"
                output_path = os.path.join(output_dir, output_filename)
                if not os.path.exists(output_path):
                    break
                counter += 1
            
            clip.write_audiofile(output_path)
            clip.close()
            
            self.last_exported_file = output_path
            wx.MessageBox(f"Audio exported to {output_path}", "Success", wx.OK | wx.ICON_INFORMATION)
            
            self.save_settings()
        except Exception as e:
            wx.MessageBox(f"Error: {str(e)}", "Error", wx.OK | wx.ICON_ERROR)
    
    def on_open(self, event):
        if hasattr(self, 'last_exported_file') and os.path.exists(self.last_exported_file):
            try:
                subprocess.Popen(['C:\\Program Files\\DAUM\\PotPlayer\\PotPlayerMini64.exe', self.last_exported_file])
            except Exception as e:
                wx.MessageBox(f"Error opening file: {str(e)}", "Error", wx.OK | wx.ICON_ERROR)
        else:
            wx.MessageBox("No file has been exported yet", "Error", wx.OK | wx.ICON_ERROR)
    
    def time_to_seconds(self, time_str):
        h, m, s = map(int, time_str.split(':'))
        return h * 3600 + m * 60 + s
    
    def save_settings(self):
        settings = {
            'last_file': self.file_picker.GetPath(),
            'start_time': self.start_time.GetValue(),
            'end_time': self.end_time.GetValue(),
            'format': self.format_choice.GetSelection(),
            'output_dir': self.dir_picker.GetPath()
        }
        with open('settings.json', 'w') as f:
            json.dump(settings, f)
    
    def load_settings(self):
        if os.path.exists('settings.json'):
            with open('settings.json', 'r') as f:
                settings = json.load(f)
            self.file_picker.SetPath(settings.get('last_file', ''))
            self.start_time.SetValue(settings.get('start_time', '00:00:00'))
            self.end_time.SetValue(settings.get('end_time', '00:00:00'))
            self.format_choice.SetSelection(settings.get('format', 0))
            self.dir_picker.SetPath(settings.get('output_dir', ''))

if __name__ == '__main__':
    app = wx.App()
    frame = AudioVideoExtractor()
    frame.Show()
    app.MainLoop()

1. 概述

这个应用程序的主要功能包括:

  • 从视频文件中提取音频
  • 从音频文件中截取特定时间段
  • 设置输出音频格式
  • 自定义输出文件名和路径
  • 使用PotPlayer播放导出的音频文件
  • 保存和加载用户设置

2. 导入必要的库

import wx
import os
import subprocess
from datetime import datetime
import json
from moviepy.editor import VideoFileClip, AudioFileClip

这些库为我们提供了以下功能:

  • wx: 用于创建图形用户界面
  • os: 用于文件和路径操作
  • subprocess: 用于启动外部程序(PotPlayer)
  • datetime: 用于生成时间戳
  • json: 用于保存和加载设置
  • moviepy.editor: 用于处理音频和视频文件

3. 主应用程序类

class AudioVideoExtractor(wx.Frame):
    def __init__(self):
        super().__init__(parent=None, title='Audio/Video Extractor')
        self.panel = wx.Panel(self)
        self.create_widgets()
        self.load_settings()

这个类继承自wx.Frame,是我们应用程序的主窗口。在初始化方法中,我们创建了一个面板,调用方法来创建UI组件,并加载之前保存的设置。

4. 创建UI组件

def create_widgets(self):
    # 文件选择器
    self.file_picker = wx.FilePickerCtrl(self.panel, message="Choose an audio or video file")
    
    # 时间范围输入
    self.start_time = wx.TextCtrl(self.panel, value="00:00:00")
    self.end_time = wx.TextCtrl(self.panel, value="00:00:00")
    
    # 输出格式选择
    self.formats = ['mp3', 'wav', 'aac']
    self.format_choice = wx.Choice(self.panel, choices=self.formats)
    
    # 输出目录选择
    self.dir_picker = wx.DirPickerCtrl(self.panel, message="Choose output directory")
    
    # 导出按钮
    self.export_btn = wx.Button(self.panel, label="Export")
    self.export_btn.Bind(wx.EVT_BUTTON, self.on_export)
    
    # 打开按钮
    self.open_btn = wx.Button(self.panel, label="Open in PotPlayer")
    self.open_btn.Bind(wx.EVT_BUTTON, self.on_open)
    
    # 布局设置
    # ...

这个方法创建了所有的UI组件,包括文件选择器、时间输入框、格式选择下拉框、目录选择器和按钮。它还设置了组件的布局。

5. 导出功能

def on_export(self, event):
    # 获取用户输入
    input_path = self.file_picker.GetPath()
    start_time = self.start_time.GetValue()
    end_time = self.end_time.GetValue()
    output_format = self.formats[self.format_choice.GetSelection()]
    output_dir = self.dir_picker.GetPath()
    
    # 检查输入是否完整
    if not all([input_path, start_time, end_time, output_format, output_dir]):
        wx.MessageBox("Please fill in all fields", "Error", wx.OK | wx.ICON_ERROR)
        return
    
    try:
        # 检查输入文件类型
        file_extension = os.path.splitext(input_path)[1].lower()
        if file_extension in ['.mp4', '.avi', '.mov', '.flv']:
            clip = VideoFileClip(input_path).audio
        elif file_extension in ['.mp3', '.wav', '.aac', '.flac']:
            clip = AudioFileClip(input_path)
        else:
            raise ValueError("Unsupported file format")

        # 处理音频
        start = self.time_to_seconds(start_time)
        end = self.time_to_seconds(end_time)
        clip = clip.subclip(start, end)
        
        # 生成输出文件名
        timestamp = datetime.now().strftime("%Y%m%d")
        counter = 1
        while True:
            output_filename = f"{timestamp}_{counter:03d}.{output_format}"
            output_path = os.path.join(output_dir, output_filename)
            if not os.path.exists(output_path):
                break
            counter += 1
        
        # 导出音频
        clip.write_audiofile(output_path)
        clip.close()
        
        self.last_exported_file = output_path
        wx.MessageBox(f"Audio exported to {output_path}", "Success", wx.OK | wx.ICON_INFORMATION)
        
        self.save_settings()
    except Exception as e:
        wx.MessageBox(f"Error: {str(e)}", "Error", wx.OK | wx.ICON_ERROR)

这个方法是程序的核心,它处理音频/视频的导出过程:

  1. 获取用户输入的所有必要信息。
  2. 检查输入文件的类型(音频或视频)。
  3. 根据用户指定的时间范围截取音频。
  4. 生成一个唯一的输出文件名。
  5. 导出音频文件。
  6. 保存用户设置以便下次使用。

6. 在PotPlayer中打开文件

def on_open(self, event):
    if hasattr(self, 'last_exported_file') and os.path.exists(self.last_exported_file):
        try:
            subprocess.Popen(['potplayer.exe', self.last_exported_file])
        except Exception as e:
            wx.MessageBox(f"Error opening file: {str(e)}", "Error", wx.OK | wx.ICON_ERROR)
    else:
        wx.MessageBox("No file has been exported yet", "Error", wx.OK | wx.ICON_ERROR)

这个方法允许用户直接在PotPlayer中打开最近导出的文件。

7. 设置的保存和加载

def save_settings(self):
    settings = {
        'last_file': self.file_picker.GetPath(),
        'start_time': self.start_time.GetValue(),
        'end_time': self.end_time.GetValue(),
        'format': self.format_choice.GetSelection(),
        'output_dir': self.dir_picker.GetPath()
    }
    with open('settings.json', 'w') as f:
        json.dump(settings, f)

def load_settings(self):
    if os.path.exists('settings.json'):
        with open('settings.json', 'r') as f:
            settings = json.load(f)
        self.file_picker.SetPath(settings.get('last_file', ''))
        self.start_time.SetValue(settings.get('start_time', '00:00:00'))
        self.end_time.SetValue(settings.get('end_time', '00:00:00'))
        self.format_choice.SetSelection(settings.get('format', 0))
        self.dir_picker.SetPath(settings.get('output_dir', ''))

这些方法允许程序保存用户的设置并在下次启动时加载它们,提高了用户体验。

8. 主程序入口

if __name__ == '__main__':
    app = wx.App()
    frame = AudioVideoExtractor()
    frame.Show()
    app.MainLoop()

这是程序的入口点,它创建了wxPython应用程序实例,实例化了我们的AudioVideoExtractor类,并启动主事件循环。

运行结果

在这里插入图片描述

结论

这个音频/视频提取器是一个功能强大yet易用的工具,展示了如何使用Python和wxPython创建实用的桌面应用程序。它结合了文件I/O、音频/视频处理、GUI编程和设置管理等多个方面,是一个很好的学习案例。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/896000.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

「iOS」——YYModel学习

iOS学习 前言优势使用方法简单的Model与JSON互转多样化的数据类型交换容器类数据交换 model中包含其他model白名单与黑名单 总结 前言 YYModel是YYKit的高效组件之一,在实际场景中的非常实用,在项目中使用MVC架构时,可以简化数据处理。在性能…

OpenShift 4 - 云原生备份容灾 - Velero 和 OADP 基础篇

《OpenShift 4.x HOL教程汇总》 说明: 本文主要说明能够云原生备份容灾的开源项目 Velero 及其红帽扩展项目 OADP 的概念和架构篇。操作篇见《OpenShift 4 - 使用 OADP 对容器应用进行备份和恢复(附视频) 》 Velero 和 OADP 包含的功能和模…

028.爬虫浏览器-抓取shadowRoot下的内容

一、什么是Shadow DOM Shadow DOM是一种在web开发中用于封装HTML标记、样式和行为的技术,以避免组件间的样式和脚本冲突。它允许开发者将网页的一部分隐藏在一个独立的作用域内,从而实现更加模块化和可维护的代码结构 二、js操作Shadow DOM // 获取宿…

邮件营销文案设计:打造个性化内容的步骤?

邮件营销文案写作技巧与方法?外贸邮件营销怎么撰写? 一个成功的邮件营销文案设计不仅能吸引客户的注意力,还能有效提升转化率。MailBing将详细探讨如何通过一系列步骤,打造出既个性化又高效的邮件营销文案设计。 邮件营销文案设…

监控易监测对象及指标之:Microsoft Message Queue(MSMQ)监控

监控易是一款强大的监控工具,能够实时监控各类IT设施和应用程序的性能指标。对于Microsoft Message Queue(简称MSMQ)的监控,监控易提供了详尽的指标,以确保企业能够准确掌握消息队列的运行状况。 在MSMQ的监控中&#…

24、darkhole_2

难度 高(个人感觉属于中) 目标 root权限2个flag 基于VMware启动(我这里启动只能选择我wifi的那个网卡才能获取到ip地址,nat的没获取到不知道为什么。) kali 192.168.1.122 靶机 192.168.1.170 信息收集 端口扫描 只开…

【python】OpenCV—Fun Mirrors

文章目录 1、准备工作2、原理介绍3、代码实现4、效果展示5、参考 1、准备工作 pip install vacm2、原理介绍 在OpenCV中,VCAM 库是一个用于简化创建三维曲面、定义虚拟摄像机、设置参数以及进行投影任务的工具。它特别适用于实现如哈哈镜等图像变形效果。 一、VC…

用你的手机/电脑运行文生图方案

随着ChatGPT和Stable Diffusion的发布,最近一两年,生成式AI已经火爆全球,已然成为移动互联网后一个重要的“风口”。就图片/视频生成领域来说,Stable Diffusion模型发挥着极其重要的作用。由于Stable Diffusion模型参数量是10亿参…

读者写者问题与读写锁

读者写者问题 读者写者 vs 生产消费 重点是有什么区别 读者写者问题如何理解 重点理解读者和写者如何完成同步 下面是一段伪代码:公共部分 uint32_t reader_count 0; lock_t count_lock; lock_t writer_lock; Reader // 加锁 lock(count_lock); if(reader_c…

Java | Leetcode Java题解之第492题构造矩形

题目: 题解: class Solution {public int[] constructRectangle(int area) {int w (int) Math.sqrt(area);while (area % w ! 0) {--w;}return new int[]{area / w, w};} }

5G物联网主机引领企业数字化转型

在当今这个信息化高度发展的时代,企业的竞争力很大程度上取决于其能否快速适应市场变化并高效地进行内部管理。郑州龙兴物联科技有限公司凭借其先进的5G物联网技术,推出了为企业量身定制的5G物联网主机,该设备充分利用其多协议、多接口的特点…

ESP32-C3 入门笔记04:gpio_key 按键 (ESP-IDF + VSCode)

1.GPIO简介 ESP32-C3是QFN32封装,GPIO引脚一共有22个,从GPIO0到GPIO21。 理论上,所有的IO都可以复用为任何外设功能,但有些引脚用作连接芯片内部FLASH或者外部FLASH功能时,官方不建议用作其它用途。 通过开发板的原…

【Vue】Vue3.0 (十二)、watchEffect 和watch的区别及使用

上篇文章: 【Vue】Vue3.0 (十二)、watch对ref定义的基本类型、对象类型;reactive定义的对象类型的监视使用 🏡作者主页:点击! 🤖Vue专栏:点击! ⏰️创作时间&…

数据仓库基础概念

数据仓库 概念 数据仓库(Data Warehouse, DW)是一个面向主题的、集成的、相对稳定的、反映历史变化的数据集合。它是为满足企业决策分析需求而设计的。 面向主题:数据仓库围绕特定的主题组织数据,例如“销售”或“人力资源”&am…

线上交友小程序源码系统 一元盲盒小程序在线开好友 带完整的安装代码包以及搭建部署教程

系统概述 线上交友小程序源码系统是基于先进的技术架构开发的一套完整的解决方案,旨在为用户提供一个便捷、有趣的线上交友平台。该系统通过一元盲盒的形式,让用户在未知中寻找惊喜,增加了交友的趣味性和神秘感。 该系统采用了先进的编程技…

UE5蓝图中忽略触发区域进行碰撞

Event Hit :只会在碰撞到实体的时候产生碰撞。如果是触发区域则会忽略。 Destroy Actor:销毁自身。

openrtp 音视频时间戳问题

解决音视频发送的rtp问题 openrtp增加了音频aac的发送,地址 OpenRTP Gitee开源地址 同时使用两个rtp ,来发送音频和视频 使用以下音频rtp,是可以发送和接收的,音频端口在视频端口上2 v0 o- 0 0 IN IP4 127.0.0.1 sMy Stream cI…

sentinel dashboard分布式改造落地设计实现解释(二)-分布式discovery组件

discovery discovery负责维护app/机器资料库,transport健康检测, transport上下线处理。discovery关键是分布式存储,后续研究一下raft,其复制,状态机,快照技术,但个人觉得,discover…

【网络安全】护网蓝队之应急响应

蓝队技术栈 Linux入侵排查 系统排查 一、查看历史命令 在Linux系统中,检查历史命令记录是安全审计的重要步骤之一,它可以帮助您了解系统上用户(包括潜在的黑客)的活动。以下是对您描述的重新表述和补充: 检查历史命…

webpack自定义插件 ChangeScriptSrcPlugin

插件文件 class ChangeScriptSrcPlugin {apply(compiler) {const pluginName "ChangeScriptSrcPlugin";compiler.hooks.compilation.tap(pluginName, (compilation, callback) > {compilation.hooks.htmlWebpackPluginAlterAssetTags.tapAsync(pluginName,(html…