前言
影片播放在上位機開發中經常會遇到,基本上是兩種常見的解決方案
1.採用廠家提供的sdk和前端控制元件進行展示,常見的海康/大華都提供了相關sdk及文件
2.開啟相機onvif協議,捅過rtsp影片流進行播放,前端可以採用web方式,或者wpf中的影片控制元件進行展示。
專案需求,決定了最終採用開啟相機onvif供能,wpf中播放的方式。
網路調研一陣子之後,基本都是推薦Vlc.DotNet或者libvlcsharp.wpf進行前端展示。
參考了很多程式碼,無論是官方文件,還是不同部落格裡的程式碼,很難做到用mvvm的方式對於邏輯解耦。
而且Vlc.DotNet已經不再更新了。
Libvlcasharp.wpf的設計有些反人類,可以參考這篇文章WPF中使用LibVLCSharp.WPF 播放rtsp - Naylor - 部落格園 (cnblogs.com)。
所以這部分邏輯寫的很難受,需要尋找其他方案。
最近有空了,調研了幾個其他開源專案,大家的思路都比較一致,相機開啟onvif協議推送rtsp影片流,本地透過ffmpeg進行影片轉流,然後推送到wpf前端控制元件上。
unosquare/ffmediaelement: FFME: The Advanced WPF MediaElement (based on FFmpeg) (github.com)
網上有FFME的樣例程式碼,我在本地搭建沒有成功,應該是我的ffmpeg編譯版本問題,可以參考這個專案。
最終選擇了Flyleaf的方案,簡單搭建了demo給大家參考。
Flyleaf官方專案地址SuRGeoNix/Flyleaf: Media Player .NET Library for WinUI 3/ WPF/WinForms (based on FFmpeg/DirectX) (github.com)
MVVM框架使用的是CommunityToolKit.MVVM
正文
Flyleaf的使用整體分成四步走,
1.App.xaml及App.xaml.cs中配置ffmpeg的dll檔案地址;
1.1ffmpeg的dll檔案,我才用的是Flyleaf官方sample中的檔案,版本不是最新的。
1.2檔案統一放在專案中的FFmpeg資料夾中
1.3生成操作(Build Action)配置為 無(None)
1.4複製到輸出目錄(Copy to Output Directory)配置為 如果較新則複製(Copy if newer)
1.5App.xaml中新增startup事件
<Application x:Class="FlyleafDemo.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:FlyleafDemo" StartupUri="MainWindow.xaml" Startup="Application_Startup"> <Application.Resources> </Application.Resources> </Application>
1.6App.xaml.cs中配置ffmpeg的dll路徑,專案編譯後會複製ffmpeg資料夾及dll。
using FlyleafLib; using System; using System.Collections.Generic; using System.Configuration; using System.Data; using System.Linq; using System.Threading.Tasks; using System.Windows; namespace FlyleafDemo { /// <summary> /// Interaction logic for App.xaml /// </summary> public partial class App : Application { private void Application_Startup(object sender, StartupEventArgs e) { Engine.Start(new EngineConfig() { FFmpegPath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "FFmpeg"), FFmpegDevices = false, // Prevents loading avdevice/avfilter dll files. Enable it only if you plan to use dshow/gdigrab etc. #if RELEASE FFmpegLogLevel = FFmpegLogLevel.Quiet, LogLevel = LogLevel.Quiet, #else FFmpegLogLevel = FFmpegLogLevel.Warning, LogLevel = LogLevel.Debug, LogOutput = ":debug", //LogOutput = ":console", //LogOutput = @"C:\Flyleaf\Logs\flyleaf.log", #endif //PluginsPath = @"C:\Flyleaf\Plugins", UIRefresh = false, // Required for Activity, BufferedDuration, Stats in combination with Config.Player.Stats = true UIRefreshInterval = 250, // How often (in ms) to notify the UI UICurTimePerSecond = true, // Whether to notify UI for CurTime only when it's second changed or by UIRefreshInterval }); } } }
2.ViewModel中配置引數等資訊;
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using FlyleafLib.MediaPlayer; using FlyleafLib; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Media; namespace FlyleafDemo { public class MainViewModel:ObservableObject { private Player player; public Player Player { get => player; set => SetProperty(ref player, value); } private Config config; public Config Config { get => config; set => SetProperty(ref config, value); } private string uriString; public string UriString { get => uriString; set => SetProperty(ref uriString, value); } public IRelayCommand<string> PlayCommand { get; set; } public MainViewModel() { Config = new Config(); Config.Video.BackgroundColor = Colors.Transparent; // 設定播放延遲為100ms,可能我理解有誤,具體可以在專案issues裡檢視 // Config.Player.MaxLatency = 100 * 10000; Player = new Player(Config); PlayCommand = new RelayCommand<string>(PlayAction); UriString = uri1; } private string currentUri = string.Empty; private string uri1 = "rtsp://192.168.20.2:554/cam/realmonitor?channel=1&subtype=0&unicast=true&proto=Onvif"; private string uri2 = "rtsp://192.168.20.3:554/cam/realmonitor?channel=1&subtype=0&unicast=true&proto=Onvif"; private void PlayAction(string uri) { if (!string.IsNullOrEmpty(uri)) { if (currentUri == uri1) { //Player.Commands.Stop.Execute(null); currentUri = uri2; Player.Commands.Open.Execute(uri2); } else { //Player.Commands.Stop.Execute(null); currentUri = uri1; Player.Commands.Open.Execute(uri1); } } } } }
3.View中配置佈局等資訊;
<Window x:Class="FlyleafDemo.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:fl="clr-namespace:FlyleafLib.Controls.WPF;assembly=FlyleafLib" xmlns:local="clr-namespace:FlyleafDemo" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" Title="MainWindow" Width="800" Height="450" mc:Ignorable="d"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="5*" /> <RowDefinition Height="*" /> </Grid.RowDefinitions> <fl:FlyleafHost AttachedDragMove="Both" KeyBindings="Both" Player="{Binding Player, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"> <Viewbox> <TextBlock Foreground="DarkOrange" Text="Hello Flyleaf Overlay!" /> </Viewbox> </fl:FlyleafHost> <Button Grid.Row="1" Command="{Binding PlayCommand}" CommandParameter="{Binding UriString, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" /> </Grid> </Window>
4.在xaml.cs中確定View和ViewModel的繫結關係
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; namespace FlyleafDemo { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); this.DataContext = new MainViewModel(); } } }
總結
前端控制元件繫結比較方便,減少了在xaml.cs中的耦合邏輯
我嘗試過三路影片同時播放,效果不錯,系統資源消耗也不高
很多引數都可以在Config中配置,一些互動邏輯可以在Player中執行,比較清晰
但是,單影片控制元件切換影片流的時候,會有一定時間延遲,我嘗試過使用
Player.Commands.Stop.Execute(null);
但效果不大。
感興趣的可以深挖原始碼,我這裡只是拋磚引玉。
Demo原始碼地址,https://gitee.com/maoleigepu/flyleaf-demo.git,效果圖如下
————————————————
版權宣告:本文為CSDN博主「maoleigepu」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處連結及本宣告。
原文連結:https://blog.csdn.net/maoleigepu/article/details/133268837