javacv添加字幕 剧中显示
介绍
javacv目前不能像ffmpeg那样 直接加载字体文件到视频 参考这里
所以实现流程为:提取帧 -> 转图片 -> 编辑图片增加文字 -> 转回帧 -> 输出视频
上代码
/**
* 添加字幕
*
* @param videoFile 原始视频文件
* @param outputFile 输出视频文件
* @param subtitleFrames 字幕帧数组,帧是要有序的 根据时间由小到大;
*/
public static void addSubtitle(File videoFile, File outputFile, List<SubtitleFrame> subtitleFrames) {
Font font;
// 加载字体文件,防止中文乱码
try (InputStream fontStream = CvUtil.class.getResourceAsStream("/fonts/msyh.ttc")) {
if (fontStream == null) {
log.error("字体文件加载失败");
throw new BusinessException(ErrorCodeEnum.Unknow);
}
font = Font.createFont(Font.TRUETYPE_FONT, fontStream).deriveFont(Font.BOLD, 24);
} catch (Exception e) {
log.error("字体文件加载失败", e);
throw new BusinessException(e);
}
try (FFmpegFrameGrabber grabberVideo = new FFmpegFrameGrabber(videoFile)) {
grabberVideo.start();
try (FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(outputFile, grabberVideo.getImageWidth(), grabberVideo.getImageHeight())) {
// 视频参数
recorder.setFrameRate(grabberVideo.getFrameRate());
recorder.setVideoCodec(grabberVideo.getVideoCodec());
recorder.setFormat("mp4");
recorder.setVideoBitrate(grabberVideo.getVideoBitrate());
// 音频参数
recorder.setAudioCodec(grabberVideo.getAudioCodec()); // 音频编码
recorder.setAudioBitrate(grabberVideo.getAudioBitrate());
recorder.setSampleRate(grabberVideo.getSampleRate()); // 采样率
recorder.setAudioChannels(grabberVideo.getAudioChannels()); // 必须大于0,如立体声为2
recorder.start();
Frame frame;
Iterator<SubtitleFrame> subtitleFrameIterator = subtitleFrames.iterator();
SubtitleFrame subtitleFrame = subtitleFrameIterator.next();
// 是否使用过当前字幕帧,只有只用过才可以迭代下一个帧; 这个标志可以帮助实现这种 0-2秒 2-4秒 7-10秒 这种时间不连续的字幕
boolean useSubtitleFrame = false;
while ((frame = grabberVideo.grabImage()) != null) {
// 转换为秒
long time = frame.timestamp / 1000;
String subtitle = null;
if (time >= subtitleFrame.sta && time < subtitleFrame.end) {
subtitle = subtitleFrame.text;
useSubtitleFrame = true;
} else if (useSubtitleFrame && subtitleFrameIterator.hasNext()) {
// 当前的字幕帧使用过 才可以切换下一个
subtitleFrame = subtitleFrameIterator.next();
useSubtitleFrame = false; // 新字幕帧标志为未使用
}
if (subtitle != null) {
BufferedImage image = Java2DFrameUtils.toBufferedImage(frame);
Graphics2D g2 = image.createGraphics();
g2.setFont(font);
// 计算字体宽度,方便剧中
FontMetrics fm = g2.getFontMetrics();
int textWidth = fm.stringWidth(subtitleFrame.text);
// 字幕位置
int[] subtitlePosition = calcSubtitlePosition(grabberVideo.getImageWidth(), grabberVideo.getImageHeight(), textWidth);
g2.drawString(subtitle, subtitlePosition[0], subtitlePosition[1]);
g2.dispose();
recorder.record(Java2DFrameUtils.toFrame(image));
} else {
recorder.record(frame);
}
}
}
} catch (Exception e) {
throw new BusinessException(e);
}
}
/**
* 计算字幕位置
* 字体高度 10% 横向剧中
*
* @return int[]{x,y}
*/
public static int[] calcSubtitlePosition(int videoWidth, int videoHeight, int textWidth) {
int y = videoHeight - videoHeight / 10;
// 24号字体约等于 32px
int x = videoWidth / 2 - textWidth / 2;
return new int[]{x, y};
}
/**
* 字幕帧
*/
public static class SubtitleFrame {
public SubtitleFrame() {
}
public SubtitleFrame(long sta, long end, String text) {
this.sta = sta;
this.end = end;
this.text = text;
}
// 起始时间 毫秒
public long sta;
// 结束时间 毫秒
public long end;
// 字幕文本
public String text;
}
javacv添加字幕 剧中显示的更多相关文章
- (原)使用ass字幕文件通过ffmpeg给视频添加字幕的一些研究
使用ass字幕文件通过ffmpeg给视频添加字幕的一些研究 Author:lihaiping1603@aliyun.com Create:2019-09-04 最近对ffmpeg给视频文件添加字幕效果 ...
- css调用外部样式和css样式说明剧中显示
<title>边走边乔</title><link href="css/style.css" rel="stylesheet" ty ...
- 添加QScintilla时显示无法解析的外部函数
转载请注明出处:http://www.cnblogs.com/dachen408/p/7147165.html 问题:添加QScintilla时显示无法解析的外部函数 解决方案:去掉头文件qscisc ...
- C++通讯录管理系统(添加联系人,显示联系人,删除联系人,查找联系人,修改联系人,清空联系人,退出通讯录)
1 /** 2 * ProjectNmae:通讯录管理系统 3 * 功能: 4 * 添加联系人:向通讯录添加新人 5 * 显示联系人:显示通讯录中的所有联系人信息 6 * 删除联系人:按照姓名进行删除 ...
- mac 终端中添加tree命令显示文件目录结构
在Ubuntu下,通过 sudo apt-get install tree 可以使用tree命令,显示文件目录列表,如图所示: 在mac OS X系统下怎么使用呢? 在终端输入: cd $home ...
- 根据select不同的选项实现相应input框添加项的显示
实现效果: @1.单击包时,显示包时的添加项 @2.单击包里程,显示包里程的添加项 二 代码实现: 给select添加change事件 获取当前select的value 根据value判断对象显示其 ...
- Jmeter+Jenkins的聚合报告中添加QPS栏目显示
1.进入jmeter/extras目录,修改 jmeter-results-detail-report_21.xsl 2.打开文件修改 如上所示,在文件中添加6个地方关于QPS的显示即可, 然后替 ...
- video字幕无法显示,video视频在google中无法控制快进
video字幕(track)无法显示: 直接用关闭同源策略的浏览器打开你的HTML文件可以请求到字幕文件并显示字幕: 从hbuilder中打开html文件,在从里面打开google浏览器去浏览HTML ...
- Rancher 添加主机无法显示、添加主机无效的解决办法
在 Rancher UI 中,添加主机,在 Shell ssh 运行了,然后 点击 “关闭” 按钮,发现没有显示如何主机. 第一步,先去查看应用是否正常,就是 应用 - 全部应用 如果显示是 unhe ...
- VC++组合框——学习笔记1(组合框选项的添加和无法显示下拉选项)
VC++控件 ---组合框 环境VC2003 1.组合框添加下拉菜单选项 现在有尝试了两个命令 (m_com为组合框控control类型的变量.) 方法一 m_com.AddString(&qu ...
随机推荐
- SpringBoot+微信支付-JSAPI{微信支付回调}
引入微信支付SDK Maven: com.github.wechatpay-apiv3:wechatpay-java-core:0.2.12 Maven: com.github.wechatpay-a ...
- PVE虚拟平台常用简明操作,三分钟搞定虚拟机更换安装配置
Proxmox Virtual Environment是一个基于QEMU/KVM和LXC的开源服务器虚拟化管理解决方案,本文简称PVE,与之相类似的虚拟化平台是VMWARE的ESXi虚拟平台,相较于商 ...
- verilog实现32位有符号流水乘法器
verilog实现32位有符号流水乘法器 1.4bit乘法流程 1.无符号X无符号二进制乘法器 以下为4bit乘法器流程(2X6) 0 0 0 0 0 0 1 0 (2) X 0 0 0 0 0 1 ...
- Javascript 对象(object)合并
转
转载了一篇介绍的比较直观的博文.
- nodejs的http请求axios
http相关modules HTTP – the Standard Library Request Axios SuperAgent 推荐使用axios 或者super agent 使用axios和s ...
- STM32F4_HAL_CAN总线注意事项
如果CAN总线没有连接其他设备,即HL是悬空状态,则发送会失败,下图的Error_Handler需要屏蔽,否则会造成系统卡顿,或影响其他功能模块的使用 /* ********************* ...
- IDEA构建Maven项目生成的文件说明(.mvn、mvnw、mvnw.cmd、.gitignore、.iml、.idea、pom.xml)
IDEA构建的maven+springBoot项目结构如下: 1..gitignore:分布式版本控制系统git的配置文件,意思为忽略提交 在 .gitingore 文件中,遵循相应的语法,即在每一行 ...
- 工会成立100周年纪念,开发职工健身AI运动小程序、APP方案推荐
时光荏苒,转眼间2025年五一将至,这一年对于中华全国总工会而言,具有非凡的历史意义--它将迎来成立100周年的辉煌时刻.为了庆祝这一盛事,各级工会组织将精心筹备了一系列丰富多彩.形式多样的纪念活动, ...
- 匿名内部类、lambda匿名函数表达式
a.匿名内部类的定义格式: 接口名称 对象名 = new 接口名称(){ //覆盖重写所有抽象方法 }: 一. /** * lambda匿名函数的使用 * Lambda省去面向对象的条条框框,格式由3 ...
- 【FAQ】HarmonyOS SDK 闭源开放能力 — IAP Kit(6)
1.问题描述: 支付场景,表现是在沙盒情况下所有商品都可以正常跑通,但是在非沙盒情况下,线上购买年包1800大额支付华为的 iap.createPurchas 在输完密码就会报 1001860001 ...