[+] 服务端录像
This commit is contained in:
@@ -11,6 +11,8 @@ import java.util.regex.Pattern;
|
||||
import org.apache.commons.lang3.math.NumberUtils;
|
||||
|
||||
import com.acgist.taoyao.boot.config.FfmpegProperties;
|
||||
import com.acgist.taoyao.boot.config.MediaProperties;
|
||||
import com.acgist.taoyao.boot.config.MediaVideoProperties;
|
||||
import com.acgist.taoyao.boot.utils.FileUtils;
|
||||
import com.acgist.taoyao.boot.utils.NetUtils;
|
||||
import com.acgist.taoyao.boot.utils.ScriptUtils;
|
||||
@@ -48,10 +50,18 @@ public class Recorder {
|
||||
* 音频端口
|
||||
*/
|
||||
private Integer audioPort;
|
||||
/**
|
||||
* 音频控制端口
|
||||
*/
|
||||
private Integer audioRtcpPort;
|
||||
/**
|
||||
* 视频端口
|
||||
*/
|
||||
private Integer videoPort;
|
||||
/**
|
||||
* 视频控制端口
|
||||
*/
|
||||
private Integer videoRtcpPort;
|
||||
/**
|
||||
* 音频流ID
|
||||
*/
|
||||
@@ -120,6 +130,10 @@ public class Recorder {
|
||||
* 文件路径
|
||||
*/
|
||||
private final String filepath;
|
||||
/**
|
||||
* 媒体配置
|
||||
*/
|
||||
private final MediaProperties mediaProperties;
|
||||
/**
|
||||
* FFmpeg配置
|
||||
*/
|
||||
@@ -129,9 +143,13 @@ public class Recorder {
|
||||
* @param name 录像名称
|
||||
* @param room 房间
|
||||
* @param clientWrapper 终端
|
||||
* @param mediaProperties 媒体配置
|
||||
* @param ffmpegProperties FFmpeg配置
|
||||
*/
|
||||
public Recorder(String name, Room room, ClientWrapper clientWrapper, FfmpegProperties ffmpegProperties) {
|
||||
public Recorder(
|
||||
String name, Room room, ClientWrapper clientWrapper,
|
||||
MediaProperties mediaProperties, FfmpegProperties ffmpegProperties
|
||||
) {
|
||||
this.close = false;
|
||||
this.running = false;
|
||||
this.room = room;
|
||||
@@ -140,6 +158,7 @@ public class Recorder {
|
||||
this.preview = Paths.get(this.folder, "taoyao.jpg").toAbsolutePath().toString();
|
||||
this.filepath = Paths.get(this.folder, "taoyao.mp4").toAbsolutePath().toString();
|
||||
this.clientWrapper = clientWrapper;
|
||||
this.mediaProperties = mediaProperties;
|
||||
this.ffmpegProperties = ffmpegProperties;
|
||||
FileUtils.mkdirs(this.folder);
|
||||
}
|
||||
@@ -166,7 +185,13 @@ public class Recorder {
|
||||
* 录制视频
|
||||
*/
|
||||
private void record() {
|
||||
final String recordScript = String.format(this.ffmpegProperties.getRecord(), this.sdpfile, this.filepath);
|
||||
final MediaVideoProperties mediaVideoProperties = this.mediaProperties.getVideo();
|
||||
final String recordScript = String.format(
|
||||
this.ffmpegProperties.getRecord(),
|
||||
mediaVideoProperties.getFrameRate(),
|
||||
this.sdpfile,
|
||||
this.filepath
|
||||
);
|
||||
this.scriptExecutor = new ScriptExecutor(recordScript);
|
||||
try {
|
||||
log.debug("""
|
||||
@@ -189,12 +214,16 @@ public class Recorder {
|
||||
int minPort = this.ffmpegProperties.getMinPort();
|
||||
int maxPort = this.ffmpegProperties.getMaxPort();
|
||||
// 预留控制端口
|
||||
this.audioPort = NetUtils.scanPort(minPort, maxPort);
|
||||
this.videoPort = NetUtils.scanPort(this.audioPort + 2, maxPort);
|
||||
final String sdp = String.format(
|
||||
this.audioPort = NetUtils.scanPort(minPort, maxPort);
|
||||
this.audioRtcpPort = NetUtils.scanPort(this.audioPort + 1, maxPort);
|
||||
this.videoPort = NetUtils.scanPort(this.audioPort + 2, maxPort);
|
||||
this.videoRtcpPort = NetUtils.scanPort(this.audioPort + 3, maxPort);
|
||||
final String sdp = String.format(
|
||||
this.ffmpegProperties.getSdp(),
|
||||
this.audioPort,
|
||||
this.audioRtcpPort,
|
||||
this.videoPort,
|
||||
this.audioPort
|
||||
this.videoRtcpPort
|
||||
);
|
||||
Files.write(
|
||||
Paths.get(this.sdpfile),
|
||||
@@ -225,7 +254,7 @@ public class Recorder {
|
||||
*/
|
||||
private void duration() {
|
||||
log.debug("视频时长:{}", this.filepath);
|
||||
final String durationScript = String.format(this.ffmpegProperties.getDuration(), this.filepath);
|
||||
final String durationScript = String.format(this.ffmpegProperties.getDuration(), this.filepath);
|
||||
final ScriptExecutor executor = ScriptUtils.execute(durationScript);
|
||||
final Pattern pattern = Pattern.compile(this.ffmpegProperties.getDurationRegex());
|
||||
final Matcher matcher = pattern.matcher(executor.getResult());
|
||||
|
||||
@@ -10,6 +10,7 @@ import com.acgist.taoyao.boot.annotation.Description;
|
||||
import com.acgist.taoyao.boot.annotation.Protocol;
|
||||
import com.acgist.taoyao.boot.config.Constant;
|
||||
import com.acgist.taoyao.boot.config.FfmpegProperties;
|
||||
import com.acgist.taoyao.boot.config.MediaProperties;
|
||||
import com.acgist.taoyao.boot.model.Message;
|
||||
import com.acgist.taoyao.boot.utils.MapUtils;
|
||||
import com.acgist.taoyao.signal.client.Client;
|
||||
@@ -50,10 +51,12 @@ public class ControlServerRecordProtocol extends ProtocolControlAdapter implemen
|
||||
|
||||
public static final String SIGNAL = "control::server::record";
|
||||
|
||||
private final MediaProperties mediaProperties;
|
||||
private final FfmpegProperties ffmpegProperties;
|
||||
|
||||
public ControlServerRecordProtocol(FfmpegProperties ffmpegProperties) {
|
||||
public ControlServerRecordProtocol(MediaProperties mediaProperties, FfmpegProperties ffmpegProperties) {
|
||||
super("服务端录像信令", SIGNAL);
|
||||
this.mediaProperties = mediaProperties;
|
||||
this.ffmpegProperties = ffmpegProperties;
|
||||
}
|
||||
|
||||
@@ -119,18 +122,21 @@ public class ControlServerRecordProtocol extends ProtocolControlAdapter implemen
|
||||
}
|
||||
final String name = UUID.randomUUID().toString();
|
||||
// 打开录制线程
|
||||
final Recorder recorder = new Recorder(name, room, clientWrapper, this.ffmpegProperties);
|
||||
final Recorder recorder = new Recorder(name, room, clientWrapper, this.mediaProperties, this.ffmpegProperties);
|
||||
recorder.start();
|
||||
clientWrapper.setRecorder(recorder);
|
||||
// 打开媒体录制
|
||||
final Message message = this.build();
|
||||
final Map<String, Object> body = new HashMap<>();
|
||||
body.put("audioPort", recorder.getAudioPort());
|
||||
body.put("videoPort", recorder.getVideoPort());
|
||||
body.put(Constant.HOST, this.ffmpegProperties.getHost());
|
||||
body.put(Constant.ROOM_ID, room.getRoomId());
|
||||
body.put(Constant.ENABLED, true);
|
||||
body.put(Constant.FILEPATH, recorder.getFilepath());
|
||||
body.put(Constant.CLIENT_ID, clientWrapper.getClientId());
|
||||
body.put(Constant.AUDIO_PORT, recorder.getAudioPort());
|
||||
body.put(Constant.VIDEO_PORT, recorder.getVideoPort());
|
||||
body.put(Constant.AUDIO_RTCP_PORT, recorder.getAudioRtcpPort());
|
||||
body.put(Constant.VIDEO_RTCP_PORT, recorder.getVideoRtcpPort());
|
||||
body.put(Constant.RTP_CAPABILITIES, clientWrapper.getRtpCapabilities());
|
||||
clientWrapper.getProducers().values().forEach(producer -> {
|
||||
if(producer.getKind() == Kind.AUDIO) {
|
||||
|
||||
Reference in New Issue
Block a user