@
目錄
簡介
通過javaCV 視頻工具—截取視頻縮略圖、獲取視頻屬性
依賴引入
<!--javaCV 視頻工具-->
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>javacv-platform</artifactId>
<version>1.5</version>
</dependency>
實現
@Slf4j
public class VideoUtils {
private static final String IMAGEMAT = "png";
private static final String ROTATE = "rotate";
/**
* 默認截取視頻的中間幀為封面
*/
public static final int MOD = 2;
/**
* 視頻縮略圖后綴
*/
private static final String VIDEO_THUMBNAIL_SUF = "th.png";
/**
* 視頻縮略圖前綴
*/
private static final String VIDEO_THUMBNAIL_PRE = "video/thumbnail/";
private static final String SYMBOL = ".";
/**
* 獲取視頻縮略圖
* @param filePath:視頻路徑
* @param mod:視頻長度/mod獲取第幾幀
* @throws Exception
*/
public static String randomGrabberFFmpegImage(String filePath, int mod) {
String targetFilePath = "";
try{
FFmpegFrameGrabber ff = FFmpegFrameGrabber.createDefault(filePath);
ff.start();
//圖片位置是否正確
String rotate = ff.getVideoMetadata(ROTATE);
//獲取幀數
int ffLength = ff.getLengthInFrames();
Frame f;
int i = 0;
//設置截取幀數
int index = ffLength / mod;
while (i < ffLength) {
f = ff.grabImage();
if(i == index){
if (null != rotate && rotate.length() > 1) {
OpenCVFrameConverter.ToIplImage converter = new OpenCVFrameConverter.ToIplImage();
IplImage src = converter.convert(f);
f = converter.convert(rotate(src, Integer.parseInt(rotate)));
}
targetFilePath = getImagePath(filePath, i);
doExecuteFrame(f, targetFilePath);
break;
}
i++;
}
ff.stop();
}catch (Exception e){
log.error("獲取視頻縮略圖異常:" + e.getMessage());
}
return targetFilePath;
}
/**
* 隨機生成生成縮略圖存放路徑
* @param filePath:視頻路徑
* @param index:第幾幀
* @return:縮略圖的存放路徑
*/
private static String getImagePath(String filePath, int index){
String fileName = FileUtils.getName(filePath);
//去后綴
fileName = fileName.substring(0, fileName.indexOf(SYMBOL));
return TencentCosConfig.baseUrl + VIDEO_THUMBNAIL_PRE + DateUtils.datePath() + "/" + fileName + "_" + index + VIDEO_THUMBNAIL_SUF;
}
/**
* 旋轉圖片
* @param src
* @param angle
* @return
*/
public static IplImage rotate(IplImage src, int angle) {
IplImage img = IplImage.create(src.height(), src.width(), src.depth(), src.nChannels());
opencv_core.cvTranspose(src, img);
opencv_core.cvFlip(img, img, angle);
return img;
}
/**
* 截取縮略圖
* @param f
* @param targerFilePath:封面圖片
*/
public static void doExecuteFrame(Frame f, String targerFilePath) {
COSClient cosClient = TencentCosUtils.initCosClient();
if (null == f || null == f.image) {
return;
}
Java2DFrameConverter converter = new Java2DFrameConverter();
BufferedImage bi = converter.getBufferedImage(f);
ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
ImageIO.write(bi, IMAGEMAT, out);
// 獲取文件流
InputStream bufferedImage = new ByteArrayInputStream(out.toByteArray());
int length = out.size();
ObjectMetadata objectMetadata = new ObjectMetadata();
// 從輸入流上傳必須制定content length, 否則http客戶端可能會緩存所有數據,存在內存OOM的情況
objectMetadata.setContentLength(length);
// 默認下載時根據cos路徑key的后綴返回響應的contenttype, 上傳時設置contenttype會覆蓋默認值
PutObjectRequest putObjectRequest = new PutObjectRequest(TencentCosConfig.bucket, targerFilePath, bufferedImage, objectMetadata);
PutObjectResult putObjectResult = cosClient.putObject(putObjectRequest);
log.info("騰訊COS上傳視頻縮略圖成功:{}", putObjectResult.getETag());
//關閉輸入輸出流
bufferedImage.close();
out.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
cosClient.shutdown();
}
}
/**
* 根據視頻長度隨機生成隨機數集合
* @param baseNum:基礎數字,此處為視頻長度
* @param length:隨機數集合長度
* @return:隨機數集合
*/
public static List<Integer> random(int baseNum, int length) {
List<Integer> list = new ArrayList<Integer>(length);
while (list.size() < length) {
Integer next = (int) (Math.random() * baseNum);
if (list.contains(next)) {
continue;
}
list.add(next);
}
Collections.sort(list);
return list;
}
/**
* 獲取視頻時長 單位/秒
* @param video
* @return
*/
public static long getVideoDuration(File video) {
long duration = 0L;
FFmpegFrameGrabber ff = new FFmpegFrameGrabber(video);
try {
ff.start();
duration = ff.getLengthInTime() / (1000 * 1000);
ff.stop();
} catch (FrameGrabber.Exception e) {
e.printStackTrace();
}
return duration;
}
/**
* 獲取視頻時長 單位/秒
* @param inputStream 輸入流
* @return
*/
public static long getVideoDuration(InputStream inputStream) {
long duration = 0L;
FFmpegFrameGrabber ff = new FFmpegFrameGrabber(inputStream);
try {
ff.start();
duration = ff.getLengthInTime() / (1000 * 1000);
ff.stop();
} catch (FrameGrabber.Exception e) {
e.printStackTrace();
}
return duration;
}
/**
* 轉換視頻文件為mp4
* @param file
* @return
*/
public static String convertToMp4(File file) {
FFmpegFrameGrabber frameGrabber = new FFmpegFrameGrabber(file);
String fileName = null;
Frame captured_frame = null;
FFmpegFrameRecorder recorder = null;
try {
frameGrabber.start();
fileName = file.getAbsolutePath() + "__.mp4";
recorder = new FFmpegFrameRecorder(fileName, frameGrabber.getImageWidth(), frameGrabber.getImageHeight(), frameGrabber.getAudioChannels());
recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264); //avcodec.AV_CODEC_ID_H264 //AV_CODEC_ID_MPEG4
recorder.setFormat("mp4");
recorder.setFrameRate(frameGrabber.getFrameRate());
//recorder.setSampleFormat(frameGrabber.getSampleFormat()); //
recorder.setSampleRate(frameGrabber.getSampleRate());
recorder.setAudioChannels(frameGrabber.getAudioChannels());
recorder.setFrameRate(frameGrabber.getFrameRate());
recorder.start();
while ((captured_frame = frameGrabber.grabFrame()) != null) {
try {
recorder.setTimestamp(frameGrabber.getTimestamp());
recorder.record(captured_frame);
} catch (FrameRecorder.Exception e) {
e.printStackTrace();
}
}
recorder.stop();
recorder.release();
frameGrabber.stop();
} catch (Exception | FrameRecorder.Exception e) {
e.printStackTrace();
}
return fileName;
}
}