如何使用libvlcsharp在C#/VB.NET中直接播放MPEG-2 TS数据流,无需网络流
LibVLCSharp直接传递TS字节数组播放及缓冲中断问题解决方案
实现步骤
1. 替换默认MemoryStream为自定义实时流
你之前播放几秒就停止的核心原因是:默认MemoryStream在读取位置超过当前写入位置时,Read方法会直接返回0,LibVLC会判定流已结束,主动停止播放。
你需要自定义一个支持阻塞等待的实时流,无新数据时不会直接返回EOF:
Imports System.Collections.Concurrent Public Class RealtimeTsStream Inherits Stream Private ReadOnly _buffer As New BlockingCollection(Of Byte())() Private _currentChunk As Byte() Private _currentPosition As Integer Public Overrides ReadOnly Property CanRead As Boolean Get Return True End Get End Property Public Overrides ReadOnly Property CanSeek As Boolean Get Return False ' 实时流禁止seek操作 End Get End Property Public Overrides ReadOnly Property CanWrite As Boolean Get Return True End Get End Property Public Overrides ReadOnly Property Length As Long Get Throw New NotSupportedException("实时流不支持获取长度") End Get End Property Public Overrides Property Position As Long Get Throw New NotSupportedException("实时流不支持操作位置") End Get Set(value As Long) Throw New NotSupportedException("实时流不支持操作位置") End Set End Property Public Overrides Sub Write(buffer() As Byte, offset As Integer, count As Integer) Dim chunk = New Byte(count - 1) {} Buffer.BlockCopy(buffer, offset, chunk, 0, count) _buffer.Add(chunk) End Sub Public Overrides Function Read(buffer() As Byte, offset As Integer, count As Integer) As Integer Dim totalRead = 0 While totalRead < count If _currentChunk Is Nothing OrElse _currentPosition >= _currentChunk.Length Then ' 无新数据时阻塞等待,避免返回0触发流结束判定 If Not _buffer.TryTake(_currentChunk, Timeout.Infinite) Then Return totalRead End If _currentPosition = 0 End If Dim copyCount = Math.Min(_currentChunk.Length - _currentPosition, count - totalRead) Buffer.BlockCopy(_currentChunk, _currentPosition, buffer, offset + totalRead, copyCount) _currentPosition += copyCount totalRead += copyCount End While Return totalRead End Function Public Overrides Sub Flush() End Sub Public Overrides Function Seek(offset As Long, origin As SeekOrigin) As Long Throw New NotSupportedException("实时流不支持Seek操作") End Function Public Overrides Sub SetLength(value As Long) Throw New NotSupportedException("实时流不支持设置长度") End Sub Protected Overrides Sub Dispose(disposing As Boolean) MyBase.Dispose(disposing) If disposing Then _buffer.CompleteAdding() _buffer.Dispose() End If End Sub End Class
2. 初始化播放器与流配置
初始化时需要强制指定TS解复用器,配置合理的缓存参数,避免识别错误和缓冲区耗尽:
' 全局变量声明 Private vlc_memorystream As New RealtimeTsStream() Private _libVLC As LibVLC Private _mediaPlayer As MediaPlayer ' 初始化逻辑放在窗体加载或播放前执行 _libVLC = New LibVLC("--network-caching=2000", "--live-caching=2000", "--file-caching=2000") _mediaPlayer = New MediaPlayer(_libVLC) ' 绑定到你的WinForms播放控件,如VideoView VideoView1.MediaPlayer = _mediaPlayer ' 初始化流输入并播放 Dim streamInput As New StreamMediaInput(vlc_memorystream) Dim media As New Media(_libVLC, streamInput) media.AddOption(":demux=ts") ' 强制指定TS解复用器,避免识别错误 media.AddOption(":live-caching=2000") _mediaPlayer.Play(media)
3. 写入TS流逻辑保持不变
你原有的WriteStream方法无需修改,直接写入即可:
Private Sub WriteStream(ByVal Data() As Byte, ByVal len As Integer) ' Data为188字节的标准TS包 vlc_memorystream.Write(Data, 0, len) End Sub
注意事项
- 缓存参数可根据你的流码率调整,一般1000-3000ms即可,数值越小延迟越低,越容易卡顿
- 停止播放时需要主动调用
vlc_memorystream.Dispose()和_libVLC.Dispose()释放资源,避免内存泄漏 - 不要对实时流调用Seek、SetLength等方法,符合实时流的传输特性
内容的提问来源于stack exchange,提问作者cbn
相关产品推荐
相关产品推荐

