前言
javacv开发包是用于支持java多媒体开发的一套开发包,可以适用于本地多媒体(音视频)调用以及音视频,图片等文件后期操作(图片修改,音视频解码剪辑等等功能),这里只使用javacv来实现一些简单的功能,具体到项目中还需要大家自己磨合
重要:
建议使用最新javaCV1.5版本,该版本已解决更早版本中已发现的大部分bug --博主目前使用的 javaCV1.5.4
javacv系列文章使用6个jar包:
javacv.jar,javacpp.jar,ffmpeg.jar,ffmpeg-系统平台.jar,opencv.jar,opencv-系统平台.jar。
其中ffmpeg-系统平台.jar,opencv-系统平台.jar中的系统平台根据开发环境或者测试部署环境自行更改为对应的jar包,比如windows7 64位系统替换为ffmpeg-x86-x64.jar
为什么要这样做:因为ffmpeg-系统平台.jar中存放的是c/c++本地so/dll库,而ffmpeg.jar就是使用javacpp封装的对应本地库java接口的实现,而javacpp就是基于jni的一个功能性封装包,方便实现jni,javacv.jar就是对9个视觉库进行了二次封装,但是实现的功能有限,所以建议新手先熟悉openCV和ffmpeg这两个C/C++库的API后再来看javaCV思路就会很清晰了。
上一章简单的介绍了 开启本地本地视频直播:javacv-05:开启真正的本地视频直播,添加音频
下面将介绍如何 :
1、依赖配置说明
maven和gradle方式如果想要减小依赖包大小,则需要手动进行排除不需要的平台依赖即可
(注意:从其他地方下载的依赖包请积极开心的替换为官方jar包和博主提供jar包;如果使用其他jar包版本而导致出错,不要急着找博主问为啥会报错,先把jar包替换了再试试看)
(1)使用maven添加依赖
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>javacv-platform</artifactId>
<version>1.5.4</version>
</dependency>
<!-- 腾讯云的COS对象存储-->
<dependency>
<groupId>com.qcloud</groupId>
<artifactId>cos_api</artifactId>
<version>5.6.35</version>
</dependency>
(2)使用gradle添加依赖
dependencies {
compile group: 'org.bytedeco', name: 'javacv-platform', version: '1.4.4'
}
(3)使用本地jar包方式
最新版实在太大,需要下载全量包的请到官方github.com/bytedeco/javacv下载
注:博主不太赞同使用这种方式!!!(但还是进行了相关介绍)
jar包使用须知:
1、windows x64平台用到的opencv依赖:opencv.jar;oepncv-windows-x86_64.jar(其他平台替换为对应的jar包即可)
2、苹果mac需要opencv-macosx-x86_64.jar
3、linux平台需要:opencv-linux-x86_64.jar4、安卓平台arm架构的需要opencv-android-arm.jar ,基于x86的需要opencv-android-x86.jar
2、为什么不需要安装opencv?
从javacv0.8开始,已经不需要本地安装opencv,直接通过引用opencv对应的系统平台的引用包即可。
(比如oepncv-windows-x86_64.jar就是典型的64位windows环境依赖包)
3、代码实现
本次涉及到两段代码,一个是将rtsp视频流保存在本地并上传至对象存储的代码,另一个是用java实现的定时任务。本次的代码较为稚嫩,望大家轻喷~
第一段为:
import java.io.File;
import java.util.TimerTask;
import com.qcloud.cos.COSClient;
import com.qcloud.cos.ClientConfig;
import com.qcloud.cos.auth.BasicCOSCredentials;
import com.qcloud.cos.auth.COSCredentials;
import com.qcloud.cos.exception.CosClientException;
import com.qcloud.cos.exception.CosServiceException;
import com.qcloud.cos.model.PutObjectRequest;
import com.qcloud.cos.model.PutObjectResult;
import com.qcloud.cos.model.StorageClass;
import com.qcloud.cos.region.Region;
import org.bytedeco.ffmpeg.global.avcodec;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.FFmpegFrameRecorder;
import org.bytedeco.javacv.Frame;
/**
* 成功实现视频流保存至对象存储中,现阶段需要本地路径进行缓存中转,后续考虑RTMP和对象存储直接对接
* 腾讯云的cos目前可以免费使用半年,趁着免费薅羊毛
*/
public class SaveRtspCos extends TimerTask {
private static final String SECRETID = "xxx"; //腾讯云的cos中会给出该值
private static final String SECRETKEY = "xxx"; //腾讯云的cos中会给出该值
private static final String BUCKETNAME = "rtsptest"; //桶的名字
private static final String APPID = "11111"; // 可以在腾讯云官网的右上角点开头像,然后“账户信息”中查看
private static final String REGIONID = "ap-beijing";// 区域
private static final String KEY = "Rtsp.avi"; // COS上面存储的名称
// public static void main(String[] args) {
// uploadFile(); //本地简单测试时可以放在该方法
// }
@Override
public void run() {
String inputFile = "rtsp://xxx"; //rtsp视频流地址
long timestamp = System.currentTimeMillis(); //获取当前时间戳
String outputFile = "recorde" + timestamp + ".avi";
try {
frameRecord(inputFile, outputFile, 1);
uploadFile(outputFile);
System.out.println(outputFile);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 初始化CosClient相关配置, appid、SECRETID、secretKey、region
*
* @return
*/
public static COSClient getCosClient() {
// 1 init userInfo (secretId, secretKey)
COSCredentials cred = new BasicCOSCredentials(APPID, SECRETID, SECRETKEY);
// COSCredentials cred = new BasicCOSCredentials(SECRETID, SECRETKEY); //
// 不传APPID也可以,APPID和ACCESSKE已经关联过
// 2 set bucket region
ClientConfig clientConfig = new ClientConfig(new Region(REGIONID));
// 3 init cosclient
COSClient cosclient = new COSClient(cred, clientConfig);
// bucket name protocol must be {name}-{appid}
return cosclient;
}
/**
* 上传文件
*
* @return
*/
public static String uploadFile(String upFile) {
File localFile = new File(upFile);// 将RTSP视频流保存在本地的内容输入进去
// PutObjectRequest putObjectRequest = new PutObjectRequest(BUCKETNAME, KEY,
// localFile);
PutObjectRequest putObjectRequest = new PutObjectRequest(BUCKETNAME, upFile, localFile);
// 设置存储类型, 默认是标准(Standard), 低频(standard_ia)
putObjectRequest.setStorageClass(StorageClass.Standard_IA);
COSClient cc = getCosClient();
try {
PutObjectResult putObjectResult = cc.putObject(putObjectRequest);
// putobjectResult会返回文件的etag
String etag = putObjectResult.getETag();
System.out.println(etag);
} catch (CosServiceException e) {
e.printStackTrace();
} catch (CosClientException e) {
e.printStackTrace();
}
// 关闭客户端
cc.shutdown();
return null;
}
public static void frameRecord(String inputFile, String outputFile, int audioChannel)
throws Exception, org.bytedeco.javacv.FrameRecorder.Exception {
// 设置为全局控制变量,用于控制录制结束
boolean isStart = true;
// 获取视频源
FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(inputFile);
// 如果不设置成tcp连接时,默认使用UDP,丢包现象比较严重
grabber.setOption("rtsp_transport", "tcp"); // 设置成tcp以后比较稳定
// 流媒体输出地址,分辨率(长,高),是否录制音频(0:不录制/1:录制)
FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(outputFile, 1280, 720, audioChannel);
// 不进行转码时,编码格式默认为HFYU,使用VLC播放器时无法播放下载的视频 --可能和海康的摄像头有关
recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);// avcodec.AV_CODEC_ID_H264,编码
// 开始取视频源
recordByFrame(grabber, recorder, isStart);
}
private static void recordByFrame(FFmpegFrameGrabber grabber, FFmpegFrameRecorder recorder, Boolean status)
throws Exception, org.bytedeco.javacv.FrameRecorder.Exception {
try {// 建议在线程中使用该方法
grabber.start();
recorder.start();
Frame frame = null;
long t1 = System.currentTimeMillis();
while (status && (frame = grabber.grabFrame()) != null) {
long t2 = System.currentTimeMillis();
if (t2 - t1 > 50 * 1000) {
break;
}
recorder.record(frame);
// cframe.showImage(frame);
}
recorder.stop();
grabber.stop();
} finally {
if (grabber != null) {
grabber.stop();
}
}
}
}
第二段代码为:
import java.util.Timer;
import cos.SaveRtspCos;
public class TimeTest {
public static void main(String[] args) {
Timer timer = new Timer();
// timer.schedule(new Task(), 10 * 1000, 10 * 1000);
timer.schedule(new SaveRtspCos(), 1 * 1000, 60 * 1000);
// public void schedule(TimerTask task,long delay,long period)
// 第一个参数就是我们要执行的任务
// 第二个参数是一个long型的值,这是延迟的间
// 第三个参数是间隔的时间
}
}
本次代码中存在的缺陷是:未能很好的实现定时存储视频流文件,只是简易的实现了每个5分钟存储一段视频。该代码后续将会进行优化。
至此,代码已经可以成功运行,在第二段代码中运行即可在腾讯云的cos端看到存储的视频文件,其他人员想看该视频文件时,即可从COS上进行下载。
注:此次代码是基于vscode编辑器进行开发,使用起来很是方便,也是轻量级的;jdk版本为1.8。
大家如有问题可以随时留言~ 关注+点赞+转发 走一波~