在springBoot项目如何进行视频压缩
目录
- 前言
- 导入maven
- 编写实现类
- 测试
前言
本篇文章介绍如何使用maven仓库的javacv-platform的插件进行视频压缩。
导入maven
<dependency><groupId>org.bytedeco</groupId><artifactId>javacv-platform</artifactId><version>1.5.9</version></dependency>
编写实现类
package com.example.mianshi.service.impl;import org.bytedeco.javacv.*;
import org.bytedeco.ffmpeg.global.avcodec;
import org.bytedeco.ffmpeg.global.avutil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;import java.io.File;@Service
public class VideoCompressionService {private static final Logger logger = LoggerFactory.getLogger(VideoCompressionService.class);/*** 压缩视频文件* * @param inputPath 输入视频文件路径* @param outputPath 输出视频文件路径* @param targetBitrate 目标比特率 (例如: 1000000 = 1Mbps)* @param targetWidth 目标宽度 (-1表示保持原始宽高比)* @param targetHeight 目标高度 (-1表示保持原始宽高比)* @throws Exception 压缩过程中可能抛出的异常*/public void compressVideo(String inputPath, String outputPath, int targetBitrate, int targetWidth, int targetHeight) throws Exception {File inputFile = new File(inputPath);if (!inputFile.exists()) {throw new IllegalArgumentException("输入文件不存在: " + inputPath);}// 创建输出目录(如果不存在)File outputFile = new File(outputPath);File outputDir = outputFile.getParentFile();if (outputDir != null && !outputDir.exists()) {outputDir.mkdirs();}logger.info("开始压缩视频: {} -> {}", inputPath, outputPath);long startTime = System.currentTimeMillis();FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(inputPath);FFmpegFrameRecorder recorder = null;try {// 启动抓取器grabber.start();// 计算目标尺寸int width = grabber.getImageWidth();int height = grabber.getImageHeight();if (targetWidth > 0 && targetHeight > 0) {width = targetWidth;height = targetHeight;} else if (targetWidth > 0) {// 按宽度等比缩放height = (int) Math.round((double) targetWidth / width * height);width = targetWidth;} else if (targetHeight > 0) {// 按高度等比缩放width = (int) Math.round((double) targetHeight / height * width);height = targetHeight;}// 创建录制器recorder = new FFmpegFrameRecorder(outputPath, width, height);// 设置视频编码参数recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);recorder.setVideoBitrate(targetBitrate);recorder.setFrameRate(grabber.getFrameRate());recorder.setPixelFormat(avutil.AV_PIX_FMT_YUV420P);// 优化编码参数以提高性能recorder.setVideoOption("threads", "0"); // 使用自动线程数recorder.setVideoOption("preset", "ultrafast"); // 编码速度预设,从medium改为ultrafastrecorder.setVideoOption("crf", "28"); // 提高CRF值以减小编码时间,从23改为28recorder.setVideoOption("tune", "zerolatency"); // 优化实时编码recorder.setVideoOption("faststart", "1"); // 优化MP4文件以支持快速启动recorder.setVideoOption("movflags", "+faststart"); // 优化MP4文件以支持快速启动// 设置音频编码参数(如果需要保留音频)if (grabber.getAudioChannels() > 0) {recorder.setAudioCodec(avcodec.AV_CODEC_ID_AAC);recorder.setAudioBitrate(grabber.getAudioBitrate());recorder.setSampleRate(grabber.getSampleRate());recorder.setAudioChannels(grabber.getAudioChannels());recorder.setAudioOption("threads", "0"); // 音频也使用自动线程数}// 启动录制器recorder.start();// 处理视频帧Frame frame;int frameCount = 0;while ((frame = grabber.grab()) != null) {recorder.record(frame);frameCount++;// 每处理10000帧记录一次日志,进一步减少日志写入频率if (frameCount % 10000 == 0) {logger.debug("已处理 {} 帧", frameCount);}}long endTime = System.currentTimeMillis();logger.info("视频压缩完成,共处理 {} 帧,耗时 {} ms", frameCount, (endTime - startTime));} finally {// 释放资源if (recorder != null) {recorder.stop();recorder.release();}grabber.stop();grabber.release();}}/*** 快速压缩视频(使用预设参数)* * @param inputPath 输入视频文件路径* @param outputPath 输出视频文件路径* @throws Exception 压缩过程中可能抛出的异常*/public void quickCompress(String inputPath, String outputPath) throws Exception {// 使用更高的CRF值和更快的预设来加速压缩compressVideo(inputPath, outputPath, 800000, 1280, 720); // 降低比特率到0.8Mbps, 分辨率降低到720p}/*** 高质量压缩视频* * @param inputPath 输入视频文件路径* @param outputPath 输出视频文件路径* @throws Exception 压缩过程中可能抛出的异常*/public void highQualityCompress(String inputPath, String outputPath) throws Exception {compressVideo(inputPath, outputPath, 3000000, -1, -1); // 3Mbps, 保持原始尺寸}/*** 低质量压缩视频(文件更小)* * @param inputPath 输入视频文件路径* @param outputPath 输出视频文件路径* @throws Exception 压缩过程中可能抛出的异常*/public void lowQualityCompress(String inputPath, String outputPath) throws Exception {compressVideo(inputPath, outputPath, 300000, 1280, 720); // 降低比特率到0.3Mbps, 分辨率降低到720p}/*** 压缩并调整视频尺寸* * @param inputPath 输入视频文件路径* @param outputPath 输出视频文件路径* @param maxWidth 最大宽度* @param maxHeight 最大高度* @param targetBitrate 目标比特率* @throws Exception 压缩过程中可能抛出的异常*/public void compressAndResize(String inputPath, String outputPath, int maxWidth, int maxHeight, int targetBitrate) throws Exception {compressVideo(inputPath, outputPath, targetBitrate, maxWidth, maxHeight);}
}
测试
@Testvoid contextLoads() throws Exception {// 基本压缩videoCompressionService.quickCompress("F://1.mp4", "output2.mp4");// // 高质量压缩
// videoCompressionService.highQualityCompress("F://input.mp4", "high_quality.mp4");
//
// // 低质量压缩(更小文件)
// videoCompressionService.lowQualityCompress("F://input.mp4", "low_quality.mp4");
//
// // 自定义压缩参数
// videoCompressionService.compressVideo(
// "F://input.mp4", // 输入文件
// "custom.mp4", // 输出文件
// 2000000, // 比特率 2Mbps
// 1280, // 宽度
// 720 // 高度
// );
//
// // 压缩并调整尺寸
// videoCompressionService.compressAndResize(
// "F://input.mp4", // 输入文件
// "resized.mp4", // 输出文件
// 640, // 最大宽度
// 480, // 最大高度
// 1000000 // 比特率 1Mbps
// );
//
// } catch (Exception e) {
// e.printStackTrace();
// }}