去除ssrc作为流ID传递,ssrc只作为sdp消息使用。动态端口的情况下支持固定流地址,同时支持未点播时直接播放流地址,代码自动发起点播
17个文件已修改
244 ■■■■ 已修改文件
src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceChannel.java 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java 80 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMUtils.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/storager/jdbc/VideoManagerJdbcStoragerImpl.java 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/storager/redis/VideoManagerRedisStoragerImpl.java 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java 27 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/vmanager/playback/PlaybackController.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/vmanager/service/impl/PlayServiceImpl.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/web/ApiDeviceController.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/web/ApiStreamController.java 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/application-dev.yml 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/channelList.vue 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/gb28181/devicePlayer.vue 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java
@@ -4,7 +4,6 @@
public class StreamInfo {
    private String ssrc;
    private String streamId;
    private String deviceID;
    private String cahnnelId;
@@ -19,14 +18,6 @@
    private String rtmp;
    private String rtsp;
    private JSONArray tracks;
    public String getSsrc() {
        return ssrc;
    }
    public void setSsrc(String ssrc) {
        this.ssrc = ssrc;
    }
    public String getDeviceID() {
        return deviceID;
src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceChannel.java
@@ -141,7 +141,7 @@
    /**
     * 流唯一编号,存在表示正在直播
     */
    private String  ssrc;
    private String  streamId;
    /**
     *  是否含有音频
@@ -379,14 +379,6 @@
        this.subCount = subCount;
    }
    public String getSsrc() {
        return ssrc;
    }
    public void setSsrc(String ssrc) {
        this.ssrc = ssrc;
    }
    public boolean isHasAudio() {
        return hasAudio;
    }
@@ -402,4 +394,12 @@
    public void setPlay(boolean play) {
        this.play = play;
    }
    public String getStreamId() {
        return streamId;
    }
    public void setStreamId(String streamId) {
        this.streamId = streamId;
    }
}
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
@@ -277,17 +277,22 @@
        try {
            String ssrc = streamSession.createPlaySsrc();
            String streamId = null;
            if (rtpEnable) {
                streamId = String.format("gb_play_%s_%s", device.getDeviceId(), channelId);
            }else {
                streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase();
            }
            String streamMode = device.getStreamMode().toUpperCase();
            MediaServerConfig mediaInfo = storager.getMediaInfo();
            String mediaPort = null;
            // 使用动态udp端口
            if (rtpEnable) {
                mediaPort = zlmUtils.getNewRTPPort(ssrc) + "";
                mediaPort = zlmUtils.getNewRTPPort(streamId) + "";
            }else {
                mediaPort = mediaInfo.getRtpProxyPort();
            }
            String streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase();
            // 添加订阅
            JSONObject subscribeKey = new JSONObject();
            subscribeKey.put("app", "rtp");
@@ -330,10 +335,10 @@
            Request request = headerProvider.createInviteRequest(device, channelId, content.toString(), null, "live", null, ssrc);
            ClientTransaction transaction = transmitRequest(device, request);
            streamSession.put(ssrc, transaction);
            streamSession.put(streamId, transaction);
            DeviceChannel deviceChannel = storager.queryChannel(device.getDeviceId(), channelId);
            if (deviceChannel != null) {
                deviceChannel.setSsrc(ssrc);
                deviceChannel.setStreamId(streamId);
                storager.updateChannel(device.getDeviceId(), deviceChannel);
            }
@@ -378,7 +383,7 @@
            String mediaPort = null;
            // 使用动态udp端口
            if (rtpEnable) {
                mediaPort = zlmUtils.getNewRTPPort(ssrc) + "";
                mediaPort = zlmUtils.getNewRTPPort(streamId) + "";
            }else {
                mediaPort = mediaInfo.getRtpProxyPort();
            }
@@ -412,7 +417,7 @@
            Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, "playback", null);
    
            ClientTransaction transaction = transmitRequest(device, request);
            streamSession.put(ssrc, transaction);
            streamSession.put(streamId, transaction);
        } catch ( SipException | ParseException | InvalidArgumentException e) {
            e.printStackTrace();
@@ -424,10 +429,10 @@
     * 
     */
    @Override
    public void streamByeCmd(String ssrc) {
    public void streamByeCmd(String streamId) {
        
        try {
            ClientTransaction transaction = streamSession.get(ssrc);
            ClientTransaction transaction = streamSession.get(streamId);
            if (transaction == null) {
                return;
            }
@@ -453,7 +458,7 @@
                clientTransaction = udpSipProvider.getNewClientTransaction(byeRequest);
            }
            dialog.sendRequest(clientTransaction);
            streamSession.remove(ssrc);
            streamSession.remove(streamId);
        } catch (TransactionDoesNotExistException e) {
            e.printStackTrace();
        } catch (SipException e) {
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java
@@ -450,7 +450,7 @@
                StreamInfo streamInfo = storager.queryPlaybackByDevice(deviceId, "*");
                if (streamInfo != null) {
                    storager.stopPlayback(streamInfo);
                    cmder.streamByeCmd(streamInfo.getSsrc());
                    cmder.streamByeCmd(streamInfo.getStreamId());
                }
            }
        } catch (ParseException | SipException | InvalidArgumentException | DocumentException e) {
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
@@ -4,13 +4,16 @@
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.conf.MediaServerConfig;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import com.genersoft.iot.vmp.utils.IpUtil;
import com.genersoft.iot.vmp.vmanager.service.IPlayService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -44,6 +47,9 @@
    private SIPCommander cmder;
    @Autowired
    private IPlayService playService;
    @Autowired
    private IVideoManagerStorager storager;
    @Autowired
@@ -51,6 +57,9 @@
    @Autowired
    private ZLMHttpHookSubscribe subscribe;
    @Value("${media.autoApplyPlay}")
    private boolean autoApplyPlay;
    @Value("${media.ip}")
    private String mediaIp;
@@ -135,34 +144,6 @@
        ZLMHttpHookSubscribe.Event subscribe = this.subscribe.getSubscribe(ZLMHttpHookSubscribe.HookType.on_publish, json);
        if (subscribe != null) subscribe.response(json);
//        if ("rtp".equals(app)) {
//            String ssrc = new DecimalFormat("0000000000").format(Integer.parseInt(streamId, 16));
//            StreamInfo streamInfoForPlay = storager.queryPlayBySSRC(ssrc);
//            if ("rtp".equals(app) && streamInfoForPlay != null ) {
//                MediaServerConfig mediaInfo = storager.getMediaInfo();
//                streamInfoForPlay.setFlv(String.format("http://%s:%s/rtp/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
//                streamInfoForPlay.setWs_flv(String.format("ws://%s:%s/rtp/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
//                streamInfoForPlay.setFmp4(String.format("http://%s:%s/rtp/%s.live.mp4", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
//                streamInfoForPlay.setWs_fmp4(String.format("ws://%s:%s/rtp/%s.live.mp4", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
//                streamInfoForPlay.setRtmp(String.format("rtmp://%s:%s/rtp/%s", mediaInfo.getWanIp(), mediaInfo.getRtmpPort(), streamId));
//                streamInfoForPlay.setHls(String.format("http://%s:%s/rtp/%s/hls.m3u8", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
//                streamInfoForPlay.setRtsp(String.format("rtsp://%s:%s/rtp/%s", mediaInfo.getWanIp(), mediaInfo.getRtspPort(), streamId));
//                storager.startPlay(streamInfoForPlay);
//            }
//
//            StreamInfo streamInfoForPlayBack = storager.queryPlaybackBySSRC(ssrc);
//            if ("rtp".equals(app) && streamInfoForPlayBack != null ) {
//                MediaServerConfig mediaInfo = storager.getMediaInfo();
//                streamInfoForPlayBack.setFlv(String.format("http://%s:%s/rtp/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
//                streamInfoForPlayBack.setWs_flv(String.format("ws://%s:%s/rtp/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
//                streamInfoForPlayBack.setFmp4(String.format("http://%s:%s/rtp/%s.live.mp4", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
//                streamInfoForPlayBack.setWs_fmp4(String.format("ws://%s:%s/rtp/%s.live.mp4", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
//                streamInfoForPlayBack.setRtmp(String.format("rtmp://%s:%s/rtp/%s", mediaInfo.getWanIp(), mediaInfo.getRtmpPort(), streamId));
//                streamInfoForPlayBack.setHls(String.format("http://%s:%s/rtp/%s/hls.m3u8", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
//                streamInfoForPlayBack.setRtsp(String.format("rtsp://%s:%s/rtp/%s", mediaInfo.getWanIp(), mediaInfo.getRtspPort(), streamId));
//                storager.startPlayback(streamInfoForPlayBack);
//            }
//        }
        // TODO Auto-generated method stub
        
@@ -268,14 +249,12 @@
        String app = json.getString("app");
        String streamId = json.getString("stream");
        boolean regist = json.getBoolean("regist");
//        String ssrc = String.format("%10d", Integer.parseInt(streamId, 16)); // ZLM 要求大写且首位补零
        String ssrc = new DecimalFormat("0000000000").format(Integer.parseInt(streamId, 16));
        StreamInfo streamInfo = storager.queryPlayBySSRC(ssrc);
        StreamInfo streamInfo = storager.queryPlayByStreamId(streamId);
        if ("rtp".equals(app) && !regist ) {
            if (streamInfo!=null){
                storager.stopPlay(streamInfo);
            }else{
                streamInfo = storager.queryPlaybackBySSRC(ssrc);
                streamInfo = storager.queryPlaybackByStreamId(streamId);
                storager.stopPlayback(streamInfo);
            }
        }
@@ -299,16 +278,14 @@
            logger.debug("ZLM HOOK on_stream_none_reader API调用,参数:" + json.toString());
        }
        
        BigInteger bigint=new BigInteger(json.getString("stream"), 16);
        int numb=bigint.intValue();
        String ssrc = String.format("%010d", numb);
        cmder.streamByeCmd(ssrc);
        StreamInfo streamInfo = storager.queryPlayBySSRC(ssrc);
        String streamId = json.getString("stream");
        cmder.streamByeCmd(streamId);
        StreamInfo streamInfo = storager.queryPlayByStreamId(streamId);
        if (streamInfo!=null){
            storager.stopPlay(streamInfo);
        }else{
            streamInfo = storager.queryPlaybackBySSRC(ssrc);
            streamInfo = storager.queryPlaybackByStreamId(streamId);
            storager.stopPlayback(streamInfo);
        }
        
@@ -330,7 +307,30 @@
            logger.debug("ZLM HOOK on_stream_not_found API调用,参数:" + json.toString());
        }
        // TODO Auto-generated method stub
        if (autoApplyPlay) {
            String app = json.getString("app");
            String streamId = json.getString("stream");
            if ("rtp".equals(app) && streamId.indexOf("gb_play") > -1) {
                String[] s = streamId.split("_");
                if (s.length == 4) {
                    String deviceId = s[2];
                    String channelId = s[3];
                    Device device = storager.queryVideoDevice(deviceId);
                    if (device != null) {
                        UUID uuid = UUID.randomUUID();
                        cmder.playStreamCmd(device, channelId, (JSONObject response) -> {
                            logger.info("收到订阅消息: " + response.toJSONString());
                            playService.onPublishHandlerForPlay(response, deviceId, channelId, uuid.toString());
                        });
                    }
                }
            }
        }
        JSONObject ret = new JSONObject();
        ret.put("code", 0);
        ret.put("msg", "success");
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMUtils.java
@@ -21,8 +21,8 @@
    private int currentPort = 0;
    public int getNewRTPPort(String ssrc) {
        String streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase();
    public int getNewRTPPort(String streamId) {
//        String streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase();
        Map<String, Object> param = new HashMap<>();
        int newPort = getPortFromUdpPortRange();
        param.put("port", newPort);
@@ -32,7 +32,7 @@
        if (jsonObject != null && jsonObject.getInteger("code") == 0) {
            return newPort;
        } else {
            return getNewRTPPort(ssrc);
            return getNewRTPPort(streamId);
        }
    }
src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java
@@ -178,7 +178,7 @@
     */
    void cleanChannelsForDevice(String deviceId);
    StreamInfo queryPlayBySSRC(String ssrc);
    StreamInfo queryPlayByStreamId(String streamId);
    StreamInfo queryPlayByDevice(String deviceId, String code);
@@ -190,5 +190,5 @@
    StreamInfo queryPlaybackByDevice(String deviceId, String channelId);
    StreamInfo queryPlaybackBySSRC(String ssrc);
    StreamInfo queryPlaybackByStreamId(String streamId);
}
src/main/java/com/genersoft/iot/vmp/storager/jdbc/VideoManagerJdbcStoragerImpl.java
@@ -178,10 +178,6 @@
        return false;
    }
    @Override
    public StreamInfo queryPlayBySSRC(String ssrc) {
        return null;
    }
    @Override
    public StreamInfo queryPlayByDevice(String deviceId, String code) {
@@ -210,7 +206,12 @@
    }
    @Override
    public StreamInfo queryPlaybackBySSRC(String ssrc) {
    public StreamInfo queryPlayByStreamId(String streamId) {
        return null;
    }
    @Override
    public StreamInfo queryPlaybackByStreamId(String streamId) {
        return null;
    }
}
src/main/java/com/genersoft/iot/vmp/storager/redis/VideoManagerRedisStoragerImpl.java
@@ -151,7 +151,6 @@
                "_" + queryOnline + // 搜索是否在线
                "_" + queryHasSubChannel + // 搜索是否含有子节点
                "_" + "*";
//        List<Object> deviceChannelList = redis.keys(queryStr);
        List<Object> deviceChannelList = redis.scan(queryStr);
        //对查询结果排序,避免出现通道排列顺序乱序的情况
        Collections.sort(deviceChannelList,new Comparator<Object>(){
@@ -169,7 +168,7 @@
                DeviceChannel deviceChannel = (DeviceChannel)redis.get((String)deviceChannelList.get(i));
                StreamInfo streamInfo = stringStreamInfoMap.get(deviceId + "_" + deviceChannel.getChannelId());
                deviceChannel.setPlay(streamInfo != null);
                if (streamInfo != null) deviceChannel.setSsrc(streamInfo.getSsrc());
                if (streamInfo != null) deviceChannel.setStreamId(streamInfo.getStreamId());
                result.add(deviceChannel);
            }
            pageResult.setData(result);
@@ -384,7 +383,7 @@
     */
    @Override
    public boolean startPlay(StreamInfo stream) {
        return redis.set(String.format("%S_%s_%s_%s", VideoManagerConstants.PLAYER_PREFIX, stream.getSsrc(),stream.getDeviceID(), stream.getCahnnelId()),
        return redis.set(String.format("%S_%s_%s_%s", VideoManagerConstants.PLAYER_PREFIX, stream.getStreamId(),stream.getDeviceID(), stream.getCahnnelId()),
                stream);
    }
@@ -398,12 +397,12 @@
        if (streamInfo == null) return false;
        DeviceChannel deviceChannel = queryChannel(streamInfo.getDeviceID(), streamInfo.getCahnnelId());
        if (deviceChannel != null) {
            deviceChannel.setSsrc(null);
            deviceChannel.setStreamId(null);
            deviceChannel.setPlay(false);
            updateChannel(streamInfo.getDeviceID(), deviceChannel);
        }
        return redis.del(String.format("%S_%s_%s_%s", VideoManagerConstants.PLAYER_PREFIX,
                streamInfo.getSsrc(),
                streamInfo.getStreamId(),
                streamInfo.getDeviceID(),
                streamInfo.getCahnnelId()));
    }
@@ -416,22 +415,20 @@
    public StreamInfo queryPlay(StreamInfo streamInfo) {
        return (StreamInfo)redis.get(String.format("%S_%s_%s_%s",
                VideoManagerConstants.PLAYER_PREFIX,
                streamInfo.getSsrc(),
                streamInfo.getStreamId(),
                streamInfo.getDeviceID(),
                streamInfo.getCahnnelId()));
    }
    @Override
    public StreamInfo queryPlayBySSRC(String ssrc) {
//        List<Object> playLeys = redis.keys(String.format("%S_%s_*", VideoManagerConstants.PLAYER_PREFIX, ssrc));
        List<Object> playLeys = redis.scan(String.format("%S_%s_*", VideoManagerConstants.PLAYER_PREFIX, ssrc));
    public StreamInfo queryPlayByStreamId(String steamId) {
        List<Object> playLeys = redis.scan(String.format("%S_%s_*", VideoManagerConstants.PLAYER_PREFIX, steamId));
        if (playLeys == null || playLeys.size() == 0) return null;
        return (StreamInfo)redis.get(playLeys.get(0).toString());
    }
    @Override
    public StreamInfo queryPlaybackBySSRC(String ssrc) {
//        List<Object> playLeys = redis.keys(String.format("%S_%s_*", VideoManagerConstants.PLAYER_PREFIX, ssrc));
        List<Object> playLeys = redis.scan(String.format("%S_%s_*", VideoManagerConstants.PLAY_BLACK_PREFIX, ssrc));
    public StreamInfo queryPlaybackByStreamId(String steamId) {
        List<Object> playLeys = redis.scan(String.format("%S_%s_*", VideoManagerConstants.PLAY_BLACK_PREFIX, steamId));
        if (playLeys == null || playLeys.size() == 0) return null;
        return (StreamInfo)redis.get(playLeys.get(0).toString());
    }
@@ -526,7 +523,7 @@
    @Override
    public boolean startPlayback(StreamInfo stream) {
        return redis.set(String.format("%S_%s_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX, stream.getSsrc(),stream.getDeviceID(), stream.getCahnnelId()),
        return redis.set(String.format("%S_%s_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX, stream.getStreamId(),stream.getDeviceID(), stream.getCahnnelId()),
                stream);
    }
@@ -536,12 +533,12 @@
        if (streamInfo == null) return false;
        DeviceChannel deviceChannel = queryChannel(streamInfo.getDeviceID(), streamInfo.getCahnnelId());
        if (deviceChannel != null) {
            deviceChannel.setSsrc(null);
            deviceChannel.setStreamId(null);
            deviceChannel.setPlay(false);
            updateChannel(streamInfo.getDeviceID(), deviceChannel);
        }
        return redis.del(String.format("%S_%s_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX,
                streamInfo.getSsrc(),
                streamInfo.getStreamId(),
                streamInfo.getDeviceID(),
                streamInfo.getCahnnelId()));
    }
src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java
@@ -80,7 +80,7 @@
                playService.onPublishHandlerForPlay(response, deviceId, channelId, uuid.toString());
            });
        } else {
            String streamId = String.format("%08x", Integer.parseInt(streamInfo.getSsrc())).toUpperCase();
            String streamId = streamInfo.getStreamId();
            JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(streamId);
            if (rtpInfo.getBoolean("exist")) {
                RequestMessage msg = new RequestMessage();
@@ -99,21 +99,21 @@
        return result;
    }
    @PostMapping("/play/{ssrc}/stop")
    public ResponseEntity<String> playStop(@PathVariable String ssrc) {
    @PostMapping("/play/{streamId}/stop")
    public ResponseEntity<String> playStop(@PathVariable String streamId) {
        cmder.streamByeCmd(ssrc);
        StreamInfo streamInfo = storager.queryPlayBySSRC(ssrc);
        cmder.streamByeCmd(streamId);
        StreamInfo streamInfo = storager.queryPlayByStreamId(streamId);
        if (streamInfo == null)
            return new ResponseEntity<String>("ssrc not found", HttpStatus.OK);
            return new ResponseEntity<String>("streamId not found", HttpStatus.OK);
        storager.stopPlay(streamInfo);
        if (logger.isDebugEnabled()) {
            logger.debug(String.format("设备预览停止API调用,ssrc:%s", ssrc));
            logger.debug(String.format("设备预览停止API调用,streamId:%s", streamId));
        }
        if (ssrc != null) {
        if (streamId != null) {
            JSONObject json = new JSONObject();
            json.put("ssrc", ssrc);
            json.put("streamId", streamId);
            return new ResponseEntity<String>(json.toString(), HttpStatus.OK);
        } else {
            logger.warn("设备预览停止API调用失败!");
@@ -123,17 +123,16 @@
    /**
     * 将不是h264的视频通过ffmpeg 转码为h264 + aac
     * @param ssrc
     * @param streamId 流ID
     * @return
     */
    @PostMapping("/play/{ssrc}/convert")
    public ResponseEntity<String> playConvert(@PathVariable String ssrc) {
        StreamInfo streamInfo = storager.queryPlayBySSRC(ssrc);
    @PostMapping("/play/{streamId}/convert")
    public ResponseEntity<String> playConvert(@PathVariable String streamId) {
        StreamInfo streamInfo = storager.queryPlayByStreamId(streamId);
        if (streamInfo == null) {
            logger.warn("视频转码API调用失败!, 视频流已经停止!");
            return new ResponseEntity<String>("未找到视频流信息, 视频流可能已经停止", HttpStatus.OK);
        }
        String streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase();
        JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(streamId);
        if (!rtpInfo.getBoolean("exist")) {
            logger.warn("视频转码API调用失败!, 视频流已停止推流!");
src/main/java/com/genersoft/iot/vmp/vmanager/playback/PlaybackController.java
@@ -72,7 +72,7 @@
        StreamInfo streamInfo = storager.queryPlaybackByDevice(deviceId, channelId);
        if (streamInfo != null) {
            // 停止之前的回放
            cmder.streamByeCmd(streamInfo.getSsrc());
            cmder.streamByeCmd(streamInfo.getStreamId());
        }
        resultHolder.put(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid, result);
        cmder.playbackStreamCmd(device, channelId, startTime, endTime, (JSONObject response) -> {
src/main/java/com/genersoft/iot/vmp/vmanager/service/impl/PlayServiceImpl.java
@@ -61,9 +61,7 @@
    public StreamInfo onPublishHandler(JSONObject resonse, String deviceId, String channelId, String uuid) {
        String streamId = resonse.getString("id");
        String ssrc = new DecimalFormat("0000000000").format(Integer.parseInt(streamId, 16));
        StreamInfo streamInfo = new StreamInfo();
        streamInfo.setSsrc(ssrc);
        streamInfo.setStreamId(streamId);
        streamInfo.setDeviceID(deviceId);
        streamInfo.setCahnnelId(channelId);
src/main/java/com/genersoft/iot/vmp/web/ApiDeviceController.java
@@ -159,7 +159,7 @@
            deviceJOSNChannel.put("PTZType ", deviceChannel.getPTZType()); // 云台类型, 0 - 未知, 1 - 球机, 2 - 半球,
                                                                            //   3 - 固定枪机, 4 - 遥控枪机
            deviceJOSNChannel.put("CustomPTZType", "");
            deviceJOSNChannel.put("StreamID", deviceChannel.getSsrc()); // StreamID 直播流ID, 有值表示正在直播
            deviceJOSNChannel.put("StreamID", deviceChannel.getStreamId()); // StreamID 直播流ID, 有值表示正在直播
            deviceJOSNChannel.put("NumOutputs ", -1); // 直播在线人数
            channleJSONList.add(deviceJOSNChannel);
        }
src/main/java/com/genersoft/iot/vmp/web/ApiStreamController.java
@@ -96,12 +96,12 @@
//            streamInfo = cmder.playStreamCmd(device, code);
        }else {
            logger.debug("streamInfo 不等于null, 向流媒体查询是否正在推流");
            String streamId = String.format("%08x", Integer.parseInt(streamInfo.getSsrc())).toUpperCase();
            String streamId = streamInfo.getStreamId();
            JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(streamId);
            if (rtpInfo.getBoolean("exist")) {
                logger.debug("向流媒体查询正在推流, 直接返回: " + streamInfo.getRtsp());
                JSONObject result = new JSONObject();
                result.put("StreamID", streamInfo.getSsrc());
                result.put("StreamID", streamInfo.getStreamId());
                result.put("DeviceID", device.getDeviceId());
                result.put("ChannelID", code);
                result.put("ChannelName", deviceChannel.getName());
@@ -141,7 +141,7 @@
        if (logger.isDebugEnabled()) {
            logger.debug(String.format("设备预览 API调用,deviceId:%s ,channelId:%s",serial, code));
            logger.debug("设备预览 API调用,ssrc:"+streamInfo.getSsrc()+",ZLMedia streamId:"+Integer.toHexString(Integer.parseInt(streamInfo.getSsrc())));
            logger.debug("设备预览 API调用,streamId:"+streamInfo.getStreamId());
        }
        boolean lockFlag = true;
        long startTime = System.currentTimeMillis();
@@ -173,7 +173,7 @@
        }
        if(streamInfo!=null) {
            JSONObject result = new JSONObject();
            result.put("StreamID", streamInfo.getSsrc());
            result.put("StreamID", streamInfo.getStreamId());
            result.put("DeviceID", device.getDeviceId());
            result.put("ChannelID", code);
            result.put("ChannelName", deviceChannel.getName());
@@ -234,7 +234,7 @@
            result.put("error","未找到流信息");
            return result;
        }
        cmder.streamByeCmd(streamInfo.getSsrc());
        cmder.streamByeCmd(streamInfo.getStreamId());
        storager.stopPlay(streamInfo);
        return null;
    }
src/main/resources/application-dev.yml
@@ -74,6 +74,8 @@
    # 设为false可以获得更好的兼容性,保证返回后流就可以播放,
    # 设为true可以快速打开播放窗口,可以获得更好的体验
    closeWaitRTPInfo: false
    # [可选] 自动点播, 使用固定流地址进行播放时,如果未点播则自动进行点播
    autoApplyPlay: true
    # 启用udp多端口模式, 详细解释参考: https://github.com/xia-chu/ZLMediaKit/wiki/GB28181%E6%8E%A8%E6%B5%81 下的高阶使用
    rtp:
        # [可选] 是否启用udp多端口模式, 开启后会在udpPortRange范围内选择端口用于媒体流传输
web_src/src/components/channelList.vue
@@ -187,9 +187,9 @@
                url: '/api/play/' + deviceId + '/' + channelId + '?getEncoding=' + getEncoding
            }).then(function (res) {
                console.log(res.data)
                let ssrc = res.data.ssrc;
                let streamId = res.data.streamId;
                that.isLoging = false;
                if (!!ssrc) {
                if (!!streamId) {
                    // that.$refs.devicePlayer.play(res.data, deviceId, channelId, itemData.hasAudio);
                    that.$refs.devicePlayer.openDialog("media", deviceId, channelId, {
                        streamInfo: res.data,
@@ -212,7 +212,7 @@
            var that = this;
            this.$axios({
                method: 'post',
                url: '/api/play/' + itemData.ssrc + '/stop'
                url: '/api/play/' + itemData.streamId + '/stop'
            }).then(function (res) {
                console.log(JSON.stringify(res));
                that.initData();
web_src/src/components/gb28181/devicePlayer.vue
@@ -158,7 +158,6 @@
                searchHistoryResult: [] //媒体流历史记录搜索结果
            },
            showVideoDialog: false,
            ssrc: '',
            streamId: '',
            convertKey: '',
            deviceId: '',
@@ -210,7 +209,6 @@
            this.tabActiveName = tab;
            this.channelId = channelId;
            this.deviceId = deviceId;
            this.ssrc = "";
            this.streamId = "";
            this.videoUrl = ""
            if (!!this.$refs.videoPlayer) {
@@ -238,7 +236,6 @@
            this.hasaudio = hasAudio;
            this.isLoging = false;
            this.videoUrl = streamInfo.ws_flv;
            this.ssrc = streamInfo.ssrc;
            this.streamId = streamInfo.streamId;
            this.playFromStreamInfo(false, streamInfo)
        },
@@ -248,7 +245,7 @@
            this.$refs.videoPlayer.pause()
            that.$axios({
                method: 'post',
                url: '/api/play/' + that.ssrc + '/convert'
                url: '/api/play/' + that.streamId + '/convert'
                }).then(function (res) {
                    if (res.data.code == 0) {
                        that.convertKey = res.data.key;
@@ -368,9 +365,9 @@
        },
        playRecord: function (row) {
            let that = this;
            if (that.ssrc != "") {
            if (that.streamId != "") {
                that.stopPlayRecord(function () {
                    that.ssrc = "",
                    that.streamId = "",
                        that.playRecord(row);
                })
            } else {
@@ -380,7 +377,7 @@
                        row.endTime
                }).then(function (res) {
                    var streamInfo = res.data;
                    that.ssrc = streamInfo.ssrc;
                    that.streamId = streamInfo.streamId;
                    that.videoUrl = streamInfo.ws_flv;
                });
            }
@@ -390,7 +387,7 @@
            this.videoUrl = '';
            this.$axios({
                method: 'get',
                url: '/api/playback/' + this.ssrc + '/stop'
                url: '/api/playback/' + this.streamId + '/stop'
            }).then(function (res) {
                if (callback) callback()
            });