ard-work/src/main/java/com/ruoyi/media/controller/MediaController.java
New file @@ -0,0 +1,50 @@ package com.ruoyi.media.controller; import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport; import com.ruoyi.common.annotation.Anonymous; import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.media.domain.MediaInfo; import com.ruoyi.media.service.IMediaService; import com.ruoyi.media.service.impl.MediaService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; /** * @Description: * @ClassName: controller * @Author: 刘苏义 * @Date: 2023年07月13日9:26 * @Version: 1.0 **/ @RestController @Api(tags = "流媒体接口") @Anonymous public class MediaController { @Resource private IMediaService mediaService; @PostMapping("/add") @ApiOperation("增加转码") public AjaxResult addPath(@RequestBody MediaInfo mediaInfo) { String rtsp = mediaService.addPath(mediaInfo.getName(), mediaInfo.getRtspPath()); return AjaxResult.success(rtsp); } @PostMapping("/remove") @ApiOperation("移除转码") @ApiOperationSupport(includeParameters={"mediaInfo.name"}) public AjaxResult removePath(@RequestBody MediaInfo mediaInfo) { mediaService.removePath(mediaInfo.getName()); return AjaxResult.success(); } @GetMapping("/getList") @ApiOperation("获取当前转码列表") public AjaxResult getList() { return AjaxResult.success(mediaService.list()); } } ard-work/src/main/java/com/ruoyi/media/domain/Conf.java
New file @@ -0,0 +1,133 @@ package com.ruoyi.media.domain; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import java.util.List; /** * @Description: * @ClassName: MediaInfo * @Author: 刘苏义 * @Date: 2023年07月13日9:32 * @Version: 1.0 **/ @Data public class Conf { private String source; @JsonProperty("sourceFingerprint") private String sourcefingerprint; @JsonProperty("sourceOnDemand") private boolean sourceondemand; @JsonProperty("sourceOnDemandStartTimeout") private String sourceondemandstarttimeout; @JsonProperty("sourceOnDemandCloseAfter") private String sourceondemandcloseafter; @JsonProperty("publishUser") private String publishuser; @JsonProperty("publishPass") private String publishpass; @JsonProperty("publishIPs") private List<String> publiships; @JsonProperty("readUser") private String readuser; @JsonProperty("readPass") private String readpass; @JsonProperty("readIPs") private List<String> readips; @JsonProperty("disablePublisherOverride") private boolean disablepublisheroverride; private String fallback; @JsonProperty("sourceProtocol") private String sourceprotocol; @JsonProperty("sourceAnyPortEnable") private boolean sourceanyportenable; @JsonProperty("rtspRangeType") private String rtsprangetype; @JsonProperty("rtspRangeStart") private String rtsprangestart; @JsonProperty("sourceRedirect") private String sourceredirect; @JsonProperty("rpiCameraCamID") private int rpicameracamid; @JsonProperty("rpiCameraWidth") private int rpicamerawidth; @JsonProperty("rpiCameraHeight") private int rpicameraheight; @JsonProperty("rpiCameraHFlip") private boolean rpicamerahflip; @JsonProperty("rpiCameraVFlip") private boolean rpicameravflip; @JsonProperty("rpiCameraBrightness") private int rpicamerabrightness; @JsonProperty("rpiCameraContrast") private int rpicameracontrast; @JsonProperty("rpiCameraSaturation") private int rpicamerasaturation; @JsonProperty("rpiCameraSharpness") private int rpicamerasharpness; @JsonProperty("rpiCameraExposure") private String rpicameraexposure; @JsonProperty("rpiCameraAWB") private String rpicameraawb; @JsonProperty("rpiCameraDenoise") private String rpicameradenoise; @JsonProperty("rpiCameraShutter") private int rpicamerashutter; @JsonProperty("rpiCameraMetering") private String rpicamerametering; @JsonProperty("rpiCameraGain") private int rpicameragain; @JsonProperty("rpiCameraEV") private int rpicameraev; @JsonProperty("rpiCameraROI") private String rpicameraroi; @JsonProperty("rpiCameraTuningFile") private String rpicameratuningfile; @JsonProperty("rpiCameraMode") private String rpicameramode; @JsonProperty("rpiCameraFPS") private int rpicamerafps; @JsonProperty("rpiCameraIDRPeriod") private int rpicameraidrperiod; @JsonProperty("rpiCameraBitrate") private int rpicamerabitrate; @JsonProperty("rpiCameraProfile") private String rpicameraprofile; @JsonProperty("rpiCameraLevel") private String rpicameralevel; @JsonProperty("rpiCameraAfMode") private String rpicameraafmode; @JsonProperty("rpiCameraAfRange") private String rpicameraafrange; @JsonProperty("rpiCameraAfSpeed") private String rpicameraafspeed; @JsonProperty("rpiCameraLensPosition") private int rpicameralensposition; @JsonProperty("rpiCameraAfWindow") private String rpicameraafwindow; @JsonProperty("rpiCameraTextOverlayEnable") private boolean rpicameratextoverlayenable; @JsonProperty("rpiCameraTextOverlay") private String rpicameratextoverlay; @JsonProperty("runOnInit") private String runoninit; @JsonProperty("runOnInitRestart") private boolean runoninitrestart; @JsonProperty("runOnDemand") private String runondemand; @JsonProperty("runOnDemandRestart") private boolean runondemandrestart; @JsonProperty("runOnDemandStartTimeout") private String runondemandstarttimeout; @JsonProperty("runOnDemandCloseAfter") private String runondemandcloseafter; @JsonProperty("runOnReady") private String runonready; @JsonProperty("runOnReadyRestart") private boolean runonreadyrestart; @JsonProperty("runOnRead") private String runonread; @JsonProperty("runOnReadRestart") private boolean runonreadrestart; } ard-work/src/main/java/com/ruoyi/media/domain/Items.java
New file @@ -0,0 +1,23 @@ package com.ruoyi.media.domain; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import java.util.List; /** * @Description: * @ClassName: Items * @Author: 刘苏义 * @Date: 2023年07月13日10:23 * @Version: 1.0 **/ @Data public class Items { private String name; private String confname; private Conf conf; private Source source; private boolean sourceready; private List<String> tracks; } ard-work/src/main/java/com/ruoyi/media/domain/JsonsRoot.java
New file @@ -0,0 +1,23 @@ package com.ruoyi.media.domain; import lombok.Data; import java.util.List; /** * @Description: * @ClassName: JsonObject * @Author: 刘苏义 * @Date: 2023年07月13日10:06 * @Version: 1.0 **/ @Data public class JsonsRoot { private int itemcount; private int pagecount; private List<Items> items; } ard-work/src/main/java/com/ruoyi/media/domain/MediaInfo.java
New file @@ -0,0 +1,16 @@ package com.ruoyi.media.domain; import lombok.Data; /** * @Description: * @ClassName: MediaInfo * @Author: 刘苏义 * @Date: 2023年07月13日10:11 * @Version: 1.0 **/ @Data public class MediaInfo { String name; String rtspPath; } ard-work/src/main/java/com/ruoyi/media/domain/Source.java
New file @@ -0,0 +1,16 @@ package com.ruoyi.media.domain; import lombok.Data; /** * @Description: * @ClassName: Source * @Author: 刘苏义 * @Date: 2023年07月13日10:24 * @Version: 1.0 **/ @Data public class Source { private String type; private String id; } ard-work/src/main/java/com/ruoyi/media/service/IMediaService.java
New file @@ -0,0 +1,10 @@ package com.ruoyi.media.service; import com.ruoyi.media.domain.Items; import java.util.List; public interface IMediaService { public String addPath(String name, String rtspPath); public void removePath(String name); public List<Items>list(); } ard-work/src/main/java/com/ruoyi/media/service/impl/MediaService.java
New file @@ -0,0 +1,66 @@ package com.ruoyi.media.service.impl; import com.alibaba.fastjson2.JSONObject; import com.ruoyi.media.domain.Conf; import com.ruoyi.media.domain.Items; import com.ruoyi.media.domain.JsonsRoot; import com.ruoyi.media.service.IMediaService; import com.ruoyi.utils.forest.MediaClient; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.util.List; /** * @Description: * @ClassName: MediaService * @Author: 刘苏义 * @Date: 2023年07月13日9:28 * @Version: 1.0 **/ @Service public class MediaService implements IMediaService { @Resource MediaClient mediaClient; @Value("${mediamtx.host}") String mediamtxHost; @Override public String addPath(String name, String rtspPath) { String apiUrl="http://"+mediamtxHost+":9997/v2"; String rtspUrl="rtsp://"+mediamtxHost+":8554/"; Conf mediaInfo = new Conf(); //-vcodec libx264 //指定视频编码器为 libx264,使用 H.264 编码格式进行视频压缩 //-preset ultrafast //--preset的参数主要调节编码速度和质量的平衡,有ultrafast(转码速度最快,视频往往也最模糊)、superfast、veryfast、faster、fast、medium、slow、slower、veryslow、placebo这10个选项,从快到慢 //-r 25 //设置输出视频的帧率为 25 帧/秒 //-rtsp_transport tcp //这个选项告诉 FFmpeg 使用 TCP 作为 RTSP 的传输协议 //-threads 4: 指定要使用的线程数为 4。//这允许 FFmpeg 在多核处理器上使用多个线程来进行视频编码,以加快速度。 // -i //用于指定输入媒体文件或输入流的地址 //-f rtsp //这个选项告诉 FFmpeg 输出为 RTSP 格式。 //CPU软解码编码 //String cmd = "ffmpeg -rtsp_transport udp -i \"" + rtspPath + "\" -vcodec libx264 -preset:v veryfast -r 25 -threads 4 -f rtsp rtsp://localhost:$RTSP_PORT/$MTX_PATH"; //GPU硬解码编码 String cmd = "ffmpeg -hwaccel cuvid -c:v h264_cuvid -rtsp_transport udp -i \"" + rtspPath + "\" -c:v h264_nvenc -r 25 -threads 4 -f rtsp rtsp://localhost:$RTSP_PORT/$MTX_PATH"; mediaInfo.setRunoninit(cmd); mediaInfo.setRunoninitrestart(true); mediaClient.add(apiUrl, name, mediaInfo); return rtspUrl + name; } @Override public void removePath(String name) { String apiUrl="http://"+mediamtxHost+":9997/v2"; mediaClient.remove(apiUrl, name); } @Override public List<Items> list() { String apiUrl="http://"+mediamtxHost+":9997/v2"; String list = mediaClient.list(apiUrl); JsonsRoot jsonsRoot = JSONObject.parseObject(list, JsonsRoot.class); return jsonsRoot.getItems(); } } ard-work/src/main/java/com/ruoyi/utils/forest/MediaClient.java
New file @@ -0,0 +1,26 @@ package com.ruoyi.utils.forest; import com.dtflys.forest.annotation.Get; import com.dtflys.forest.annotation.JSONBody; import com.dtflys.forest.annotation.Post; import com.dtflys.forest.annotation.Var; import com.ruoyi.media.domain.Conf; /** * @Description: mediamtx流媒体客户端 * @ClassName: client * @Author: 刘苏义 * @Date: 2023年07月06日9:51 * @Version: 1.0 **/ public interface MediaClient { @Post("{apiUrl}/config/paths/add/{name}") String add(@Var("apiUrl") String apiUrl,@Var("name") String name, @JSONBody Conf body); @Post("{apiUrl}/config/paths/remove/{name}") String remove(@Var("apiUrl") String apiUrl,@Var("name") String name); @Get("{apiUrl}/paths/list") String list(@Var("apiUrl") String apiUrl); } ard-work/src/main/java/com/ruoyi/utils/forest/client.java
File was deleted