李振海
2018-01-01 21:02:04
javacv获取视频第一帧
公司网站需要上传视频,上传视频后在电脑浏览器上可以显示视频的封面,但是在手机微信浏览器上看不到封面,
在网上找了半天,说的最多的就俩中方法,这方面资源也挺少的,第一种是用ffmpeg工具,不过还得安装客户端软件,于是放弃了,还有一种是javacv开源工具,
今天讲的是第二种,javacv,
<dependency> <groupId>org.bytedeco</groupId> <artifactId>javacv</artifactId> <version>0.8</version> </dependency>
/** * 获取指定视频的帧并保存为图片至指定目录 * @param videofile 源视频文件路径 * @param framefile 截取帧的图片存放路径 * @throws Exception */ public static void fetchFrame(String videofile, String framefile) throws Exception { long start = System.currentTimeMillis(); File targetFile = new File(framefile); FFmpegFrameGrabber ff = new FFmpegFrameGrabber(videofile); ff.start(); int lenght = ff.getLengthInFrames(); int i = 0; Frame f = null; while (i < lenght) { // 过滤前5帧,避免出现全黑的图片,依自己情况而定 f = ff.grabFrame(); if ((i > 5) && (f.image != null)) { break; } i++; } IplImage img = f.image; int owidth = img.width(); int oheight = img.height(); // 对截取的帧进行等比例缩放 int width = 800; int height = (int) (((double) width / owidth) * oheight); BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR); bi.getGraphics().drawImage(f.image.getBufferedImage().getScaledInstance(width, height, Image.SCALE_SMOOTH), 0, 0, null); ImageIO.write(bi, "jpg", targetFile); //ff.flush(); ff.stop(); System.out.println(System.currentTimeMillis() - start); } public static void main(String[] args) { try { Test.fetchFrame("http://wemewtest.oss-cn-qingdao.aliyuncs.com/2017-06-08-14/wKPPSfepDZ.mp4", "D:/new/test4.jpg"); } catch (Exception e) { e.printStackTrace(); } } }
这是从
http://blog.csdn.net/syz_mumu/article/details/77203247
csdn博客上弄过来的,刚开始运行的时候没问题,可以正常截取,后来把手机视频放上去,截出来的是方向不对
左边是需要的,右边是通过上边工具截出来的,
最后又找了相关资料终于在
http://blog.csdn.net/z562743237/article/details/54667252
这篇博客的启发下,把方向调整过来了,
解决图片旋转问题
通过一段时间的搜索了解到,如果拍摄的视频中带有旋转(rotate)信息,那么截取出来的图片就会被旋转。通过查询API发现FFmpegFrameGrabber的getVideoMetadata("rotate")方法可以获取到视频的旋转信息。根据获取到的rotate信息对ff.grabImage()得到的Frame进行旋转,但是Frame并没有提供旋转接口。但有一个IpImage对象提供了旋转方法
public static IplImage rotate(IplImage src, int rotate) { 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; }
如果需要随机获取视频中的截图,那就去上边那个csdn博客里,我改了他的方法,获取的是视频的第一帧
import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import javax.imageio.ImageIO; import org.bytedeco.javacpp.opencv_core; import org.bytedeco.javacpp.opencv_core.IplImage; import org.bytedeco.javacv.FFmpegFrameGrabber; import org.bytedeco.javacv.Frame; import org.bytedeco.javacv.FrameGrabber.Exception; import org.bytedeco.javacv.Java2DFrameConverter; import org.bytedeco.javacv.OpenCVFrameConverter; public abstract class FrameGrabberKit { public static void main(String[] args) throws Exception { randomGrabberFFmpegImage("C:/Users\\Administrator\\Desktop\\VID_20171229_162251.mp4", "G:\\test", "111"); } public static void randomGrabberFFmpegImage(String filePath, String targerFilePath, String targetFileName) throws Exception { FFmpegFrameGrabber ff = FFmpegFrameGrabber.createDefault(filePath); ff.start(); String rotate =ff.getVideoMetadata("rotate"); Frame f; int i = 0; while (i <1) { f =ff.grabImage(); IplImage src = null; if(null !=rotate &&rotate.length() > 1) { OpenCVFrameConverter.ToIplImage converter =new OpenCVFrameConverter.ToIplImage(); src =converter.convert(f); f =converter.convert(rotate(src, Integer.valueOf(rotate))); } doExecuteFrame(f,targerFilePath,targetFileName); i++; } ff.stop(); } /* * 旋转角度的 */ 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; } public static void doExecuteFrame(Frame f, String targerFilePath, String targetFileName) { if (null ==f ||null ==f.image) { return; } Java2DFrameConverter converter =new Java2DFrameConverter(); String imageMat ="jpg"; String FileName =targerFilePath + File.separator +targetFileName +"." +imageMat; BufferedImage bi =converter.getBufferedImage(f); System.out.println("width:" + bi.getWidth()); System.out.println("height:" + bi.getHeight()); File output =new File(FileName); try { ImageIO.write(bi,imageMat,output); }catch (IOException e) { e.printStackTrace(); } } }
这个是
<dependency> <groupId>org.bytedeco</groupId> <artifactId>javacv-platform</artifactId> <version>1.3.1</version> </dependency>
大家看清楚 jar包的版本,,javacv0.8和java1.3 的 f.image 不一样,大家自己改改,我喜欢用新版本,哈哈,觉得有用的话给点个赞,纯手写的
评论