• python视频转码脚本


    今天有一个临时的需求,就是需要将一个wmv的初步转码成mp4的格式。找了一圈,免费的工具少,即使有免费的工具,在功能上也是有所限制,或者会给你塞广告或者附带安装其它流氓小游戏或者杀毒程序。

    我并非不支持正版,我本人不是专业的视频创作者,平日里对视频转码编辑的需求极少,为这临时需要而买个正常软件,一没必要,二不划算。

    FFmpeg 是一个强大的开源视频工具包,通过命令行可以轻易的将一个 wmv 文件转码成需要的目标格式文件,例如转码成mp4

    Python 也是个很好用的脚本语言。为可以快速的搜索视频文档,然后对其进行转码操作,使用Python写了一个简单的脚本,该脚本可以借助Everything的强大搜索功能,协助用户快速的搜索定位需要转码的文档,然后对其进行转码。

    Python 脚本

    Python脚本比较简单,逻辑也比较清晰。截图如下:

    20240511141928

    如👆上图所示,脚本首先定义了一个命令行入参的类,用于管理和解析命令行传入的参数。
    然后定义了一个小的函数,这个函数并不是核心功能,仅用于对比两个指定的字符串中的差异。

    在主程序中(if __name__ == '__main__'部分),脚本首先解析了来自命令行的参数;
    然后定义了一个Everything搜索接口对象(该Everything搜索接口对象提供了基于Everything的搜索功能),用于协助用户快速的搜索定位兴趣文档。

    在功能逻辑循环体中,首先引导用户搜索定位待转码的视频文档;然后与用户交互确定转码的目标格式;最后借助 moviepy这个Python包完成视频转码操作。

    以上,脚本逻辑清晰自然,贴出Python代码如下👇。

    # -*- coding:UTF-8 -*-
    """
    @author: dyy
    @contact: douyaoyuan@126.com
    @time: 2024/5/10 21:40
    @file: 视频转码.py
    @desc: xxxxxx
    """
    
    # region 引入必要的依赖
    import os
    
    模块名 = 'DebugInfo'
    try:
        from DebugInfo.DebugInfo import *
    except ImportError as impErr:
        print(f"尝试导入 {模块名} 依赖时检测到异常:{impErr}")
        print(f"尝试安装 {模块名} 模块:")
        try:
            os.system(f"pip install {模块名}")
        except OSError as osErr:
            print(f"尝试安装模块 {模块名} 时检测到异常:{osErr}")
            exit(0)
        else:
            try:
                from DebugInfo.DebugInfo import *
            except ImportError as impErr:
                print(f"再次尝试导入 {模块名} 依赖时检测到异常:{impErr}")
                exit(0)
    
    模块名 = 'difflib'
    try:
        import difflib  # 需要安装 difflib 模块,以支持字符差异对比操作
    except ImportError as impErr:
        print(f"尝试导入 {模块名} 依赖时检测到异常:{impErr}")
        print(f"尝试安装 {模块名} 模块:")
        try:
            os.system(f"pip install {模块名}")
        except OSError as osErr:
            print(f"尝试安装模块 {模块名} 时检测到异常:{osErr}")
            exit(0)
        else:
            try:
                import difflib
            except ImportError as impErr:
                print(f"再次尝试导入 {模块名} 依赖时检测到异常:{impErr}")
                exit(0)
    
    模块名 = 'moviepy'
    try:
        from moviepy.editor import VideoFileClip  # 需要引入 moviepy 模块,以支持视频转码的操作
    except ImportError as impErr:
        print(f"尝试导入 {模块名} 依赖时检测到异常:{impErr}")
        print(f"尝试安装 {模块名} 模块:")
        try:
            os.system(f"pip install {模块名}")
        except OSError as osErr:
            print(f"尝试安装模块 {模块名} 时检测到异常:{osErr}")
            exit(0)
        else:
            try:
                from moviepy.editor import VideoFileClip
            except ImportError as impErr:
                print(f"再次尝试导入 {模块名} 依赖时检测到异常:{impErr}")
                exit(0)
    # endregion
    
    # 定义一个 命令行参数类,用于解析和记录命令行参数
    class 命令行参数类(入参基类):
        def __init__(self):
            super().__init__()
            self._添加参数('搜索关键字', str, '指定文档搜索的关键字')
            self._添加参数('everything服务端口', str, 'everything HTTP 服务端口', '22')
    
        # region 访问器
        @property
        def jsonCfg(self) -> str:
            if 'jsonCfg' in self._参数字典:
                return self._参数字典['jsonCfg'].else:
                return ''
    
        @jsonCfg.setter
        def jsonCfg(self,: str):
            if 'jsonCfg' in self._参数字典:
                self._参数字典['jsonCfg'].= str()
    
        @property
        def 搜索关键字(self) -> str:
            if '搜索关键字' in self._参数字典:
                return self._参数字典['搜索关键字'].else:
                return ''
    
        @搜索关键字.setter
        def 搜索关键字(self,: str):
            if '搜索关键字' in self._参数字典:
                self._参数字典['搜索关键字'].= str()
    
        @property
        def everything服务端口(self) -> str:
            if 'everything服务端口' in self._参数字典:
                return self._参数字典['everything服务端口'].else:
                return ''
    
        @everything服务端口.setter
        def everything服务端口(self,: str):
            if 'everything服务端口' in self._参数字典:
                self._参数字典['everything服务端口'].= str()
        # endregion
    
    
    # 标注两个字符串的差异项
    def 差异标注(字串1: str, 字串2: str) -> tuple[str, str]:
        字串1 = str(字串1 if 字串1 else '').strip()
        字串2 = str(字串2 if 字串2 else '').strip()
    
        # region 原文档变动对齐
        # 使用SequenceMatcher()类计算两个字符串的相似度
        匹配器 = difflib.SequenceMatcher(None, 字串1, 字串2)
        差异 = 匹配器.get_opcodes()
    
        # 差异标注
        字串1差异标注: str = ''
        字串2差异标注: str = ''
        for opcode, i1, i2, j1, j2 in 差异:
            if opcode == 'equal':
                字串1差异标注 = 字串1差异标注 + 字串1[i1:i2]
                字串2差异标注 = 字串2差异标注 + 字串2[j1:j2]
            elif opcode == 'delete':
                字串1差异标注 = 字串1差异标注 + 红字(字串1[i1:i2])
            elif opcode == 'insert':
                字串2差异标注 = 字串2差异标注 + 绿字(字串2[j1:j2])
            elif opcode == 'replace':
                字串1差异标注 = 字串1差异标注 + 红字(字串1[i1:i2])
                字串2差异标注 = 字串2差异标注 + 绿字(字串2[j1:j2])
    
        return 字串1差异标注, 字串2差异标注
    
    
    if __name__ == '__main__':
        画板 = 打印模板(False)
        画板.执行位置(__file__)
    
        # region 解析入参
        入参 = 命令行参数类()
        入参.解析Json(画板=画板.副本.缩进())
        入参.解析入参(画板=画板.副本.缩进())
        if 画板.正在调试:
            入参.展示(画板=画板.副本.缩进())
    
        搜索关键字: str = 入参.搜索关键字 if 入参.搜索关键字 else ''
        # endregion
    
        # region 定义搜索接口
        本地搜索: 搜索接口类 = 搜索接口类()
        if 在nt系统中():
            if 入参.everything服务端口:
                本地搜索.everything服务端口 = int(入参.everything服务端口)
            else:
                画板.提示错误('入参.everything服务端口 参数无效')
                exit(1)
        # endregion
    
        # region 开始逻辑循环
        while True:
            def 文档排除规则(文档: str) -> bool:  # 排除一些不必要的干扰文档
                if not 文档:  # 空文档不要
                    return True
                if '\\recent\\' in 文档.lower():  # recent 文档夹内的文档不要
                    return True
                if 文档.lower().endswith('.lnk'):  # *.lnk 文档不要
                    return True
    
            # region 引导用户选择需要转码的视频文档
            while True:
                原视频文档列表 = 交互接口类.指定选择文档(输入提示='请输入关键字以定位视频文档(0: 退出程序):',
                                                     搜索接口=本地搜索,
                                                     搜索关键字=搜索关键字,
                                                     候选项上限=250,
                                                     排除规则=文档排除规则,
                                                     多选=True,
                                                     画板=画板.副本.缩进())
                if '0' in 原视频文档列表:
                    # 用户要求退出程序
                    exit(0)
    
                if 原视频文档列表:
                    画板.消息('您选择的文档列出如下:')
                    for 文档 in 原视频文档列表:
                        画板.消息(绿字(文档))
                    break
            # endregion
    
            # region 目标格式信息交互
            目标视频文档列表: list[str] = []
            while True:
                目标格式后缀名: str = 交互接口类.发起文本交互(输入提示='请输入视频目标格式(0: 退出程序):',
                                                              画板=画板.副本.缩进())
                if '0' == 目标格式后缀名:
                    # 用户要求退出程序
                    exit(0)
    
                if 目标格式后缀名.startswith('。'):
                    目标格式后缀名 = f'.{目标格式后缀名[1:]}'
                if not 目标格式后缀名.startswith('.'):
                    目标格式后缀名 = f'.{目标格式后缀名}'
    
                if not 目标格式后缀名.strip('.'):
                    # 如果后缀名是空的,则重新要求输入
                    continue
    
                # 后缀名统一转换成小写格式
                目标格式后缀名 = 目标格式后缀名.lower()
    
                # 合成目标文档名:
                for 文档 in 原视频文档列表:
                    目标视频文档列表.append(f'{文档}{目标格式后缀名}')
    
                # 打的并提示用户确认转换方式
                画板.消息(黄字('即将启动的视频转码如下:'))
                画板.准备表格(对齐控制串='rl')
                for 序号 in range(len(原视频文档列表)):
                    原文档,目标文档 = 差异标注(原视频文档列表[序号],目标视频文档列表[序号])
                    画板.添加一行(原文档,洋红字('->'),目标文档)
                画板.展示表格(列间距=[0,0])
    
                转码确认: str = 交互接口类.发起文本交互(输入提示='是否确认转码?(y: 确认; n: 修改目标格式; 0: 退出程序)',
                                                        限定范围='YyNn0',
                                                        画板=画板.副本.缩进())
                if '0' == 转码确认:
                    # 用户要求退出
                    exit(0)
                elif 'y' == 转码确认.lower():
                    # 用户确认转码
                    break
            # endregion
    
            # region 开始视频转码
            编解码格式: str = ''
            for 序号 in range(len(原视频文档列表)):
                视频切片 = VideoFileClip(原视频文档列表[序号])
                while True:
                    if not 编解码格式:
                        编解码格式 = 交互接口类.发起文本交互(输入提示=f'默认 codec 参数是 libx264, 输入 {绿字("y")} 以确认; '
                                                                      f'或者您可以输入其它编码格式({红字("0")}: {红字("退出程序")}):',
                                                             画板=画板.副本.缩进())
                    if '0' == 编解码格式:
                        # 用户要求退出程序
                        exit(0)
                    编解码格式 = 编解码格式.lower()
                    if 'y' == 编解码格式:
                        # 用户确认使用 libx264 作为 codec 参数
                        编解码格式 = 'libx264'
    
                    try:
                        if 目标格式后缀名.endswith('gif'):
                            视频切片.write_gif(filename=目标视频文档列表[序号])
                        elif 编解码格式:
                            视频切片.write_videofile(filename=目标视频文档列表[序号], codec=编解码格式)
                        else:
                            视频切片.write_videofile(filename=目标视频文档列表[序号])
                    except Exception as exp:
                        画板.提示错误('视频转码遇到异常如下:')
                        画板.消息(exp.__str__())
    
                        # 清除 codec 参数,重新发起交互
                        编解码格式 = ''
                        continue
                    else:
                        # 如果转码顺利完成,则关闭 视频切片,开始下一段视频的处理
                        视频切片.close()
                        break
            # endregion
        # endregion
    
    '
    运行

    使用演示

    👉第一步,脚本首先引导用户搜索和定位视频文件,我们可以输入视频文件名信息以定位视频文档,然后参过序号选择目标文档;如下👇:
    20240511144403

    👉第二步,脚本询问我们需要将视频文档转换为什么样的目标格式,我们输入目标文档的后缀名,然后再一次确认脚本的问询;如下👇:
    20240511144652
    在这一步中,如果我们输入了错误的目标格式,我们还可以输入 n 来重新修改目标格式。

    👉第三步,脚本会询问我们是否使用默认的 codec 参数(默认为libx264)进行视频转码,如果我们希望使用其它 codec 参数,例如 png,或者libvorbis 等,我们也可以直接输入 codec 值来告诉脚本;如下👇:
    Snipaste_2024-05-11_14-51-48
    Snipaste_2024-05-11_14-51-52
    以上👆脚本交互完成后,脚本即开始了视频转码过程,我们耐心等待转码完成即可,如下👇:
    20240511145705

    懒人包

    以上Python脚本的功能比较简单,对于视频转码的参数控制较少,但如果大家有需要,可以轻易的加入更多的转码参数控制功能。

    以上 Python脚本,对应的bat调用脚本,和对应的cfg参数文档,统一进行了打包,见:Python 视频转码脚本

  • 相关阅读:
    【2023研电赛】华东赛区一等奖:基于EtherCAT通信有限时间位置收敛伺服系统
    2023 极术通讯-Arm SystemReady本地化兼容性标准与测试研讨会召开
    BGP高级特性——BGP路由控制
    Macos视频增强修复工具:Topaz Video AI for mac
    vue+cesium项目demo
    sql语句
    [附源码]SSM计算机毕业设计拾穗在线培训考试系统JAVA
    JAVA 网络编程(这章还有后续哦)
    error: size of array ‘__curl_rule_01__‘ is negative
    C++之log4cpp库
  • 原文地址:https://blog.csdn.net/weixin_42148809/article/details/138716479