zlm 录像api
This commit is contained in:
parent
c993a15711
commit
14d9a80759
@ -0,0 +1,41 @@
|
||||
package cn.skcks.docking.gb28181.media.dto.record;
|
||||
|
||||
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonNaming;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
|
||||
@Data
|
||||
public class DeleteRecordDirectory {
|
||||
/**
|
||||
* 添加的流的虚拟主机,例如__defaultVhost__
|
||||
*/
|
||||
@Builder.Default
|
||||
private String vhost = "__defaultVhost__";
|
||||
|
||||
/**
|
||||
* 添加的流的应用名,例如live
|
||||
*/
|
||||
private String app;
|
||||
|
||||
/**
|
||||
* 添加的流的id名
|
||||
*/
|
||||
private String stream;
|
||||
|
||||
/**
|
||||
* 流的录像日期,格式为 2020-02-01,如果不是完整的日期,那么是搜索录像文件夹列表,否则搜索对应日期下的 mp4 文件列表
|
||||
*/
|
||||
private String period;
|
||||
|
||||
/**
|
||||
* 自定义搜索路径,与 startRecord 方法中的 customized_path 一样,默认为配置文件的路径
|
||||
*/
|
||||
private String customizedPath;
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package cn.skcks.docking.gb28181.media.dto.record;
|
||||
|
||||
import cn.skcks.docking.gb28181.media.dto.status.ResponseStatus;
|
||||
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonNaming;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
|
||||
@Data
|
||||
public class DeleteRecordDirectoryResp {
|
||||
private ResponseStatus code;
|
||||
private String path;
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
package cn.skcks.docking.gb28181.media.dto.record;
|
||||
|
||||
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonNaming;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
|
||||
@Data
|
||||
public class GetMp4RecordFile {
|
||||
/**
|
||||
* 添加的流的虚拟主机,例如__defaultVhost__
|
||||
*/
|
||||
@Builder.Default
|
||||
private String vhost = "__defaultVhost__";
|
||||
|
||||
/**
|
||||
* 添加的流的应用名,例如live
|
||||
*/
|
||||
private String app;
|
||||
|
||||
/**
|
||||
* 添加的流的id名
|
||||
*/
|
||||
private String stream;
|
||||
|
||||
/**
|
||||
* 流的录像日期,格式为 2020-02-01,如果不是完整的日期,那么是搜索录像文件夹列表,否则搜索对应日期下的 mp4 文件列表
|
||||
*/
|
||||
private String period;
|
||||
|
||||
/**
|
||||
* 自定义搜索路径,与 startRecord 方法中的 customized_path 一样,默认为配置文件的路径
|
||||
*/
|
||||
private String customizedPath;
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package cn.skcks.docking.gb28181.media.dto.record;
|
||||
|
||||
import cn.skcks.docking.gb28181.media.dto.response.ZlmResponse;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@NoArgsConstructor
|
||||
public class GetMp4RecordFileResp extends ZlmResponse<GetMp4RecordFileRespData> {
|
||||
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package cn.skcks.docking.gb28181.media.dto.record;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Data
|
||||
public class GetMp4RecordFileRespData {
|
||||
private List<String> paths;
|
||||
private String rootPath;
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package cn.skcks.docking.gb28181.media.dto.record;
|
||||
|
||||
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonNaming;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Data
|
||||
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
|
||||
public class IsRecording {
|
||||
/**
|
||||
* 添加的流的虚拟主机,例如__defaultVhost__
|
||||
*/
|
||||
@Builder.Default
|
||||
private String vhost = "__defaultVhost__";
|
||||
|
||||
/**
|
||||
* 0 为 hls,1 为 mp4
|
||||
*/
|
||||
@Builder.Default
|
||||
private Integer type = 1;
|
||||
|
||||
/**
|
||||
* 添加的流的应用名,例如live
|
||||
*/
|
||||
private String app;
|
||||
/**
|
||||
* 添加的流的id名
|
||||
*/
|
||||
private String stream;
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package cn.skcks.docking.gb28181.media.dto.record;
|
||||
|
||||
import cn.skcks.docking.gb28181.media.dto.status.ResponseStatus;
|
||||
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonNaming;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Data
|
||||
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
|
||||
public class IsRecordingResp {
|
||||
private ResponseStatus code;
|
||||
private Boolean status;
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
package cn.skcks.docking.gb28181.media.dto.record;
|
||||
|
||||
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonNaming;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Data
|
||||
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
|
||||
public class StartRecord {
|
||||
/**
|
||||
* 添加的流的虚拟主机,例如__defaultVhost__
|
||||
*/
|
||||
@Builder.Default
|
||||
private String vhost = "__defaultVhost__";
|
||||
|
||||
/**
|
||||
* 0 为 hls,1 为 mp4
|
||||
*/
|
||||
@Builder.Default
|
||||
private Integer type = 1;
|
||||
|
||||
/**
|
||||
* 添加的流的应用名,例如live
|
||||
*/
|
||||
private String app;
|
||||
/**
|
||||
* 添加的流的id名
|
||||
*/
|
||||
private String stream;
|
||||
|
||||
/**
|
||||
* 录像保存目录
|
||||
*/
|
||||
private String customizedPath;
|
||||
|
||||
/**
|
||||
* mp4 录像切片时间大小,单位秒,置 0 则采用配置项
|
||||
*/
|
||||
private int maxSecond = 0;
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package cn.skcks.docking.gb28181.media.dto.record;
|
||||
|
||||
import cn.skcks.docking.gb28181.media.dto.status.ResponseStatus;
|
||||
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonNaming;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Data
|
||||
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
|
||||
public class StartRecordResp {
|
||||
private ResponseStatus code;
|
||||
private Boolean result;
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package cn.skcks.docking.gb28181.media.dto.record;
|
||||
|
||||
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonNaming;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Data
|
||||
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
|
||||
public class StopRecord {
|
||||
/**
|
||||
* 添加的流的虚拟主机,例如__defaultVhost__
|
||||
*/
|
||||
@Builder.Default
|
||||
private String vhost = "__defaultVhost__";
|
||||
|
||||
/**
|
||||
* 0 为 hls,1 为 mp4
|
||||
*/
|
||||
@Builder.Default
|
||||
private Integer type = 1;
|
||||
|
||||
/**
|
||||
* 添加的流的应用名,例如live
|
||||
*/
|
||||
private String app;
|
||||
/**
|
||||
* 添加的流的id名
|
||||
*/
|
||||
private String stream;
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package cn.skcks.docking.gb28181.media.dto.record;
|
||||
|
||||
import cn.skcks.docking.gb28181.media.dto.status.ResponseStatus;
|
||||
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonNaming;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Data
|
||||
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
|
||||
public class StopRecordResp {
|
||||
private ResponseStatus code;
|
||||
private Boolean result;
|
||||
}
|
@ -4,6 +4,7 @@ import cn.skcks.docking.gb28181.media.dto.config.ServerConfig;
|
||||
import cn.skcks.docking.gb28181.media.dto.media.GetMediaList;
|
||||
import cn.skcks.docking.gb28181.media.dto.media.MediaResp;
|
||||
import cn.skcks.docking.gb28181.media.dto.proxy.*;
|
||||
import cn.skcks.docking.gb28181.media.dto.record.*;
|
||||
import cn.skcks.docking.gb28181.media.dto.response.ZlmResponse;
|
||||
import cn.skcks.docking.gb28181.media.dto.rtp.*;
|
||||
import cn.skcks.docking.gb28181.media.dto.snap.Snap;
|
||||
@ -17,6 +18,7 @@ import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@FeignClient(name="zlmMediaServerProxy", url = "${media.url}", configuration = IgnoreSSLFeignClientConfig.class)
|
||||
public interface ZlmMediaHttpClient {
|
||||
@ -83,4 +85,18 @@ public interface ZlmMediaHttpClient {
|
||||
@GetMapping("/index/api/delFFmpegSource")
|
||||
ZlmResponse<DelFFmpegSourceResp> delFFmpegSource(@RequestParam String secret, @RequestParam String key);
|
||||
|
||||
@PostMapping("/index/api/startRecord")
|
||||
StartRecordResp startRecord(@RequestParam String secret, @RequestBody StartRecord params);
|
||||
|
||||
@PostMapping("/index/api/stopRecord")
|
||||
StopRecordResp stopRecord(@RequestParam String secret, @RequestBody StopRecord params);
|
||||
|
||||
@PostMapping("/index/api/isRecording")
|
||||
IsRecordingResp isRecording(@RequestParam String secret, @RequestBody IsRecording params);
|
||||
|
||||
@PostMapping("/index/api/getMp4RecordFile")
|
||||
GetMp4RecordFileResp getMp4RecordFile(@RequestParam String secret, @RequestBody GetMp4RecordFile params);
|
||||
|
||||
@PostMapping("/index/api/deleteRecordDirectory")
|
||||
DeleteRecordDirectoryResp deleteRecordDirectory(@RequestParam String secret, @RequestBody DeleteRecordDirectory params);
|
||||
}
|
||||
|
@ -4,14 +4,19 @@ import cn.skcks.docking.gb28181.media.dto.config.ServerConfig;
|
||||
import cn.skcks.docking.gb28181.media.dto.media.GetMediaList;
|
||||
import cn.skcks.docking.gb28181.media.dto.media.MediaResp;
|
||||
import cn.skcks.docking.gb28181.media.dto.proxy.*;
|
||||
import cn.skcks.docking.gb28181.media.dto.record.*;
|
||||
import cn.skcks.docking.gb28181.media.dto.response.ZlmResponse;
|
||||
import cn.skcks.docking.gb28181.media.dto.rtp.*;
|
||||
import cn.skcks.docking.gb28181.media.dto.snap.Snap;
|
||||
import cn.skcks.docking.gb28181.media.dto.version.VersionResp;
|
||||
import lombok.Builder;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Builder
|
||||
@SuppressWarnings("unused")
|
||||
@ -173,5 +178,41 @@ public class ZlmMediaService {
|
||||
public ZlmResponse<DelFFmpegSourceResp> delFfmpegSource(String key){
|
||||
return exchange.delFFmpegSource(secret, key);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 开始录制 hls 或 MP4
|
||||
*/
|
||||
public StartRecordResp startRecord(@RequestBody StartRecord params){
|
||||
return exchange.startRecord(secret, params);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 停止录制流
|
||||
*/
|
||||
public StopRecordResp stopRecord(@RequestBody StopRecord params){
|
||||
return exchange.stopRecord(secret, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取流录制状态
|
||||
*/
|
||||
public IsRecordingResp isRecording(@RequestBody IsRecording params){
|
||||
return exchange.isRecording(secret, params);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 搜索文件系统,获取流对应的录像文件列表或日期文件夹列表
|
||||
*/
|
||||
public GetMp4RecordFileResp getMp4RecordFile(@RequestBody GetMp4RecordFile params){
|
||||
return exchange.getMp4RecordFile(secret, params);
|
||||
}
|
||||
|
||||
|
||||
public DeleteRecordDirectoryResp deleteRecordDirectory(@RequestBody DeleteRecordDirectory params){
|
||||
return exchange.deleteRecordDirectory(secret, params);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,7 @@ project:
|
||||
|
||||
media:
|
||||
ip: 10.10.10.200
|
||||
url: 'http://10.10.10.200:5080'
|
||||
url: 'http://10.10.10.200:5081'
|
||||
# url: 'http://10.10.10.200:12580/anything/'
|
||||
id: amrWMKmbKqoBjRQ9
|
||||
secret: 4155cca6-2f9f-11ee-85e6-8de4ce2e7333
|
||||
|
@ -1,6 +1,7 @@
|
||||
package cn.skcks.docking.gb28181.test;
|
||||
|
||||
import cn.hutool.core.codec.Base64;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||
import cn.skcks.docking.gb28181.common.json.JsonResponse;
|
||||
import cn.skcks.docking.gb28181.common.json.JsonUtils;
|
||||
@ -10,6 +11,7 @@ import cn.skcks.docking.gb28181.media.dto.config.ServerConfig;
|
||||
import cn.skcks.docking.gb28181.media.dto.media.GetMediaList;
|
||||
import cn.skcks.docking.gb28181.media.dto.media.MediaResp;
|
||||
import cn.skcks.docking.gb28181.media.dto.proxy.*;
|
||||
import cn.skcks.docking.gb28181.media.dto.record.*;
|
||||
import cn.skcks.docking.gb28181.media.dto.response.ZlmResponse;
|
||||
import cn.skcks.docking.gb28181.media.dto.response.ZlmResponseConvertor;
|
||||
import cn.skcks.docking.gb28181.media.dto.rtp.*;
|
||||
@ -31,6 +33,10 @@ import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Slf4j
|
||||
@SpringBootTest
|
||||
@ -41,6 +47,7 @@ public class MediaServiceTest {
|
||||
private ZlmMediaService zlmMediaService;
|
||||
@Autowired
|
||||
private ZlmMediaConfig config;
|
||||
private final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
|
||||
|
||||
@Test
|
||||
void test(){
|
||||
@ -212,4 +219,73 @@ public class MediaServiceTest {
|
||||
GetRtpInfoResp rtpInfo = zlmMediaService.getRtpInfo("test");
|
||||
log.info("{}", rtpInfo);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@Test
|
||||
void recordTest(){
|
||||
CountDownLatch countDownLatch = new CountDownLatch(1);
|
||||
|
||||
String customizedPath = "/tmp/record";
|
||||
|
||||
DeleteRecordDirectoryResp deleteRecordDirectoryResp = zlmMediaService.deleteRecordDirectory(DeleteRecordDirectory.builder()
|
||||
.app("live")
|
||||
.stream("test")
|
||||
.period(DateUtil.formatDate(DateUtil.date()))
|
||||
.customizedPath(customizedPath).build());
|
||||
log.info("{}", deleteRecordDirectoryResp);
|
||||
// ZlmResponse<AddStreamProxyResp> addedStreamProxy = zlmMediaService.addStreamProxy(AddStreamProxy.builder()
|
||||
// .app("live")
|
||||
// .stream("test")
|
||||
// .vhost("__defaultVhost__")
|
||||
// .url("rtsp://10.10.10.200:554/camera/121")
|
||||
// .build());
|
||||
// log.info("addedStreamProxy {}", addedStreamProxy);
|
||||
ZlmResponse<AddFFmpegSourceResp> addFFmpegSourceRespZlmResponse = zlmMediaService.addFfmpegSource(AddFFmpegSource.builder()
|
||||
.dstUrl("rtmp://10.10.10.200:1936/live/test")
|
||||
.srcUrl("http://10.10.10.200:18183/video")
|
||||
.timeoutMs(30 * 1000L)
|
||||
.enableHls(false)
|
||||
.enableMp4(false)
|
||||
.build());
|
||||
log.info("addFfmpegSource {}", addFFmpegSourceRespZlmResponse);
|
||||
|
||||
ZlmResponse<List<MediaResp>> mediaList = zlmMediaService.getMediaList(GetMediaList.builder()
|
||||
.schema("rtsp")
|
||||
.app("live")
|
||||
.stream("test")
|
||||
.build());
|
||||
log.info("mediaList {}", mediaList);
|
||||
|
||||
|
||||
StartRecordResp startRecordResp = zlmMediaService.startRecord(StartRecord.builder()
|
||||
.app("live")
|
||||
.stream("test")
|
||||
.vhost("__defaultVhost__")
|
||||
.customizedPath(customizedPath)
|
||||
.build());
|
||||
|
||||
log.info("startRecordResp {}", startRecordResp);
|
||||
|
||||
scheduledExecutorService.schedule(() -> {
|
||||
zlmMediaService.delFfmpegSource(addFFmpegSourceRespZlmResponse.getData().getKey());
|
||||
// log.info("{}", zlmMediaService.delStreamProxy(addedStreamProxy.getData().getKey()));
|
||||
|
||||
zlmMediaService.getMp4RecordFile(GetMp4RecordFile.builder()
|
||||
.app("live")
|
||||
.stream("test")
|
||||
.period(DateUtil.formatDate(DateUtil.date()))
|
||||
.customizedPath(customizedPath).build());
|
||||
|
||||
zlmMediaService.stopRecord(StopRecord.builder()
|
||||
.app("live")
|
||||
.stream("test")
|
||||
.vhost("__defaultVhost__")
|
||||
.build());
|
||||
countDownLatch.countDown();
|
||||
}, 15, TimeUnit.SECONDS);
|
||||
|
||||
|
||||
|
||||
countDownLatch.await();
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user