Java获取视频时长、分辨率、帧截图

1,207 阅读2分钟

前言

因为目前现在正在做毕业设计,需要一个功能能够将用户上传的视频上传到腾讯云的cos后获取视频的时长、分辨率、第一帧截图作为封面。而腾讯云上传后并不能获取视频的这些信息,所以只能再根据视频url地址来转换、流化,实现这一功能就需要使用FFmpeg来完成了。 image.png

下载安装

FFmpeg官网地址

FFmpeg的git地址

下载完windows系统的之后需要将它的bin目录配置到环境变量中。 image.png

在cmd下输入“ffmpeg -i” 如果出现这个则代表安装成功。

image.png

Java调用

使用java调用其实就是使用cmd命令来使用FFmpeg,首先导入maven包

<!-- 视频流处理 -->
<dependency>
    <groupId>org.bytedeco</groupId>
    <artifactId>javacv-platform</artifactId>
    <version>1.5.5</version>
</dependency>
<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.7.22</version>
</dependency>

搞一个util方便调用

import cn.hutool.core.util.IdUtil;
import cn.hutool.http.HttpUtil;
import org.bytedeco.javacpp.Loader;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;

public class VideoUtil {
    /**
     * 提取主方法
     *
     * @param path MP4视频路径
     * @param tmpDir 存放封面图片和网络视频的临时目录
     * @return 视频信息map
     */
    public static Map<String,String> extract(String path, String tmpDir) throws Exception {
        String mp4Path;
        // 如果是网络视频先下载到临时目录
        if (path.startsWith("http")) {
            mp4Path = tmpDir + "/" + IdUtil.simpleUUID() + ".mp4";
            HttpUtil.downloadFile(path, mp4Path);
        } else {
            mp4Path = path;
        }
        return ffmpegExtractImage(mp4Path, tmpDir + "\" + IdUtil.simpleUUID() + ".jpg");
    }

    /**
     * 提取视频第一帧图片
     *
     * @param mp4Path 视频地址
     * @param picPath 图片存放地址
     * @return 提取的图片地址
     */
    public static Map<String,String> ffmpegExtractImage(String mp4Path, String picPath) throws Exception {
        String ffmpeg = Loader.load(org.bytedeco.ffmpeg.ffmpeg.class);

        ProcessBuilder extractBuilder =
                new ProcessBuilder(
                        ffmpeg, "-i", mp4Path, "-f", "image2", "-ss", "1","-frames:v", "1", picPath);
        Map<String,String> map;
        Process start = extractBuilder.start();
        map = videoBaseInfo(start.getErrorStream());
        start.waitFor();
        // 添加图片文件路径
        map.put("coverPath",picPath);
        return map;
    }

    /**
     * 获取视频的基本信息
     *
     * @param inputStream ffmpeg的输入流
     * @return
     */
    public static Map<String,String> videoBaseInfo(InputStream inputStream) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
        Map<String,String> map = new HashMap<>();
        String line = "";
        while ((line = br.readLine()) != null) {
            // 解析出视频信息
            if (line.contains("Duration")) {
                String duration = line.substring(line.indexOf("Duration") + 10).split(",")[0];
                map.put("duration",duration);
            }
            if (line.contains("Stream")) {
                String ratio = line.split(",")[3].substring(1);
                map.put("ratio",ratio);
                break;
            }
        }
        return map;
    }

    public static void main(String[] args) throws Exception {
//        System.out.println(extract("C:\Users\linyuxian\Downloads\436977885-1-208.mp4", "C:\Users\linyuxian\Downloads"));
        System.out.println(extract("https://lmusic-1302280959.cos.ap-chengdu.myqcloud.com/lin/foodRecord/video/1063904913-1-208.mp4","C:\Users\linyuxian\Desktop"));
    }
}

image.png

image.png

弊端

FFmpg使用起来确实简单方便,但它对于java程序来说也有两个弊端

  1. Java项目最终打包是要使用jar包的,一般都是运行在Linux服务器上,要想使用FFmpg又必须要在服务器上下载安装并且还需要单独的一套linux代码,十分不方便。
  2. FFmpg不能直接解析MultipartFile,需要根据视频地址把视频下载下来才能去解析,最后又需要把临时视频删除,增加了无端的流量耗用和性能消耗。