添加 rtmp-port 参数
调整 视频下载 download 尽可能以最快速度收流
This commit is contained in:
parent
071e2a2491
commit
205c903294
@ -0,0 +1,12 @@
|
|||||||
|
package cn.skcks.docking.gb28181.wvp.config;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Configuration
|
||||||
|
@ConfigurationProperties(prefix = "media")
|
||||||
|
public class MediaRtmpConfig {
|
||||||
|
private int rtmpPort = 1935;
|
||||||
|
}
|
@ -27,8 +27,10 @@ import cn.skcks.docking.gb28181.sdp.GB28181SDPBuilder;
|
|||||||
import cn.skcks.docking.gb28181.sdp.media.MediaStreamMode;
|
import cn.skcks.docking.gb28181.sdp.media.MediaStreamMode;
|
||||||
import cn.skcks.docking.gb28181.service.record.vo.RecordInfoItemVO;
|
import cn.skcks.docking.gb28181.service.record.vo.RecordInfoItemVO;
|
||||||
import cn.skcks.docking.gb28181.service.ssrc.SsrcService;
|
import cn.skcks.docking.gb28181.service.ssrc.SsrcService;
|
||||||
|
import cn.skcks.docking.gb28181.wvp.config.MediaRtmpConfig;
|
||||||
import cn.skcks.docking.gb28181.wvp.config.ProxySipConfig;
|
import cn.skcks.docking.gb28181.wvp.config.ProxySipConfig;
|
||||||
import cn.skcks.docking.gb28181.wvp.config.WvpProxyConfig;
|
import cn.skcks.docking.gb28181.wvp.config.WvpProxyConfig;
|
||||||
|
import cn.skcks.docking.gb28181.wvp.executor.DefaultVideoExecutor;
|
||||||
import cn.skcks.docking.gb28181.wvp.orm.mybatis.dynamic.model.WvpProxyDevice;
|
import cn.skcks.docking.gb28181.wvp.orm.mybatis.dynamic.model.WvpProxyDevice;
|
||||||
import cn.skcks.docking.gb28181.wvp.orm.mybatis.dynamic.model.WvpProxyDocking;
|
import cn.skcks.docking.gb28181.wvp.orm.mybatis.dynamic.model.WvpProxyDocking;
|
||||||
import cn.skcks.docking.gb28181.wvp.service.device.DeviceService;
|
import cn.skcks.docking.gb28181.wvp.service.device.DeviceService;
|
||||||
@ -56,6 +58,7 @@ import jakarta.servlet.http.HttpServletResponse;
|
|||||||
import lombok.*;
|
import lombok.*;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.web.context.request.async.DeferredResult;
|
import org.springframework.web.context.request.async.DeferredResult;
|
||||||
@ -90,6 +93,10 @@ public class Gb28181DownloadService {
|
|||||||
private final VideoService videoService;
|
private final VideoService videoService;
|
||||||
private final WvpProxyConfig wvpProxyConfig;
|
private final WvpProxyConfig wvpProxyConfig;
|
||||||
private final RecordInfoService recordInfoService;
|
private final RecordInfoService recordInfoService;
|
||||||
|
private final MediaRtmpConfig mediaRtmpConfig;
|
||||||
|
|
||||||
|
@Qualifier(DefaultVideoExecutor.EXECUTOR_BEAN_NAME)
|
||||||
|
private final Executor executor;
|
||||||
|
|
||||||
private final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
|
private final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
|
||||||
private final ConcurrentMap<String, DeferredResult<JsonResponse<String>>> requestMap = new ConcurrentHashMap<>();
|
private final ConcurrentMap<String, DeferredResult<JsonResponse<String>>> requestMap = new ConcurrentHashMap<>();
|
||||||
@ -129,7 +136,8 @@ public class Gb28181DownloadService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private String videoUrl(String streamId) {
|
private String videoUrl(String streamId) {
|
||||||
return StringUtils.joinWith("/", zlmMediaConfig.getUrl(), "rtp", streamId + ".live.mp4");
|
String rtmpSchema = "rtmp://" + zlmMediaConfig.getIp() + ":" + mediaRtmpConfig.getRtmpPort();
|
||||||
|
return StringUtils.joinWith("/", rtmpSchema, "rtp", streamId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
@ -206,6 +214,7 @@ public class Gb28181DownloadService {
|
|||||||
|
|
||||||
download(deviceCode, startTime, endTime, useDownload).whenComplete((videoInfo, e) -> {
|
download(deviceCode, startTime, endTime, useDownload).whenComplete((videoInfo, e) -> {
|
||||||
writeFileHeader(response, deviceCode, startTime, endTime, fileHeader);
|
writeFileHeader(response, deviceCode, startTime, endTime, fileHeader);
|
||||||
|
log.info("videoInfo {}", videoInfo);
|
||||||
if (e != null) {
|
if (e != null) {
|
||||||
writeErrorToResponse(asyncResponse, JsonResponse.error(e.getMessage()));
|
writeErrorToResponse(asyncResponse, JsonResponse.error(e.getMessage()));
|
||||||
} else if (videoInfo == null) {
|
} else if (videoInfo == null) {
|
||||||
@ -350,7 +359,9 @@ public class Gb28181DownloadService {
|
|||||||
} else if(videoInfo == null){
|
} else if(videoInfo == null){
|
||||||
writeErrorToResponse(asyncResponse, JsonResponse.error("下载失败"));
|
writeErrorToResponse(asyncResponse, JsonResponse.error("下载失败"));
|
||||||
} else if(wvpProxyConfig.getUseFfmpeg()){
|
} else if(wvpProxyConfig.getUseFfmpeg()){
|
||||||
videoService.ffmpegRecord(asyncResponse, videoInfo.getUrl(), DateUtil.between(startTime,endTime,DateUnit.SECOND) + 60,videoInfo.getDevice(),videoInfo.getCallId());
|
scheduledExecutorService.submit(()->{
|
||||||
|
videoService.ffmpegRecord(asyncResponse, videoInfo.getUrl(), DateUtil.between(startTime,endTime,DateUnit.SECOND) + 60,videoInfo.getDevice(),videoInfo.getCallId());
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
videoService.javaCVrecord(asyncResponse, videoInfo.getUrl(), DateUtil.between(startTime,endTime,DateUnit.SECOND) + 60);
|
videoService.javaCVrecord(asyncResponse, videoInfo.getUrl(), DateUtil.between(startTime,endTime,DateUnit.SECOND) + 60);
|
||||||
}
|
}
|
||||||
@ -502,6 +513,7 @@ public class Gb28181DownloadService {
|
|||||||
result.complete(null);
|
result.complete(null);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
String ssrc = ssrcService.getPlaySsrc();
|
String ssrc = ssrcService.getPlaySsrc();
|
||||||
TimeField timeField = new TimeField();
|
TimeField timeField = new TimeField();
|
||||||
timeField.setStartTime(start);
|
timeField.setStartTime(start);
|
||||||
@ -559,6 +571,7 @@ public class Gb28181DownloadService {
|
|||||||
ScheduledFuture<?>[] schedule = new ScheduledFuture<?>[1];
|
ScheduledFuture<?>[] schedule = new ScheduledFuture<?>[1];
|
||||||
Flow.Subscriber<SIPResponse> subscriber = new Flow.Subscriber<>() {
|
Flow.Subscriber<SIPResponse> subscriber = new Flow.Subscriber<>() {
|
||||||
private Flow.Subscription subscription;
|
private Flow.Subscription subscription;
|
||||||
|
private boolean isStart = false;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSubscribe(Flow.Subscription subscription) {
|
public void onSubscribe(Flow.Subscription subscription) {
|
||||||
@ -574,10 +587,19 @@ public class Gb28181DownloadService {
|
|||||||
if (statusCode == Response.TRYING) {
|
if (statusCode == Response.TRYING) {
|
||||||
log.info("订阅 {} {} 尝试连接流媒体服务", MessageProcessor.Method.INVITE, subscribeKey);
|
log.info("订阅 {} {} 尝试连接流媒体服务", MessageProcessor.Method.INVITE, subscribeKey);
|
||||||
subscription.request(1);
|
subscription.request(1);
|
||||||
|
String callId = item.getCallId().getCallId();
|
||||||
|
if(!isStart){
|
||||||
|
isStart = true;
|
||||||
|
result.completeAsync(() -> new VideoInfo(streamId,videoUrl(streamId), callId, device), executor);
|
||||||
|
}
|
||||||
} else if (statusCode >= Response.OK && statusCode < Response.MULTIPLE_CHOICES) {
|
} else if (statusCode >= Response.OK && statusCode < Response.MULTIPLE_CHOICES) {
|
||||||
log.info("订阅 {} {} 流媒体服务连接成功, 开始推送视频流", MessageProcessor.Method.INVITE, subscribeKey);
|
log.info("订阅 {} {} 流媒体服务连接成功, 开始推送视频流", MessageProcessor.Method.INVITE, subscribeKey);
|
||||||
log.info("收到响应状态 {}", statusCode);
|
log.info("收到响应状态 {}", statusCode);
|
||||||
String callId = item.getCallId().getCallId();
|
String callId = item.getCallId().getCallId();
|
||||||
|
if(!isStart){
|
||||||
|
isStart = true;
|
||||||
|
result.completeAsync(() -> new VideoInfo(streamId,videoUrl(streamId), callId, device), executor);
|
||||||
|
}
|
||||||
sender.sendRequest(((provider, ip, port) -> {
|
sender.sendRequest(((provider, ip, port) -> {
|
||||||
String fromTag = item.getFromTag();
|
String fromTag = item.getFromTag();
|
||||||
String toTag = item.getToTag();
|
String toTag = item.getToTag();
|
||||||
@ -586,7 +608,6 @@ public class Gb28181DownloadService {
|
|||||||
subscribe.getByeSubscribe().addSubscribe(key, byeSubscriber(key, device, cacheKey, streamId, time, unit));
|
subscribe.getByeSubscribe().addSubscribe(key, byeSubscriber(key, device, cacheKey, streamId, time, unit));
|
||||||
return SipRequestBuilder.createAckRequest(Response.OK, ip, port, docking, device.getGbDeviceChannelId(), fromTag, toTag, callId);
|
return SipRequestBuilder.createAckRequest(Response.OK, ip, port, docking, device.getGbDeviceChannelId(), fromTag, toTag, callId);
|
||||||
}));
|
}));
|
||||||
result.complete(new VideoInfo(streamId,videoUrl(streamId), callId, device));
|
|
||||||
} else {
|
} else {
|
||||||
log.info("订阅 {} {} 连接流媒体服务时出现异常, 终止订阅", MessageProcessor.Method.INVITE, subscribeKey);
|
log.info("订阅 {} {} 连接流媒体服务时出现异常, 终止订阅", MessageProcessor.Method.INVITE, subscribeKey);
|
||||||
zlmMediaService.closeRtpServer(new CloseRtpServer(streamId));
|
zlmMediaService.closeRtpServer(new CloseRtpServer(streamId));
|
||||||
|
@ -40,11 +40,12 @@ media:
|
|||||||
id: amrWMKmbKqoBjRQ9
|
id: amrWMKmbKqoBjRQ9
|
||||||
# secret: 035c73f7-bb6b-4889-a715-d9eb2d1925cc
|
# secret: 035c73f7-bb6b-4889-a715-d9eb2d1925cc
|
||||||
secret: 4155cca6-2f9f-11ee-85e6-8de4ce2e7333
|
secret: 4155cca6-2f9f-11ee-85e6-8de4ce2e7333
|
||||||
|
rtmp-port: 1936
|
||||||
|
|
||||||
proxy:
|
proxy:
|
||||||
wvp:
|
wvp:
|
||||||
#url: http://127.0.0.1:18978
|
url: http://127.0.0.1:18978
|
||||||
url: http://192.168.3.12:18978
|
# url: http://192.168.3.12:18978
|
||||||
user: admin
|
user: admin
|
||||||
passwd: admin
|
passwd: admin
|
||||||
use-ffmpeg: true
|
use-ffmpeg: true
|
||||||
@ -64,13 +65,14 @@ proxy:
|
|||||||
realtime-video-duration: 15m
|
realtime-video-duration: 15m
|
||||||
gb28181:
|
gb28181:
|
||||||
sip:
|
sip:
|
||||||
id: 44050100002000000005
|
id: 44050100002000000003
|
||||||
|
# id: 44050100002000000005
|
||||||
domain: 4405010000
|
domain: 4405010000
|
||||||
password: 123456
|
password: 123456
|
||||||
port: 5063
|
port: 5063
|
||||||
ip:
|
ip:
|
||||||
# - 10.10.10.20
|
- 10.10.10.20
|
||||||
- 192.168.0.195
|
# - 192.168.0.195
|
||||||
stream-mode: udp
|
stream-mode: udp
|
||||||
use-playback-to-download: false
|
use-playback-to-download: false
|
||||||
proxy-media-url: 'https://10.10.10.200:18181/media'
|
proxy-media-url: 'https://10.10.10.200:18181/media'
|
||||||
@ -90,8 +92,10 @@ ffmpeg-support:
|
|||||||
rtp:
|
rtp:
|
||||||
# input: -i http://10.10.10.200:5080/live/test.live.flv
|
# input: -i http://10.10.10.200:5080/live/test.live.flv
|
||||||
input: -re -i
|
input: -re -i
|
||||||
output: -preset ultrafast -vcodec libx264 -acodec aac -movflags empty_moov+frag_keyframe+default_base_moof -f mp4 # -rtsp_transport tcp
|
# output: -preset ultrafast -vcodec libx264 -acodec aac -movflags empty_moov+frag_keyframe+default_base_moof -vsync 2 -copyts -f flv # -rtsp_transport tcp
|
||||||
# output: -enc_time_base -1 -preset ultrafast -tune zerolatency -vcodec libx264 -an -movflags faststart -f flv # -rtsp_transport tcp
|
# output: -enc_time_base -1 -preset ultrafast -tune zerolatency -vcodec libx264 -an -movflags faststart -f flv # -rtsp_transport tcp
|
||||||
|
#output: -c:v libx264 -an -f flv # -rtsp_transport tcp
|
||||||
|
output: -c:v copy -an -f flv
|
||||||
download: -thread_queue_size 128 -i
|
download: -thread_queue_size 128 -i
|
||||||
debug:
|
debug:
|
||||||
download: false
|
download: false
|
||||||
|
Loading…
Reference in New Issue
Block a user