java多媒体处理

方法一

<!--引入全平台windows 32/64 linux 32/64 下的ffmpeg 可执行程序,实际运行不需要这么多-->
        <!--<dependency>
            <groupId>ws.schild</groupId>
            <artifactId>jave-all-deps</artifactId>
            <version>3.2.0</version>
        </dependency>-->
        <!--操作ffmpeg命令的jar-->
        <dependency>
            <groupId>ws.schild</groupId>
            <artifactId>jave-core</artifactId>
            <version>3.2.0</version>
        </dependency>
        <!--linux 引用jar,主要集成 ffmpeg-amd64-3.1.1 linux下可执行文件  -->
        <dependency>
            <groupId>ws.schild</groupId>
            <artifactId>jave-nativebin-linux64</artifactId>
            <version>3.2.0</version>
        </dependency>
/**
     * 获取播放时长
     *
     * @param multipartFile 文件流
     */
    private int getPlayTime(MultipartFile multipartFile) {
        // 获取文件名
        String fileName = multipartFile.getOriginalFilename();
        // 播放时长
        int playTime = -1;
        File file = new File(fileName);
        try {
            FileUtils.copyInputStreamToFile(multipartFile.getInputStream(), file);
            MultimediaObject multimediaObject = new MultimediaObject(file);
            MultimediaInfo multimediaInfo = multimediaObject.getInfo();
            playTime = (int) multimediaInfo.getDuration() / 1000;
        } catch (Exception e) {
            BusinessExceptionUtil.throwErrorCodeException(ErrorCode.Status.UPLOAD_FILE_FAIL, e.toString());
            log.error("获取播放时长异常", e);
        } finally {
            file.delete();
        }
        return playTime;
    }

 

方法二

<!-- 视觉库 -->
        <!-- 总包太大,不需要这么多 -->
        <!-- <dependency>
            <groupId>org.bytedeco</groupId>
            <artifactId>javacv-platform</artifactId>
            <version>1.5.7</version>
        </dependency> -->
        <!-- javacv基础包 -->
        <dependency>
            <groupId>org.bytedeco</groupId>
            <artifactId>javacv</artifactId>
            <version>1.5.7</version>
        </dependency>
        <!-- ffmpeg,根据javacv总包的版本 -->
        <dependency>
            <groupId>org.bytedeco</groupId>
            <artifactId>ffmpeg-platform</artifactId>
            <version>5.0-1.5.7</version>
        </dependency>
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.FrameGrabber;
import org.bytedeco.javacv.Java2DFrameConverter;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.HashMap;
import java.util.Map;

@Slf4j
public class ToolVideo {
    // 获取要取得的帧数
    private static final int GET_FRAMES_LENGTH = 6;

    /**
     * 测试
     *
     * @param args
     */
    public static void main(String[] args) throws FrameGrabber.Exception {
        File file = new File("D:\\Users\\外出乞讨\\Desktop\\测试用素材\\摩托.mp4");
        Map<String, Object> screenshot = getScreenshot(file);
    }

    /**
     * 视频:获取一张视频截图并保存同名的jpg文件到指定目录
     * 音频:获取播放时长
     *
     * @param file 文件
     * @return
     */
    public static Map<String, Object> getScreenshot(File file) {
        log.info("视频文件[{}]截图开始", file.getName());

        Map<String, Object> result = new HashMap<>();

        // 文件路径
        String filePath = file.getPath();
        // 视频文件名
        String fileName = file.getName();

        // 第一帧图片存储位置(也是视频路径)
        String targerFilePath = "";
        if (filePath.contains("\\")) {
            targerFilePath = filePath.substring(0, filePath.lastIndexOf("\\"));
            targerFilePath = targerFilePath + File.separator;
        } else if (filePath.contains("/")) {
            targerFilePath = filePath.substring(0, filePath.lastIndexOf("/"));
            targerFilePath = targerFilePath + File.separator;
        }

        // 图片名称
        String targetFileName = fileName.substring(0, fileName.lastIndexOf("."));
        // 图片的类型
        String imageMat = "jpg";
        // 图片的完整路径
        String imagePath = targerFilePath + targetFileName + "." + imageMat;

        // 创建文件
        File output = new File(imagePath);

        FFmpegFrameGrabber grabber;
        try {
            grabber = FFmpegFrameGrabber.createDefault(file);
            grabber.start();
            // 视频总帧数
            int videoLength = grabber.getLengthInFrames();

            Frame frame = null;
            int i = 0;
            while (i < videoLength) {
                // 过滤前5帧,避免出现全黑的图片,依自己情况而定(每循环一次取一帧)
                frame = grabber.grabFrame();
                if ((i > GET_FRAMES_LENGTH) && (frame.image != null)) {
                    break;
                }
                i++;
            }

            // 视频旋转度
            String rotate = grabber.getVideoMetadata("rotate");
            Java2DFrameConverter converter = new Java2DFrameConverter();
            // 绘制图片
            BufferedImage bi = converter.getBufferedImage(frame);
            if (rotate != null) {
                // 旋转图片
                bi = rotate(bi, Integer.parseInt(rotate));
            }

            // 输出图片
            ImageIO.write(bi, imageMat, output);

            // 拼接Map信息
            result.put("videoLength", videoLength); // 视频总帧数
            result.put("videoWide", bi.getWidth()); // 第一帧的宽
            result.put("videoHigh", bi.getHeight());// 第一帧的高
            long duration = grabber.getLengthInTime() / (1000 * 1000); // 此视频时长(s/秒)
            result.put("rotate", (null == rotate || "".equals(rotate)) ? "0" : rotate); // 视频的旋转度
            result.put("format", grabber.getFormat()); // 视频的格式
            result.put("imgPath", output.getPath());
            result.put("imgName", output.getName());
            result.put("duration", duration);

            log.info("视频文件[{}]截图结束,图片地址为[{}]", filePath, imagePath);

            grabber.close();
        } catch (Exception e) {
            log.error("视频信息帧数处理发生异常 [{}]", e.getMessage());
            e.printStackTrace();

            BusinessExceptionUtil.throwErrorCodeException(ErrorCode.Status.UPLOAD_FILE_FAIL, e.toString());
        }

        return result;
    }

    /**
     * file 转 btye[]
     *
     * @param file
     * @return
     */
    public static byte[] fileTobyte(File file) {
        byte[] buffer = null;
        try {
            FileInputStream fis = new FileInputStream(file);
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            byte[] b = new byte[1024];
            int n;
            while ((n = fis.read(b)) != -1) {
                bos.write(b, 0, n);
            }
            fis.close();
            bos.close();
            buffer = bos.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return buffer;
    }

    /**
     * 获取音频/视频时长
     * @param multipartFile 文件流
     * @return
     */
    public static int getPlayTime(MultipartFile multipartFile) {
        // 播放时长
        int playTime = -1;
        File file = null;
        FFmpegFrameGrabber grabberOne = null;
        try {
            // MultipartFile转file
            file = new File(multipartFile.getOriginalFilename());
            FileUtils.copyInputStreamToFile(multipartFile.getInputStream(), file);

            // file转FFmpegFrameGrabber
            grabberOne = FFmpegFrameGrabber.createDefault(file);
            grabberOne.start();
            // 计算时长
            playTime = (int) grabberOne.getFormatContext().duration() / 1000000;
            grabberOne.stop();
        } catch (Exception e) {
            BusinessExceptionUtil.throwErrorCodeException(ErrorCode.Status.UPLOAD_FILE_FAIL, e.toString());
            log.error("获取播放时长异常", e);
        } finally {
            try{
                grabberOne.stop();
            }catch (Exception e) {
                BusinessExceptionUtil.throwErrorCodeException(ErrorCode.Status.UPLOAD_FILE_FAIL, e.toString());
                log.error("关闭流异常", e);
            }

            file.delete();
        }
        return playTime;
    }

    // ==================== private method ====================

    /**
     * <h5>功能:根据视频旋转度来调整图片</h5>
     *
     * @param src   捕获的图像
     * @param angel 视频旋转度
     * @return BufferedImage
     */
    private static BufferedImage rotate(BufferedImage src, int angel) {
        int src_width = src.getWidth(null);
        int src_height = src.getHeight(null);
        int type = src.getColorModel().getTransparency();
        Rectangle rect_des = calcRotatedSize(new Rectangle(new Dimension(src_width, src_height)), angel);
        BufferedImage bi = new BufferedImage(rect_des.width, rect_des.height, type);
        Graphics2D g2 = bi.createGraphics();
        g2.translate((rect_des.width - src_width) / 2, (rect_des.height - src_height) / 2);
        g2.rotate(Math.toRadians(angel), src_width / 2, src_height / 2);
        g2.drawImage(src, 0, 0, null);
        g2.dispose();
        return bi;
    }

    /**
     * <h5>功能:计算图片旋转大小</h5>
     *
     * @param src   屏幕坐标中捕获的矩形区域
     * @param angel 视频旋转度
     * @return
     */
    private static Rectangle calcRotatedSize(Rectangle src, int angel) {
        if (angel >= 90) {
            if (angel / 90 % 2 == 1) {
                int temp = src.height;
                src.height = src.width;
                src.width = temp;
            }
            angel = angel % 90;
        }
        double r = Math.sqrt(src.height * src.height + src.width * src.width) / 2;
        double len = 2 * Math.sin(Math.toRadians(angel) / 2) * r;
        double angel_alpha = (Math.PI - Math.toRadians(angel)) / 2;
        double angel_dalta_width = Math.atan((double) src.height / src.width);
        double angel_dalta_height = Math.atan((double) src.width / src.height);
        int len_dalta_width = (int) (len * Math.cos(Math.PI - angel_alpha - angel_dalta_width));
        int len_dalta_height = (int) (len * Math.cos(Math.PI - angel_alpha - angel_dalta_height));
        int des_width = src.width + len_dalta_width * 2;
        int des_height = src.height + len_dalta_height * 2;
        return new Rectangle(new Dimension(des_width, des_height));
    }
}

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值