Python和FFmpeg强强联合

录制项目终于作完,不用老是提醒本身抓紧时间这样来想问题了。
在完成以后带着一些知足感,回头看看哪些地方是须要改进的,哪些地方又是有更好的替代方案,本身又有哪些不足。java

下面按照软件的各部分分别做总结记录:

0. 软件应用场景:

  客户但愿用视频+音频的方式录制下会议的内容。除了录制会议室状况以外,会议中还有可能须要录制电脑屏幕内容,好比在作PPT讲解等,因此须要一个在两种录制方式之间快捷切换的软件。除此以外,须要一个防止复制运行的机制和完整的安装包。python

1. 核心:subprocess子进程运行控制。

  由应用来看,关键是录制屏幕和录制摄像头,以及用快捷键控制在这二者之间切换。
  个人实现是经过python3调用ffmpeg,ffmpeg实现录制,python来完成切换。
  从开发角度来讲,并不算难,抛去录制这个功能,这个软件实际上应该这样描述:python彻底控制ffmpeg.exe进程的应用。
  进一步地说,ffmpeg能作到的,软件大部分均可以作到,不一样的是能够添加快捷键控制等,能够用python对除了ffmpeg功能以外作一些必要的补充。好比,客户在需求实现以前测试发现win10系统下自买的摄像头运行时间长了以后会随机的中断录制,卖家也无办法解决,由于是win10系统兼容性问题。因此客户提出在录制异常中断的状况下,可以自动从新开始录制。这个需求的知足就依赖python对ffmpeg的补充。
  另外,彻底控制ffmpeg进程关键在于如何天然退出。ffmpeg在cmd运行按下q键是退出,利用这一点往子进程输入流写入'q'实现了天然退出,保证了数据的正常写入和保存,而且不会引起异常状况。若是不得益于这一点,用os.kill(process_id)等方式都很难去控制进程的正常退出。
  下面是代码结构简化版思惟导图:
思惟导图c++

2. 界面和pyqt5:

  界面至关的简单,主界面是一个按钮+录制时间显示。
  clipboard.pnggit

  功能性的右键菜单:
  右键菜单github

  设置界面:数据库

  软件为了客户方便定制化使用,提供了必要的参数设置。实现时用到了configparser。快捷键部分还有待完善。c#

  
通常设备设置快捷键设置录制参数设置

  程序主要的录制状态变化经过托盘图标的来展现。三种录制状态的托盘图标以下:
clipboard.png
  为了尽量少的让主界面出如今录制内容中,当失去焦点时,窗口就会隐藏,这大概也就是客户可以容忍的缘由:)。
  界面实现用的是pyqt5,由于之前本身作过c#的winform和java的swing开发,界面的处理逻辑又大同小异,因此参照着qt的文档这块可以比较顺手的处理。
  pyqt源自qt,而qt的文档很是全面,参照着文档在写pyqt代码时注意一点与c++语法的区别就行了。
  若是可以更深刻的用pyqt开发,有想过写一篇《qt大局观》的总结,就是整理一下图形界面开发的模型以及与qt相比的相同点不一样点,一来是本身以为若是有这样一篇大局观的介绍文章可以帮助本身节省大量的时间;二来可以帮助从其余语言切换到qt或者新学习qt的开发人员在查询qt文档以前有更清晰的思路,那就更好了。
  若是要写这篇文章大体从如下几个方面入手:windows

共同性,好比都是基于事件驱动
一般有哪些经常使用或特别的控件?
每一个或某类控件都有哪些通用的事件?
窗体加载机制有何不一样?
在qt开发时又是怎么样的?
具体一点,好比quitOnLastWindowClosed()的效果是怎样的?会带来什么问题?
qt的信号槽机制相比winform事件机制有何不一样?等等。

3. 简易的防复制运行机制

  这个机制的目的是限制不是经过安装包安装的,运行都要受到限制。限制条件是超过三个月快捷键失效。实现分两步:app

1.安装时在注册表特定位置,假如是A,写入目录相关信息。
2.在程序运行时,检测当前目录是否存在于注册表A下。

  具体实现时,A位置下保存两类信息,一类是正常安装的目录,好比以'INSTALL+时间'为键名称,值为安装目录,时间用以区分屡次安装;另外一类是在非安装目录第一次运行的时间,实际就一个并且不可改变,这样保证了全部非安装目录都有同一个时间限制基础。
  更完善的实现应该对全部的键值加密处理。框架

4. 软件打包,包括cx_Freeze编译和inno setup打包安装文件。

  这是第一个有本身署名的软件,也是第一次从无到有完整的作出一个有安装包的软件。
  软件打包分红了两步:

  1. 用cx_Freeze将python代码编译为exe文件。编译python代码为exe通常常见的工具备py2exe、pyinstaller、cx_Freeze等,由于此次开发用的python3.6,而只有cx_Freeze对3.6支持最好,因此天然也就用了cx_Freeze。本来网上的教程看到cx_Freeze也是能够定制打包复杂安装文件的,可是在本身的实验过程当中始终在access数据库相关的模块报错。使用bdist_msi生成的简单安装包不够用,并且中文支持很差。而后仔细看过一篇文档,发现cx_Freeze推荐的inno setup。
  2. 用inno setup定制软件安装包。按照inno setup默认的生成安装包向导实验一遍后,发现这东西太强了太好用了,前面花在cx_Freeze上折腾的时间简直是浪费。
    inno setup使用相似配置文件的结构来定制安装包所须要的功能。
    最经常使用的应该是[Tasks]即任务节点,在该节点下面定义安装包须要执行的任务。任务属性有名称、描述、触发条件、可选属性等,其余节点可经过任务的名称来关联任务。
    好比给用户添加是否开机启动的选择项,首先定义任务:

    [Tasks]
    Name: "startupicon"; Description: "开机启动"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked

    而后,当这个任务startupicon被选中须要执行时,在用户电脑的启动目录添加快捷方式:

    [Icons]
    Name: "{userstartup}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: startupicon

    这里[Icons]节点和[Tasks]关联起来的属性就是[Icons]的Tasks: startupicon。其余的Files等节点也能够用一样的方式关联任务。
    一个完整的inno配置文件在保证逻辑性的同时还很是简洁,这一点很是强大。本项目的打包文件参见目录中的setup.iss文件。
    不过它的强大还不止于这一点,另外一个缘由是inno自带一个叫Pascal的脚本语言,这可就让可定制性直接上升一个台阶。Pascal不只内置经常使用的函数,还能够本身写Pascal代码。看过示例脚本事后,也就不难想象如今的下载网站下载下来的安装包有各类各样的广告是怎么实现的了。

5. 不能再忘的git

  版本管理软件对开发人员来讲就像一个保险柜同样,重要性不言而喻。之前本身老是零零碎碎的接触到git,始终没有用git真正的来管理一个项目,此次利用这个软件正好好好的学习git,不能再忘了。
  如下本身按照使用逻辑再手敲一遍经常使用git(version:2.16.2.windows)管理命令及注释:

git init 梦开始的地方
    git status 查看项目状态,使用率最高
    git add <file>/. 将文件修改让git管理
    git reset HEAD <file> 撤销git管理
    git checkout -- <file> 撤销修改(未add以前)
    
    git rm [-r] <file> 删除git已管理的文件,文件被删除
    git rm [-r] --cached <file> 撤销git已管理的文件,文件仍存在
    撤销删除跟撤销修改同样.
    
    git commit -m '注释' 提交修改并备注修改原因
    git log 提交记录
    git reflog 命令历史记录
    git reset --hard HEAD^^/HEAD~2/commit_id 回退到上上个版本或者回到指定commit_id版本
    
    git pull origin master  与远程仓库origin下的master分支同步 
    git push origin master 将本地的修改推送到远程仓库origin下的master分支
    
    git remote -v 查看远程仓库信息
    git branch 查看所有分支
    git branch <branch_name> 建立分支
    git checkout <branch_name> 切换到分支
    git checkout -b <branch_name> 建立分支并切换到该分支
    git branch -d/-D <branch_name> 删除分支
    
    git merge [--no-ff保留分支信息] <branch_name> 合并分支
    
    git stash [list] [apply恢复] [drop删除] [pop恢复并删除] 将修改临时保存

暂时熟练的就这些,之后再更新。
软件代码发布在record-camera-and-screen
建立了两个分支gutin和dev。gutin是给客户的版本,dev是本身想在这个软件上进一步的完善。

6. 交付效果:

  软件运行效果:在分辨率为1024x76八、帧率30/s、h264编码、i5 cpu threads=4的状况下录制,cpu占有率保持在30%~40%之间(这是ffmpeg的功劳)。
  开发分两次提出,客户第一次的需求主要是录制,第二次是调整和增长附加功能。两次合做及时完成了客户的需求,都获得了用户满意的反馈。

7. 项目收获:

  1. 加深了对python的了解,更熟练的编写python代码。
  2. 在开发过程当中,练习使用git管理本身的代码。而且利用版本回退帮助本身查找bug引起的缘由,相信之后git会成为我开发工做中必不可少的帮手。此次不一样的是,是在本身一手写出来的代码基础上进行管理,因此驾轻就熟不少。以往老是试着去github上clone别人的项目别人的代码,做为一个新手,本身首先就面对的是不熟悉的项目和代码,若是说在这个基础上再学习git的操做和概念,实际上是很难的。因此之前老是没能好好的掌握git。
  3. 开发这个软件第一目的是再学习如何解决在开发过程当中遇到的问题。
    此次开发遇到最大的难题是write(q),为何这么说?肯定是否是采用python+ffmpeg.exe的形式来实现的关键点在于对ffmpeg.exe进程的彻底控制。首先,查看了subprocess的文档,肯定了彻底控制一个子进程不成问题;而后在cmd下实验了摄像头录制和屏幕录制,就是ffmpeg在单独运行的状况下,实现录制功能。这两点实验事后都没有问题,而后自觉得二者的结合会顺其天然的顺利。结果就卡在了中止录制时,怎么处理ffmpeg进程的退出方式。

    第一次实验是Popen.terminate()和kill(),实际发现ffmpeg根本无动于衷。[缘由待确认]
    而后用Popen.send_signal(CTRL_C_EVENT)确实是能够控制ffmpeg进程退出了,结果看录制的视频,最后一部分录制内容丢失了,很显然是ffmpeg不正常退出致使的。由此也明白了,光退出还不行,还得天然的退出。虽然知道凡强制的方式一定不是天然的,期间抱着试试的态度也用到了os.kill(),结果果真不如人愿。
    而后回头复盘,想着CTRL_C_EVENT是模拟按键进行退出,那么模拟q键退出是否是可行呢?CTRL_C_EVENT是python提供的,那么怎么模拟自定义按键呢?接着就尝试了stdin.write('q')方式,结果使人振奋,不只录制内容完整,并且没有强制退出时偶尔引发的程序异常。事实证实这样的处理方式是最天然的。还记得当时解决这个难题是多么的开心和知足,这种知足感也正是本身的开发乐趣所在。不过解决旧问题的同时,经常也许会引起新的问题。与输入流交互的write('q')方式也就必须让Popen(universal_newlines=True),而这后面也凸显了ffmpeg对中文支持不太友好的问题,不过都获得了解决。

  4. 最后通过这个软件的开发,让本身从总体上对软件有了一个新的认识。
    任何一个软件简洁到能够用一句话说清楚。知道最终的目的是什么,从一个模型框架开始,咱们所作的工做无非就是在这个模型之上添砖加瓦。软件的不一样之处在于,包含的砖瓦种类数目,每种砖每一个瓦的开发难度,以及它们用什么样的方式合在一块儿。最终构建成一座高楼大厦。收获了完成一件做品时的喜悦,同时,也看到了本身能力的局限性。
    想构建更强更大的软件不光是要提高本身的能力,找到一个好的团队,并一块儿合做创造才是最佳途径。

8. 将来改进和扩展:

完善快捷键
录制状态切换音效和添加动画【学习pyqt的绘制】
视频输出优化:添加水印和标签等
界面美化:用圆形框取代方形按钮
添加支付接口
添加实时录制预览窗口
改为我的的演讲练习录制工具

9. 我的其余开发项目

github: www.github.com/ilinxiao

相关文章
相关标签/搜索