相信我們都會或多或少需要給前端返回視頻或者音頻的一些信息,那么今天這篇文章通過Java語言使用javacv來獲取視頻、音頻、圖片等元數(shù)據(jù)信息(分辨率、大小、幀等信息)文章來源:http://www.zghlxwxcb.cn/news/detail-758166.html
一、首先導(dǎo)入依賴
可以先導(dǎo)入javacv/javacv-platform依賴,由于依賴比較大,所以我們可以先去除部分不需要的依賴如下:文章來源地址http://www.zghlxwxcb.cn/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);
//執(zhí)行截圖并放入指定位置
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();
//對幀圖片進(jìn)行等比例縮放(縮略圖)
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){
// 得到數(shù)據(jù)
byte[] imageFromURL = getImageFromURL(urlPath);
// 轉(zhuǎn)換
String byte2kb = bytes2kb(imageFromURL.length);
return byte2kb;
}
/**
* 根據(jù)圖片地址獲取圖片信息
*
* @param urlPath 網(wǎng)絡(luò)圖片地址
* @return
*/
public static byte[] getImageFromURL(String urlPath) {
// 字節(jié)數(shù)組
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);
// 設(shè)置請求方式
conn.setRequestMethod("GET");
// 設(shè)置超時時間
conn.setConnectTimeout(6000);
// 得到訪問的數(shù)據(jù)流
is = conn.getInputStream();
// 驗證訪問狀態(tài)是否是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) {
// 關(guān)閉流
is.close();
}
} catch (IOException e) {
e.printStackTrace();
}
// 關(guān)閉連接
conn.disconnect();
}
return data;
}
/**
* 將流轉(zhuǎn)換為字節(jié)
*
* @param is
* @return
*/
public static byte[] readInputStream(InputStream is) {
/**
* 捕獲內(nèi)存緩沖區(qū)的數(shù)據(jù),轉(zhuǎn)換成字節(jié)數(shù)組
* ByteArrayOutputStream類是在創(chuàng)建它的實例時,程序內(nèi)部創(chuàng)建一個byte型別數(shù)組的緩沖區(qū),然后利用ByteArrayOutputStream和ByteArrayInputStream的實例向數(shù)組中寫入或讀出byte型數(shù)據(jù)。
* 在網(wǎng)絡(luò)傳輸中我們往往要傳輸很多變量,我們可以利用ByteArrayOutputStream把所有的變量收集到一起,然后一次性把數(shù)據(jù)發(fā)送出去。
*/
ByteArrayOutputStream baos = new ByteArrayOutputStream();
// 創(chuàng)建字節(jié)數(shù)組 1024 = 1M
byte[] buffer = new byte[1024];
// 防止無限循環(huán)
int length = -1;
try {
// 循環(huán)寫入數(shù)據(jù)到字節(jié)數(shù)組
while ((length = is.read(buffer)) != -1) {
baos.write(buffer, 0, length);
}
// 強制刷新,掃尾工作,主要是為了,讓數(shù)據(jù)流在管道的傳輸工程中全部傳輸過去,防止丟失數(shù)據(jù)
baos.flush();
} catch (IOException e) {
e.printStackTrace();
}
// 字節(jié)流轉(zhuǎn)換字節(jié)數(shù)組
byte[] data = baos.toByteArray();
try {
// 關(guān)閉讀取流
is.close();
// 關(guān)閉寫入流
baos.close();
} catch (IOException e) {
e.printStackTrace();
}
return data;
}
/**
* 獲取本地圖片的字節(jié)數(shù)
*
* @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);
}
/**
* 將獲取到的字節(jié)數(shù)轉(zhuǎn)換為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 {
// 字節(jié)數(shù)組
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);
// 設(shè)置請求方式
conn.setRequestMethod("GET");
// 設(shè)置超時時間
conn.setConnectTimeout(6000);
// 得到訪問的數(shù)據(jù)流
is = conn.getInputStream();
// 驗證訪問狀態(tài)是否是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) {
// 關(guān)閉流
is.close();
}
if(imageInputStream != null){
imageInputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
// 關(guān)閉連接
conn.disconnect();
}
return format;
}
/**
* 將inputStream轉(zhuǎn)化為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();
// 讀取視頻幀數(shù)
videoInfoVO.setLengthInFrames(grabber.getLengthInVideoFrames());
// 讀取視頻幀率
videoInfoVO.setFrameRate(grabber.getVideoFrameRate());
// 讀取視頻秒數(shù)
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 無法關(guān)閉
grabber.stop();
grabber.release();
}
} catch (FFmpegFrameGrabber.Exception e) {
log.error("getVideoInfo grabber.release failed 獲取文件信息失?。簕}", e.getMessage());
}
}
}
}
VideoInfoVO實體
@Getter
@Setter
public class VideoInfoVO {
/**
* 總幀數(shù)
**/
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轉(zhuǎn)FileInputStream
/**
* inputStream轉(zhuǎn)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();
// 對截圖進(jìn)行等比例縮放(縮略圖)
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;
}
}
到了這里,關(guān)于Java通過javacv獲取視頻、音頻、圖片等元數(shù)據(jù)信息(分辨率、大小、幀等信息)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!