基于Swt、ffmpeg、jacob、vlc、SApi、h2技术编写简单的旁白生成器
一、简介:
前一段时间尝试录制了几集3D编程方面的视频教程,我发现录制时最大的障碍是让脑中的思考、手上的操作和嘴里的解说保持同步,一旦三个“线程”中有一个出错,就必须停下来重新录制出错的部分,同时一心三用也会极大的增加精力消耗,减少有效录制时间。为了解决这一问题、降低视频教程的编写门槛,我尝试编写了一个将预先设定的文本插入视频中作为旁白的小工具,尝试将思考、操作和解说三个线程分解到三个时间片中运行。
因为以前没接触过完整的java窗口程序编写,这个小工具的代码非常简陋生硬,程序名为Saltedfish(中文翻译咸鱼,本文中简称为sf)。
二、使用流程:
sf运行包可以从https://pan.baidu.com/s/1i69LBs5下载
1、程序针对安装了64位java1.7的完整版win7系统编写,参考网络上的资料,使用Java语言开发。
2、导出的运行目录如下:
其中h2是用来存储项目配置的微型数据库,sf9_lib是MyEclipse导出的依赖jar包,ffmpeg是视频处理工具,jacob是java调用com组件工具,mylist是ffmpeg合并音频流时使用的配置文件,sf9.jar是可执行jar文件,startup是启动脚本,vlc是视频播放器。
3、初次使用时需要安装vlc视频播放器,安装目录没有限制。
4、启动h2数据库:
执行h2-2017-06-10\h2\bin\h2w.bat脚本启动数据库,数据库启动成功后会使用默认浏览器弹出一个数据库控制台窗口:
使用JDBC URL:jdbc:h2:tcp://127.0.0.1/../../saltedfish访问已经建立的saltedfish数据库,用户名密码均为saltedfish。点击连接后可以看到项目表和文件表:
可以看到已经建立了“test”和“test2”两个测试项目,限于时间,sf程序里并没有做删除项目的功能,如果需要删除项目或文件可以直接在数据库中操作。
h2数据库启动后会在后台运行,关闭控制台不会影响数据库运行,可以在系统窗口的右下角看到h2数据库的小图标。
5、执行startup脚本启动sf9.jar
startup脚本内容:
java -Dfile.encoding=utf-8 -Xms1024m -Xmx1024m -jar sf9.jar
使用系统默认java,以utf-8编码执行jar包,为了防止内存不够,给java堆分配了1GB内存。
6、sf页面样式如下:
左上区域用来显示正在处理的视频片段,右上区域分为三个选项卡,最右侧的选项卡用来对项目进行操作,中间的选项卡对项目中的某一个文件进行操作,左边的选项卡是根据建议添加的对文件的另一种处理方式,但里面还没有做任何内容。
点击项目操作选项卡,在列表里选择一个项目并打开后,可以看到项目所包含的文件以水平列表的形式显示在下面,您也可以添加新的项目或者在项目里添加新的文件(目前只支持avi格式):
列表中还显示了每个文件的文件名和以毫秒数表示的文件长度,点击“导出目标文件”按钮可以把列表中的文件合并成一个视频导出(因为时间限制,这里使用的是最简单的文件合并方法,只支持编码完全相同的视频合并)
7、在列表中选择一个文件,点击“处理这一段”按钮,可以对这个文件进行操作:
类似普通视频播放器可以对视频文件进行播放、暂停,拖动滑块可以调整播放进度。
8、点击读文本按钮,选择要插入的旁白文本:
点击播放,程序在播放视频的同时也会一句接一句的朗读旁白,在某一时刻点击某一句旁白所在的按钮,会重新定位这一句旁白的位置,通过这种方式调整每一句旁白的发音时机(假设视频的长度总比旁白的长度长)
9、播放完毕或者点击停止后可以对旁白进行导出:
点击“srt”按钮时以srt字幕文件的方式导出旁白文字(限于时间,字幕以默认的utf-8编码导出,但是实验发现大部分视频播放器不支持这种编码的字幕,需要用户自己用文本工具将字幕的编码转为ANSI),点击“wav”按钮时以wav音频文件的方式导出旁白朗读音频和原视频音频的叠加音频,点击”合并”按钮则可以把叠加的wav替换到avi里(限于时间,只是导出了一个avi文件,如需要替换请自己替换文件或者修改数据库)
10、限于时间,只对动态定位旁白语句的部分使用了多线程,最后的导出部分没有使用多线程,这意味着点击导出按钮之后到导出完成之前sf不会响应用户的任何操作。
三、技术选型与设计流程:
1、选择java作为操作文件和调度各种工具的语言。
2、选择前台页面绘制方法:
Java程序的前台绘制有两种思路,一是用html*css*js网页作为前台,通过访问服务器方式(Ajax,Websocket等)调用后台的java程序工作;二是直接使用java语言编写桌面应用程序。显然第一种方式在设计前台页面时有更多的自由,但是考虑到附带产生的前后台沟通成本和用户部署成本以及思维切换成本,选择使用java直接编写桌面程序。
常用的Java桌面程序框架有三种:Swing、Awt、Swt,参考网络上的评价决定使用Swt框架,在实际使用中发现Swt具有以下缺点:
a、无法像html一样方便的选取元素,除非在程序中用专用的变量保存对象,否则再想找到就很难了。
b、不能像css一样方便的批量定义和继承ui样式,需要对每一个元素单独设置样式。
c、只有创建窗口的主线程可以修改ui的状态,其他线程想要修改ui状态(比如播放进度条的变化),需要用特殊的语法通知主线程在主线程认为合适的时候进行操作,这一点比JavaScript差距不可以道里计。
(也许这些缺点是因为作者对Swt掌握的还不够深入,但同样的时间用来学习html技术能够产生更好的效果)
3、对文字转语音工具进行选择:
常见的文字转语音方式有两种,一是通过http等协议调用百度、讯飞等“语音云”,将语音云生成的朗读结果返回给用户;二是在本地安装语音生成程序。考虑到离线操作的可能性,使用本地语音生成;考虑到安装的方便性,使用Window操作系统自带的语音朗读工具(SAPI)。
4、思考程序所必须的主干流程,针对每个流程画出页面草图。
5、根据确定的流程设计相应的文件管理办法
参考一些大型商业软件设计了两个版本,发现都需要花费不短的时间开发专门的文件管理模块,限于时间使用一个微型数据库h2Database对项目的结构进行保存。
6、根据确定的数据流在网上查询每个节点的相关知识,先编写用于实验的小例程,然后把实验完毕的小例程整合到主程序中。
四、代码结构介绍
程序代码可以在https://github.com/ljzc002/Saltedfish下载
工程结构如下:
1、程序的入口main方法在Win_sf类中,这个类继承自Swt的窗口类Shell(值得注意的是Shell类默认不可被继承,所以需要在Win_sf的构造函数中添加一行“checkSubclass();”,并且为它定义一个空方法)。
其中 :
initGui() 方法设定了整个Swt窗口的布局,并在布局的同时设定了按钮点击和进度条拖动的事件监听;
InitAssats()方法初始化了vlc播放器与左上方容器的绑定,并且通过vlc播放器的回调函数修改进度条位置;
Win_sf类的最后是按钮点击事件的响应方法,在进行事件响应时,要特别注意响应方法是否由主线程执行,如果不是要使用syncExec(同步)或asyncExec(异步)方法将响应交给主线程执行,如果是,则要注意响应方法会不会引起主线程卡顿。
2、CompositeVideoSurface和SwtEmbeddedMediaPlayer是从github下载的两个类,它们实现了通过Swt调用vlc播放器的功能。vlc的Java官方示例是使用swing框架实现的,试验过程中我尝试了使用Swt调用Awt,再用Awt调用swing的方法,结果播放器有声音无图像。
3、Event_cb类里编写了两个通过Java反射设置按钮响应函数的方法,分别是不带参数和带参数的版本。
4、Util_File类里包含了文件处理和数据库操作的相关方法,主要是常规的JDBC实现和Java流操作。
5、Comp_sf类是显示在窗口下部水平列表里的小容器的类,这个笑容器包含了对应文件的一些信息,并且可以被选中
6、Btn_sf类是窗口右上区域显示每一列旁白文本的按钮类。
7、MSTTSSpeech1类是负责通过Jacob调用Windows TTS组件的类,这个类的功能相对完善,包括了对朗读线程的初始化、开始、停止、释放四个主要环节的控制,线程之间的关系如下:
在这里语音朗读由com线程进行,ThreadDemo线程只负责对旁白语句和com线程的调度,ThreadDemo进程的消亡并不会立即令com线程停止,com线程仍会完成它当前的任务或者在接到明确的关闭命令时停止;每次播放暂停,com线程和ThreadDemo线程都会被释放,继续播放时将建立新的com线程和ThreadDemo线程。
微软TTS组件的一个缺点是无法方便的生成“特定长度的沉默”,所以只好生成许多段语音,再把它们拼接起来
对音视频文件的剪切与合并也在这个类中进行,ffmpeg是一款功能强大的开源视频处理工具,这里使用JNI技术对其进行调用,使用ffmpeg时遇到的难点主要有两处:
一是ffmpeg似乎没有直接的方法能够把一个流偏移一定长度叠加到另一个流里,所以我只好使用一个迂回的方法:
这个方法会在工作目录下产生一些中间文件
二是在使用ffmpeg前一定要搞明白要操作的流的编码格式,然后选用合适的解/编码器进行解/编码,否则会导致经过处理后的片段无法合并到一起。
sf用到的部分ffmpeg命令如下:
#带编码剪切
ffmpeg -i 2017FFFHHH-HC720P国语中字.mp4 -vcodec h264 -t -ss ./temp4/fh2h264.avi #提取第一个音频流
ffmpeg -y -i fh2.avi -map :a: tempa.wav #提升音频流的音量和采样数、声道数
ffmpeg -y -i temptts.wav -af volume=10dB -ar -ac tempttsl.wav #截取音频流
ffmpeg -y -i tempa.wav -t -ss temp1.wav ffmpeg -y -i tempa.wav -ss temp2.wav #叠加混音
ffmpeg -y -i temp1.wav -i tempttsl.wav -filter_complex amix=inputs=:duration=longest:dropout_transition= temp1ttsl.wav #这种是文件层面的整合,要求文件的格式必须完全相同
ffmpeg -y -i "concat:temp1ttsl.wav|temp2.wav" -c copy tempa.wav
#这个是流层面的整合
ffmpeg -y -f concat -safe -i mylist.txt -c copy tempa.wav
#mylist.txt文件
#file temp1ttsl.wav
#file temp2.wav #最终替换音频,使用编解码器时间更长文件更小,使用copy模式则相反
ffmpeg -y -i fh2.avi -i bbb.wav -vcodec h264 -map :v -map fh2bbb2.avi
8、H2_db类负责新建或关闭与h2数据库的JDBC连接,这里选用了h2数据库的TCP连接方式,并且使用了相对路径进行连接。
9、BarUpdater类是在网上找到的一个进度条更新线程,sf并没有使用它。
编写完毕的程序可以使用MyEclipse导出为可执行的jar包,更近一步的,我们也可以使用exe4j工具把jar包打包成一个exe文件,您可以在我的github上找到一个exe4j配置文件来方便您的打包过程(打包时我把sfx.jar放在了sfx_lib文件夹里)
关于打包另一个需要注意的地方是:jar和exe4j导出的exe调用dll和exe的根路径相同,但可运行jar操作文件的根路径是jar所在的文件夹,而exe4j导出的exe的操作文件的根路径则是所使用的jdk的bin目录!
五、代码引用:
sf编写过程中在网络上进行了数百次搜索,其中引用代码较多的来源如下:
1、在编写SwtUI时学习了IBM developerWorks上的Swt教程:
https://www.ibm.com/developerworks/cn/opensource/os-jface2/index.html?ca=drs-
2、在编写h2数据库模块时参考了博客园·孤傲苍狼博客:
http://www.cnblogs.com/xdp-gacl/p/4171024.html
3、为了在Swt中使用vlc,引用了github上的caprica/vlcj-swt-demo项目,该项目基于GNU GENERAL PUBLIC LICENSE协议发布
https://github.com/caprica/vlcj-swt-demo
4、jacob工具基于GNU LESSER GENERAL PUBLIC LICENSE协议发布,我不确定只是调用这个工具是否需要继承其开源协议。
可能有一些代码引用被忽略了,如果您发现被忽略的引用代码,请联系我添加它们。
sf引用了两个使用不同GNU协议的开源工具,所以我也不知道sf应该以何种方式开源,如果还有GNU以外的可授权部分,则以MIT协议开源。
限于时间和水平,sf只实现了我所需要的最简单的功能,并且存在各种缺陷和bug,如果您需要更多的功能可以自己添加。
基于Swt、ffmpeg、jacob、vlc、SApi、h2技术编写简单的旁白生成器的更多相关文章
- 基于Babylon.js编写简单的骨骼动画生成器
使用骨骼动画技术可以将网格的顶点分配给若干骨头,通过给骨头设定关键帧和父子关系,可以赋予网格高度动态并具有传递性的变形 效果.这里结合之前的相关研究在网页端使用JavaScript实现了一个简单的骨骼 ...
- 基于Live555,ffmpeg的RTSP播放器直播与点播
基于Live555,ffmpeg的RTSP播放器直播与点播 多路RTSP高清视频播放器下载地址:http://download.csdn.net/detail/u011352914/6604437多路 ...
- Comet:基于 HTTP 长连接的“服务器推”技术解析
原文链接:http://www.cnblogs.com/deepleo/p/Comet.html 一.背景介绍 传统web请求,是显式的向服务器发送http Request,拿到Response后显示 ...
- Comet:基于 HTTP 长连接的“服务器推”技术
“服务器推”技术的应用 请访问 Ajax 技术资源中心,这是有关 Ajax 编程模型信息的一站式中心,包括很多文档.教程.论坛.blog.wiki 和新闻.任何 Ajax 的新信息都能在这里找到. c ...
- 转载:Comet:基于 HTTP 长连接的“服务器推”技术
转自:http://www.ibm.com/developerworks/cn/web/wa-lo-comet/ 很多应用譬如监控.即时通信.即时报价系统都需要将后台发生的变化实时传送到客户端而无须客 ...
- 转:基于ASP.NET的Comet长连接技术解析
原文来自于: Comet技术原理 来自维基百科:Comet是一种用于web的技术,能使服务器能实时地将更新的信息传送到客户端,而无须客户端发出请求,目前有两种实现方式,长轮询和iframe流. 简单的 ...
- [转载] Comet:基于 HTTP 长连接的“服务器推”技术
转载自http://www.ibm.com/developerworks/cn/web/wa-lo-comet/ “服务器推”技术的应用 传统模式的 Web 系统以客户端发出请求.服务器端响应的方式工 ...
- 【公开课】【阿里在线技术峰会】魏鹏:基于Java容器的多应用部署技术实践
对于公开课,可能目前用不上这些,但是往往能在以后想解决方案的时候帮助到我.以下是阿里对公开课的整理 摘要: 在首届阿里巴巴在线峰会上,阿里巴巴中间件技术部专家魏鹏为大家带来了题为<基于Java容 ...
- SRS流媒体服务器搭建+ffmpeg推流VLC取流观看
一.编译SRS https://github.com/winlinvip/simple-rtmp-server 目前有1.0-release.2.0.3.0等版本 2.0官方文档地址:https:// ...
随机推荐
- Docker三十分钟快速入门(上)
一.背景 最近,Docker技术真是一片火热,它的出现也弥补了虚拟机资源消耗过高的问题,直接让虚拟化技术有了质的飞跃.那么本文我们来聊一聊Docker,和大家一起认识Docker,简单入门Dock ...
- java equals == contentEquals
equals与== 经常用于比较,用法如下:字符串比较相同用equals,普通数值(基本数据类型)比较用==, contentEquals下面讲 理论准备: java的基本类型如int.float,d ...
- windows 异常处理
为了程序的健壮性,windows 中提供了异常处理机制,称为结构化异常,异常一般分为硬件异常和软件异常,硬件异常一般是指在执行机器指令时发生的异常,比如试图向一个拥有只读保护的页面写入内容,或者是硬件 ...
- JavaScript基础知识(数据类型及转换、运算符)
9.数据类型 概念:表示当前存储的数据的分类(表示数字 - 整数和小数) u 原始类型(原始值) -----[typeof运算符:判断变量的原始类型] *number(数字):表示数字 ...
- RHM-M10汽车吊力矩限制器/载荷指示器
一 产品特点 1. 采用7.0寸工业65K色TFT LCD真彩屏,亮度250nit,分辨率800×480: 2. 传感器采用进口机芯,过载能力强: 3. 采用油压取力和大臂弯曲 ...
- Mysql ibd文件恢复指南
背景 mysql在使用的过程中,难免遇到数据库表误操作,基于此,作者亲力亲为,对mysql数据表ibd文件的恢复做以下详细的说明,对开发或者初级dba提供一定的指导作用,博客中如若存在相关问题,请指明 ...
- 跨浏览器开发:CSS
理解CSS盒子模型 如果不需要很多奇巧淫技的跨浏览器兼容的 CSS 代码,透彻地理解 CSS 盒子模型是首要事情,CSS 盒子模型并不难,且基本支持所有浏览器,除了某些特定条件下的 IE 浏览器.CS ...
- Spring(一)Spring的第一滴血
前言 开始工作了,但是一进来公司本来是做爬虫和数据分析的,但是走了一个后端的,导致我必须要去顶替他的工作.因为这个项目使用的是Spring. SpringMVC.Hibernate所以我又要去回忆一下 ...
- [bzoj2288][POJ Challenge]生日礼物
用堆维护双向链表来贪心... 数据范围显然不容许O(nm)的傻逼dp>_<..而且dp光是状态就n*m个了..显然没法优化 大概就会想到贪心乱搞了吧...一开始想贪心地通过几段小的负数把正 ...
- BZOJ1258: [CQOI2007]三角形tri
题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1258 如果最后一位是4,那就改成123就好了. 然后最后一位不是4的话,至多三个答案,然后可以 ...