ONVIF NVR通道回放技术求助:时间过滤失效与通道获取不全
问题解答
1. RecordingInformationFilter的正确用法
当前的过滤字符串格式不符合ONVIF规范,RecordingInformationFilter要求使用XPath表达式,而非自定义的逗号分隔格式。要实现时间范围过滤,需同时指定开始和结束时间,并结合录像的时间属性进行匹配:
正确的XPath过滤表达式
需同时满足两个核心条件:
- 过滤视频轨道:
//Track[TrackType="Video"] - 时间范围匹配:
../StartTime <= '{endTime}' and ../EndTime >= '{startTime}'(..表示向上定位到RecordingInformation节点)
修改后的代码片段:
// 定义时间范围:10分钟前到9分钟前 var startTime = DateTime.Now.AddMinutes(-10).ToString("yyyy-MM-ddTHH:mm:ss.fffffffZ", CultureInfo.InvariantCulture); var endTime = DateTime.Now.AddMinutes(-9).ToString("yyyy-MM-ddTHH:mm:ss.fffffffZ", CultureInfo.InvariantCulture); // 组合符合规范的XPath过滤条件 searchScope.RecordingInformationFilter = $"boolean(//Track[TrackType=\"Video\"] and ../StartTime <= '{endTime}' and ../EndTime >= '{startTime}')";
补充:强制限定回放时间范围
仅通过搜索过滤还不够,获取回放URL时需在StreamSetup中添加回放配置参数,直接指定播放的时间范围:
Replay.StreamSetup streamSetup = new Replay.StreamSetup(); streamSetup.Stream = Replay.StreamType.RTPUnicast; streamSetup.Transport = new Replay.Transport(); streamSetup.Transport.Protocol = Replay.TransportProtocol.RTSP; // 添加回放时间范围控制 streamSetup.ReplayConfiguration = new Replay.ReplayConfiguration(); streamSetup.ReplayConfiguration.PlaybackSpeed = 1.0F; streamSetup.ReplayConfiguration.PlaybackMode = Replay.PlaybackMode.Normal; streamSetup.ReplayConfiguration.Range = new Replay.TimeRange(); streamSetup.ReplayConfiguration.Range.StartTime = DateTime.Parse(startTime).ToUniversalTime(); streamSetup.ReplayConfiguration.Range.EndTime = DateTime.Parse(endTime).ToUniversalTime();
2. 全通道回放URL获取方法
仅获取到通道1的回放,原因在于SearchScope未覆盖所有通道的录制源,或者搜索逻辑仅匹配了通道1的录制令牌。
解决步骤
- 先获取所有通道的录制源:调用
GetRecordings接口获取NVR上所有通道的录制信息,而非直接通过FindRecordings过滤 - 逐个通道匹配时间范围:对每个通道的录制令牌,单独检查是否存在目标时间范围内的录像
修改后的核心代码:
// 获取所有通道的录制源信息 var allRecordings = searchClient.GetRecordings(null, 0, 100); foreach (var recording in allRecordings.RecordingInformation) { // 针对当前通道的录制令牌,单独设置时间过滤规则 Search.SearchScope singleChannelScope = new Search.SearchScope(); singleChannelScope.RecordingTokens = new string[] { recording.RecordingToken }; singleChannelScope.RecordingInformationFilter = $"boolean(//Track[TrackType=\"Video\"] and ../StartTime <= '{endTime}' and ../EndTime >= '{startTime}')"; // 搜索该通道下符合时间条件的录像 var searchToken = searchClient.FindRecordings(singleChannelScope, 100, "PT30S"); var searchResults = searchClient.GetRecordingSearchResults(searchToken, 0, 10, "PT30S"); if (searchResults != null && searchResults.RecordingInformation.Length > 0) { // 获取该通道的回放URL string replayUrl = replayClient.GetReplayUri(streamSetup, recording.RecordingToken); Console.WriteLine($"通道[{recording.Source.Name}]回放URL: {replayUrl}"); } }
额外提示
部分NVR的RecordingToken或RecordingInformation.Source.Name会包含通道标识(如channel1、通道1),可通过这些字段直接区分不同通道。
3. 直播流URL与通道、码流的关联区分
由于不同品牌NVR的RTSP URL格式不统一,推荐通过以下两种方式实现关联:
方式1:通过ONVIF标准接口关联(推荐)
调用GetProfiles接口获取每个通道的媒体配置文件,每个配置文件对应一个码流(主/子码流各有独立的Profile),其中包含:
Token: 配置文件令牌,调用GetStreamUri时传入该令牌即可获取对应码流的URLName: 配置文件名称(通常包含通道和码流类型,如Channel 1 Main、通道1子码流)VideoEncoderConfiguration: 码流参数(分辨率、码率,可通过参数高低区分主/子码流)
示例代码逻辑:
MediaPortClient mediaClient = new MediaPortClient(customBinding, new EndpointAddress("http://" + deviceIp + ":" + port + "/onvif/media_service")); mediaClient.Endpoint.Behaviors.Add(passwordDigestBehavior); var profiles = mediaClient.GetProfiles(); foreach (var profile in profiles) { // 区分主/子码流:通过名称或分辨率判断 bool isMainStream = profile.Name.Contains("Main") || profile.VideoEncoderConfiguration.Resolution.Width >= 1920; string streamType = isMainStream ? "主码流" : "子码流"; string channelName = profile.Source.Name; // 获取对应码流的URL var streamUri = mediaClient.GetStreamUri(new Media.StreamSetup { Stream = Media.StreamType.RTPUnicast, Transport = new Media.Transport { Protocol = Media.TransportProtocol.RTSP } }, profile.Token); Console.WriteLine($"通道[{channelName}] {streamType} URL: {streamUri.Uri}"); }
方式2:解析URL特征字段(兼容方案)
如果必须通过URL解析,可提取各品牌URL中的通用特征:
- 通道标识:URL中包含
channel=1、ch01、stream1等字段 - 码流标识:URL中包含
main、sub、high、low、101(通道1+主码流)、102(通道1+子码流)等字段
例如:
- 海康NVR主码流:
rtsp://admin:xxx@192.168.1.1:554/Streaming/Channels/101 - 海康NVR子码流:
rtsp://admin:xxx@192.168.1.1:554/Streaming/Channels/102
内容的提问来源于stack exchange,提问作者S. Lui




