javacv获取视频第一帧
第一种是用ffmpeg工具,不过还得安装客户端软件,于是放弃了,还有一种是javacv开源工具,所以选择第二种:
第一种:ffmpeg工具
需要安装ffmpeg软件,支持windows和linux,视频安装教程参考:https://www.cnblogs.com/rxbook/p/9652185.html
然后用以下代码:
import java.awt.Image; import java.awt.image.BufferedImage; import java.io.*; import javax.imageio.IIOImage; import javax.imageio.ImageIO; import javax.imageio.ImageWriteParam; import javax.imageio.ImageWriter; public class FirstFrameUtil { protected String ffmpegApp; public FirstFrameUtil(String ffmpegApp) { this.ffmpegApp = ffmpegApp; } @SuppressWarnings("unused") /**** * 获取指定时间内的图片 * @param videoFilename:视频路径 * @param thumbFilename:图片保存路径 * @param width:图片长 * @param height:图片宽 * @param hour:指定时 * @param min:指定分 * @param sec:指定秒 * @throws IOException * @throws InterruptedException */ public void getThumb(String videoFilename, String thumbFilename, int hour, int min, float sec) throws IOException, InterruptedException { ProcessBuilder processBuilder = new ProcessBuilder(ffmpegApp, "-y", "-i", videoFilename, "-vframes", "1", "-ss", hour + ":" + min + ":" + sec, "-f", "mjpeg", "-an", thumbFilename); Process process = processBuilder.start(); InputStream stderr = process.getErrorStream(); InputStreamReader isr = new InputStreamReader(stderr); BufferedReader br = new BufferedReader(isr); String line; while ((line = br.readLine()) != null) ; process.waitFor(); if (br != null) br.close(); if (isr != null) isr.close(); if (stderr != null) stderr.close(); } public static void main(String[] args) { String path = "D:\\config\\ffmpeg-win64\\bin\\ffmpeg.exe"; FirstFrameUtil videoThumbTaker = new FirstFrameUtil(path); try { videoThumbTaker.getThumb("D:\\test2.mp4", "D:\\test\\result.png", 0, 0, 1); File ffmpegFile = new File("D:\\test\\result.png"); FileInputStream input=new FileInputStream(ffmpegFile); System.out.println("over"); } catch (Exception e) { e.printStackTrace(); } } }
即可获取第一帧图片
第二种javacv
直接上代码:(后边有介绍pom文件的引用)
import org.bytedeco.javacpp.opencv_core; import org.bytedeco.javacpp.opencv_core.IplImage; import org.bytedeco.javacv.FFmpegFrameGrabber; import org.bytedeco.javacv.Java2DFrameConverter; import org.bytedeco.javacv.OpenCVFrameConverter; import org.bytedeco.javacv.Frame; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; public class VideoTool { public static void main(String[] args) throws Exception { // randomGrabberFFmpegImage("http://101.132.110.90/group1/M00/00/05/rBN4LFq8p5SAJT0wA5k4vpHKf7Q325.mp4", "D:\\test", "test2"); randomGrabberFFmpegImage("D:\\test2.mp4", "D:\\test", "test2"); //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(); //获取旋转角度信息(90度) String rotate =ff.getVideoMetadata("rotate"); //帧 Frame f; //i可以控制获取第几帧 int i = 0; while (i <5) { //一帧一帧去抓取视频图片,ff.grabImage();每次抓取下一帧 f =ff.grabImage(); IplImage src = null; //旋转图像并输出第29帧 if(i==4){ //手机录的视频有旋转角度,需要旋转处理 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+i); } 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(); } } }
如果不判断旋转,把手机视频放上去,截出来的是方向不对,如图左边是旋转过的,右边没有旋转的:
解决图片旋转问题参考:http://blog.csdn.net/z562743237/article/details/54667252,通过一段时间的搜索了解到,如果拍摄的视频中带有旋转(rotate)信息,那么截取出来的图片就会被旋转。通过查询API发现FFmpegFrameGrabber的getVideoMetadata("rotate")方法可以获取到视频的旋转信息。根据获取到的rotate信息对ff.grabImage()得到的Frame进行旋转,但是Frame并没有提供旋转接口。但IpImage对象提供了旋转方法 。
大多数人都是直接引入
javacv-platform
<dependency> <groupId>org.bytedeco</groupId> <artifactId>javacv-platform</artifactId> <version>1.3.1</version> </dependency>
javacv-platform这种方式依赖的jar包300M,太大了,经过精简后pom文件如下:(在用,40兆左右)
<properties> <javacpp.version>1.3</javacpp.version> </properties> <dependencies> <dependency> <groupId>org.bytedeco</groupId> <artifactId>javacv</artifactId> <version>1.3.1</version> <exclusions> <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>artoolkitplus</artifactId> </exclusion> <exclusion> <groupId>org.bytedeco.javacpp-presets</groupId> <artifactId>artoolkitplus</artifactId> </exclusion> <exclusion> <groupId>org.bytedeco.javacpp-presets</groupId> <artifactId>flandmark</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.bytedeco.javacpp-presets</groupId> <artifactId>opencv</artifactId> <version>3.1.0-${javacpp.version}</version> <classifier>linux-x86_64</classifier> </dependency> <dependency> <groupId>org.bytedeco.javacpp-presets</groupId> <artifactId>opencv</artifactId> <version>3.1.0-${javacpp.version}</version> <classifier>windows-x86_64</classifier> </dependency> <dependency> <groupId>org.bytedeco.javacpp-presets</groupId> <artifactId>ffmpeg</artifactId> <version>3.2.1-${javacpp.version}</version> <classifier>windows-x86_64</classifier> </dependency> <dependency> <groupId>org.bytedeco.javacpp-presets</groupId> <artifactId>ffmpeg</artifactId> <version>3.2.1-${javacpp.version}</version> <classifier>linux-x86_64</classifier> </dependency> </dependencies>
共8个jar