This theme is built with aw|

努力的小韩

园龄:2年11个月粉丝:0关注:2

Spring boot 整合 ffmpeg 实现给视频添加文字水印 只有上传minio(理论通用!!)

只要有ffmpeg 命令理论可以实现所有ffmpeg 能做的的事儿!!

思路:
前端上传视频通过commons-io的FileUtils.copyInputStreamToFile()将流复制到文件中 java执行ffmpeg 命令对这个文件进行转换输出到另外一个临时文件 在将添加水印后的文件转成inputStream流上传到minio(本人小白 可能有更好的思路!!!)
上代码:

首先是minio的配置文件不需要的掠过

application.yml

spring:
  servlet:
    multipart:
      max-file-size: 200MB
      max-request-size: 200MB
minio:
  endpoint: http://192.168.22.129:9090  #minio地址 注意一定要加 协议不然报错
  accessKey: admin  # 账号
  secretKey: admin123456 #密码
  bucketName: text # 桶的名字(可以理解为文件夹目录)

MinIoClientConfig:

import io.minio.MinioClient;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

@Data
@Component
public class MinIoClientConfig {
    @Value("${minio.endpoint}")
    private String endpoint;
    @Value("${minio.accessKey}")
    private String accessKey;
    @Value("${minio.secretKey}")
    private String secretKey;

    /**
     * 注入minio 客户端
     * @return
     */
    @Bean
    public MinioClient minioClient(){

        return MinioClient.builder()
                .endpoint(endpoint)
                .credentials(accessKey, secretKey)
                .build();
    }

}

MinioUtilS:注意里面包含了 视频添加文字水印的方法 等下我也会贴出来!!!

import io.minio.*;
import io.minio.messages.DeleteError;
import io.minio.messages.DeleteObject;
import io.minio.messages.Item;
import org.apache.commons.io.FileUtils;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * @description: minio工具类
 * @version:3.0
 */
@Component
public class MinioUtilS {
    @Autowired
    private MinioClient minioClient;

    @Value("${minio.bucketName}")
    private String bucketName;
    /**
     * description: 判断bucket是否存在,不存在则创建
     *
     * @return: void
     */
    public void existBucket(String name) {
        try {
            boolean exists = minioClient.bucketExists(BucketExistsArgs.builder().bucket(name).build());
            if (!exists) {
                minioClient.makeBucket(MakeBucketArgs.builder().bucket(name).build());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 创建存储bucket
     * @param bucketName 存储bucket名称
     * @return Boolean
     */
    public Boolean makeBucket(String bucketName) {
        try {
            minioClient.makeBucket(MakeBucketArgs.builder()
                    .bucket(bucketName)
                    .build());
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * 删除存储bucket
     * @param bucketName 存储bucket名称
     * @return Boolean
     */
    public Boolean removeBucket(String bucketName) {
        try {
            minioClient.removeBucket(RemoveBucketArgs.builder()
                    .bucket(bucketName)
                    .build());
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }
    /**
     * description: 上传文件
     *
     * @param multipartFile
     * @return: java.lang.String

     */
    public List<String> upload(MultipartFile[] multipartFile) {
        List<String> names = new ArrayList<>(multipartFile.length);
        for (MultipartFile file : multipartFile) {
            String fileName = file.getOriginalFilename();
            String[] split = fileName.split("\\.");
            if (split.length > 1) {
                fileName = split[0] + "_" + System.currentTimeMillis() + "." + split[1];
            } else {
                fileName = fileName + System.currentTimeMillis();
            }
            InputStream in = null;
            System.err.println("文件名是:"+fileName);
            try {
                in = file.getInputStream();
//                InputStream stream = addWatermark(file.getInputStream(),fileName);
                File videoFile = File.createTempFile(split[0],"."+split[1]);
                FileUtils.copyInputStreamToFile(in, videoFile);
                String text = "Hello, World!";
                System.err.println("路径"+videoFile.getAbsolutePath());
                String newFile = UUID.randomUUID().toString()+"."+split[1];
                addTextWatermark(videoFile.getAbsolutePath(),text, newFile);
                File output = new File(newFile);
                InputStream inputStream = new FileInputStream(output);

                minioClient.putObject(PutObjectArgs.builder()
                        .bucket(bucketName)
                        .object(fileName)
                        .stream(inputStream, inputStream.available(), -1)
                        .contentType(file.getContentType())
                        .build()
                );
                inputStream.close();
                output.delete();
                videoFile.delete();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (in != null) {
                    try {
                        in.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
            names.add(fileName);
        }
        return names;
    }

    /**
     * 视频添加文字水印
     * @param videoFilePath
     * @param text
     * @param outputFilePath
     * @throws IOException
     * @throws InterruptedException
     */
    public static void addTextWatermark(String videoFilePath, String text, String outputFilePath) throws IOException, InterruptedException {
        ProcessBuilder pb = new ProcessBuilder("ffmpeg", "-i", videoFilePath, "-vf", "drawtext=text='智慧学堂':fontfile=font.ttf:fontsize=24:fontcolor=black@1.0:x=10:y=10", outputFilePath);
        pb.redirectErrorStream(true);
        pb.redirectInput(ProcessBuilder.Redirect.INHERIT);
        pb.redirectOutput(ProcessBuilder.Redirect.INHERIT);
        pb.redirectError(ProcessBuilder.Redirect.INHERIT);
        pb.environment().put("LANG", "zh_CN.GBK");
        try {
            Process process = pb.start();
            InputStream is = process.getInputStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(is));
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }
            process.waitFor();
            System.out.println("FFmpeg command completed.");
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
    }


    /**
     * description: 下载文件
     *
     * @param fileName
     * @return: org.springframework.http.ResponseEntity<byte [ ]>
     */
    public ResponseEntity<byte[]> download(String fileName) {
        ResponseEntity<byte[]> responseEntity = null;
        InputStream in = null;
        ByteArrayOutputStream out = null;
        try {
            in = minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(fileName).build());
            out = new ByteArrayOutputStream();
            IOUtils.copy(in, out);
            //封装返回值
            byte[] bytes = out.toByteArray();
            HttpHeaders headers = new HttpHeaders();
            try {
                headers.add("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            headers.setContentLength(bytes.length);
            headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
            headers.setAccessControlExposeHeaders(Arrays.asList("*"));
            responseEntity = new ResponseEntity<byte[]>(bytes, headers, HttpStatus.OK);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (in != null) {
                    try {
                        in.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (out != null) {
                    out.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return responseEntity;
    }

    /**
     * 查看文件对象
     * @param bucketName 存储bucket名称
     * @return 存储bucket内文件对象信息
     */
    public List<ObjectItem> listObjects(String bucketName) {
        Iterable<Result<Item>> results = minioClient.listObjects(
                ListObjectsArgs.builder().bucket(bucketName).build());
        List<ObjectItem> objectItems = new ArrayList<>();
        try {
            for (Result<Item> result : results) {
                Item item = result.get();
                ObjectItem objectItem = new ObjectItem();
                objectItem.setObjectName(item.objectName());
                objectItem.setSize(item.size());
                objectItems.add(objectItem);
            }
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        return objectItems;
    }

    /**
     * 批量删除文件对象
     * @param bucketName 存储bucket名称
     * @param objects 对象名称集合
     */
    public Iterable<Result<DeleteError>> removeObjects(String bucketName, List<String> objects) {
        List<DeleteObject> dos = objects.stream().map(e -> new DeleteObject(e)).collect(Collectors.toList());
        Iterable<Result<DeleteError>> results = minioClient.removeObjects(RemoveObjectsArgs.builder().bucket(bucketName).objects(dos).build());
        return results;
    }


}

上传文件到minio的方法:

/**
     * description: 上传文件
     *
     * @param multipartFile
     * @return: java.lang.String

     */
    public List<String> upload(MultipartFile[] multipartFile) {
        List<String> names = new ArrayList<>(multipartFile.length);
        for (MultipartFile file : multipartFile) {
            String fileName = file.getOriginalFilename();
            String[] split = fileName.split("\\.");
            if (split.length > 1) {
                fileName = split[0] + "_" + System.currentTimeMillis() + "." + split[1];
            } else {
                fileName = fileName + System.currentTimeMillis();
            }
            InputStream in = null;
            //文件名简单的处理了下 你们可以自己处理
            System.err.println("文件名是:"+fileName);
            try {
                in = file.getInputStream();
                //定义临时文件 吧前端传入的流转成临时文件
                File videoFile = File.createTempFile(split[0],"."+split[1]);
                FileUtils.copyInputStreamToFile(in, videoFile);
                //定义文字水印
                String text = "Hello, World!";
                //定义输出文件(添加完水印的视频)的名称以及后缀
                String newFile = UUID.randomUUID().toString()+"."+split[1];
                //调用添加水印的方法 传入
                addTextWatermark(videoFile.getAbsolutePath(),text, newFile);
                // 读取添加完成的文件转成 InputStream
                File output = new File(newFile);
                InputStream inputStream = new FileInputStream(output);
                // 上传到minio
                minioClient.putObject(PutObjectArgs.builder()
                        .bucket(bucketName)
                        .object(fileName)
                        .stream(inputStream, inputStream.available(), -1)
                        .contentType(file.getContentType())
                        .build()
                );
                //因为作用域的原因我在这里进行关闭流 不然临时文件我发删除
                inputStream.close();
                //删除临时文件
                output.delete();
                videoFile.delete();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (in != null) {
                    try {
                        in.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
            names.add(fileName);
        }
        return names;
    }

视频添加文字水印的方法:

/**
     * 视频添加文字水印
     * @param videoFilePath
     * @param text
     * @param outputFilePath
     * @throws IOException
     * @throws InterruptedException
     */
    public static void addTextWatermark(String videoFilePath, String text, String outputFilePath) throws IOException, InterruptedException {
        // 理论修改命令可以完成更多操作   我这里的文字水印写死了 你们改下
        ProcessBuilder pb = new ProcessBuilder("ffmpeg", "-i", videoFilePath, "-vf", "drawtext=text='测试一下':fontfile=font.ttf:fontsize=24:fontcolor=black@1.0:x=10:y=10", outputFilePath);
        pb.redirectErrorStream(true);
        pb.redirectInput(ProcessBuilder.Redirect.INHERIT);
        pb.redirectOutput(ProcessBuilder.Redirect.INHERIT);
        pb.redirectError(ProcessBuilder.Redirect.INHERIT);
        // 处理中文水印乱码的问题
        pb.environment().put("LANG", "zh_CN.GBK");
        try {
            Process process = pb.start();
            InputStream is = process.getInputStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(is));
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }
            process.waitFor();
            System.out.println("FFmpeg command completed.");
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
    }

本文作者:努力的小韩

本文链接:https://www.cnblogs.com/HanYork/p/17412983.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   努力的小韩  阅读(281)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起
  1. 1 雪下的时候 乔佳旭
雪下的时候 - 乔佳旭
00:00 / 00:00
An audio error has occurred.

作词 : 乔佳旭

作曲 : 乔佳旭

编曲:侯江浩

如果你有空 陪我过个冬

这话多像肆意的寒风

我不会感动 不会道保重

你有多想我无动于衷

我以为会不痛 学了几遍从容

无师自通 眼看匆匆

你曾说的心疼 曾深拥过的梦

我倒想问这算哪门子喜欢

雪下的时候 是想念的汹涌

雪停的时候 大概扑了空

你千万别念旧 别对我宽容

我多半会心动

雪下的刚好 提醒我抱不到

这白色的外表 多像在求饶

那冻裂的伤口 还需不需要

你医治好

我以为会不痛 学了几遍从容

无师自通 眼看匆匆

你曾说的心疼 曾深拥过的梦

我倒想问这算哪门子喜欢

雪下的时候 是想念的汹涌

雪停的时候 大概扑了空

你千万别念旧 别对我宽容

我多半会心动

雪下的刚好 提醒我抱不到

这白色的外表 多像在求饶

那冻裂的伤口 还需不需要

你医治好

雪下的时候 是想念的汹涌

雪停的时候 大概扑了空

你千万别念旧 别对我宽容

我多半会心动

雪下的刚好 提醒我抱不到

这白色的外表 多像在求饶

那冻裂的伤口 还需不需要

你医治好

吉他:吴海锋

混音:张栩赫(Ethan)

录音:觉醒爷爷(Kent)

和声编写/和声:觉醒爷爷(Kent)

配唱制作人/制作人:觉醒爷爷(Kent)

录音工作室: 1803 Music Studio

混音工作室:Hot Music Studio

企划营销:梦童娱乐

监制:三千

OP:千和世纪

(版权所有未经许可请勿使用)