增加 SmartFrame 强制收回逻辑

This commit is contained in:
2026-01-17 15:41:55 +08:00
parent e06c60968d
commit 2992306056
7 changed files with 205 additions and 48 deletions

View File

@@ -257,6 +257,10 @@ public abstract class BaseVideoSource : IVideoSource, IAsyncDisposable, IDeviceC
/// </summary>
public async Task StartAsync()
{
// Optimized: [原因] 增加销毁前置检查,配合 Bug 修复方案
if (_isDisposed || _lifecycleLock == null)
throw new ObjectDisposedException(nameof(BaseVideoSource), "设备实例已销毁");
// 死锁免疫:不捕获当前同步上下文
await _lifecycleLock.WaitAsync().ConfigureAwait(false);
try
@@ -443,7 +447,7 @@ public abstract class BaseVideoSource : IVideoSource, IAsyncDisposable, IDeviceC
var changeLog = new List<string>();
if (options.StreamType.HasValue) changeLog.Add($"码流类型={options.StreamType}");
if (options.RenderHandle.HasValue) changeLog.Add($"渲染句柄已更新");
if (options.TargetAnalyzeFps.HasValue) changeLog.Add($"分析帧率={options.TargetAnalyzeFps}fps");
if (options.TargetFps.HasValue) changeLog.Add($"分析帧率={options.TargetFps}fps");
AddAuditLog($"动态参数应用: {string.Join(" | ", changeLog)}");
}
@@ -533,13 +537,13 @@ public abstract class BaseVideoSource : IVideoSource, IAsyncDisposable, IDeviceC
// --- B. 结算网络带宽 (Mbps) ---
// 公式: (字节数 * 8位) / 1024 / 1024 / 秒数
long bytes = Interlocked.Exchange(ref _tempByteCounter, 0);
_currentBitrate = Math.Round((bytes * 8.0) / 1024 / 1024 / duration, 2);
_currentBitrate = Math.Round((bytes * 8.0) / 1048576.0 / duration, 2);
}
else
{
// 初始化重置
_tempFrameCounter = 0;
_tempByteCounter = 0;
// 初始化重置:确保原子性
Interlocked.Exchange(ref _tempFrameCounter, 0);
Interlocked.Exchange(ref _tempByteCounter, 0);
}
// 更新结算时间锚点
@@ -635,6 +639,14 @@ public abstract class BaseVideoSource : IVideoSource, IAsyncDisposable, IDeviceC
{
_sdkLog.Fatal(ex, "设备 {Id} 状态分发器致命异常", Id);
}
finally
{
// Optimized: [原因] 确保在分发器关闭后,缓冲区内残余的状态消息能被强制消费完。
while (_statusQueue.Reader.TryRead(out var args))
{
try { StatusChanged?.Invoke(this, args); } catch { /* 忽略销毁期的回调异常 */ }
}
}
}
/// <summary>
@@ -744,6 +756,10 @@ public abstract class BaseVideoSource : IVideoSource, IAsyncDisposable, IDeviceC
// 防止重复 Dispose
if (_isDisposed) return;
// 提前锁定并获取引用
var semaphore = _lifecycleLock;
if (semaphore == null) return;
// Optimized: [原因] 获取生命周期锁,防止在 DisposeAsync 执行期间被并发触发 Start/Stop 操作
await _lifecycleLock.WaitAsync().ConfigureAwait(false);
@@ -751,11 +767,12 @@ public abstract class BaseVideoSource : IVideoSource, IAsyncDisposable, IDeviceC
{
// 防止重复 Dispose
if (_isDisposed) return;
_isDisposed = true;
// 1. 停止业务逻辑
await StopAsync().ConfigureAwait(false);
_isDisposed = true;
// 2. 优雅关闭状态分发器
_statusQueue.Writer.TryComplete(); // 标记队列不再接受新消息
_distributorCts?.Cancel(); // 触发分发器取消
@@ -776,9 +793,13 @@ public abstract class BaseVideoSource : IVideoSource, IAsyncDisposable, IDeviceC
}
finally
{
// Modified: [原因] 保证计数锁在任何情况下都能释放
if (!_isDisposed)
_lifecycleLock.Release();
// Optimized: [原因] 修复信号量销毁顺序。
// 先释放锁,让可能存在的阻塞线程(虽然被 _isDisposed 阻断)能正常通过,
// 然后检查是否为销毁流程的最后一步。
semaphore.Release();
// 彻底销毁信号量并清空引用,确保后续调用不再访问已释放的对象
_lifecycleLock?.Dispose();
// 6. 抑制垃圾回收器的终结器
GC.SuppressFinalize(this);