相信我们都会或多或少需要给前端返回视频或者音频的一些信息,那么今天这篇文章通过Java语言使用javacv来获取视频、音频、图片等元数据信息(分辨率、大小、帧等信息)文章来源:https://www.toymoban.com/news/detail-758166.html
一、首先导入依赖
可以先导入javacv/javacv-platform依赖,由于依赖比较大,所以我们可以先去除部分不需要的依赖如下:文章来源地址https://www.toymoban.com/news/detail-758166.html
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>javacv</artifactId>
<version>1.4.4</version>
<exclusions>
<exclusion>
<groupId>org.bytedeco</groupId>
<artifactId>javacpp</artifactId>
</exclusion>
<exclusion>
<groupId>org.bytedeco.javacpp-presets</groupId>
<artifactId>flycapture</artifactId>
</exclusion>
<exclusion>
<groupId>org.bytedeco.javacpp-presets</groupId>
<artifactId>libdc1394</artifactId>
</exclusion>
<exclusion>
<groupId>org.bytedeco.javacpp-presets</groupId>
<artifactId>libfreenect</artifactId>
</exclusion>
<exclusion>
<groupId>org.bytedeco.javacpp-presets</groupId>
<artifactId>libfreenect2</artifactId>
</exclusion>
<exclusion>
<groupId>org.bytedeco.javacpp-presets</groupId>
<artifactId>librealsense</artifactId>
</exclusion>
<exclusion>
<groupId>org.bytedeco.javacpp-presets</groupId>
<artifactId>videoinput</artifactId>
</exclusion>
<exclusion>
<groupId>org.bytedeco.javacpp-presets</groupId>
<artifactId>opencv</artifactId>
</exclusion>
<exclusion>
<groupId>org.bytedeco.javacpp-presets</groupId>
<artifactId>tesseract</artifactId>
</exclusion>
<exclusion>
<groupId>org.bytedeco.javacpp-presets</groupId>
<artifactId>leptonica</artifactId>
</exclusion>
<exclusion>
<groupId>org.bytedeco.javacpp-presets</groupId>
<artifactId>flandmark</artifactId>
</exclusion>
<exclusion>
<groupId>org.bytedeco.javacpp-presets</groupId>
<artifactId>artoolkitplus</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>javacv-platform</artifactId>
<version>1.4.4</version>
<exclusions>
<exclusion>
<groupId>org.bytedeco</groupId>
<artifactId>javacv</artifactId>
</exclusion>
<exclusion>
<groupId>org.bytedeco.javacpp-presets</groupId>
<artifactId>flycapture-platform</artifactId>
</exclusion>
<exclusion>
<groupId>org.bytedeco.javacpp-presets</groupId>
<artifactId>libdc1394-platform</artifactId>
</exclusion>
<exclusion>
<groupId>org.bytedeco.javacpp-presets</groupId>
<artifactId>libfreenect-platform</artifactId>
</exclusion>
<exclusion>
<groupId>org.bytedeco.javacpp-presets</groupId>
<artifactId>libfreenect2-platform</artifactId>
</exclusion>
<exclusion>
<groupId>org.bytedeco.javacpp-presets</groupId>
<artifactId>librealsense-platform</artifactId>
</exclusion>
<exclusion>
<groupId>org.bytedeco.javacpp-presets</groupId>
<artifactId>videoinput-platform</artifactId>
</exclusion>
<exclusion>
<groupId>org.bytedeco.javacpp-presets</groupId>
<artifactId>opencv-platform</artifactId>
</exclusion>
<exclusion>
<groupId>org.bytedeco.javacpp-presets</groupId>
<artifactId>tesseract-platform</artifactId>
</exclusion>
<exclusion>
<groupId>org.bytedeco.javacpp-presets</groupId>
<artifactId>leptonica-platform</artifactId>
</exclusion>
<exclusion>
<groupId>org.bytedeco.javacpp-presets</groupId>
<artifactId>flandmark-platform</artifactId>
</exclusion>
<exclusion>
<groupId>org.bytedeco.javacpp-presets</groupId>
<artifactId>artoolkitplus-platform</artifactId>
</exclusion>
</exclusions>
</dependency>
二、获取视频、音频或图片实体元信息
FFmpegUtil实体
@Slf4j
@Service
public class FFmpegUtil {
private static final String IMAGE_SUFFIX = "png";
/**
* 获取视频时长,单位为秒S
* @param file 视频源
* @return
*/
@SuppressWarnings("resource")
public static long videoDuration(File file) {
long duration = 0L;
FFmpegFrameGrabber ff = new FFmpegFrameGrabber(file);
try {
ff.start();
duration = ff.getLengthInTime() / (1000 * 1000);
ff.stop();
} catch (java.lang.Exception e) {
e.printStackTrace();
}
return duration;
}
/**
* 获取视频帧图片
* @param file 视频源
* @param number 第几帧
* @param dir 文件存放根目录
* @param args 文件存放根目录
* @return
*/
@SuppressWarnings("resource")
public static String videoImage(File file, Integer number, String dir, String args) {
String picPath = StringUtils.EMPTY;
FFmpegFrameGrabber ff = new FFmpegFrameGrabber(file);
try {
ff.start();
int i = 0;
int length = ff.getLengthInFrames();
Frame frame = null;
while (i < length) {
frame = ff.grabFrame();
//截取第几帧图片
if ((i > number) && (frame.image != null)) {
//获取生成图片的路径
picPath = getImagePath(args);
//执行截图并放入指定位置
doExecuteFrame(frame, dir + File.separator + picPath);
break;
}
i++;
}
ff.stop();
} catch (FrameGrabber.Exception e) {
e.printStackTrace();
}
return picPath;
}
/**
* 截取缩略图
* @param frame
* @param targerFilePath 图片存放路径
*/
public static void doExecuteFrame(Frame frame, String targerFilePath) {
//截取的图片
if (null == frame || null == frame.image) {
return;
}
Java2DFrameConverter converter = new Java2DFrameConverter();
BufferedImage srcImage = converter.getBufferedImage(frame);
int srcImageWidth = srcImage.getWidth();
int srcImageHeight = srcImage.getHeight();
//对帧图片进行等比例缩放(缩略图)
int width = 480;
int height = (int) (((double) width / srcImageWidth) * srcImageHeight);
BufferedImage thumbnailImage = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
thumbnailImage.getGraphics().drawImage(srcImage.getScaledInstance(width, height, Image.SCALE_SMOOTH), 0, 0, null);
File output = new File(targerFilePath);
try {
ImageIO.write(thumbnailImage, IMAGE_SUFFIX, output);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 生成图片的相对路径
* @param args 传入生成图片的名称、为空则用UUID命名
* @return 例如 upload/images.png
*/
public static String getImagePath(String args) {
if (StringUtils.isNotEmpty(args)) {
return args + "." + IMAGE_SUFFIX;
}
return getUUID() + "." + IMAGE_SUFFIX;
}
/**
* 生成唯一的uuid
* @return uuid
*/
public static String getUUID(){
return UUID.randomUUID().toString().replace("-","");
}
/**
* 时长格式换算
* @param duration 时长
* @return HH:mm:ss
*/
public static String formatDuration(Long duration) {
String formatTime = StringUtils.EMPTY;
double time = Double.valueOf(duration);
if (time > -1) {
int hour = (int) Math.floor(time / 3600);
int minute = (int) (Math.floor(time / 60) % 60);
int second = (int) (time % 60);
if (hour < 10) {
formatTime = "0";
}
formatTime += hour + ":";
if (minute < 10) {
formatTime += "0";
}
formatTime += minute + ":";
if (second < 10) {
formatTime += "0";
}
formatTime += second;
}
return formatTime;
}
/**
* 获取图片大小Kb
* @param urlPath
* @return
*/
public static String getImageSize(String urlPath){
// 得到数据
byte[] imageFromURL = getImageFromURL(urlPath);
// 转换
String byte2kb = bytes2kb(imageFromURL.length);
return byte2kb;
}
/**
* 根据图片地址获取图片信息
*
* @param urlPath 网络图片地址
* @return
*/
public static byte[] getImageFromURL(String urlPath) {
// 字节数组
byte[] data = null;
// 输入流
InputStream is = null;
// Http连接对象
HttpURLConnection conn = null;
try {
// Url对象
URL url = new URL(urlPath);
// 打开连接
conn = (HttpURLConnection) url.openConnection();
// 打开读取 写入是setDoOutput
// conn.setDoOutput(true);
conn.setDoInput(true);
// 设置请求方式
conn.setRequestMethod("GET");
// 设置超时时间
conn.setConnectTimeout(6000);
// 得到访问的数据流
is = conn.getInputStream();
// 验证访问状态是否是200 正常
if (conn.getResponseCode() == 200) {
data = readInputStream(is);
} else {
data = null;
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (is != null) {
// 关闭流
is.close();
}
} catch (IOException e) {
e.printStackTrace();
}
// 关闭连接
conn.disconnect();
}
return data;
}
/**
* 将流转换为字节
*
* @param is
* @return
*/
public static byte[] readInputStream(InputStream is) {
/**
* 捕获内存缓冲区的数据,转换成字节数组
* ByteArrayOutputStream类是在创建它的实例时,程序内部创建一个byte型别数组的缓冲区,然后利用ByteArrayOutputStream和ByteArrayInputStream的实例向数组中写入或读出byte型数据。
* 在网络传输中我们往往要传输很多变量,我们可以利用ByteArrayOutputStream把所有的变量收集到一起,然后一次性把数据发送出去。
*/
ByteArrayOutputStream baos = new ByteArrayOutputStream();
// 创建字节数组 1024 = 1M
byte[] buffer = new byte[1024];
// 防止无限循环
int length = -1;
try {
// 循环写入数据到字节数组
while ((length = is.read(buffer)) != -1) {
baos.write(buffer, 0, length);
}
// 强制刷新,扫尾工作,主要是为了,让数据流在管道的传输工程中全部传输过去,防止丢失数据
baos.flush();
} catch (IOException e) {
e.printStackTrace();
}
// 字节流转换字节数组
byte[] data = baos.toByteArray();
try {
// 关闭读取流
is.close();
// 关闭写入流
baos.close();
} catch (IOException e) {
e.printStackTrace();
}
return data;
}
/**
* 获取本地图片的字节数
*
* @param imgPath
* @return
*/
public static String pathSize(String imgPath) {
File file = new File(imgPath);
FileInputStream fis;
int fileLen = 0;
try {
fis = new FileInputStream(file);
fileLen = fis.available();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return bytes2kb(fileLen);
}
/**
* 将获取到的字节数转换为KB,MB模式
*
* @param bytes
* @return
*/
public static String bytes2kb(long bytes) {
BigDecimal filesize = new BigDecimal(bytes);
// BigDecimal megabyte = new BigDecimal(1024 * 1024);
// float returnValue = filesize.divide(megabyte, 2, BigDecimal.ROUND_UP).floatValue();
// if (returnValue > 1)
// return (returnValue + "MB");
// BigDecimal kilobyte = new BigDecimal(1024);
// returnValue = filesize.divide(kilobyte, 2, BigDecimal.ROUND_UP).floatValue();
// return (returnValue + "KB");
return filesize.toString();
}
public static String getImageFormat(String imagePath) throws IOException {
// 字节数组
byte[] data = null;
String format = null;
// 输入流
InputStream is = null;
// Http连接对象
HttpURLConnection conn = null;
ImageInputStream imageInputStream = null;
try {
// Url对象
URL url = new URL(imagePath);
// 打开连接
conn = (HttpURLConnection) url.openConnection();
// 打开读取 写入是setDoOutput
// conn.setDoOutput(true);
conn.setDoInput(true);
// 设置请求方式
conn.setRequestMethod("GET");
// 设置超时时间
conn.setConnectTimeout(6000);
// 得到访问的数据流
is = conn.getInputStream();
// 验证访问状态是否是200 正常
if (conn.getResponseCode() == 200) {
imageInputStream = ImageIO.createImageInputStream(is);
ImageReader imageReader = ImageIO.getImageReaders(imageInputStream).next();
format = imageReader.getFormatName();
} else {
format = null;
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (is != null) {
// 关闭流
is.close();
}
if(imageInputStream != null){
imageInputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
// 关闭连接
conn.disconnect();
}
return format;
}
/**
* 将inputStream转化为file
* @param is
* @param file 要输出的文件目录
*/
public static void inputStream2File(InputStream is, File file) throws IOException {
OutputStream os = null;
try {
os = new FileOutputStream(file);
int len = 0;
byte[] buffer = new byte[8192];
while ((len = is.read(buffer)) != -1) {
os.write(buffer, 0, len);
}
} finally {
os.close();
is.close();
}
}
/**
* 获取时长
*/
public static long getDuration(String filePath) throws Exception {
FFmpegFrameGrabber ff = FFmpegFrameGrabber.createDefault(filePath);
ff.start();
long duration = ff.getLengthInTime() / (1000 * 1000);
ff.stop();
return duration;
}
/**
* 获取视频详情
* @param file
* @return
*/
public static VideoInfoVO getVideoInfo(String file) {
VideoInfoVO videoInfoVO = new VideoInfoVO();
FFmpegFrameGrabber grabber = null;
try {
grabber = FFmpegFrameGrabber.createDefault(file);
// 启动 FFmpeg
grabber.start();
// 读取视频帧数
videoInfoVO.setLengthInFrames(grabber.getLengthInVideoFrames());
// 读取视频帧率
videoInfoVO.setFrameRate(grabber.getVideoFrameRate());
// 读取视频秒数
videoInfoVO.setDuration(grabber.getLengthInTime() / 1000000.00);
// 读取视频宽度
videoInfoVO.setWidth(grabber.getImageWidth());
// 读取视频高度
videoInfoVO.setHeight(grabber.getImageHeight());
videoInfoVO.setAudioChannel(grabber.getAudioChannels());
videoInfoVO.setVideoCode(grabber.getVideoCodecName());
videoInfoVO.setAudioCode(grabber.getAudioCodecName());
// String md5 = MD5Util.getMD5ByInputStream(new FileInputStream(file));
videoInfoVO.setSampleRate(grabber.getSampleRate());
return videoInfoVO;
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
try {
if (grabber != null) {
// 此处代码非常重要,如果没有,可能造成 FFmpeg 无法关闭
grabber.stop();
grabber.release();
}
} catch (FFmpegFrameGrabber.Exception e) {
log.error("getVideoInfo grabber.release failed 获取文件信息失败:{}", e.getMessage());
}
}
}
}
VideoInfoVO实体
@Getter
@Setter
public class VideoInfoVO {
/**
* 总帧数
**/
private int lengthInFrames;
/**
* 帧率
**/
private double frameRate;
/**
* 时长
**/
private double duration;
/**
* 视频编码
*/
private String videoCode;
/**
* 音频编码
*/
private String audioCode;
private int width;
private int height;
private int audioChannel;
private String md5;
/**
* 音频采样率
*/
private Integer sampleRate;
private Double fileSize;
public String toJson() {
try {
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.writeValueAsString(this);
} catch (Exception e) {
return "";
}
}
}
InputStream转FileInputStream
/**
* inputStream转FileInputStream
* @param inputStream
* @return
* @throws IOException
*/
public static FileInputStream convertToFileInputStream(InputStream inputStream) throws IOException {
File tempFile = File.createTempFile("temp", ".tmp");
tempFile.deleteOnExit();
try (FileOutputStream outputStream = new FileOutputStream(tempFile)) {
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
}
return new FileInputStream(tempFile);
}
获取文件大小
/**
* 获取文件大小
* @param inputStream
* @return
*/
public String getFileSize(InputStream inputStream){
FileChannel fc = null;
String size = "0";
try {
FileInputStream fis = convertToFileInputStream(inputStream);
fc = fis.getChannel();
BigDecimal fileSize = new BigDecimal(fc.size());
size = String.valueOf(fileSize);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (null != fc) {
try {
fc.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return size;
}
截取视频帧封面
/**
* 截取视频获得指定帧的图片
*
* @param video 源视频文件
* @param picPath 截图存放路径
*/
public String getVideoPic(InputStream video, String picPath) {
FFmpegFrameGrabber ff = new FFmpegFrameGrabber(video);
try {
ff.start();
// 截取中间帧图片(具体依实际情况而定)
int i = 0;
int length = ff.getLengthInFrames();
// int middleFrame = length / 2;
int middleFrame = 5;
Frame frame = null;
while (i < length) {
frame = ff.grabFrame();
if ((i > middleFrame) && (frame.image != null)) {
break;
}
i++;
}
// 截取的帧图片
Java2DFrameConverter converter = new Java2DFrameConverter();
BufferedImage srcImage = converter.getBufferedImage(frame);
int srcImageWidth = srcImage.getWidth();
int srcImageHeight = srcImage.getHeight();
// 对截图进行等比例缩放(缩略图)
int width = 480;
int height = (int) (((double) width / srcImageWidth) * srcImageHeight);
BufferedImage thumbnailImage = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
thumbnailImage.getGraphics().drawImage(srcImage.getScaledInstance(width, height, Image.SCALE_SMOOTH), 0, 0, null);
InputStream inputStream = bufferedImageToInputStream(thumbnailImage);
// File picFile = new File(picPath);
// ImageIO.write(thumbnailImage, "jpg", picFile);
// int available = inputStream.available();
String imgUrl = ossUtils.putThumbInputStream(inputStream, picPath);
ff.stop();
return imgUrl;
} catch (java.lang.Exception e) {
e.printStackTrace();
System.out.println(e);
return null;
}
}
到了这里,关于Java通过javacv获取视频、音频、图片等元数据信息(分辨率、大小、帧等信息)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!