WPF實(shí)現(xiàn)播放RTSP視頻流
在WPF中可以使用LibVLCSharp.WPF、Vlc.DotNet.Wpf組件直接播放RTSP流,此外還可以通過(guò)LibVLCSharp + SkiaSharp的方式將VLC視頻流通過(guò)WriteableBitmap的方式關(guān)聯(lián)到Image對(duì)象。
1、LibVLCSharp.WPF
使用VideoView控件可以方便地播放RTSP視頻流。該方法使用簡(jiǎn)單,但是不能很好的對(duì)RTSP流圖像進(jìn)行處理。
(1) 引入NuGet包
LibVLCSharp.WPF。
(2) 初始化LibVLCSharp
LibVLCSharp.Shared.Core.Initialize();
(3) 使用VideoView控件
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch"> <wpf:VideoView x:Name="VideoView"/> </Grid>
(4) 初始化LibVLC對(duì)象
_libVlc = new LibVLC(true); _mediaPlayer = new MediaPlayer(_libVlc) { Volume = 0, //靜音 EnableHardwareDecoding = true //硬件加速 }; _mediaPlayer.EndReached += OnPlayerEndReached; _mediaPlayer.Stopped += OnPlayerStopped; VideoView.IsManipulationEnabled = true; VideoView.IsEnabled = true; VideoView.Loaded += (sender, args) => { VideoView.MediaPlayer = _mediaPlayer; };
(5) Unloaded事件中銷毀VLC對(duì)象
_mediaPlayer.Stop(); _mediaPlayer.Dispose(); _libVlc.Dispose();
(6) 播放RTSP
var options = new[] { "file-caching=300", "live-capture-caching=300", "disc-caching-caching=300", "network-caching=333", "live-caching=300" }; using (var media = new Media(_libVlc, new Uri(CameraPara.Url), options)) { VideoView.MediaPlayer.Play(media); }
(7) 停止播放
if (VideoView.MediaPlayer.IsPlaying) { VideoView.MediaPlayer.Stop(); }
2、Vlc.DotNet.Wpf
借助于VlcVideoSourceProvider類,可以將RTSP視頻流經(jīng)過(guò)處理后輕松綁定到Image對(duì)象。同時(shí),通過(guò)改造VlcVideoSourceProvider類可以實(shí)現(xiàn)自由設(shè)置RTSP視頻流的播放幀率(FPS)。
(1) 引入NuGet包
Vlc.DotNet.Wpf。
(2) 啟用位圖緩存
<UserControl.CacheMode> <BitmapCache/> </UserControl.CacheMode>
(3) 初始化SourceProvider
_sourceProvider = new VlcVideoSourceProvider(Dispatcher); _sourceProvider.CreatePlayer(_libDirectory, "--no-audio", "--rtsp-tcp"); _sourceProvider.MediaPlayer.Stopped += OnPlayerStopped; VideoImage.SetBinding(Image.SourceProperty, new Binding(nameof(VlcVideoSourceProvider.VideoSource)) { Source = _sourceProvider });
(4) 播放RTSP視頻流
var options = new[] { "file-caching=300", "live-capture-caching=300", "disc-caching-caching=300", "network-caching=333", "live-caching=300", HardDecoding ? "avcodec-hw=any" : "" //硬解碼 }; _sourceProvider.MediaPlayer.Play(new Uri(CameraPara.Url), options);
(5) 停止播放
if (_sourceProvider.MediaPlayer.IsPlaying()) { _sourceProvider?.MediaPlayer?.Dispose(); _sourceProvider?.Dispose(); _sourceProvider = null; }
3、LibVLCSharp + SkiaSharp
通過(guò)設(shè)置MediaPlayer的視頻回調(diào)方法,在視頻VideoLock回調(diào)中將視頻圖像拷貝至緩存中,然后在VideoDisplay回調(diào)中將緩存中的數(shù)據(jù)轉(zhuǎn)換為SKImage繪制在Skia畫布中,之后刷新關(guān)聯(lián)的位圖即可。
(1) 引入NuGet包
LibVLCSharp、SkiaSharp。
(2) 初始化LibVLCSharp
LibVLCSharp.Shared.Core.Initialize();
(3) 初始化LibVLC對(duì)象
_libVlc = new LibVLC(true); _mediaPlayer = new MediaPlayer(_libVlc) { Volume = 0, //靜音 EnableHardwareDecoding = true //硬件加速 }; _mediaPlayer.EndReached += OnPlayerEndReached; _mediaPlayer.Stopped += OnPlayerStopped;
(4) Loaded事件中設(shè)置視頻回調(diào)
_mediaPlayer.SetVideoFormatCallbacks(OnLibVLCVideoFormat, null); _mediaPlayer.SetVideoCallbacks(OnLibVLCVideoLock, null, OnLibVLCVideoDisplay);
(5) Unloaded事件中銷毀VLC對(duì)象
_mediaPlayer.Stop(); _mediaPlayer.Dispose(); _libVlc.Dispose();
(6) 視頻回調(diào)處理
private uint OnLibVLCVideoFormat(ref IntPtr opaque, IntPtr chroma, ref uint width, ref uint height, ref uint pitches, ref uint lines) // ReSharper restore RedundantAssignment { var bytes = Encoding.ASCII.GetBytes("RV32"); //I420, RV32, AVC1 for (var i = 0; i < bytes.Length; i++) { Marshal.WriteByte(chroma, i, bytes[i]); } if (_mediaPlayer.Media is Media media) { foreach (MediaTrack track in media.Tracks) { if (track.TrackType == TrackType.Video) { var trackInfo = track.Data.Video; if (trackInfo.Width > 0 && trackInfo.Height > 0) { width = trackInfo.Width; height = trackInfo.Height; } break; } } } var pixelFormat = PixelFormats.Bgra32; pitches = (uint) (width * pixelFormat.BitsPerPixel) / 8; lines = height; _videoWidth = (int) width; _videoHeight = (int) height; _buffer = new byte[_videoWidth * _videoHeight * 4]; _plane = Marshal.UnsafeAddrOfPinnedArrayElement(_buffer, 0); Dispatcher.Invoke(delegate { _bitmap = new WriteableBitmap(_videoWidth, _videoHeight, 96, 96, PixelFormats.Bgra32, null); _imageInfo = new SKImageInfo(_videoWidth, _videoHeight, SKColorType.Bgra8888); _surface = SKSurface.Create( new SKImageInfo(_videoWidth, _videoHeight, SKImageInfo.PlatformColorType, SKAlphaType.Premul), _bitmap.BackBuffer, _bitmap.BackBufferStride); _rect = new Int32Rect(0, 0, _videoWidth, _videoHeight); VideoImage.Source = _bitmap; VideoImage.Stretch = IsMainControl ? Stretch.Fill : Stretch.Uniform; }); return 1; } private IntPtr OnLibVLCVideoLock(IntPtr opaque, IntPtr planes) { IntPtr[] dataArray = {_plane}; Marshal.Copy(dataArray, 0, planes, dataArray.Length); return IntPtr.Zero; } private void OnLibVLCVideoDisplay(IntPtr opaque, IntPtr picture) { var image = SKImage.FromPixels(_imageInfo, _plane); _surface.Canvas.DrawImage(image, new SKPoint(0, 0)); Dispatcher.Invoke(delegate { _bitmap.Lock(); _bitmap.AddDirtyRect(_rect); _bitmap.Unlock(); }); }
(7) 播放RTSP視頻
var options = new[] { "file-caching=300", "live-capture-caching=300", "disc-caching-caching=300", "network-caching=333", "live-caching=300" }; using (var media = new Media(_libVlc, new Uri(CameraPara.Url), options)) { _mediaPlayer.Play(media); }
(8) 停止播放
if (_mediaPlayer.IsPlaying) { _mediaPlayer.Stop(); }
到此這篇關(guān)于WPF實(shí)現(xiàn)播放RTSP視頻流的文章就介紹到這了,更多相關(guān)WPF播放RTSP視頻流內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C#中Predicate<T>與Func<T, bool>泛型委托的用法實(shí)例
這篇文章主要介紹了C#中Predicate<T>與Func<T, bool>泛型委托的用法,指出了其用法中的誤區(qū)及易錯(cuò)點(diǎn),有助于更好的理解泛型委托的用法,需要的朋友可以參考下2014-09-09C#?Socket數(shù)據(jù)接收的三種實(shí)現(xiàn)方式
本文主要介紹了C#?Socket數(shù)據(jù)接收的三種實(shí)現(xiàn)方式,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07WPF簡(jiǎn)單的數(shù)據(jù)庫(kù)查詢實(shí)例
下面小編就為大家分享一篇WPF簡(jiǎn)單的數(shù)據(jù)庫(kù)查詢實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2017-11-11C#實(shí)現(xiàn)的調(diào)用DOS命令操作類實(shí)例
這篇文章主要介紹了C#實(shí)現(xiàn)的調(diào)用DOS命令操作類,實(shí)例分析了C#調(diào)用系統(tǒng)常用DOS命令的相關(guān)技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2015-04-04C#如何在窗體程序中操作數(shù)據(jù)庫(kù)數(shù)據(jù)
這篇文章主要介紹了C#如何在窗體程序中操作數(shù)據(jù)庫(kù)數(shù)據(jù),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-04-04