介绍

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添加字幕 剧中显示的更多相关文章

  1. (原)使用ass字幕文件通过ffmpeg给视频添加字幕的一些研究

    使用ass字幕文件通过ffmpeg给视频添加字幕的一些研究 Author:lihaiping1603@aliyun.com Create:2019-09-04 最近对ffmpeg给视频文件添加字幕效果 ...

  2. css调用外部样式和css样式说明剧中显示

    <title>边走边乔</title><link href="css/style.css" rel="stylesheet" ty ...

  3. 添加QScintilla时显示无法解析的外部函数

    转载请注明出处:http://www.cnblogs.com/dachen408/p/7147165.html 问题:添加QScintilla时显示无法解析的外部函数 解决方案:去掉头文件qscisc ...

  4. C++通讯录管理系统(添加联系人,显示联系人,删除联系人,查找联系人,修改联系人,清空联系人,退出通讯录)

    1 /** 2 * ProjectNmae:通讯录管理系统 3 * 功能: 4 * 添加联系人:向通讯录添加新人 5 * 显示联系人:显示通讯录中的所有联系人信息 6 * 删除联系人:按照姓名进行删除 ...

  5. mac 终端中添加tree命令显示文件目录结构

      在Ubuntu下,通过 sudo apt-get install tree 可以使用tree命令,显示文件目录列表,如图所示: 在mac OS X系统下怎么使用呢? 在终端输入: cd $home ...

  6. 根据select不同的选项实现相应input框添加项的显示

    实现效果: @1.单击包时,显示包时的添加项 @2.单击包里程,显示包里程的添加项 二  代码实现: 给select添加change事件 获取当前select的value 根据value判断对象显示其 ...

  7. Jmeter+Jenkins的聚合报告中添加QPS栏目显示

    1.进入jmeter/extras目录,修改 jmeter-results-detail-report_21.xsl   2.打开文件修改 如上所示,在文件中添加6个地方关于QPS的显示即可, 然后替 ...

  8. video字幕无法显示,video视频在google中无法控制快进

    video字幕(track)无法显示: 直接用关闭同源策略的浏览器打开你的HTML文件可以请求到字幕文件并显示字幕: 从hbuilder中打开html文件,在从里面打开google浏览器去浏览HTML ...

  9. Rancher 添加主机无法显示、添加主机无效的解决办法

    在 Rancher UI 中,添加主机,在 Shell ssh 运行了,然后 点击 “关闭” 按钮,发现没有显示如何主机. 第一步,先去查看应用是否正常,就是 应用 - 全部应用 如果显示是 unhe ...

  10. VC++组合框——学习笔记1(组合框选项的添加和无法显示下拉选项)

    VC++控件 ---组合框  环境VC2003 1.组合框添加下拉菜单选项  现在有尝试了两个命令 (m_com为组合框控control类型的变量.) 方法一  m_com.AddString(&qu ...

随机推荐

  1. SpringBoot+微信支付-JSAPI{微信支付回调}

    引入微信支付SDK Maven: com.github.wechatpay-apiv3:wechatpay-java-core:0.2.12 Maven: com.github.wechatpay-a ...

  2. PVE虚拟平台常用简明操作,三分钟搞定虚拟机更换安装配置

    Proxmox Virtual Environment是一个基于QEMU/KVM和LXC的开源服务器虚拟化管理解决方案,本文简称PVE,与之相类似的虚拟化平台是VMWARE的ESXi虚拟平台,相较于商 ...

  3. 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 ...

  4. Javascript 对象(object)合并 转

    转载了一篇介绍的比较直观的博文.

  5. nodejs的http请求axios

    http相关modules HTTP – the Standard Library Request Axios SuperAgent 推荐使用axios 或者super agent 使用axios和s ...

  6. STM32F4_HAL_CAN总线注意事项

    如果CAN总线没有连接其他设备,即HL是悬空状态,则发送会失败,下图的Error_Handler需要屏蔽,否则会造成系统卡顿,或影响其他功能模块的使用 /* ********************* ...

  7. IDEA构建Maven项目生成的文件说明(.mvn、mvnw、mvnw.cmd、.gitignore、.iml、.idea、pom.xml)

    IDEA构建的maven+springBoot项目结构如下: 1..gitignore:分布式版本控制系统git的配置文件,意思为忽略提交 在 .gitingore 文件中,遵循相应的语法,即在每一行 ...

  8. 工会成立100周年纪念,开发职工健身AI运动小程序、APP方案推荐

    时光荏苒,转眼间2025年五一将至,这一年对于中华全国总工会而言,具有非凡的历史意义--它将迎来成立100周年的辉煌时刻.为了庆祝这一盛事,各级工会组织将精心筹备了一系列丰富多彩.形式多样的纪念活动, ...

  9. 匿名内部类、lambda匿名函数表达式

    a.匿名内部类的定义格式: 接口名称 对象名 = new 接口名称(){ //覆盖重写所有抽象方法 }: 一. /** * lambda匿名函数的使用 * Lambda省去面向对象的条条框框,格式由3 ...

  10. 【FAQ】HarmonyOS SDK 闭源开放能力 — IAP Kit(6)

    1.问题描述: 支付场景,表现是在沙盒情况下所有商品都可以正常跑通,但是在非沙盒情况下,线上购买年包1800大额支付华为的 iap.createPurchas 在输完密码就会报 1001860001 ...