You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.23 15:06:07