[1078] 支持通用通道的点播

This commit is contained in:
lin
2025-07-29 14:46:16 +08:00
parent 4c97022c78
commit 0ed395ff2e
8 changed files with 134 additions and 10 deletions

View File

@@ -307,7 +307,6 @@ public class CommonChannelController {
wvpResult.setCode(code); wvpResult.setCode(code);
wvpResult.setMsg(msg); wvpResult.setMsg(msg);
} }
result.setResult(wvpResult); result.setResult(wvpResult);
}else { }else {
result.setResult(WVPResult.fail(code, msg)); result.setResult(WVPResult.fail(code, msg));

View File

@@ -21,12 +21,16 @@ public interface IGbChannelPlayService {
void playProxy(CommonGBChannel channel, Boolean record, ErrorCallback<StreamInfo> callback); void playProxy(CommonGBChannel channel, Boolean record, ErrorCallback<StreamInfo> callback);
void playJt1078(CommonGBChannel channel, Boolean record, ErrorCallback<StreamInfo> callback);
void stopPlayProxy(CommonGBChannel channel); void stopPlayProxy(CommonGBChannel channel);
void playPush(CommonGBChannel channel, String platformDeviceId, String platformName, ErrorCallback<StreamInfo> callback); void playPush(CommonGBChannel channel, String platformDeviceId, String platformName, ErrorCallback<StreamInfo> callback);
void stopPlayPush(CommonGBChannel channel); void stopPlayPush(CommonGBChannel channel);
void stopPlayJt1078(CommonGBChannel channel);
void pauseRtp(String streamId); void pauseRtp(String streamId);
void resumeRtp(String streamId); void resumeRtp(String streamId);

View File

@@ -12,6 +12,7 @@ import com.genersoft.iot.vmp.gb28181.bean.Platform;
import com.genersoft.iot.vmp.gb28181.bean.PlayException; import com.genersoft.iot.vmp.gb28181.bean.PlayException;
import com.genersoft.iot.vmp.gb28181.service.IGbChannelPlayService; import com.genersoft.iot.vmp.gb28181.service.IGbChannelPlayService;
import com.genersoft.iot.vmp.gb28181.service.IPlayService; import com.genersoft.iot.vmp.gb28181.service.IPlayService;
import com.genersoft.iot.vmp.jt1078.service.Ijt1078PlayService;
import com.genersoft.iot.vmp.service.bean.ErrorCallback; import com.genersoft.iot.vmp.service.bean.ErrorCallback;
import com.genersoft.iot.vmp.streamProxy.service.IStreamProxyPlayService; import com.genersoft.iot.vmp.streamProxy.service.IStreamProxyPlayService;
import com.genersoft.iot.vmp.streamPush.service.IStreamPushPlayService; import com.genersoft.iot.vmp.streamPush.service.IStreamPushPlayService;
@@ -34,6 +35,9 @@ public class GbChannelPlayServiceImpl implements IGbChannelPlayService {
@Autowired @Autowired
private IStreamProxyPlayService streamProxyPlayService; private IStreamProxyPlayService streamProxyPlayService;
@Autowired
private Ijt1078PlayService jt1078PlayService;
@Autowired @Autowired
private IStreamPushPlayService streamPushPlayService; private IStreamPushPlayService streamPushPlayService;
@@ -54,6 +58,9 @@ public class GbChannelPlayServiceImpl implements IGbChannelPlayService {
if (channel.getDataType() == ChannelDataType.GB28181.value) { if (channel.getDataType() == ChannelDataType.GB28181.value) {
// 国标通道 // 国标通道
playbackGbDeviceChannel(channel, inviteInfo.getStartTime(), inviteInfo.getStopTime(), callback); playbackGbDeviceChannel(channel, inviteInfo.getStartTime(), inviteInfo.getStopTime(), callback);
} else if (channel.getDataType() == ChannelDataType.JT_1078.value) {
// 部标通道
playbackJtDeviceChannel(channel, inviteInfo.getStartTime(), inviteInfo.getStopTime(), callback);
} else if (channel.getDataType() == ChannelDataType.STREAM_PROXY.value) { } else if (channel.getDataType() == ChannelDataType.STREAM_PROXY.value) {
// 拉流代理 // 拉流代理
log.warn("[回放通用通道] 不支持回放拉流代理的录像: {}({})", channel.getGbName(), channel.getGbDeviceId()); log.warn("[回放通用通道] 不支持回放拉流代理的录像: {}({})", channel.getGbName(), channel.getGbDeviceId());
@@ -78,6 +85,10 @@ public class GbChannelPlayServiceImpl implements IGbChannelPlayService {
// 国标通道 // 国标通道
downloadGbDeviceChannel(channel, inviteInfo.getStartTime(), inviteInfo.getStopTime(), downloadSpeed, callback); downloadGbDeviceChannel(channel, inviteInfo.getStartTime(), inviteInfo.getStopTime(), downloadSpeed, callback);
} else if (channel.getDataType() == ChannelDataType.JT_1078.value) {
// 部标录像下载
log.warn("[下载通用通道录像] 不支持下载部标的录像: {}({})", channel.getGbName(), channel.getGbDeviceId());
throw new PlayException(Response.FORBIDDEN, "forbidden");
} else if (channel.getDataType() == ChannelDataType.STREAM_PROXY.value) { } else if (channel.getDataType() == ChannelDataType.STREAM_PROXY.value) {
// 拉流代理 // 拉流代理
log.warn("[下载通用通道录像] 不支持下载拉流代理的录像: {}({})", channel.getGbName(), channel.getGbDeviceId()); log.warn("[下载通用通道录像] 不支持下载拉流代理的录像: {}({})", channel.getGbName(), channel.getGbDeviceId());
@@ -109,6 +120,9 @@ public class GbChannelPlayServiceImpl implements IGbChannelPlayService {
} else if (channel.getDataType() == ChannelDataType.STREAM_PUSH.value) { } else if (channel.getDataType() == ChannelDataType.STREAM_PUSH.value) {
// 推流 // 推流
stopPlayPush(channel); stopPlayPush(channel);
} else if (channel.getDataType() == ChannelDataType.JT_1078.value) {
// 推流
stopPlayJt1078(channel);
} else { } else {
// 通道数据异常 // 通道数据异常
log.error("[点播通用通道] 通道数据异常,无法识别通道来源: {}({})", channel.getGbName(), channel.getGbDeviceId()); log.error("[点播通用通道] 通道数据异常,无法识别通道来源: {}({})", channel.getGbName(), channel.getGbDeviceId());
@@ -116,6 +130,8 @@ public class GbChannelPlayServiceImpl implements IGbChannelPlayService {
} }
} }
@Override @Override
public void play(CommonGBChannel channel, Platform platform, Boolean record, ErrorCallback<StreamInfo> callback) { public void play(CommonGBChannel channel, Platform platform, Boolean record, ErrorCallback<StreamInfo> callback) {
log.info("[通用通道] 播放, 类型: {} 编号:{}", channel.getDataType(), channel.getGbDeviceId()); log.info("[通用通道] 播放, 类型: {} 编号:{}", channel.getDataType(), channel.getGbDeviceId());
@@ -133,6 +149,9 @@ public class GbChannelPlayServiceImpl implements IGbChannelPlayService {
// 推流 // 推流
playPush(channel, null, null, callback); playPush(channel, null, null, callback);
} }
} else if (channel.getDataType() == ChannelDataType.JT_1078.value) {
// 部标设备
playJt1078(channel, record, callback);
} else { } else {
// 通道数据异常 // 通道数据异常
log.error("[点播通用通道] 通道数据异常,无法识别通道来源: {}({})", channel.getGbName(), channel.getGbDeviceId()); log.error("[点播通用通道] 通道数据异常,无法识别通道来源: {}({})", channel.getGbName(), channel.getGbDeviceId());
@@ -172,6 +191,18 @@ public class GbChannelPlayServiceImpl implements IGbChannelPlayService {
try { try {
streamProxyPlayService.start(channel.getDataDeviceId(), record, callback); streamProxyPlayService.start(channel.getDataDeviceId(), record, callback);
}catch (Exception e) { }catch (Exception e) {
log.info("[通用通道] 拉流代理点播异常 {}", e.getMessage());
callback.run(Response.BUSY_HERE, "busy here", null);
}
}
@Override
public void playJt1078(CommonGBChannel channel, Boolean record, ErrorCallback<StreamInfo> callback){
// 部标设备通道
try {
jt1078PlayService.start(channel.getDataDeviceId(), record, callback);
}catch (Exception e) {
log.info("[通用通道] 部标设备点播异常 {}", e.getMessage());
callback.run(Response.BUSY_HERE, "busy here", null); callback.run(Response.BUSY_HERE, "busy here", null);
} }
} }
@@ -209,6 +240,16 @@ public class GbChannelPlayServiceImpl implements IGbChannelPlayService {
} }
} }
@Override
public void stopPlayJt1078(CommonGBChannel channel) {
// 推流
try {
jt1078PlayService.stop(channel.getDataDeviceId());
}catch (Exception e) {
log.error("[停止点播失败] {}({})", channel.getGbName(), channel.getGbDeviceId(), e);
}
}
private void playbackGbDeviceChannel(CommonGBChannel channel, Long startTime, Long stopTime, ErrorCallback<StreamInfo> callback){ private void playbackGbDeviceChannel(CommonGBChannel channel, Long startTime, Long stopTime, ErrorCallback<StreamInfo> callback){
try { try {
deviceChannelPlayService.playBack(channel, startTime, stopTime, callback); deviceChannelPlayService.playBack(channel, startTime, stopTime, callback);
@@ -219,6 +260,16 @@ public class GbChannelPlayServiceImpl implements IGbChannelPlayService {
} }
} }
private void playbackJtDeviceChannel(CommonGBChannel channel, Long startTime, Long stopTime, ErrorCallback<StreamInfo> callback){
try {
jt1078PlayService.playBack(channel.getDataDeviceId(), startTime, stopTime, callback);
} catch (PlayException e) {
callback.run(e.getCode(), e.getMsg(), null);
} catch (Exception e) {
callback.run(Response.BUSY_HERE, "busy here", null);
}
}
@Override @Override
public void pauseRtp(String streamId) { public void pauseRtp(String streamId) {
try { try {
@@ -243,6 +294,4 @@ public class GbChannelPlayServiceImpl implements IGbChannelPlayService {
callback.run(Response.BUSY_HERE, "busy here", null); callback.run(Response.BUSY_HERE, "busy here", null);
} }
} }
} }

View File

@@ -26,7 +26,7 @@ public class J0200 extends Re {
@Override @Override
protected Rs decode0(ByteBuf buf, Header header, Session session) { protected Rs decode0(ByteBuf buf, Header header, Session session) {
positionInfo = JTPositionBaseInfo.decode(buf); positionInfo = JTPositionBaseInfo.decode(buf);
log.info("[JT-位置汇报]: phoneNumber={} {}", header.getPhoneNumber(), positionInfo.toSimpleString()); log.debug("[JT-位置汇报]: phoneNumber={} {}", header.getPhoneNumber(), positionInfo.toSimpleString());
// 读取附加信息 // 读取附加信息
// JTPositionAdditionalInfo positionAdditionalInfo = new JTPositionAdditionalInfo(); // JTPositionAdditionalInfo positionAdditionalInfo = new JTPositionAdditionalInfo();
// Map<Integer, byte[]> additionalMsg = new HashMap<>(); // Map<Integer, byte[]> additionalMsg = new HashMap<>();

View File

@@ -2,8 +2,10 @@ package com.genersoft.iot.vmp.jt1078.service;
import com.genersoft.iot.vmp.common.CommonCallback; import com.genersoft.iot.vmp.common.CommonCallback;
import com.genersoft.iot.vmp.common.StreamInfo; import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.gb28181.bean.CommonGBChannel;
import com.genersoft.iot.vmp.jt1078.bean.*; import com.genersoft.iot.vmp.jt1078.bean.*;
import com.genersoft.iot.vmp.jt1078.proc.request.J1205; import com.genersoft.iot.vmp.jt1078.proc.request.J1205;
import com.genersoft.iot.vmp.service.bean.ErrorCallback;
import com.genersoft.iot.vmp.vmanager.bean.WVPResult; import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
import java.util.List; import java.util.List;
@@ -33,4 +35,9 @@ public interface Ijt1078PlayService {
void playbackControl(String phoneNumber, Integer channelId, Integer command, Integer playbackSpeed, String time); void playbackControl(String phoneNumber, Integer channelId, Integer command, Integer playbackSpeed, String time);
void start(Integer channelId, Boolean record, ErrorCallback<StreamInfo> callback);
void stop(Integer channelId);
void playBack(Integer channelId, Long startTime, Long stopTime, ErrorCallback<StreamInfo> callback);
} }

View File

@@ -7,9 +7,7 @@ import com.genersoft.iot.vmp.conf.DynamicTask;
import com.genersoft.iot.vmp.conf.UserSetting; import com.genersoft.iot.vmp.conf.UserSetting;
import com.genersoft.iot.vmp.conf.exception.ControllerException; import com.genersoft.iot.vmp.conf.exception.ControllerException;
import com.genersoft.iot.vmp.conf.ftpServer.FtpSetting; import com.genersoft.iot.vmp.conf.ftpServer.FtpSetting;
import com.genersoft.iot.vmp.gb28181.bean.Device; import com.genersoft.iot.vmp.gb28181.bean.*;
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
import com.genersoft.iot.vmp.gb28181.bean.SendRtpInfo;
import com.genersoft.iot.vmp.jt1078.bean.*; import com.genersoft.iot.vmp.jt1078.bean.*;
import com.genersoft.iot.vmp.jt1078.cmd.JT1078Template; import com.genersoft.iot.vmp.jt1078.cmd.JT1078Template;
import com.genersoft.iot.vmp.jt1078.event.FtpUploadEvent; import com.genersoft.iot.vmp.jt1078.event.FtpUploadEvent;
@@ -29,6 +27,7 @@ import com.genersoft.iot.vmp.media.event.media.MediaNotFoundEvent;
import com.genersoft.iot.vmp.media.event.mediaServer.MediaSendRtpStoppedEvent; import com.genersoft.iot.vmp.media.event.mediaServer.MediaSendRtpStoppedEvent;
import com.genersoft.iot.vmp.media.service.IMediaServerService; import com.genersoft.iot.vmp.media.service.IMediaServerService;
import com.genersoft.iot.vmp.service.ISendRtpServerService; import com.genersoft.iot.vmp.service.ISendRtpServerService;
import com.genersoft.iot.vmp.service.bean.ErrorCallback;
import com.genersoft.iot.vmp.service.bean.InviteErrorCode; import com.genersoft.iot.vmp.service.bean.InviteErrorCode;
import com.genersoft.iot.vmp.service.bean.SSRCInfo; import com.genersoft.iot.vmp.service.bean.SSRCInfo;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
@@ -45,6 +44,7 @@ import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import javax.sip.message.Response;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -191,7 +191,12 @@ public class jt1078PlayServiceImpl implements Ijt1078PlayService {
if (channel == null) { if (channel == null) {
throw new ControllerException(ErrorCode.ERROR100.getCode(), "通道不存在"); throw new ControllerException(ErrorCode.ERROR100.getCode(), "通道不存在");
} }
play(device, channel, type, callback);
}
private void play(JTDevice device, JTChannel channel, int type, CommonCallback<WVPResult<StreamInfo>> callback) {
String phoneNumber = device.getPhoneNumber();
int channelId = channel.getId();
String app = "1078"; String app = "1078";
String stream = phoneNumber + "_" + channelId; String stream = phoneNumber + "_" + channelId;
// 检查流是否已经存在,存在则返回 // 检查流是否已经存在,存在则返回
@@ -375,6 +380,8 @@ public class jt1078PlayServiceImpl implements Ijt1078PlayService {
return JRecordItemList; return JRecordItemList;
} }
@Override @Override
public void playback(String phoneNumber, Integer channelId, String startTime, String endTime, Integer type, public void playback(String phoneNumber, Integer channelId, String startTime, String endTime, Integer type,
Integer rate, Integer playbackType, Integer playbackSpeed, CommonCallback<WVPResult<StreamInfo>> callback) { Integer rate, Integer playbackType, Integer playbackSpeed, CommonCallback<WVPResult<StreamInfo>> callback) {
@@ -387,7 +394,27 @@ public class jt1078PlayServiceImpl implements Ijt1078PlayService {
if (channel == null) { if (channel == null) {
throw new ControllerException(ErrorCode.ERROR100.getCode(), "通道不存在"); throw new ControllerException(ErrorCode.ERROR100.getCode(), "通道不存在");
} }
playback(device, channel, startTime, endTime, type, rate, playbackType, playbackSpeed, callback);
}
/**
* 回放
* @param device 设备
* @param channel 通道
* @param startTime 开始时间
* @param endTime 结束时间
* @param type 音视频资源类型0.音视频 1.音频 2.视频 3.视频或音视频
* @param rate 码流类型0.所有码流 1.主码流 2.子码流(如果此通道只传输音频,此字段置0)
* @param playbackType 回放方式0.正常回放 1.快进回放 2.关键帧快退回放 3.关键帧播放 4.单帧上传
* @param playbackSpeed 快进或快退倍数0.无效 1.1倍 2.2倍 3.4倍 4.8倍 5.16倍 (回放控制为1和2时,此字段内容有效,否则置0)
* @param callback 结束回调
*/
private void playback(JTDevice device, JTChannel channel, String startTime, String endTime, Integer type,
Integer rate, Integer playbackType, Integer playbackSpeed, CommonCallback<WVPResult<StreamInfo>> callback) {
String phoneNumber = device.getPhoneNumber();
Integer channelId = channel.getChannelId();
log.info("[JT-回放] 回放,设备:{} 通道: {} 开始时间: {} 结束时间: {} 音视频类型: {} 码流类型: {} " + log.info("[JT-回放] 回放,设备:{} 通道: {} 开始时间: {} 结束时间: {} 音视频类型: {} 码流类型: {} " +
"回放方式: {} 快进或快退倍数: {}", phoneNumber, channelId, startTime, endTime, type, rate, playbackType, playbackSpeed); "回放方式: {} 快进或快退倍数: {}", phoneNumber, channelId, startTime, endTime, type, rate, playbackType, playbackSpeed);
// 检查流是否已经存在,存在则返回 // 检查流是否已经存在,存在则返回
@@ -646,4 +673,40 @@ public class jt1078PlayServiceImpl implements Ijt1078PlayService {
} }
} }
} }
@Override
public void start(Integer channelId, Boolean record, ErrorCallback<StreamInfo> callback) {
JTChannel channel = jt1078Service.getChannelByDbId(channelId);
Assert.notNull(channel, "通道不存在");
JTDevice device = jt1078Service.getDeviceById(channel.getDataDeviceId());
Assert.notNull(device, "设备不存在");
jt1078Template.checkTerminalStatus(device.getPhoneNumber());
play(device, channel, 0,
result -> callback.run(result.getCode(), result.getMsg(), result.getData()));
}
@Override
public void stop(Integer channelId) {
JTChannel channel = jt1078Service.getChannelByDbId(channelId);
Assert.notNull(channel, "通道不存在");
JTDevice device = jt1078Service.getDeviceById(channel.getDataDeviceId());
Assert.notNull(device, "设备不存在");
stopPlay(device.getPhoneNumber(), channel.getChannelId());
}
@Override
public void playBack(Integer channelId, Long startTime, Long stopTime, ErrorCallback<StreamInfo> callback) {
if (startTime == null || stopTime == null) {
throw new PlayException(Response.BAD_REQUEST, "bad request");
}
JTChannel channel = jt1078Service.getChannelByDbId(channelId);
Assert.notNull(channel, "通道不存在");
JTDevice device = jt1078Service.getDeviceById(channel.getDataDeviceId());
Assert.notNull(device, "设备不存在");
jt1078Template.checkTerminalStatus(device.getPhoneNumber());
String startTimeStr = DateUtil.timestampTo_yyyy_MM_dd_HH_mm_ss(startTime);
String stopTimeStr = DateUtil.timestampTo_yyyy_MM_dd_HH_mm_ss(stopTime);
playback(device, channel, startTimeStr, stopTimeStr, 0, 1, 0, 0,
result -> callback.run(result.getCode(), result.getMsg(), result.getData()));
}
} }

View File

@@ -40,9 +40,10 @@ Vue.use(VueClipboard)
Vue.config.productionTip = false Vue.config.productionTip = false
Vue.prototype.$channelTypeList = { Vue.prototype.$channelTypeList = {
1: { id: 1, name: '国标设备', style: { color: '#409eff', borderColor: '#b3d8ff' }}, 1: { id: 1, name: '国标设备', style: { color: '#409eff', borderColor: '#b3d8ff' } },
2: { id: 2, name: '推流设备', style: { color: '#67c23a', borderColor: '#c2e7b0' }}, 2: { id: 2, name: '推流设备', style: { color: '#67c23a', borderColor: '#c2e7b0' } },
3: { id: 3, name: '拉流代理', style: { color: '#e6a23c', borderColor: '#f5dab1' }} 3: { id: 3, name: '拉流代理', style: { color: '#e6a23c', borderColor: '#f5dab1' } },
200: { id: 200, name: '部标设备', style: { color: '#36c6fa', borderColor: '#90e3fb' } }
} }
new Vue({ new Vue({

View File

@@ -218,6 +218,7 @@ export default {
this.getChannelList() this.getChannelList()
}, },
getChannelList: function() { getChannelList: function() {
this.channelList = []
this.$store.dispatch('commonChanel/getList', { this.$store.dispatch('commonChanel/getList', {
page: this.currentPage, page: this.currentPage,
count: this.count, count: this.count,