四、JAVA调用海康威视SDK实现摄像头内网推流到阿里云

接上一章:三、JAVA调用海康威视SDK实现摄像头本地存储

本章实现摄像头内网推流到阿里云服务器。

环境准备

  1. 开发工具:eclipse
  2. Jdk版本:jdk1.8
  3. 开发语言:java,界面使用swing开发
  4. 摄像头:DS-2CD1221D-I3
  5. 海康威视SDK下载地址:海康威视开放平台
  6. SDK版本:CH-HCNetSDKV6.0.2.35_build20190411_Win64
  7. EasyRTMPLive:EasyRTMPLive

转发流程

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5Yab5Yab5ZCbMDE=,size_19,color_FFFFFF,t_70,g_se,x_16

账号准备

  1. 海康威视摄像头账号密码及rtsp推拉地址
  2. 阿里云账号,需开通阿里云视频直播相关功能,需获取阿里云推流地址、推流KEY及推流APPNAME,具体参考:快速入门 - 视频直播 - 阿里云

推流域名配置:

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5Yab5Yab5ZCbMDE=,size_20,color_FFFFFF,t_70,g_se,x_16

 推流域名设置:

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5Yab5Yab5ZCbMDE=,size_20,color_FFFFFF,t_70,g_se,x_16

 推流KEY:

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5Yab5Yab5ZCbMDE=,size_20,color_FFFFFF,t_70,g_se,x_16

 

 

代码实现

EasyPushProcess

package com.kx.hcws;

import java.util.Date;

import com.kx.hcws.easy.EasyRtspToRtmpLiveSDK;
import com.kx.hcws.easy.EasyRtspToRtmpLiveSDK.EASY_FRAME_INFO;
import com.kx.hcws.easy.EasyRtspToRtmpLiveSDK.PushLiveInfoCallBack;
import com.kx.hcws.easy.EasyRtspToRtmpLiveSDK.StatusCallBack;
import com.kx.hcws.ui.Player;

/**
 * 
 * 类: EasyPushProcess,描述:
 * 
 * <p style="padding-left:20px">
 * 推流处理器
 * </p>
 *
 * @author kxy
 *
 * @date 2020年5月27日 上午10:45:51
 *
 * @version V1.0.0
 */
public class EasyPushProcess {
	// 日志
	private static org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger(HCSaveProcess.class);
	public int width = 860, height = 480;

	public boolean pushing = false;

	protected String pushurl = "";

	public long errorcount = 0, counttime = 0, alltime = 0, laststarttime = -1, framesize = 0;

	private Long deviceId;
	private String m_sDeviceIP;
	private String username;
	private String password;
	private int port;
	private long iChannelNum;
	protected String mediaappname;

	private static Player player;

	// 状态回调
	private static StatusCallBack statusCallBack = new StatusCallBack() {
		@Override
		public void invoke(int _channelId, int status) {
			if (status == EasyRtspToRtmpLiveSDK.EASY_RTMP_STATE_DISCONNECTED) {
				logger.info("设备m_sDeviceIPRTMP断开连接 :");
			}
			if (status == EasyRtspToRtmpLiveSDK.EASY_RTMP_STATE_CONNECT_ABORT) {
				logger.info("设备m_sDeviceIPRTMP连接异常中断 :");
			}
			if (status == EasyRtspToRtmpLiveSDK.EASY_RTMP_STATE_CONNECT_FAILED) {
				logger.info("设备m_sDeviceIPRTMP连接失败 :");
			}
			if (status == EasyRtspToRtmpLiveSDK.EASY_RTMP_STATE_START_ERROR) {
				logger.info("设备m_sDeviceIPRTSP启动异常 :");
			}
			if (status == EasyRtspToRtmpLiveSDK.EASY_RTMP_STATE_ERROR) {
				logger.info("设备m_sDeviceIPRTSP链接异常 :");
			}
			if (status == EasyRtspToRtmpLiveSDK.EASY_RTMP_STATE_TIMEOUT) {// 链接超时或者RTMP创建异常
				logger.info("设备m_sDeviceIPRTMP链接超时自动退出:");
			}
		}
	};
	// 推流信息回调
	private static PushLiveInfoCallBack pushLiveInfoCallBack = new PushLiveInfoCallBack() {
		@Override
		public void invoke(int _channelId, int _mediatype, EASY_FRAME_INFO frameinfo) {
			if (frameinfo != null) {
				Double ss = Double.parseDouble(frameinfo.bitrate + "");
				logger.info("推流帧率:" + ss.longValue());
				player.setPushBitrate(ss.longValue());
			}
		}
	};
	// SDK
	private EasyRtspToRtmpLiveSDK easyRtspToRtmpLiveSDK;
	// 推流帧信息
	private EASY_FRAME_INFO frameinfo = null;
	// 通道号
	private int channelId = -1;

	public EasyPushProcess(String m_sDeviceIP, String username, String password, int port, Long deviceId,
			String pushkey, String pushurl, String mediaappname, Player player) {
		this.deviceId = deviceId;
		this.m_sDeviceIP = m_sDeviceIP;
		this.username = username;
		this.password = password;
		this.port = port;
		this.mediaappname = mediaappname;
		this.player = player;

		pushurl = getPushUrl(pushkey, pushurl, mediaappname);

		/**
		 * 海康威视IP摄像头rtsp协议地址如下:
		 * 
		 * rtsp://[username]:[passwd]@[ip]:[port]/[codec]/[channel]/[subtype]/
		 * av_stream
		 * 
		 * 说明:
		 * 
		 * username:用户名,例如admin
		 * 
		 * passwd:密码,例如12345
		 * 
		 * ip:设备的ip地址,例如192.0.0.64
		 * 
		 * port:端口号默认554,若为默认可以不写
		 * 
		 * codec:有h264、MPEG-4、mpeg4这几种
		 * 
		 * channel:通道号,起始为1
		 * 
		 * subtype:码流类型,主码流为main,子码流为sub
		 * 
		 * rtsp://admin:[email protected]:554/h265/ch1/sub/av_stream
		 * 
		 */
		String src = "rtsp://" + username + ":" + password + "@" + m_sDeviceIP + ":554/h265/ch1/main/av_stream";// 组织海康威视rtsp拉流地址

		easyRtspToRtmpLiveSDK = EasyRtspToRtmpLiveSDK.create();
		channelId = easyRtspToRtmpLiveSDK.push(src, pushurl, deviceId.intValue());
		easyRtspToRtmpLiveSDK.registerStatusCallBack(channelId, statusCallBack);
		easyRtspToRtmpLiveSDK.registerInfoCallBack(channelId, pushLiveInfoCallBack);
	}

	public void start() {
		if (pushing) {
			return;
		}

		errorcount = counttime = alltime = framesize = 0;
		laststarttime = System.currentTimeMillis();

		pushing = true;
		new Thread(new Runnable() {
			@Override
			public void run() {
				if (!easyRtspToRtmpLiveSDK.start(channelId)) {// 返回后会自动停止
					stop_();
				}
			}
		}).start();
	}

	public void stop_() {
		pushing = false;
	}

	/**
	 * 
	 * 方法: info ,描述:
	 * 
	 * <p style="padding-left:20px">
	 * 取得推流信息
	 * </p>
	 * kangxiaoyu
	 * 
	 * @return
	 */
	public EASY_FRAME_INFO info() {
		if (channelId >= 0 && isPushing()) {
			return frameinfo;
		}
		return null;
	}

	/**
	 * 是否正在推流
	 * 
	 * @return
	 */
	public boolean isPushing() {
		return pushing && easyRtspToRtmpLiveSDK.ispushing(channelId);
	}

	/**
	 * 
	 * 方法: ispushing_ ,描述:
	 * 
	 * <p style="padding-left:20px">
	 * 判断SDK是否推流
	 * </p>
	 * kangxiaoyu
	 * 
	 * @param channelId
	 * @return
	 */
	public boolean isSdkPushing(int channelId) {
		return easyRtspToRtmpLiveSDK.ispushing(channelId);
	}

	/**
	 * 
	 * 方法: isSdkStop ,描述:
	 * 
	 * <p style="padding-left:20px">
	 * 调用SDK停止推流
	 * </p>
	 * kangxiaoyu
	 * 
	 * @param channelId
	 * @return
	 */
	public String isSdkStop(int channelId) {
		return easyRtspToRtmpLiveSDK.stop(channelId) + "";
	}

	public int getChannelId() {
		return channelId;
	}

	/**
	 * 组织推流地址
	 * 
	 * @param pushkey
	 *            阿里云推流KEY
	 * @param pushurl
	 *            阿里云推流地址
	 * @param mediaappname
	 *            阿里云推流APPNAME
	 * @return
	 */
	public String getPushUrl(String pushkey, String pushurl, String mediaappname) {
		String url = pushurl;
		if (url.contains(";")) {
			url = url.split(";")[(int) (deviceId % pushurl.split(";").length)];
		}
		if (pushkey.contains(";")) {
			pushkey = pushkey.split(";")[(int) (deviceId % pushkey.split(";").length)];
		}
		url += deviceId;

		Date date = new Date();
		String time = date.getTime() + "";
		System.out.println("/" + mediaappname + "/" + deviceId + "-" + time + "-0-0-" + pushkey);
		String auth_key = MD5Utils.getMd5("/" + mediaappname + "/" + deviceId + "-" + time + "-0-0-" + pushkey);
		System.out.println("推流地址:" + url + "?auth_key=" + time + "-0-0-" + auth_key);
		// return url + "?auth_key=" + time + "-0-0-" + auth_key;
		return url;
	}
}

EasyRtspToRtmpLiveSDK

package com.kx.hcws.easy;

import com.sun.jna.Native;
import com.sun.jna.Structure;
import com.sun.jna.win32.StdCallLibrary;

public interface EasyRtspToRtmpLiveSDK extends StdCallLibrary {
	// 日志
	static org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger(EasyRtspToRtmpLiveSDK.class);

	public static int EASY_RTMP_STATE_CONNECTING = 1; /* 连接中 */
	public static int EASY_RTMP_STATE_CONNECTED = 2; /* 连接成功 */
	public static int EASY_RTMP_STATE_CONNECT_FAILED = 3; /* 连接失败 */
	public static int EASY_RTMP_STATE_CONNECT_ABORT = 4; /* 连接异常中断 */
	public static int EASY_RTMP_STATE_PUSHING = 5; /* 推流中 */
	public static int EASY_RTMP_STATE_DISCONNECTED = 6; /* 断开连接 */
	public static int EASY_RTMP_STATE_ERROR = 7;
	public static int EASY_RTMP_STATE_TIMEOUT = -1;
	public static int EASY_RTMP_STATE_START_ERROR = -2;

	public static int EASY_ACTIVATE_INVALID_KEY = -1; /* 无效Key */
	public static int EASY_ACTIVATE_TIME_ERR = -2; /* 时间错误 */
	public static int EASY_ACTIVATE_PROCESS_NAME_LEN_ERR = -3; /* 进程名称长度不匹配 */
	public static int EASY_ACTIVATE_PROCESS_NAME_ERR = -4; /* 进程名称不匹配 */
	public static int EASY_ACTIVATE_VALIDITY_PERIOD_ERR = -5; /* 有效期校验不一致 */
	public static int EASY_ACTIVATE_PLATFORM_ERR = -6; /* 平台不匹配 */
	public static int EASY_ACTIVATE_COMPANY_ID_LEN_ERR = -7; /* 授权使用商不匹配 */
	public static int EASY_ACTIVATE_SUCCESS = 0; /* 激活成功 */

	public static int Easy_NoErr = 0;
	public static int Easy_RequestFailed = -1;
	public static int Easy_Unimplemented = -2;
	public static int Easy_RequestArrived = -3;
	public static int Easy_OutOfState = -4;
	public static int Easy_NotAModule = -5;
	public static int Easy_WrongVersion = -6;
	public static int Easy_IllegalService = -7;
	public static int Easy_BadIndex = -8;
	public static int Easy_ValueNotFound = -9;
	public static int Easy_BadArgument = -10;
	public static int Easy_ReadOnly = -11;
	public static int Easy_NotPreemptiveSafe = -12;
	public static int Easy_NotEnoughSpace = -13;
	public static int Easy_WouldBlock = -14;
	public static int Easy_NotConnected = -15;
	public static int Easy_FileNotFound = -16;
	public static int Easy_NoMoreData = -17;
	public static int Easy_AttrDoesntExist = -18;
	public static int Easy_AttrNameExists = -19;
	public static int Easy_InstanceAttrsNotAllowed = -20;
	public static int Easy_InvalidSocket = -21;
	public static int Easy_MallocError = -22;
	public static int Easy_ConnectError = -23;
	public static int Easy_SendError = -24;

	// EasyRtspToRtmpLiveSDK推流key,需要从官网获取
	public static String RTSPKEY = "6D75724D7A4969576B5A75414B304A646F7232332B2B394659584E35556C525455457870646D55755A58686C4B56634D5671446A652F34675A57467A65513D3D";
	public static String RTMPKEY = "79736C36655969576B5A75414B304A646F7232332B2B394659584E35556C525455457870646D55755A58686C4931634D5671446A652F34675A57467A65513D3D";

	public static LogCallBack logCallBack = new LogCallBack() {
		@Override
		public void invoke(String logText) {
			logger.info(logText);
		}
	};

	public static EasyRtspToRtmpLiveSDK create() {
		System.setProperty("jna.debug_load", "true");
		System.setProperty("jna.protected", "true");
		System.setProperty("jna.encoding", "GBK");
		EasyRtspToRtmpLiveSDK easyRtspToRtmpLiveSDK = (EasyRtspToRtmpLiveSDK) Native
				.loadLibrary("EasyRtspToRtmpLiveSDK", EasyRtspToRtmpLiveSDK.class);

		easyRtspToRtmpLiveSDK.SetDisplayLog(logCallBack);
		int res = easyRtspToRtmpLiveSDK.init(RTSPKEY, RTMPKEY);
		if (res == 0) {
			logger.info("初始化结果:" + (res == 0 ? "初始化成功" : "初始化失败:" + res));
		} else {
			switch (res) {
			case EASY_ACTIVATE_INVALID_KEY:
				logger.info("初始化结果:" + "初始化失败,无效Key");
				break;
			case EASY_ACTIVATE_TIME_ERR:
				logger.info("初始化结果:" + "初始化失败,时间错误");
				break;
			case EASY_ACTIVATE_PROCESS_NAME_LEN_ERR:
				logger.info("初始化结果:" + "初始化失败,进程名称长度不匹配");
				break;
			case EASY_ACTIVATE_PROCESS_NAME_ERR:
				logger.info("初始化结果:" + "初始化失败,进程名称不匹配");
				break;
			case EASY_ACTIVATE_VALIDITY_PERIOD_ERR:
				logger.info("初始化结果:" + "初始化失败,有效期校验不一致");
				break;
			case EASY_ACTIVATE_PLATFORM_ERR:
				logger.info("初始化结果:" + "初始化失败,平台不匹配");
				break;
			case EASY_ACTIVATE_COMPANY_ID_LEN_ERR:
				logger.info("初始化结果:" + "初始化失败,授权使用商不匹配");
				break;
			default:
				logger.info("初始化结果:" + "初始化失败,未知异常-" + res);
				break;
			}
		}
		return easyRtspToRtmpLiveSDK;
	}

	public static void init() {
		System.setProperty("jna.debug_load", "true");
		System.setProperty("jna.protected", "true");
		System.setProperty("jna.encoding", "GBK");

		if (EasyRtspToRtmpLiveSDKManger.INSTANCE == null) {
			try {
				// EasyRtspToRtmpLiveSDKManger.INSTANCE =
				// (EasyRtspToRtmpLiveSDK) Native
				// .loadLibrary("D:\\sdk\\EasyRtspToRtmpLiveSDK",
				// EasyRtspToRtmpLiveSDK.class);

				EasyRtspToRtmpLiveSDKManger.INSTANCE = (EasyRtspToRtmpLiveSDK) Native
						.loadLibrary(".\\EasyRtspToRtmpLiveSDK", EasyRtspToRtmpLiveSDK.class);

			} catch (Exception e) {
				e.printStackTrace();
			} catch (Throwable e) {
				e.printStackTrace();
			}
		}

		EasyRtspToRtmpLiveSDKManger.INSTANCE.SetDisplayLog(logCallBack);
		int res = EasyRtspToRtmpLiveSDKManger.INSTANCE.init(RTSPKEY, RTMPKEY);
		if (res == 0) {
			logger.info("初始化结果:" + (res == 0 ? "初始化成功" : "初始化失败:" + res));
		} else {
			switch (res) {
			case EASY_ACTIVATE_INVALID_KEY:
				logger.info("初始化结果:" + "初始化失败,无效Key");
				break;
			case EASY_ACTIVATE_TIME_ERR:
				logger.info("初始化结果:" + "初始化失败,时间错误");
				break;
			case EASY_ACTIVATE_PROCESS_NAME_LEN_ERR:
				logger.info("初始化结果:" + "初始化失败,进程名称长度不匹配");
				break;
			case EASY_ACTIVATE_PROCESS_NAME_ERR:
				logger.info("初始化结果:" + "初始化失败,进程名称不匹配");
				break;
			case EASY_ACTIVATE_VALIDITY_PERIOD_ERR:
				logger.info("初始化结果:" + "初始化失败,有效期校验不一致");
				break;
			case EASY_ACTIVATE_PLATFORM_ERR:
				logger.info("初始化结果:" + "初始化失败,平台不匹配");
				break;
			case EASY_ACTIVATE_COMPANY_ID_LEN_ERR:
				logger.info("初始化结果:" + "初始化失败,授权使用商不匹配");
				break;
			default:
				logger.info("初始化结果:" + "初始化失败,未知异常-" + res);
				break;
			}
		}
	}

	public void SetDisplayLog(LogCallBack DisplayLog);

	// 超时时间,单位秒
	public void setTimeOut(long timeout_);

	// rtmp:79736C36655969576B5A75414B304A646F7232332B2B394659584E35556C525455457870646D55755A58686C4931634D5671446A652F34675A57467A65513D3D
	// rtsp:6D75724D7A4969576B5A75414B304A646F7232332B2B394659584E35556C525455457870646D55755A58686C4B56634D5671446A652F34675A57467A65513D3D
	public int init(String rtspkey, String rtmpkey);

	public int push(String rtspurl, String rtmpurl, int deviceid);

	public boolean start(int channelId);

	public boolean close(int channelId);

	public boolean stop(int channelId);

	public EASY_FRAME_INFO info(int channelId);

	public boolean ispushing(int channelId);

	public int registerStatusCallBack(int channelId, StatusCallBack _callback);

	public int registerInfoCallBack(int channelId, PushLiveInfoCallBack _callback);

	public boolean stopAll();

	public String fileCreateTime(String filename);

	public static class EASY_FRAME_INFO extends Structure {
		public int codec; /* 音视频格式 */

		public int type; /* 视频帧类型 */
		public byte fps; /* 视频帧率 */
		public short width; /* 视频宽 */
		public short height; /* 视频高 */

		public int reserved1; /* 保留参数1 */
		public int reserved2; /* 保留参数2 */

		public int sample_rate; /* 音频采样率 */
		public int channels; /* 音频声道数 */
		public int bits_per_sample; /* 音频采样精度 */

		public int length; /* 音视频帧大小 */
		public int timestamp_usec; /* 时间戳,微妙 */
		public int timestamp_sec; /* 时间戳 秒 */

		public float bitrate; /* 比特率 */
		public float losspacket; /* 丢包率 */

		@Override
		public String toString() {
			return "EASY_FRAME_INFO [codec=" + codec + ", type=" + type + ", fps=" + fps + ", width=" + width
					+ ", height=" + height + ", reserved1=" + reserved1 + ", reserved2=" + reserved2 + ", sample_rate="
					+ sample_rate + ", channels=" + channels + ", bits_per_sample=" + bits_per_sample + ", length="
					+ length + ", timestamp_usec=" + timestamp_usec + ", timestamp_sec=" + timestamp_sec + ", bitrate="
					+ bitrate + ", losspacket=" + losspacket + "]";
		}
	}

	public static interface PushLiveInfoCallBack extends StdCallCallback {
		public void invoke(int _channelId, int _mediatype, EASY_FRAME_INFO frameinfo);
	}

	public static interface StatusCallBack extends StdCallCallback {
		public void invoke(int _channelId, int status);
	}

	public static interface LogCallBack extends StdCallCallback {
		public void invoke(String logText);
	}

}

EasyRtspToRtmpLiveSDKManger

package com.kx.hcws.easy;

public class EasyRtspToRtmpLiveSDKManger {
	private static org.apache.log4j.Logger logger = org.apache.log4j.Logger
			.getLogger(EasyRtspToRtmpLiveSDKManger.class);

	public static EasyRtspToRtmpLiveSDK INSTANCE = null;

}

效果预览

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5Yab5Yab5ZCbMDE=,size_20,color_FFFFFF,t_70,g_se,x_16

 本地预览:watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5Yab5Yab5ZCbMDE=,size_20,color_FFFFFF,t_70,g_se,x_16

本地预览:watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5Yab5Yab5ZCbMDE=,size_20,color_FFFFFF,t_70,g_se,x_16 本地预览并推流:

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5Yab5Yab5ZCbMDE=,size_20,color_FFFFFF,t_70,g_se,x_16 推流成功:

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5Yab5Yab5ZCbMDE=,size_20,color_FFFFFF,t_70,g_se,x_16 推流监控:

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5Yab5Yab5ZCbMDE=,size_20,color_FFFFFF,t_70,g_se,x_16查看在线流: 

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5Yab5Yab5ZCbMDE=,size_20,color_FFFFFF,t_70,g_se,x_16 获取播放地址:

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5Yab5Yab5ZCbMDE=,size_20,color_FFFFFF,t_70,g_se,x_16 VLC播放:

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5Yab5Yab5ZCbMDE=,size_20,color_FFFFFF,t_70,g_se,x_16

项目源码

源码下载

猜你喜欢

转载自blog.csdn.net/m0_37631110/article/details/118335224#comments_26665804
今日推荐