Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.zhangzlyuyx.easy.media.zlmediakit.ZLMediaKitClient Maven / Gradle / Ivy
package com.zhangzlyuyx.easy.media.zlmediakit;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.zhangzlyuyx.easy.core.IResult;
import com.zhangzlyuyx.easy.core.Result;
import com.zhangzlyuyx.easy.core.ResultCallback;
import com.zhangzlyuyx.easy.core.util.DateUtils;
import com.zhangzlyuyx.easy.core.util.HttpUtils;
import com.zhangzlyuyx.easy.media.zlmediakit.vo.LoadAndDeplay;
import com.zhangzlyuyx.easy.media.zlmediakit.vo.MediaInfo;
import com.zhangzlyuyx.easy.media.zlmediakit.vo.MediaRecordFile;
import com.zhangzlyuyx.easy.media.zlmediakit.vo.MediaStream;
/**
* ZLMediaKit 流媒体服务器客户端
* @author zhangzlyux
*
*/
public class ZLMediaKitClient {
private final static Logger log = LoggerFactory.getLogger(ZLMediaKitClient.class);
private final static String api_getThreadsLoad = "/index/api/getThreadsLoad";
private final static String api_getWorkThreadsLoad = "/index/api/getWorkThreadsLoad";
private final static String api_getServerConfig = "/index/api/getServerConfig";
private final static String api_setServerConfig = "/index/api/setServerConfig";
private final static String api_restartServer = "/index/api/restartServer";
private final static String api_isMediaOnline = "/index/api/isMediaOnline";
private final static String api_getMediaList = "/index/api/getMediaList";
private final static String api_getMediaInfo = "/index/api/getMediaInfo";
private final static String api_close_streams = "/index/api/close_streams";
private final static String api_getAllSession = "/index/api/getAllSession";
private final static String api_kick_session = "/index/api/kick_session";
private final static String api_kick_sessions = "/index/api/kick_sessions";
private final static String api_addStreamProxy = "/index/api/addStreamProxy";
private final static String api_delStreamProxy = "/index/api/delStreamProxy";
private final static String api_addFFmpegSource = "/index/api/addFFmpegSource";
private final static String api_delFFmpegSource = "/index/api/delFFmpegSource";
private final static String api_getSsrcInfo = "/index/api/getSsrcInfo";
private final static String api_getMp4RecordFile = "/index/api/getMp4RecordFile";
private final static String api_startRecord = "/index/api/startRecord";
private final static String api_stopRecord = "/index/api/stopRecord";
private final static String api_isRecording = "/index/api/isRecording";
private final static String api_getSnap = "/index/api/getSnap";
private ZLMediaKitConfig config;
public ZLMediaKitConfig getConfig() {
return this.config;
}
public void setConfig(ZLMediaKitConfig config) {
this.config = config;
}
public ZLMediaKitClient(ZLMediaKitConfig config) {
this.config = config;
}
/**
* 获取各epoll(或select)线程负载以及延时
* @return
*/
public Result> getThreadsLoad(){
Result ret = this.request(api_getThreadsLoad, new HashMap());
if(!ret.isSuccess()) {
return new Result<>(false, ret.getMsg());
}
JSONArray array = ret.getData().getJSONArray("data");
List list = LoadAndDeplay.parse(array);
return new Result>(true, "请求成功", list);
}
/**
* 获取各后台epoll(或select)线程负载以及延时
* @return
*/
public Result> getWorkThreadsLoad(){
Result ret = this.request(api_getWorkThreadsLoad, new HashMap());
if(!ret.isSuccess()) {
return new Result<>(false, ret.getMsg());
}
JSONArray array = ret.getData().getJSONArray("data");
List list = LoadAndDeplay.parse(array);
return new Result>(true, "请求成功", list);
}
/**
* 动态添加rtsp/rtmp/hls拉流代理(只支持H264/H265/aac/G711负载)
* @param mediaStream 流信息
* @param url 拉流地址,例如rtmp://live.hkstv.hk.lxdns.com/live/hks2
* @param enableRtsp 是否转rtsp
* @param enableRtmp 是否转rtmp
* @param enableHls 是否转hls
* @param enableMp4 是否mp4录制
* @param rtp_type rtsp拉流时,拉流方式,0:tcp,1:udp,2:组播
* @return
*/
public Result addStreamProxy(MediaStream mediaStream, String url, Boolean enableRtsp, Boolean enableRtmp, Boolean enableHls, Boolean enableMp4, Integer rtp_type) {
Map params = new HashMap<>();
params.put("vhost", mediaStream.getVhost());
params.put("app", mediaStream.getApp());
params.put("stream", mediaStream.getStream());
params.put("url", url);
params.put("enable_rtsp", enableRtsp != null && enableRtsp.booleanValue() ? "1" : "0");
params.put("enable_rtmp", enableRtmp == null || enableRtmp.booleanValue() ? "1" : "0");
params.put("enable_hls", enableHls == null || enableHls.booleanValue() ? "1" : "0");
params.put("enable_mp4", enableMp4 != null && enableMp4.booleanValue() ? "1" : "0");
params.put("rtp_type", rtp_type != null ? String.valueOf(rtp_type) : "0");
Result ret = this.request(api_addStreamProxy, params);
if(!ret.isSuccess()) {
return new Result<>(false, ret.getMsg());
}
MediaStream key = MediaStream.parse(ret.getData().getJSONObject("data").getString("key"));
return new Result<>(true, "", key);
}
/**
* 关闭拉流代理
* @param mediaStream 流信息
* @return
*/
public Result delStreamProxy(MediaStream mediaStream) {
Map params = new HashMap<>();
params.put("key", mediaStream.toString());
Result ret = this.request(api_delStreamProxy, params);
if(!ret.isSuccess()) {
return new Result<>(false, ret.getMsg());
}
JSONObject data = ret.getData().getJSONObject("data");
Boolean flag = data.getBoolean("flag");
return new Result<>(true, "", flag);
}
/**
* 通过fork FFmpeg进程的方式拉流代理,支持任意协议
* @param srcUrl FFmpeg拉流地址,支持任意协议或格式(只要FFmpeg支持即可)
* @param dstUrl FFmpeg rtmp推流地址,一般都是推给自己,例如rtmp://127.0.0.1/live/stream_form_ffmpeg
* @param timeoutMs FFmpeg推流成功超时时间
* @return
*/
public Result addFFmpegSource(String srcUrl, String dstUrl, Integer timeoutMs) {
Map params = new HashMap<>();
params.put("src_url", srcUrl);
params.put("dst_url", dstUrl);
params.put("timeout_ms", String.valueOf(timeoutMs));
Result ret = this.request(api_addFFmpegSource, params);
if(!ret.isSuccess()) {
return new Result<>(false, ret.getMsg());
}
String key = ret.getData().getJSONObject("data").getString("key");
return new Result<>(true, "", key);
}
/**
* 关闭ffmpeg拉流代理
* @param key
* @return
*/
public Result delFFmpegSource(String key) {
Map params = new HashMap<>();
params.put("key", key);
Result ret = this.request(api_delFFmpegSource, params);
if(!ret.isSuccess()) {
return new Result<>(false, ret.getMsg());
}
JSONObject data = ret.getData().getJSONObject("data");
Boolean flag = data.getBoolean("flag");
return new Result<>(true, "", flag);
}
/**
* 关闭流(目前所有类型的流都支持关闭)
* @param schema 协议,例如 rtsp或rtmp
* @param mediaStream 流信息
* @return
*/
public Result closeStreams(String schema, MediaStream mediaStream){
return this.closeStreams(schema, mediaStream, null);
}
/**
* 关闭流(目前所有类型的流都支持关闭)
* @param schema 协议,例如 rtsp或rtmp
* @param mediaStream 流信息
* @param force 是否强制关闭(有人在观看是否还关闭)
* @return
*/
public Result closeStreams(String schema, MediaStream mediaStream, Boolean force){
Map params = new HashMap<>();
if(schema != null) {
params.put("schema", schema);
}
if(mediaStream.getVhost() != null) {
params.put("vhost", mediaStream.getVhost());
}
if(mediaStream.getApp() != null) {
params.put("app", mediaStream.getApp());
}
if(mediaStream.getStream() != null) {
params.put("stream", mediaStream.getStream());
}
if(force != null) {
params.put("force", force ? "1": "0");
}
//请求
Result ret = this.request(api_close_streams, params);
if(!ret.isSuccess()) {
return new Result<>(false, ret.getMsg());
}
//json转对象列表
Integer closedCount = ret.getData().getInteger("count_closed");
return new Result<>(true, "", closedCount);
}
/**
* 判断直播流是否在线
* @param schema 协议,例如 rtsp或rtmp
* @param mediaStream
* @return
*/
public Result isMediaOnline(String schema, MediaStream mediaStream){
Map params = new HashMap<>();
params.put("schema", schema != null ? schema : "rtmp");
if(mediaStream.getVhost() != null) {
params.put("vhost", mediaStream.getVhost());
}
if(mediaStream.getApp() != null) {
params.put("app", mediaStream.getApp());
}
if(mediaStream.getStream() != null) {
params.put("stream", mediaStream.getStream());
}
//请求
Result ret = this.request(api_isMediaOnline, params);
if(!ret.isSuccess()) {
return new Result<>(false, ret.getMsg());
}
//json转对象列表
Boolean online = ret.getData().getBoolean("online");
return new Result<>(true, "", online);
}
/**
* 获取流相关信息
* @param schema 协议,例如 rtsp或rtmp
* @param mediaStream
* @return
*/
public Result getMediaInfo(String schema, MediaStream mediaStream){
Map params = new HashMap<>();
params.put("schema", schema != null ? schema : "rtmp");
if(mediaStream.getVhost() != null) {
params.put("vhost", mediaStream.getVhost());
}
if(mediaStream.getApp() != null) {
params.put("app", mediaStream.getApp());
}
if(mediaStream.getStream() != null) {
params.put("stream", mediaStream.getStream());
}
//请求
Result ret = this.request(api_getMediaInfo, params);
if(!ret.isSuccess()) {
return new Result<>(false, ret.getMsg());
}
//json转对象列表
MediaInfo mediaInfo = ret.getData().toJavaObject(MediaInfo.class);
return new Result<>(true, "", mediaInfo);
}
/**
* 获取流列表,可选筛选参数
* @param schema 筛选协议,例如 rtsp或rtmp
* @param vhost 筛选虚拟主机,例如__defaultVhost__
* @param app 筛选应用名,例如 live
* @param merge 是否合并相同的流
* @return
*/
public Result> getMediaList(String schema, String vhost, String app, Boolean merge){
Map params = new HashMap<>();
if(schema != null) {
params.put("schema", schema);
}
if(vhost != null) {
params.put("vhost", vhost);
}
if(app != null) {
params.put("app", app);
}
//请求
Result ret = this.request(api_getMediaList, params);
if(!ret.isSuccess()) {
return new Result<>(false, ret.getMsg());
}
//json转对象列表
List mediaInfos = new ArrayList<>();
Map map = new HashMap<>();
JSONArray array = ret.getData().getJSONArray("data");
for(int i = 0; i < array.size(); i++) {
MediaInfo mediaInfo = array.getObject(i, MediaInfo.class);
mediaInfo.setOnline(true);
//流key
String streamKey = mediaInfo.getStreamKey().toString();
//判断是否需要合并记录
if(merge && map.containsKey(streamKey)) {
MediaInfo existsMediaInfo = map.get(streamKey);
existsMediaInfo.setReaderCount(existsMediaInfo.getReaderCount() + mediaInfo.getReaderCount());
existsMediaInfo.setSchema(existsMediaInfo.getSchema() + "," + mediaInfo.getSchema());
} else {
map.put(streamKey, mediaInfo);
mediaInfos.add(mediaInfo);
}
}
return new Result<>(true, "", mediaInfos);
}
/**
* 搜索文件系统,获取流对应的录像文件列表或日期文件夹列表
* @param mediaStream 流信息
* @param period 流的录像日期,格式为2020-02-01,如果不是完整的日期,那么是搜索录像文件夹列表,否则搜索对应日期下的mp4文件列表
* @return
*/
public Result getMp4RecordFile(MediaStream mediaStream, String period){
Map params = new HashMap<>();
params.put("vhost", mediaStream.getVhost());
params.put("app", mediaStream.getApp());
params.put("stream", mediaStream.getStream());
params.put("period", period != null ? period : DateUtils.format(new Date(), "yyyy-MM-dd"));
//请求
Result ret = this.request(api_getMp4RecordFile, params);
if(!ret.isSuccess()) {
return new Result<>(false, ret.getMsg());
}
MediaRecordFile recordFile = ret.getData().getObject("data", MediaRecordFile.class);
return new Result<>(true, "", recordFile);
}
/**
* 开始录制视频
* @param type 录制类型(0为hls,1为mp4)
* @param mediaStream 流信息
* @param customizedPath 录像保存目录
* @return
*/
public Result startRecord(Integer type, MediaStream mediaStream, String customizedPath){
Map params = new HashMap<>();
params.put("type", String.valueOf(type != null ? type : 1));
params.put("vhost", mediaStream.getVhost());
params.put("app", mediaStream.getApp());
params.put("stream", mediaStream.getStream());
params.put("customized_path", customizedPath);
//请求
Result ret = this.request(api_startRecord, params);
if(!ret.isSuccess()) {
return new Result<>(false, ret.getMsg());
}
Boolean result = ret.getData().getBoolean("result");
return new Result<>(true, "", result);
}
/**
* 停止录制流
* @param type 类型(0为hls,1为mp4)
* @param mediaStream 流信息
* @return
*/
public Result stopRecord(Integer type, MediaStream mediaStream){
Map params = new HashMap<>();
params.put("type", String.valueOf(type != null ? type : 1));
params.put("vhost", mediaStream.getVhost());
params.put("app", mediaStream.getApp());
params.put("stream", mediaStream.getStream());
//请求
Result ret = this.request(api_stopRecord, params);
if(!ret.isSuccess()) {
return new Result<>(false, ret.getMsg());
}
Boolean result = ret.getData().getBoolean("result");
return new Result<>(true, "", result);
}
/**
* 获取流录制状态
* @param type 类型(0为hls,1为mp4)
* @param mediaStream 流信息
* @return
*/
public Result isRecording(Integer type, MediaStream mediaStream){
Map params = new HashMap<>();
params.put("type", String.valueOf(type != null ? type : 1));
params.put("vhost", mediaStream.getVhost());
params.put("app", mediaStream.getApp());
params.put("stream", mediaStream.getStream());
//请求
Result ret = this.request(api_isRecording, params);
if(!ret.isSuccess()) {
return new Result<>(false, ret.getMsg());
}
Boolean status = ret.getData().getBoolean("status");
return new Result<>(true, status ? "正在录制" : "未录制", status);
}
/**
* 获取截图或生成实时截图并返回
* @param url 需要截图的url,可以是本机的,也可以是远程主机的
* @param timeoutSec 截图失败超时时间,防止FFmpeg一直等待截图
* @param expireSec 截图的过期时间,该时间内产生的截图都会作为缓存返回
* @param outputStream 输出流
* @return
*/
public Result getSnap(String url, Integer timeoutSec, Integer expireSec, OutputStream outputStream) {
//headers
Map headers = new HashMap<>();
headers.put("X-Requested-With", "XMLHttpRequest");
//params
Map params = new HashMap<>();
params.put("secret", this.getConfig().getSecret());
params.put("url", url);
params.put("timeout_sec", String.valueOf(timeoutSec));
params.put("expire_sec", String.valueOf(expireSec));
//url
String requestUrl = this.getConfig().getApiServer() + api_getSnap;
//get
Result ret = HttpUtils.httpFileDownload(requestUrl, headers, params, outputStream, false, new ResultCallback>() {
@Override
public IResult> result(Map hs) {
return new Result<>(true, "");
}
});
if(!ret.isSuccess()) {
return new Result<>(false, ret.getMsg());
}
return new Result<>(true, "");
}
/**
* 统一请求
* @param url
* @param jsonObject
* @return
*/
protected Result request(String url, final Map params) {
//url
String requestUrl = url.startsWith(this.getConfig().getApiServer()) ? url : (this.getConfig().getApiServer() + url);
//headers
Map headers = new HashMap<>();
headers.put("X-Requested-With", "XMLHttpRequest");
//params
if(params != null && !params.containsKey("secret")) {
params.put("secret", this.getConfig().getSecret());
}
if(log.isDebugEnabled()) {
log.info("ZLMediaKit api 接口URL: {}", requestUrl);
}
//post
Result retPost = HttpUtils.httpPostReturnString(requestUrl, headers, params);
if(!retPost.isSuccess()) {
if(log.isDebugEnabled()) {
log.info("ZLMediaKit api 响应错误: {}", retPost.getMsg());
}
return new Result<>(false, retPost.getMsg());
}
try {
JSONObject json = JSONObject.parseObject(retPost.getData());
if(log.isDebugEnabled()) {
log.info("ZLMediaKit api 响应成功: {}", json.toJSONString());
}
if(!json.containsKey("code")) {
return new Result<>(false, json.toJSONString());
}
Integer code = json.getInteger("code");
String msg = json.containsKey("msg") ? json.getString("msg") : null;
ZLMediaKitError apiErr = ZLMediaKitError.parse(code);
if(apiErr == null || !apiErr.equals(ZLMediaKitError.Success)) {
return new Result<>(false, msg != null ? msg : apiErr.getMsg());
} else {
return new Result<>(true, "", json);
}
} catch (Exception e) {
if(log.isDebugEnabled()) {
log.info("ZLMediaKit api 响应错误: {}", e.getMessage());
}
return new Result<>(false, e.getMessage());
}
}
public static void main(String[] args) {
ZLMediaKitConfig config = new ZLMediaKitConfig();
config.setLanHost("localhost");
config.setLanHttpPort(880);
ZLMediaKitClient client = new ZLMediaKitClient(config);
System.out.println(client.getThreadsLoad());
}
}