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 ...
随机推荐
- linux服务器通过X11实现图形化界面显示 1 背景描述
有些LINUX服务器出于性能和效率的考虑,通常都是没有安装图形化界面的,那么图形化程序在服务器上压根儿就跑不起来,或者无法直接显示出来,这就很尴尬了!那么如何解决这个问题呢?可以基于X11 Forwa ...
- 【Python】文件批量重命名
需求: 经常有很多相似的文件需要重命名,如果一个一个来太麻烦了,正好会Python,所以用Python写了个脚本,把符合要求的文件的文件名修改为新的. 代码: # coding:utf-8 # @Ti ...
- raw.githubusercontent.com 访问不了
访问 Github 中的 raw 文件内容时会跳转到 raw.githubusercontent.com 这个域名 但是访问不了. 解决办法 Windows 在 C:\Windows\System32 ...
- 从客户端(XXX)中检测到有潜在危险的 Request.Form 值
维护别人的某功能模块的时候,页面返回如下错误信息: [HttpRequestValidationException (0x80004005): 从客户端(TextBox1="<?xml ...
- HTML5
转
贴个图:
- # 🤖 **DeepSeek 深度解析 PasteForm:一个让管理端开发爽到飞起的全栈解决方案**
DeepSeek 深度解析 PasteForm:一个让管理端开发爽到飞起的全栈解决方案 各位开发者注意啦!今天我要带大家全方位解剖 PasteForm 这个神奇框架--不仅介绍核心思想,更要重点展示它 ...
- [.net core] 创建和发布NuGet包 (dotnet CLI)
[原文] :https://docs.microsoft.com/zh-cn/nuget/quickstart/create-and-publish-a-package-using-the-dotne ...
- CocoaPods+Gitee 制作私有库过程以及错误总结
前言 最近由于要做组件化,所以就顺便看了看私有库的制作,整体上制作的过程是比较简单的,但有一些点你注意到的话会在制作过程会少去很多的麻烦,在网上搜的制作过程的文章是一大把,但当你真的遇到一些问题的时候 ...
- 详细介绍FutureTask类
一.详细介绍FutureTask类 FutureTask 未来将要执行的任务对象,继承 Runnable.Future 接口,用于包装 Callable 对象,实现任务的提交 public stati ...
- Mybatis-Plus中的@TableId
简介 在 MyBatis Plus 中,@TableId 注解是用于标记实体类中的主键字段.它可以更方便地处理主键相关的操作,如自动填充主键值或识别主键字段. 用法 public class User ...