提交 a89a7de3 编写于 作者: eguid_1's avatar eguid_1

1、增加连续截图功能,目前只限通过BytesGrabber进行连续截图

1.1、连续截图提供视频源地址、截图总数、间隔(隔几帧)
1.2、简单测试了连续截图功能暂时未发现问题,近期将实现其他接口的连续截图功能语法糖
2、代码结构调整,抽象出一个桥接接口Grabber,用于方便不同接口实现能够对像素格式进行不同方式的操作
上级 5ea11a65
...@@ -4,7 +4,13 @@ ...@@ -4,7 +4,13 @@
Video recorder and snapshot(video image capture) service,based on javaCV. Video recorder and snapshot(video image capture) service,based on javaCV.
基于javaCV的跨平台视频录像和快照(视频截图)服务,开箱即用。 基于javaCV的跨平台视频录像和快照(视频截图)服务,开箱即用。
### 更新 ### 更新
2019年7月17日更新 2019年7月17日b
1、增加连续截图功能,目前只限通过BytesGrabber进行连续截图
1.1、连续截图提供视频源地址、截图总数、间隔(隔几帧)
1.2、简单测试了连续截图功能暂时未发现问题,近期将实现其他接口的连续截图功能语法糖
2、代码结构调整,抽象出一个桥接接口Grabber,用于方便不同接口实现能够对像素格式进行不同方式的操作
2019年7月17日a
1、调整了截图库代码结构 1、调整了截图库代码结构
2、向下兼容老版本,但不再推荐使用原有的调用方式 2、向下兼容老版本,但不再推荐使用原有的调用方式
3、新增了一个图像像素数据字节数组抓取器(BytesGrabber),它能够获得图像的像素数组 3、新增了一个图像像素数据字节数组抓取器(BytesGrabber),它能够获得图像的像素数组
...@@ -23,7 +29,7 @@ ...@@ -23,7 +29,7 @@
` `
根据需要自行调用和管理,本项目只提供可靠的截图库,而不是大而全的框架。 根据需要自行调用和管理,本项目只提供可靠的截图库,而不是大而全的框架。
2019年4月18日更新 2019年4月18日
1、录像服务的持久层设计不合理,现去除录像服务的持久层接口 1、录像服务的持久层设计不合理,现去除录像服务的持久层接口
2、新增两个与springboot+postgre数据库演示demo 2、新增两个与springboot+postgre数据库演示demo
......
...@@ -8,7 +8,8 @@ import cc.eguid.cv.corelib.videoimageshot.grabber.Base64Grabber; ...@@ -8,7 +8,8 @@ import cc.eguid.cv.corelib.videoimageshot.grabber.Base64Grabber;
import cc.eguid.cv.corelib.videoimageshot.grabber.BufferGrabber; import cc.eguid.cv.corelib.videoimageshot.grabber.BufferGrabber;
import cc.eguid.cv.corelib.videoimageshot.grabber.BufferedImageGrabber; import cc.eguid.cv.corelib.videoimageshot.grabber.BufferedImageGrabber;
import cc.eguid.cv.corelib.videoimageshot.grabber.BytesGrabber; import cc.eguid.cv.corelib.videoimageshot.grabber.BytesGrabber;
import cc.eguid.cv.corelib.videoimageshot.grabber.FFmpeg4VideoImageGrabber; import cc.eguid.cv.corelib.videoimageshot.grabber.ffmpeg.FFmpeg4VideoImageGrabber;
import cc.eguid.cv.corelib.videoimageshot.util.Console;
import cc.eguid.cv.corelib.videoimageshot.util.ImageView; import cc.eguid.cv.corelib.videoimageshot.util.ImageView;
/** /**
...@@ -29,6 +30,11 @@ public class NewSample { ...@@ -29,6 +30,11 @@ public class NewSample {
BytesGrabber grabber=new FFmpeg4VideoImageGrabber(); BytesGrabber grabber=new FFmpeg4VideoImageGrabber();
return grabber.grabBytes(url); return grabber.grabBytes(url);
} }
public static byte[][] bytesImageSample3(String url,int sum,int interval) throws IOException{
BytesGrabber grabber=new FFmpeg4VideoImageGrabber();
return grabber.grabBytes(url, sum, interval);
}
public static BufferedImage bufferImageSample(String url) throws IOException { public static BufferedImage bufferImageSample(String url) throws IOException {
BufferedImageGrabber grabber=new FFmpeg4VideoImageGrabber(url); BufferedImageGrabber grabber=new FFmpeg4VideoImageGrabber(url);
...@@ -71,15 +77,23 @@ public class NewSample { ...@@ -71,15 +77,23 @@ public class NewSample {
//截图保存图片到指定位置并返回base64数据 //截图保存图片到指定位置并返回base64数据
return grabber.shotAndGetBase64Image(url, "test.png", "png",800, 600); return grabber.shotAndGetBase64Image(url, "test.png", "png",800, 600);
} }
public static void main(String[] args) throws IOException { public static void main(String[] args) throws IOException, InterruptedException {
String url="rtmp://live.hkstv.hk.lxdns.com/live/hks1"; String url="rtmp://live.hkstv.hk.lxdns.com/live/hks1";
byte[][] ret=bytesImageSample3(url,5,100);
Console.log(ret.length);
for(byte[] r:ret) {
Console.log("像素数据长度:"+r.length);
ImageView.showBGR(480,288,r);
Thread.sleep(1000);
}
// ImageView.showBGR(480,288,bytesImageSample2(url)); // ImageView.showBGR(480,288,bytesImageSample2(url));
//显示 //显示
// ImageView.show(bufferImageSample(url)); // ImageView.show(bufferImageSample(url));
ImageView.showBGR(480,288,bufferedImageSample(url)); // ImageView.showBGR(480,288,bufferedImageSample(url));
// Console.log(base64ImageSample(url)); // Console.log(base64ImageSample(url));
// Console.log(base64ImageSample4(url)); // Console.log(base64ImageSample4(url));
} }
......
...@@ -8,7 +8,7 @@ import java.io.IOException; ...@@ -8,7 +8,7 @@ import java.io.IOException;
* @author eguid * @author eguid
* *
*/ */
public interface Base64Grabber { public interface Base64Grabber extends Grabber{
/** /**
* 截取已转换为base64的图像数据 * 截取已转换为base64的图像数据
......
...@@ -8,7 +8,7 @@ import java.nio.ByteBuffer; ...@@ -8,7 +8,7 @@ import java.nio.ByteBuffer;
* @author eguid * @author eguid
* *
*/ */
public interface BufferGrabber { public interface BufferGrabber{
/** /**
* 抓取图像缓冲区(确保已经设置了url参数,默认获取BGR数据) * 抓取图像缓冲区(确保已经设置了url参数,默认获取BGR数据)
......
...@@ -3,7 +3,7 @@ package cc.eguid.cv.corelib.videoimageshot.grabber; ...@@ -3,7 +3,7 @@ package cc.eguid.cv.corelib.videoimageshot.grabber;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.IOException; import java.io.IOException;
public interface BufferedImageGrabber { public interface BufferedImageGrabber{
/** /**
* 抓取图像(确保已经设置了url参数,默认获取BGR数据) * 抓取图像(确保已经设置了url参数,默认获取BGR数据)
* @return * @return
......
...@@ -4,10 +4,11 @@ import java.io.IOException; ...@@ -4,10 +4,11 @@ import java.io.IOException;
/** /**
* 图像字节数组抓取 * 图像字节数组抓取
* @author eguid-matebook * @author eguid
* *
*/ */
public interface BytesGrabber { public interface BytesGrabber extends Grabber{
/** /**
* 抓取图像缓冲区(确保已经设置了url参数,默认获取BGR数据) * 抓取图像缓冲区(确保已经设置了url参数,默认获取BGR数据)
* @return * @return
...@@ -32,6 +33,16 @@ public interface BytesGrabber { ...@@ -32,6 +33,16 @@ public interface BytesGrabber {
*/ */
byte[] grabBytes(String url, Integer fmt) throws IOException; byte[] grabBytes(String url, Integer fmt) throws IOException;
/**
* 连续获取图像帧
* @param url -视频地址(默认BGR24像素格式)
* @param sum -截图总次数
* @param interval -间隔(每隔几帧截图一次,需要自行确定视频帧率)
* @return
* @throws IOException
*/
byte[][] grabBytes(String url, int sum, int interval) throws IOException;
/** /**
* 连续获取图像帧 * 连续获取图像帧
* @param url -视频地址 * @param url -视频地址
......
package cc.eguid.cv.corelib.videoimageshot.grabber; package cc.eguid.cv.corelib.videoimageshot.grabber.ffmpeg;
import static org.bytedeco.javacpp.avutil.AV_PIX_FMT_BGR24; import static org.bytedeco.javacpp.avutil.AV_PIX_FMT_BGR24;
...@@ -10,18 +10,21 @@ import org.bytedeco.javacpp.BytePointer; ...@@ -10,18 +10,21 @@ import org.bytedeco.javacpp.BytePointer;
import org.bytedeco.javacpp.avutil.AVFrame; import org.bytedeco.javacpp.avutil.AVFrame;
import cc.eguid.cv.corelib.videoimageshot.core.JavaImgConverter; import cc.eguid.cv.corelib.videoimageshot.core.JavaImgConverter;
import cc.eguid.cv.corelib.videoimageshot.grabber.Base64Grabber;
import cc.eguid.cv.corelib.videoimageshot.grabber.BufferGrabber;
import cc.eguid.cv.corelib.videoimageshot.grabber.BufferedImageGrabber;
import cc.eguid.cv.corelib.videoimageshot.grabber.BytesGrabber;
/** /**
* 使用新版本的ffmpeg-api重写了整个流程 * Updated the code according to the new ffmpeg api to better support the screenshot function
* @author eguid-matebook * @author eguid
*
*/ */
public class FFmpeg4VideoImageGrabber extends GrabberTemplate4 implements Base64Grabber,BufferedImageGrabber,BufferGrabber,BytesGrabber{ public class FFmpeg4VideoImageGrabber extends GrabberTemplate4 implements Base64Grabber,BufferedImageGrabber,BufferGrabber,BytesGrabber{
public final static String DETAULT_FORMAT = "jpg"; public final static String DETAULT_FORMAT = "jpg";
@Override @Override
byte[] saveFrame(AVFrame frameRGB, int width, int height) { public byte[] saveFrame(AVFrame frameRGB, int width, int height) {
BytePointer data = frameRGB.data(0); BytePointer data = frameRGB.data(0);
int size = width * height * 3; int size = width * height * 3;
//复制虚拟机外内存数据到java虚拟机中,因为这个方法之后会清理内存 //复制虚拟机外内存数据到java虚拟机中,因为这个方法之后会清理内存
...@@ -65,9 +68,18 @@ public class FFmpeg4VideoImageGrabber extends GrabberTemplate4 implements Base64 ...@@ -65,9 +68,18 @@ public class FFmpeg4VideoImageGrabber extends GrabberTemplate4 implements Base64
return buf; return buf;
} }
@Override
public byte[][] grabBytes(String url, int sum, int interval) throws IOException {
return grabBytes(url,null,sum,interval);
}
@Override @Override
public byte[][] grabBytes(String url, Integer fmt, int sum, int interval) throws IOException { public byte[][] grabBytes(String url, Integer fmt, int sum, int interval) throws IOException {
return grabVideoFrame(url, fmt, sum, interval); byte[][] bufs=null;
if(validateAndInit(url,fmt)) {
bufs= grabVideoFrame(url, this.fmt, sum, interval);
}
return bufs;
} }
@Override @Override
......
package cc.eguid.cv.corelib.videoimageshot.grabber; package cc.eguid.cv.corelib.videoimageshot.grabber.ffmpeg;
import static org.bytedeco.javacpp.avutil.AV_PIX_FMT_BGR24; import static org.bytedeco.javacpp.avutil.AV_PIX_FMT_BGR24;
...@@ -10,14 +10,18 @@ import org.bytedeco.javacpp.BytePointer; ...@@ -10,14 +10,18 @@ import org.bytedeco.javacpp.BytePointer;
import org.bytedeco.javacpp.avutil.AVFrame; import org.bytedeco.javacpp.avutil.AVFrame;
import cc.eguid.cv.corelib.videoimageshot.core.JavaImgConverter; import cc.eguid.cv.corelib.videoimageshot.core.JavaImgConverter;
import cc.eguid.cv.corelib.videoimageshot.grabber.BufferGrabber;
import cc.eguid.cv.corelib.videoimageshot.grabber.BufferedImageGrabber;
import cc.eguid.cv.corelib.videoimageshot.util.Console; import cc.eguid.cv.corelib.videoimageshot.util.Console;
/** /**
* 视频帧抓取 * 视频帧抓取
* * 推荐使用FFmpeg4VideoImageGrabber
* @see FFmpeg4VideoImageGrabber
* @author eguid * @author eguid
* *
*/ */
@Deprecated
public class FFmpegVideoImageGrabber extends GrabberTmplate implements BufferGrabber,BufferedImageGrabber{ public class FFmpegVideoImageGrabber extends GrabberTmplate implements BufferGrabber,BufferedImageGrabber{
public FFmpegVideoImageGrabber setWidth(Integer width) { public FFmpegVideoImageGrabber setWidth(Integer width) {
......
package cc.eguid.cv.corelib.videoimageshot.grabber; package cc.eguid.cv.corelib.videoimageshot.grabber.ffmpeg;
import static org.bytedeco.javacpp.avcodec.*; import static org.bytedeco.javacpp.avcodec.*;
import static org.bytedeco.javacpp.avformat.*; import static org.bytedeco.javacpp.avformat.*;
...@@ -23,6 +23,7 @@ import cc.eguid.cv.corelib.videoimageshot.exception.CodecNotFoundExpception; ...@@ -23,6 +23,7 @@ import cc.eguid.cv.corelib.videoimageshot.exception.CodecNotFoundExpception;
import cc.eguid.cv.corelib.videoimageshot.exception.FileNotOpenException; import cc.eguid.cv.corelib.videoimageshot.exception.FileNotOpenException;
import cc.eguid.cv.corelib.videoimageshot.exception.StreamInfoNotFoundException; import cc.eguid.cv.corelib.videoimageshot.exception.StreamInfoNotFoundException;
import cc.eguid.cv.corelib.videoimageshot.exception.StreamNotFoundException; import cc.eguid.cv.corelib.videoimageshot.exception.StreamNotFoundException;
import cc.eguid.cv.corelib.videoimageshot.grabber.Grabber;
import cc.eguid.cv.corelib.videoimageshot.util.Console; import cc.eguid.cv.corelib.videoimageshot.util.Console;
/** /**
...@@ -30,7 +31,7 @@ import cc.eguid.cv.corelib.videoimageshot.util.Console; ...@@ -30,7 +31,7 @@ import cc.eguid.cv.corelib.videoimageshot.util.Console;
* @author eguid * @author eguid
* *
*/ */
public abstract class GrabberTemplate4 { public abstract class GrabberTemplate4 implements Grabber{
/* /*
* Register all formats and codecs * Register all formats and codecs
...@@ -332,8 +333,6 @@ public abstract class GrabberTemplate4 { ...@@ -332,8 +333,6 @@ public abstract class GrabberTemplate4 {
*/ */
public byte[][] grabVideoFrame(String url,int fmt,int sum,int interval) throws IOException { public byte[][] grabVideoFrame(String url,int fmt,int sum,int interval) throws IOException {
Console.log("截图总数:"+sum);
//初始化存储数组 //初始化存储数组
byte[][] byteBuffers=null; byte[][] byteBuffers=null;
if(sum>0) { if(sum>0) {
...@@ -347,13 +346,10 @@ public abstract class GrabberTemplate4 { ...@@ -347,13 +346,10 @@ public abstract class GrabberTemplate4 {
} }
try { try {
for(int i=0,num=0 ;num<sum&&av_read_frame(pFormatCtx, packet) == 0;){ for(int i=0,num=0 ;num<sum&&av_read_frame(pFormatCtx, packet) == 0;){
Console.log("读取视频帧次数:"+i);
// Is this a packet from the video stream? // Is this a packet from the video stream?
Console.log("是否视频帧:"+(packet.stream_index()== videoStreamIndex));
if (packet.stream_index() == videoStreamIndex) { if (packet.stream_index() == videoStreamIndex) {
Console.log("是否符合截图要求:"+(i%interval));
if(i%interval==0) { if(i%interval==0) {
Console.log("符合截图要求,正在进行解码");
//把需要解码的视频帧送进解码器 //把需要解码的视频帧送进解码器
//Send video packet to be decoding //Send video packet to be decoding
if(avcodec_send_packet(pCodecCtx, packet)==0) { if(avcodec_send_packet(pCodecCtx, packet)==0) {
...@@ -369,7 +365,6 @@ public abstract class GrabberTemplate4 { ...@@ -369,7 +365,6 @@ public abstract class GrabberTemplate4 {
// Convert the image from its native format to BGR // Convert the image from its native format to BGR
sws_scale(sws_ctx, pFrame.data(), pFrame.linesize(), 0, srcHeight, outFrameRGB.data(),outFrameRGB.linesize()); sws_scale(sws_ctx, pFrame.data(), pFrame.linesize(), 0, srcHeight, outFrameRGB.data(),outFrameRGB.linesize());
//Convert BGR to ByteBuffer //Convert BGR to ByteBuffer
Console.log("转换像素格式");
byteBuffers[num++]= saveFrame(outFrameRGB, width, height); byteBuffers[num++]= saveFrame(outFrameRGB, width, height);
av_free(buffer);//free buffer av_free(buffer);//free buffer
...@@ -381,7 +376,6 @@ public abstract class GrabberTemplate4 { ...@@ -381,7 +376,6 @@ public abstract class GrabberTemplate4 {
// Free the packet that was allocated by av_read_frame // Free the packet that was allocated by av_read_frame
av_packet_unref(packet); av_packet_unref(packet);
} }
Console.log("结束,返回数组");
//读取错误或读取完成 //读取错误或读取完成
return byteBuffers; return byteBuffers;
}finally { }finally {
...@@ -389,14 +383,4 @@ public abstract class GrabberTemplate4 { ...@@ -389,14 +383,4 @@ public abstract class GrabberTemplate4 {
} }
} }
/**
* BGR图像帧转字节缓冲区(BGR结构)
*
* @param pFrame BGR图像帧
* @param width
* @param height
* @return
* @throws IOException
*/
abstract byte[] saveFrame(AVFrame pFrameRGB, int width, int height);
} }
package cc.eguid.cv.corelib.videoimageshot.grabber; package cc.eguid.cv.corelib.videoimageshot.grabber.ffmpeg;
import static org.bytedeco.javacpp.avcodec.*; import static org.bytedeco.javacpp.avcodec.*;
import static org.bytedeco.javacpp.avformat.*; import static org.bytedeco.javacpp.avformat.*;
...@@ -21,6 +21,13 @@ import cc.eguid.cv.corelib.videoimageshot.exception.StreamInfoNotFoundException; ...@@ -21,6 +21,13 @@ import cc.eguid.cv.corelib.videoimageshot.exception.StreamInfoNotFoundException;
import cc.eguid.cv.corelib.videoimageshot.exception.StreamNotFoundException; import cc.eguid.cv.corelib.videoimageshot.exception.StreamNotFoundException;
import cc.eguid.cv.corelib.videoimageshot.util.Console; import cc.eguid.cv.corelib.videoimageshot.util.Console;
/**
* 推荐使用GrabberTmplate4来替换该实现
* @see GrabberTmplate4
* @author eguid
*
*/
@Deprecated
public abstract class GrabberTmplate { public abstract class GrabberTmplate {
/* /*
......
package cc.eguid.cv.corelib.videoimageshot.threaddata; package cc.eguid.cv.corelib.videoimageshot.threaddata;
import cc.eguid.cv.corelib.videoimageshot.grabber.FFmpegVideoImageGrabber; import cc.eguid.cv.corelib.videoimageshot.grabber.ffmpeg.FFmpegVideoImageGrabber;
/** /**
* 当前线程共享数据 * 当前线程共享数据
......
...@@ -4,7 +4,7 @@ import java.awt.image.BufferedImage; ...@@ -4,7 +4,7 @@ import java.awt.image.BufferedImage;
import java.io.IOException; import java.io.IOException;
import cc.eguid.cv.corelib.videoimageshot.core.JavaImgConverter; import cc.eguid.cv.corelib.videoimageshot.core.JavaImgConverter;
import cc.eguid.cv.corelib.videoimageshot.grabber.FFmpegVideoImageGrabber; import cc.eguid.cv.corelib.videoimageshot.grabber.ffmpeg.FFmpegVideoImageGrabber;
import cc.eguid.cv.corelib.videoimageshot.util.ImageView; import cc.eguid.cv.corelib.videoimageshot.util.ImageView;
public class GrabberShotAndViewTest { public class GrabberShotAndViewTest {
......
...@@ -4,7 +4,7 @@ import java.awt.image.BufferedImage; ...@@ -4,7 +4,7 @@ import java.awt.image.BufferedImage;
import java.io.IOException; import java.io.IOException;
import cc.eguid.cv.corelib.videoimageshot.core.JavaImgConverter; import cc.eguid.cv.corelib.videoimageshot.core.JavaImgConverter;
import cc.eguid.cv.corelib.videoimageshot.grabber.FFmpegVideoImageGrabber; import cc.eguid.cv.corelib.videoimageshot.grabber.ffmpeg.FFmpegVideoImageGrabber;
import cc.eguid.cv.corelib.videoimageshot.util.ImageView; import cc.eguid.cv.corelib.videoimageshot.util.ImageView;
public class GrabberTest { public class GrabberTest {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册