Java -- 视频压缩(返回压缩后的base64字符串)

前言:

  • 压缩时间较长, 10M压缩至1M大概需要2~3秒, 不怎么失帧;
  • Demo中返回base64字符串, 可根据自己需求改返回值类型;

环境:

  • JDK 1.8
  • IDEA 2021.3

具体请看代码:

注意: 

  • Window环境和Linux环境需要引用不同的包,建议都引用; 
  • 如果是32位,请把64改为32;
        <dependency>
            <groupId>ws.schild</groupId>
            <artifactId>jave-core</artifactId>
            <version>2.7.3</version>
        </dependency>

        <dependency>
            <groupId>ws.schild</groupId>
            <artifactId>jave-nativebin-win64</artifactId>
            <version>2.7.3</version>
        </dependency>
        <dependency>
            <groupId>ws.schild</groupId>
            <artifactId>jave-nativebin-linux64</artifactId>
            <version>2.7.3</version>
        </dependency>
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.*;

@RestController
public class DemoController {

    /** 01_main方法测试 */
    public static void main(String[] args) {
        try {
            File file = new File("C:/原视频.mp4");
            String s = VideoUtil.compressVideoByFile(file);
            System.out.println(s);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    /** 02_项目中测试 */
    @PostMapping("/test/compressVideo")
    public  String getParams(MultipartFile file){
        try {
            String s = VideoUtil.compressVideoByMultipartFile(file);
            System.out.println(s);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return "成功";
    }
}
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.multipart.MultipartFile;
import sun.misc.BASE64Decoder;
import ws.schild.jave.*;
import java.io.*;
import java.util.*;

/**
 * 视频工具类
 */
@Slf4j
public class VideoUtil {

    /**
     *  压缩视频,返回base64;
     *  接收MultipartFile格式文件;
     * @param multipartFile
     * @return
     * @throws Exception
     */
    public static String compressVideoByMultipartFile(MultipartFile multipartFile) throws Exception {
        File sourceFile = MultipartFileToFile(multipartFile);
        return compressVideoByFile(sourceFile);
    }

    /**
     * 压缩视频,返回base64字符串
     * sourceFile: 源文件;
     */
    public static String compressVideoByFile(File sourceFile) throws Exception {
        String fileName = sourceFile.getName();
        File targetFile = new File(System.currentTimeMillis() + fileName.substring(fileName.lastIndexOf(".")));
        //参数:
        int maxBitRate = 128000; //设置最大值:比特率越高,清晰度/音质越好
        int maxSamplingRate = 44100; //设置编码时候的音量值,未设置为0,如果256,则音量值不会改变
        int bitRate = 2000000; // 设置音频比特率,单位:b (比特率越高,清晰度/音质越好,当然文件也就越大 800000 = 800kb)
        int maxFrameRate = 20; // 视频帧率:15 f / s 帧率越低,效果越差
        int maxWidth = 1920;    //视频最大宽度(这里没使用)
        try {
            MultimediaObject object = new MultimediaObject(sourceFile);
            // 视频属性设置
            AudioInfo audioInfo = object.getInfo().getAudio();
            AudioAttributes audio = new AudioAttributes();
            // 设置通用编码格式
            audio.setCodec("aac");
            if (audioInfo.getBitRate() > maxBitRate) {
                audio.setBitRate(new Integer(maxBitRate));
            }
            audio.setChannels(audioInfo.getChannels());
            if (audioInfo.getSamplingRate() > maxSamplingRate) {
                audio.setSamplingRate(maxSamplingRate);
            }

            // 视频编码属性配置
            VideoInfo videoInfo = object.getInfo().getVideo();
            VideoAttributes video = new VideoAttributes();
            video.setCodec("h264");
            if (videoInfo.getBitRate() > bitRate) {
                video.setBitRate(bitRate);
            }
            if (videoInfo.getFrameRate() > maxFrameRate) {
                video.setFrameRate(maxFrameRate);
            }
            // 限制视频宽高: 不推荐设置; 如果视频宽度大于maxWidth值,则压缩后的视频宽度会拉宽变形(亲身经历);
            //int width = videoInfo.getSize().getWidth();
            //int height = videoInfo.getSize().getHeight();
            //if (width > maxWidth) {
            //    float rat = (float) width / maxWidth;
            //    video.setSize(new VideoSize(maxWidth, (int) (height / rat)));
            //}
            EncodingAttributes attr = new EncodingAttributes();
            attr.setFormat("mp4");
            attr.setAudioAttributes(audio);
            attr.setVideoAttributes(video);
            Encoder encoder = new Encoder();
            encoder.encode(new MultimediaObject(sourceFile), targetFile, attr);
            log.info("压缩后视频大小:[{}]",targetFile.length());
            String base64FromFile = getBase64FromFile(targetFile);

            //压缩后的base64转视频文件,可查看压缩后的视频:
            getFileFromBase64(base64FromFile,null);

            return base64FromFile;
        } catch (Exception e) {
            throw e;
        } finally {
            targetFile.delete();
        }
    }

    /**
     * 将文件转为base64
     */
    public static String getBase64FromFile(File file) throws IOException {
        FileInputStream in = null;
        ByteArrayOutputStream out = null;
        try {
            in = new FileInputStream(file);
            out = new ByteArrayOutputStream();
            int read = 0;
            byte[] buffer = new byte[1024];
            while ((read = in.read(buffer, 0, 1024)) != -1) {
                out.write(buffer, 0, read);
            }

            return Base64.getEncoder().encodeToString(out.toByteArray());
        } catch (IOException e) {
            throw e;
        } finally {
            if (in != null) {
                in.close();
            }
            if (out != null){
                out.close();
            }
        }
    }

    /**
     * 将MultipartFile转换为File
     */
    public static File MultipartFileToFile(MultipartFile multiFile) throws IOException {
        String fileName = multiFile.getOriginalFilename();
        String prefix = fileName.substring(fileName.lastIndexOf("."));
        InputStream in = null;
        OutputStream out = null;
        try {
            File file = File.createTempFile(fileName, prefix);
            out = new FileOutputStream(file);
            in = multiFile.getInputStream();
            int read = 0;
            byte[] buffer = new byte[1024];
            while ((read = in.read(buffer, 0, 1024)) != -1) {
                out.write(buffer, 0, read);
            }

            return file;
        } catch (Exception e) {
            throw e;
        }finally {
            if (in != null){
                in.close();
            }
            if (out != null){
                out.close();
            }
        }
    }

    /**
     * base64字符串转视频
     * @param base64Pic
     * @param filePath: 传空,则临时文件存放到项目更目录下;
     * @return
     * @throws Exception
     */
    public static File getFileFromBase64(String base64Pic,String filePath) throws Exception {
        File file = null;
        if (base64Pic != null) {
            try {
                filePath = Optional.ofNullable(filePath).orElse("");

                //文件目录
                if (!"".equals(filePath)) {
                    File fileMk = new File(filePath);
                    if (!fileMk.exists() && !fileMk.isDirectory()) {
                        fileMk.mkdirs();
                    }
                }

                BASE64Decoder decoder = new BASE64Decoder();
                //前台在用Ajax传base64值的时候会把base64中的+换成空格,所以需要替换回来。
                String baseValue = base64Pic.replaceAll(" ", "+");
                //去除base64中无用的部分
                byte[] b = decoder.decodeBuffer(baseValue.replace("data:video/mp4;base64,", ""));
                for (int i = 0; i < b.length; ++i) {
                    if (b[i] < 0) {
                        b[i] += 256;
                    }
                }

                //存到临时文件中
                file = new File(filePath + System.currentTimeMillis()+".mp4");
                OutputStream out = new FileOutputStream(file.getPath());
                out.write(b);
                out.flush();
                out.close();
            } catch (Exception e) {
                throw e;
            }finally {
                //删除filePath下的临时文件
                if (file != null) {
                    file.delete();
                }
            }
        }
        return file;
    }
}

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
首先,需要用JavaBase64类将Base64字符串解码成byte数组,然后将byte数组通过GZIP进行压缩,最后再把压缩后的byte数组通过Base64类编码成压缩后的Base64字符串。以下是示例代码: ```java import java.util.zip.Deflater; import java.util.zip.Inflater; import java.util.Base64; public class Base64Compression { public static String compress(String base64String) { byte[] decodedBytes = Base64.getDecoder().decode(base64String); byte[] compressedBytes = compressBytes(decodedBytes); return Base64.getEncoder().encodeToString(compressedBytes); } public static String decompress(String compressedBase64String) { byte[] compressedBytes = Base64.getDecoder().decode(compressedBase64String); byte[] decompressedBytes = decompressBytes(compressedBytes); return Base64.getEncoder().encodeToString(decompressedBytes); } private static byte[] compressBytes(byte[] data) { Deflater deflater = new Deflater(); deflater.setInput(data); deflater.finish(); byte[] buffer = new byte[data.length]; int compressedSize = deflater.deflate(buffer); byte[] compressedData = new byte[compressedSize]; System.arraycopy(buffer, 0, compressedData, 0, compressedSize); return compressedData; } private static byte[] decompressBytes(byte[] data) { Inflater inflater = new Inflater(); inflater.setInput(data); byte[] buffer = new byte[data.length * 2]; int decompressedSize; try { decompressedSize = inflater.inflate(buffer); } catch (Exception e) { throw new RuntimeException("Failed to decompress data", e); } byte[] decompressedData = new byte[decompressedSize]; System.arraycopy(buffer, 0, decompressedData, 0, decompressedSize); return decompressedData; } } ``` 可以使用以下代码测试: ```java String base64String = "SGVsbG8gV29ybGQh"; String compressedBase64String = Base64Compression.compress(base64String); System.out.println(compressedBase64String); // 输出: "eJwrSS0uyczPAQAAP//I1g==" String decompressedBase64String = Base64Compression.decompress(compressedBase64String); System.out.println(decompressedBase64String); // 输出: "SGVsbG8gV29ybGQh" ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值