用JAVA获取视频文件中的帧图片并等比缩放

原创 2014年09月29日 18:58:04

最近项目中有一个需要用JAVA获取视频文件中的帧图片的场景,之前没有用过JAVA对视频文件进行编辑,于是上网看看有没有现成的方案,

搜索的结果是要用到第三方的工具库,其中有一个是开源的javacv,做过模式识别和图像处理的肯定知道openCV,而javacv就是利用jni封装了

调用openCV中的方法,而且javacv中还封装了对ffmpeg的调用,于是我就决定研究一下怎么用javacv来获取视频中的帧。

1、获取相关的JAR包和DLL库

我的个人习惯是到Maven的中央仓库上找,果然一下就找到了,下载了bin.zip文件包。

在工程中我用到了其中几个jar包,其实这几个包是一次一次试出来的,因为运行时会报class not found,所以少什么我就加什么。具体如下:

2、如何开始写代码

由于网上我没找到用javacv截视频的demo,后来没办法只能读源码来猜了,于是我又找到这几个包的源码包,首先是从javacv包开始

仔细看了一下,发现了一个相关的英文单词:Grabber(抓取的意思),我猜差不多就是FFmpegFrameGrabber了,开是我打开了这个类(FFmpegFrameGrabber),发现应该是猜对了,可是源码里一点有帮助的注释也没有,但是我发现了有帧相关的方法,如下所示:

于是我就从构造函数开始,然后一步步试,最终可以运行的代码如下

import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.File;

import javax.imageio.ImageIO;

import org.bytedeco.javacpp.opencv_core.IplImage;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.Frame;

public class Grabber {

	/**
	 * 获取指定视频的帧并保存为图片至指定目录
	 * @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) {
			// 过滤前100帧
			f = ff.grabFrame();
			if ((i > 100) && (f.image != null)) {
				break;
			}
			i++;
		}
		IplImage img = f.image;
		int owidth = img.width();
		int oheight = img.height();
		// 对截取的帧进行等比例缩放
		int width = 270;
		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 {
			Grabber.fetchFrame("E:\\ceshi\\11.mp4", "E:\\ceshi\\test.jpg");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

刚开始我也不知道ff.grabFrame()是每次取一帧,而且是按顺序一直往下取,所以对于有的视频会出现帧截图是全黑的,我还以为是我写的有问题,后来我换了好几个视频测试,才发现是因为第一帧本身就是全黑的,于是我加了个过滤,把开始的几十或几百帧过滤掉,取中间的帧图片。

3、关于JNI与DLL

代码写好后不是立马就能运行的,由于这个工具用的是jni,所以我们要把DLL文件放在java.library.path里,我是直接把ffmpeg-windows-x86.jar和opencv-windows-x86.jar里的DLL文件直接解压放在C:\Program Files\Java\jdk1.7.0_60\bin里的,对于64位和linux的环境,则要用javacv-bin文件夹里其他的平台jar:

如果DLL文件放的不对的话,则会报类似如下的错误:

Caused by: java.lang.UnsatisfiedLinkError: no opencv_core249 in java.library.path

也可以在java代码里输出java.library.path,然后把DLL文件放入其中的一个。

4、测试结果

我的测试数据是一个19MB的MP4文件,结果生成的图片只有8KB:


程序的运行结果如下:

4654
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'E:\ceshi\11.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 1
    compatible_brands: isomavc1
    creation_time   : 2010-12-18 05:39:40
  Duration: 00:03:29.54, start: 0.000000, bitrate: 744 kb/s
    Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p, 752x424 [SAR 424:437 DAR 752:437], 680 kb/s, SAR 729:752 DAR 729:424, 25 fps, 25 tbr, 25k tbn, 50 tbc (default)
    Metadata:
      creation_time   : 2010-12-18 05:39:40
      handler_name    : GPAC ISO Video Handler
    Stream #0:1(und): Audio: aac (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 61 kb/s (default)
    Metadata:
      creation_time   : 2010-12-18 05:39:41
      handler_name    : GPAC ISO Audio Handler


版权声明:本文为博主原创文章,未经博主允许不得转载。

Android使用OpengGL Es2.0技术(GLSurfaceView含缩放功能)yuv视频流展示总结

因为项目需求的更改,不得不将以前用SurfaceView的监控视频显示更改为Openg GL ES2.0技术实现,通过使用GLSurfaceView来展示监控视频流的显示。首先在这里感谢 @李狗蛋52...

用Java代码提取视频的缩略图的两种办法

用Java代码提取视频的缩略图的两种办法今天项目中有个需求,让在后台用Java提取每一个视频的缩略图,然后将图片传给前端页面。在网上搜了一下,发现基本上都是使用ffmpeg工具来进行视频格式转换和提取...

用java实现视频截帧的方法

在软件系统中有时在wed端、移动端显示视频时,如果同时显示多个视频,有可能会将多个视频的数据全部装入内存,在一定程度 上回影响系统性能。比较好的一中解决方案是显示视频的一帧图片,点击图片之后即可播放视...

java对视频进行截图

import java.io.File; import java.util.List; //生成视频文件的首帧为图片 //windows下的版本 public class CreatePh { //...

Delphi7高级应用开发随书源码

  • 2003年04月30日 00:00
  • 676KB
  • 下载

Java+Windows+ffmpeg实现视频剪切

又是好久没有将做的工作给记录下来,真是罪过好记性不如烂笔头~ 接触ffmpeg有一段时间了,由于没有细细研究所以很多细节都没有理解,因而出了问题也不知道是什么原因。这次的问题出在视频剪切上,与视...

java用ffmpeg插件来捕获视频第一帧

1.获取视频信息   package com.qs.util.videoUtil; import java.io.*; import java.util.regex.Matcher; import j...

Delphi7高级应用开发随书源码

  • 2003年04月30日 00:00
  • 676KB
  • 下载

Java中使用Opencv从视频文件中获取帧

实现功能:使用Java获取mp4、mov、avi等视频文件中的图像帧,每秒获取一帧图像,并保存 环境要求:需要安装Opencv,安装FFmpeg,下载javacv包 操作系统:本次实验使用的Ubunt...

通过 ffmpeg 获取视频第一帧(指定时间)图片

1、VideoInfo.java 获取视频信息。读者可认真研究此方法。 import java.io.*; import java.util.regex.Matcher; import ja...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:用JAVA获取视频文件中的帧图片并等比缩放
举报原因:
原因补充:

(最多只允许输入30个字)