[*] 服务端录像
This commit is contained in:
@@ -42,7 +42,8 @@
|
|||||||
|:--|:--|:--|:--|
|
|:--|:--|:--|:--|
|
||||||
|Mediasoup|支持|完成|视频房间(会议)|
|
|Mediasoup|支持|完成|视频房间(会议)|
|
||||||
|控制|支持|完成|部分控制信令|
|
|控制|支持|完成|部分控制信令|
|
||||||
|录像|支持|完成|录像|
|
|拍照|支持|未完成|拍照|
|
||||||
|
|录像|支持|未完成|录像|
|
||||||
|
|
||||||
### Android终端功能
|
### Android终端功能
|
||||||
|
|
||||||
|
|||||||
@@ -816,7 +816,7 @@ class Taoyao {
|
|||||||
await audioTransport.connect({
|
await audioTransport.connect({
|
||||||
ip : host,
|
ip : host,
|
||||||
port : audioPort,
|
port : audioPort,
|
||||||
rtcpPort: audioPort
|
rtcpPort: audioPort + 1
|
||||||
});
|
});
|
||||||
audioConsumer = await audioTransport.consume({
|
audioConsumer = await audioTransport.consume({
|
||||||
producerId: audioProducerId,
|
producerId: audioProducerId,
|
||||||
@@ -847,7 +847,7 @@ class Taoyao {
|
|||||||
await videoTransport.connect({
|
await videoTransport.connect({
|
||||||
ip : host,
|
ip : host,
|
||||||
port : videoPort,
|
port : videoPort,
|
||||||
rtcpPort: videoPort
|
rtcpPort: videoPort + 1
|
||||||
});
|
});
|
||||||
videoConsumer = await videoTransport.consume({
|
videoConsumer = await videoTransport.consume({
|
||||||
producerId: videoProducerId,
|
producerId: videoProducerId,
|
||||||
@@ -865,11 +865,12 @@ class Taoyao {
|
|||||||
});
|
});
|
||||||
console.log("controlServerRecord video:", videoTransportId, videoConsumerId, videoTransport.tuple, videoRtpParameters);
|
console.log("controlServerRecord video:", videoTransportId, videoConsumerId, videoTransport.tuple, videoRtpParameters);
|
||||||
}
|
}
|
||||||
if(audioConsumer) {
|
|
||||||
await audioConsumer.resume();
|
|
||||||
}
|
|
||||||
if(videoConsumer) {
|
if(videoConsumer) {
|
||||||
await videoConsumer.resume();
|
await videoConsumer.resume();
|
||||||
|
videoConsumer.requestKeyFrame();
|
||||||
|
}
|
||||||
|
if(audioConsumer) {
|
||||||
|
await audioConsumer.resume();
|
||||||
}
|
}
|
||||||
message.body = {
|
message.body = {
|
||||||
roomId : roomId,
|
roomId : roomId,
|
||||||
|
|||||||
@@ -1,4 +1,14 @@
|
|||||||
|
server:
|
||||||
|
# 使用反向代理建议不要配置HTTPS
|
||||||
|
ssl:
|
||||||
|
key-alias: taoyao
|
||||||
|
key-store: classpath:server.p12
|
||||||
|
key-store-type: PKCS12
|
||||||
|
key-store-password: 123456
|
||||||
|
key-password: 123456
|
||||||
taoyao:
|
taoyao:
|
||||||
|
ffmpeg:
|
||||||
|
host: 192.168.8.93
|
||||||
security:
|
security:
|
||||||
permit:
|
permit:
|
||||||
- /
|
- /
|
||||||
@@ -7,4 +17,5 @@ taoyao:
|
|||||||
- /favicon.ico
|
- /favicon.ico
|
||||||
- /v3/api-docs/**
|
- /v3/api-docs/**
|
||||||
- /swagger-ui/**
|
- /swagger-ui/**
|
||||||
- /swagger-ui.html
|
- /swagger-ui.html
|
||||||
|
|
||||||
@@ -2,12 +2,6 @@ server:
|
|||||||
port: 8888
|
port: 8888
|
||||||
http2:
|
http2:
|
||||||
enabled: true
|
enabled: true
|
||||||
ssl:
|
|
||||||
key-alias: taoyao
|
|
||||||
key-store: classpath:server.p12
|
|
||||||
key-store-type: PKCS12
|
|
||||||
key-store-password: 123456
|
|
||||||
key-password: 123456
|
|
||||||
tomcat:
|
tomcat:
|
||||||
thread:
|
thread:
|
||||||
max: 256
|
max: 256
|
||||||
@@ -17,9 +11,6 @@ server:
|
|||||||
port-header: X-Forwarded-Port
|
port-header: X-Forwarded-Port
|
||||||
protocol-header: X-Forwarded-Proto
|
protocol-header: X-Forwarded-Proto
|
||||||
remote-ip-header: X-Forwarded-For
|
remote-ip-header: X-Forwarded-For
|
||||||
# 服务前缀
|
|
||||||
# servlet:
|
|
||||||
# context-path: /taoyao
|
|
||||||
spring:
|
spring:
|
||||||
# 快速启动
|
# 快速启动
|
||||||
# main:
|
# main:
|
||||||
@@ -58,11 +49,10 @@ taoyao:
|
|||||||
description: 桃夭WebRTC信令服务
|
description: 桃夭WebRTC信令服务
|
||||||
# 全局超时时间
|
# 全局超时时间
|
||||||
timeout: 5000
|
timeout: 5000
|
||||||
|
# ID生成策略
|
||||||
id:
|
id:
|
||||||
# 服务端
|
|
||||||
max-index: 999999
|
max-index: 999999
|
||||||
server-index: 0
|
server-index: 0
|
||||||
# 终端
|
|
||||||
min-client-index: 10000
|
min-client-index: 10000
|
||||||
max-client-index: 99999
|
max-client-index: 99999
|
||||||
# 媒体配置
|
# 媒体配置
|
||||||
@@ -103,6 +93,7 @@ taoyao:
|
|||||||
bitrate: 1200
|
bitrate: 1200
|
||||||
frame-rate: 24
|
frame-rate: 24
|
||||||
resolution: 1920*1080
|
resolution: 1920*1080
|
||||||
|
# 音频质量
|
||||||
audios:
|
audios:
|
||||||
# 超清
|
# 超清
|
||||||
fd-audio:
|
fd-audio:
|
||||||
@@ -115,13 +106,14 @@ taoyao:
|
|||||||
format: OPUS
|
format: OPUS
|
||||||
bitrate: 128
|
bitrate: 128
|
||||||
sample-size: 24
|
sample-size: 24
|
||||||
sample-rate: 44100
|
sample-rate: 32000
|
||||||
# 标清
|
# 标清
|
||||||
sd-audio:
|
sd-audio:
|
||||||
format: OPUS
|
format: OPUS
|
||||||
bitrate: 96
|
bitrate: 96
|
||||||
sample-size: 24
|
sample-size: 24
|
||||||
sample-rate: 32000
|
sample-rate: 16000
|
||||||
|
# 视频质量
|
||||||
videos:
|
videos:
|
||||||
# 4K:UD=UHD=4K
|
# 4K:UD=UHD=4K
|
||||||
ud-video:
|
ud-video:
|
||||||
@@ -153,6 +145,44 @@ taoyao:
|
|||||||
bitrate: 800
|
bitrate: 800
|
||||||
frame-rate: 15
|
frame-rate: 15
|
||||||
resolution: 720*480
|
resolution: 720*480
|
||||||
|
# FFmpeg配置
|
||||||
|
ffmpeg:
|
||||||
|
# 录像SDP:VP8 | H264
|
||||||
|
sdp: |
|
||||||
|
v=0
|
||||||
|
o=- 0 0 IN IP4 127.0.0.1
|
||||||
|
s=TaoyaoRecord
|
||||||
|
t=0 0
|
||||||
|
a=group:BUNDLE video audio
|
||||||
|
m=video %d RTP/AVP 101 102
|
||||||
|
c=IN IP4 0.0.0.0
|
||||||
|
a=rtpmap:101 VP8/90000
|
||||||
|
a=recvonly
|
||||||
|
m=audio %d RTP/AVP 100
|
||||||
|
c=IN IP4 0.0.0.0
|
||||||
|
a=rtpmap:100 OPUS/48000/2
|
||||||
|
a=recvonly
|
||||||
|
# 录像命令
|
||||||
|
record: ffmpeg -protocol_whitelist "file,rtp,udp" -y -thread_queue_size 1024 -i %s -c:a aac -c:v h264 %s
|
||||||
|
# 预览命令
|
||||||
|
preview: ffmpeg -y -i %s -ss %d -vframes 1 -f image2 %s
|
||||||
|
# 时长命令
|
||||||
|
duration: ffprobe -i %s -show_entries format=duration
|
||||||
|
# 存储目录
|
||||||
|
storage-path: /data/taoyao/storage
|
||||||
|
# 图片存储目录
|
||||||
|
storage-image-path: /data/taoyao/storage/image
|
||||||
|
# 视频存储目录
|
||||||
|
storage-video-path: /data/taoyao/storage/video
|
||||||
|
# 预览时间
|
||||||
|
preview-time: 4
|
||||||
|
# 时长提取
|
||||||
|
duration-regex: .*duration\=([0-9\.]+).*
|
||||||
|
# 录像地址
|
||||||
|
host: 127.0.0.1
|
||||||
|
# 端口范围
|
||||||
|
min-port: 50000
|
||||||
|
max-port: 59999
|
||||||
# Socket信令
|
# Socket信令
|
||||||
socket:
|
socket:
|
||||||
enabled: true
|
enabled: true
|
||||||
@@ -168,16 +198,19 @@ taoyao:
|
|||||||
keep-alive-time: 60000
|
keep-alive-time: 60000
|
||||||
buffer-size: 2048
|
buffer-size: 2048
|
||||||
max-buffer-size: 32768
|
max-buffer-size: 32768
|
||||||
|
# 脚本配置
|
||||||
|
script:
|
||||||
|
enabled: true
|
||||||
|
system-reboot: reboot
|
||||||
|
system-shutdown: shutdown now
|
||||||
|
platform-reboot: systemctl restart taoyao-signal-server
|
||||||
|
platform-shutdown: systemctl stop taoyao-signal-server
|
||||||
# WebRTC配置
|
# WebRTC配置
|
||||||
webrtc:
|
webrtc:
|
||||||
# 是否加密:E2E
|
# 是否加密:E2E
|
||||||
encrypt: false
|
encrypt: false
|
||||||
# STUN服务
|
# STUN服务
|
||||||
stun:
|
stun:
|
||||||
# - host: 192.168.1.110
|
|
||||||
# port: 3478
|
|
||||||
# - host: 192.168.8.110
|
|
||||||
# port: 3478
|
|
||||||
- host: stun1.l.google.com
|
- host: stun1.l.google.com
|
||||||
port: 19302
|
port: 19302
|
||||||
- host: stun2.l.google.com
|
- host: stun2.l.google.com
|
||||||
@@ -217,54 +250,14 @@ taoyao:
|
|||||||
ip-rewrite:
|
ip-rewrite:
|
||||||
enabled: true
|
enabled: true
|
||||||
prefix: 24
|
prefix: 24
|
||||||
|
# 重写规则
|
||||||
rule:
|
rule:
|
||||||
- network: 192.168.1.0
|
# - network: 192.168.1.0
|
||||||
inner-host:
|
# inner-host:
|
||||||
outer-host:
|
# outer-host:
|
||||||
- network: 192.168.8.0
|
# - network: 192.168.8.0
|
||||||
inner-host:
|
# inner-host:
|
||||||
outer-host:
|
# outer-host:
|
||||||
ffmpeg:
|
# 服务前缀
|
||||||
# SDP:VP8 | H264
|
# servlet:
|
||||||
sdp: |
|
# context-path: /taoyao
|
||||||
v=0
|
|
||||||
o=- 0 0 IN IP4 127.0.0.1
|
|
||||||
s=TaoyaoRecord
|
|
||||||
t=0 0
|
|
||||||
m=audio %d RTP/AVP 100
|
|
||||||
c=IN IP4 127.0.0.1
|
|
||||||
a=rtpmap:100 OPUS/48000/2
|
|
||||||
a=fmtp:100 sprop-stereo=1
|
|
||||||
m=video %d RTP/AVP 101
|
|
||||||
c=IN IP4 127.0.0.1
|
|
||||||
a=rtpmap:101 VP8/90000
|
|
||||||
# a=fmtp:101 packetization-mode=1
|
|
||||||
# 录像命令
|
|
||||||
record: ffmpeg -protocol_whitelist "file,rtp,udp" -y -i %s %s
|
|
||||||
# 预览命令
|
|
||||||
preview: ffmpeg -y -i %s -ss %d -vframes 1 -f image2 %s
|
|
||||||
# 时长命令
|
|
||||||
duration: ffprobe -i %s -show_entries format=duration
|
|
||||||
# 存储目录
|
|
||||||
storage-path: /data/taoyao/storage
|
|
||||||
# 图片存储目录
|
|
||||||
storage-image-path: /data/taoyao/storage/image
|
|
||||||
# 视频存储目录
|
|
||||||
storage-video-path: /data/taoyao/storage/video
|
|
||||||
# 预览时间
|
|
||||||
preview-time: 4
|
|
||||||
# 时长提取
|
|
||||||
duration-regex: .*duration\=([0-9\.]+).*
|
|
||||||
# 录像地址
|
|
||||||
#host: 127.0.0.1
|
|
||||||
host: 192.168.8.40
|
|
||||||
# 端口范围
|
|
||||||
min-port: 50000
|
|
||||||
max-port: 59999
|
|
||||||
# 脚本配置
|
|
||||||
script:
|
|
||||||
enabled: true
|
|
||||||
system-reboot: reboot
|
|
||||||
system-shutdown: shutdown now
|
|
||||||
platform-reboot: systemctl restart taoyao-signal-server
|
|
||||||
platform-shutdown: systemctl stop taoyao-signal-server
|
|
||||||
|
|||||||
@@ -159,7 +159,7 @@ public class Recorder {
|
|||||||
this.thread.setDaemon(true);
|
this.thread.setDaemon(true);
|
||||||
this.thread.setName("TaoyaoRecord");
|
this.thread.setName("TaoyaoRecord");
|
||||||
this.thread.start();
|
this.thread.start();
|
||||||
log.info("开始录像:{}", this.folder);
|
log.info("开始媒体录像:{}", this.folder);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -186,16 +186,15 @@ public class Recorder {
|
|||||||
*/
|
*/
|
||||||
private void buildSdpfile() {
|
private void buildSdpfile() {
|
||||||
try {
|
try {
|
||||||
this.audioPort = NetUtils.scanPort(this.ffmpegProperties.getMinPort(), this.ffmpegProperties.getMaxPort());
|
int minPort = this.ffmpegProperties.getMinPort();
|
||||||
|
int maxPort = this.ffmpegProperties.getMaxPort();
|
||||||
// 预留控制端口
|
// 预留控制端口
|
||||||
this.videoPort = NetUtils.scanPort(this.audioPort + 16, this.ffmpegProperties.getMaxPort());
|
this.audioPort = NetUtils.scanPort(minPort, maxPort);
|
||||||
|
this.videoPort = NetUtils.scanPort(this.audioPort + 2, maxPort);
|
||||||
final String sdp = String.format(
|
final String sdp = String.format(
|
||||||
this.ffmpegProperties.getSdp(),
|
this.ffmpegProperties.getSdp(),
|
||||||
// this.ffmpegProperties.getHost(),
|
this.videoPort,
|
||||||
this.audioPort,
|
this.audioPort
|
||||||
// this.ffmpegProperties.getHost(),
|
|
||||||
this.videoPort
|
|
||||||
// this.ffmpegProperties.getHost()
|
|
||||||
);
|
);
|
||||||
Files.write(
|
Files.write(
|
||||||
Paths.get(this.sdpfile),
|
Paths.get(this.sdpfile),
|
||||||
@@ -255,7 +254,7 @@ public class Recorder {
|
|||||||
if(this.scriptExecutor == null) {
|
if(this.scriptExecutor == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
log.debug("结束媒体录像:{}", this.folder);
|
log.info("结束媒体录像:{}", this.folder);
|
||||||
this.scriptExecutor.stop("q");
|
this.scriptExecutor.stop("q");
|
||||||
this.preview();
|
this.preview();
|
||||||
this.duration();
|
this.duration();
|
||||||
|
|||||||
Reference in New Issue
Block a user