JavaCV本地视频流通过帧图片添加文本进行字幕合成

 音视频的Java框架找了一大圈,除了JavaCV,目前找不到其他的。JavaCV封装了对底层C的调用,最终实际上执行的都是FFMPEG的函数。现在有个头疼的问题,FFMPEG的字幕合成用命令行一敲就完事了,比如想往input.mkv里合入字幕subtitles.srt,输出到output.mkv,简单的很:

ffmpeg -i input.mkv -vf subtitles=subtitles.srt output.mkv

上面的-vf参数表示内嵌字幕,也就是不用手动在播放器里设置,字幕就自己出来了。JavaCV怎么实现字幕合成呢?找了一大圈,没有。OpenCV倒是可以实现,就是比较麻烦,大概思路是:音视频帧 -> 视频帧 -> 视频帧转图片 -> 字幕文本画到图片指定位置上 ->  图片转回视频帧 -> 写视频帧 -> 写音频帧。说白了就是文本水印。可惜OpenCV不支持中文,画出来都是问号。

  OpenCV就是一个画图工具而已,换,用Java自带的awt画图工具对象Graphics2D。不废话,上代码:

  1、pom.xml添加Java CV依赖:

        <dependency>
            <groupId>org.bytedeco</groupId>
            <artifactId>javacv-platform</artifactId>
            <version>1.5.2</version>
        </dependency>

2、示例代码,这里用几句话模拟字幕循环输出,并展示合入字幕的时间:

import org.bytedeco.ffmpeg.global.avcodec;
import org.bytedeco.javacv.*;
import org.bytedeco.javacv.Frame;
import sun.font.FontDesignMetrics;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class SubtitleMix {

    private final static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    public static void main(String[] args) throws FrameGrabber.Exception, FrameRecorder.Exception {
        // 构造测试字幕
        String[] test = {
                "世上无难事",
                "只怕有心人",
                "只要思想不滑坡",
                "办法总比困难多",
                "长江后浪推前浪",
                "前浪死在沙滩上"
        };

        // 为连续的50帧设置同一个测试字幕文本
        List<String> testStr = new ArrayList<>();
        for (int i = 0; i < 300; i++) {
            testStr.add(test[i / 50]);
        }

        // 设置源视频、加字幕后的视频文件路径
        FFmpegFrameGrabber grabber = FFmpegFrameGrabber.createDefault("E:\\BaiduNetdiskDownload\\testout.mkv");
        grabber.start();
        FFmpegFrameRecorder recorder = new FFmpegFrameRecorder("E:\\BaiduNetdiskDownload\\outtest.mkv",
                1280, 720, 2);

        // 视频相关配置,取原视频配置
        recorder.setFrameRate(grabber.getFrameRate());
        recorder.setVideoCodec(grabber.getVideoCodec());
        recorder.setVideoBitrate(grabber.getVideoBitrate());

        // 音频相关配置,取原音频配置
        recorder.setSampleRate(grabber.getSampleRate());
        recorder.setAudioCodec(avcodec.AV_CODEC_ID_MP3);

        recorder.start();
        System.out.println("准备开始推流...");
        Java2DFrameConverter converter = new Java2DFrameConverter();
        Frame frame;
        int i = 0;
        while ((frame = grabber.grab()) != null) {
            // 从视频帧中获取图片
            if (frame.image != null) {

                BufferedImage bufferedImage = converter.getBufferedImage(frame);

                // 对图片进行文本合入
                bufferedImage = addSubtitle(bufferedImage, testStr.get(i++ % 300));

                // 视频帧赋值,写入输出流
                frame.image = converter.getFrame(bufferedImage).image;
                recorder.record(frame);
            }

            // 音频帧写入输出流
            if(frame.samples != null) {
                recorder.record(frame);
            }
        }
        System.out.println("推流结束...");
        grabber.stop();
        recorder.stop();
    }

    /**
     * 图片添加文本
     *
     * @param bufImg
     * @param subTitleContent
     * @return
     */
    private static BufferedImage addSubtitle(BufferedImage bufImg, String subTitleContent) {

        // 添加字幕时的时间
        Font font = new Font("微软雅黑", Font.BOLD, 32);
        String timeContent = sdf.format(new Date());
        FontDesignMetrics metrics = FontDesignMetrics.getMetrics(font);
        Graphics2D graphics = bufImg.createGraphics();
        graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
        graphics.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));

        //设置图片背景
        graphics.drawImage(bufImg, 0, 0, bufImg.getWidth(), bufImg.getHeight(), null);

        //设置左上方时间显示
        graphics.setColor(Color.orange);
        graphics.setFont(font);
        graphics.drawString(timeContent, 0, metrics.getAscent());

        // 计算文字长度,计算居中的x点坐标
        int textWidth = metrics.stringWidth(subTitleContent);
        int widthX = (bufImg.getWidth() - textWidth) / 2;
        graphics.setColor(Color.red);
        graphics.setFont(font);
        graphics.drawString(subTitleContent, widthX, bufImg.getHeight() - 100);
        graphics.dispose();
        return bufImg;
    }
}
 

 打完收工,看看效果:

 

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
要使用Java代码去除视频字幕,你可以使用FFmpeg进行视频处理。下面是一个示例代码,演示如何使用Java运行FFmpeg命令来去除视频字幕: ```java import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; public class RemoveSubtitles { public static void main(String[] args) { String inputVideo = "input.mp4"; // 输入视频文件路径 String outputVideo = "output.mp4"; // 输出视频文件路径 // 构建FFmpeg命令 String ffmpegCmd = "ffmpeg -i " + inputVideo + " -map 0 -scodec copy -c:v copy -c:a copy -c:s mov_text -map -0 " + outputVideo; try { // 执行FFmpeg命令 Process process = Runtime.getRuntime().exec(ffmpegCmd); // 读取命令输出 BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); String line; while ((line = reader.readLine()) != null) { System.out.println(line); } // 等待命令执行完成 int exitCode = process.waitFor(); if (exitCode == 0) { System.out.println("视频字幕已成功去除!"); } else { System.out.println("视频字幕去除失败!"); } } catch (IOException | InterruptedException e) { e.printStackTrace(); } } } ``` 请确保将FFmpeg的可执行文件路径添加到系统环境变量中,或者在代码中指定FFmpeg的完整路径。该代码会执行一个FFmpeg命令,将输入视频的字幕移除,并生成一个新的视频文件作为输出。 请注意,这里假设你已经安装了FFmpeg并将其添加到了系统环境变量中。如果没有安装FFmpeg,请先下载并安装它。另外,这段代码只是一个示例,你可以根据自己的需求进行修改和扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码农汉子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值