You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过Java调用ffmpeg实现带水印视频的Web端流式服务?

解决方案

一、添加个性化水印的FFmpeg命令

先通过FFmpeg的drawtext滤镜生成带个人信息的水印视频,命令示例如下(可根据需求调整位置、字体、透明度):

ffmpeg -i input.mp4 -vf "drawtext=text='用户ID:12345':fontsize=24:fontcolor=white@0.7:x=w-tw-10:y=h-th-10" -c:v libx264 -c:a copy -y output_watermarked.mp4

参数说明:

  • -vf "drawtext=...":视频滤镜,指定水印文本、大小、颜色、透明度及右下角位置
  • -c:a copy:复用原音频流,减少处理时间
  • -y:自动覆盖已存在的输出文件

二、Java通过Runtime#exec调用FFmpeg

Java中调用FFmpeg需注意处理进程的输入输出流(避免阻塞),示例代码如下:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class FfmpegWatermarkHandler {
    public static void generateWatermarkedVideo(String inputPath, String outputPath, String userInfo) throws IOException, InterruptedException {
        // 构建FFmpeg命令数组
        String[] cmd = {
            "ffmpeg",
            "-i", inputPath,
            "-vf", String.format("drawtext=text='%s':fontsize=24:fontcolor=white@0.7:x=w-tw-10:y=h-th-10", userInfo),
            "-c:v", "libx264",
            "-c:a", "copy",
            "-y",
            outputPath
        };

        // 启动进程并处理流
        Process process = Runtime.getRuntime().exec(cmd);

        // 异步处理FFmpeg标准输出
        new Thread(() -> {
            try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    // 可记录日志
                    System.out.println("FFmpeg日志: " + line);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }).start();

        // 异步处理FFmpeg错误输出
        new Thread(() -> {
            try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream()))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    // 记录错误日志
                    System.err.println("FFmpeg错误: " + line);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }).start();

        // 等待命令执行完成
        int exitCode = process.waitFor();
        if (exitCode != 0) {
            throw new RuntimeException("视频加水印失败,FFmpeg退出码: " + exitCode);
        }
    }
}

推荐使用ProcessBuilder替代Runtime#exec,它支持设置工作目录、环境变量,还能合并输出/错误流,更易维护。

三、让Web端访问带水印的视频输出

无需依赖ffserver,有两种简便方案:

1. 文件输出 + Java静态资源服务

生成带水印的视频文件后,将输出目录配置为Java后端的静态资源目录。比如Spring Boot中配置:

spring:
  web:
    resources:
      static-locations: file:/path/to/watermarked-videos/

前端通过HTTP直接访问:http://your-backend-domain/videos/output_watermarked.mp4

2. 实时流输出 + 轻量HTTP转发

用FFmpeg将带水印的视频实时推流到Java后端的HTTP端点,再由后端转发给前端。示例FFmpeg命令:

ffmpeg -i input.mp4 -vf "drawtext=text='用户ID:12345':fontsize=24:fontcolor=white@0.7:x=w-tw-10:y=h-th-10" -c:v libx264 -c:a copy -f flv http://localhost:8080/stream

Java后端可基于Netty或Jetty搭建简单的HTTP服务器接收FLV流,再转成浏览器支持的格式(如HLS)供前端播放。

四、FFmpeg能否直接作为服务器供Web端访问?

FFmpeg本身不是专门的Web/流媒体服务器,仅提供基础的协议监听能力(如RTSP的-listen 1参数),不适合生产环境的Web访问:

  • 它的HTTP服务功能极简,无缓存、权限控制、负载均衡等Web必备特性
  • 浏览器原生支持的HLS/DASH流媒体协议,FFmpeg仅能生成对应分片文件,无法直接提供服务

更稳妥的方案是:Java调用FFmpeg生成带水印的视频/流,配合Java后端或Nginx作为Web服务层,提供带权限控制的视频访问入口。

额外防抄袭建议:除水印外,可配合动态签名URL(带过期时间)、视频分片加密、前端登录鉴权等方式,进一步限制未经授权的下载与分享。

内容的提问来源于stack exchange,提问作者Jose A. Matarán

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 03:15:46