在Java中调用FFmpeg:基于JavaCV实现FFmpeg设置视频moov前置以及截取封面图片
1 JavaCV
JavaCV是一个用于计算机视觉的开源框架,它封装了OpenCV、FFmpeg等库的功能,主要包括javacv和javacv-platform两部分,前者是核心功能,相当于一个Java的调用封装,需要先安装OpenCV或FFMpeg等库,而javacv-platform已经包含了各个Windows、Linux、MacOS等平台下的OpenCV和FFmpeg等原生库,直接引入jar包即可使用。
在项目的pom.xml中加入以下代码,引入包
xml
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>javacv-platform</artifactId>
<version>1.5.9</version>
</dependency>
2 调用JavaCV
java
import org.bytedeco.ffmpeg.avcodec.AVPacket;
import org.bytedeco.ffmpeg.global.avcodec;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.FFmpegFrameRecorder;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.Java2DFrameConverter;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
public class JavaCVTest {
public static void main(String args[]){
FFmpegFrameGrabber grabber = null;
FFmpegFrameRecorder recorder = null;
System.out.println(new File(".").getAbsolutePath());
try {
long startTime = System.nanoTime();
// 输入视频文件
String inputFile = "1.mp4";
// 输出视频文件
String outputFile = "output.mp4";
grabber = new FFmpegFrameGrabber(inputFile);
grabber.start();
recorder = new FFmpegFrameRecorder(outputFile, 0);
recorder.setFormat("mp4");
// 设置movflags为faststart,确保moov前置
recorder.setOption("movflags", "faststart");
// 复制视频和音频编解码参数
recorder.setVideoCodec(grabber.getVideoCodec());
recorder.setAudioCodec(grabber.getAudioCodec());
// 设置媒体参数,如分辨率、采样率等
recorder.setImageWidth(grabber.getImageWidth());
recorder.setImageHeight(grabber.getImageHeight());
recorder.setSampleRate(grabber.getSampleRate());
recorder.setAudioChannels(grabber.getAudioChannels());
recorder.setAudioBitrate(grabber.getAudioBitrate());
// 启动录制器
recorder.start(grabber.getFormatContext());
AVPacket packet;
while ((packet = grabber.grabPacket()) != null) {
// 直接写入数据包,避免编解码
recorder.recordPacket(packet);
avcodec.av_packet_unref(packet); // 释放数据包资源
}
// 截取指定帧作为封面
double timestampInSeconds = 1.0; // 提取第10秒的帧
// 跳到指定的时间点
grabber.setTimestamp((long) (timestampInSeconds * 1000 * 1000));
// 抓取一帧
Frame frame = grabber.grabImage();
if (frame != null) {
// 将帧转换为BufferedImage
Java2DFrameConverter converter = new Java2DFrameConverter();
BufferedImage bufferedImage = converter.getBufferedImage(frame);
// 保存图像
File file = new File("./cover.jpg");
ImageIO.write(bufferedImage, "jpg", file);
System.out.println("缩略图已生成: ");
} else {
System.out.println("未能在指定时间点找到帧");
}
grabber.stop(); // 停止抓取
long endTime = System.nanoTime();
long executionTime = endTime - startTime;
System.out.println("执行时间: " + executionTime / 1_000_000.0 + " ms");
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (recorder != null) {
recorder.close();
}
if (grabber != null) {
grabber.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}