增加 SmartFrame 强制收回逻辑
This commit is contained in:
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user