问题描述
有谁知道 VLC 项目是否为 libvlc_state_t
状态定义了状态机?状态机状态通过 libvlc 公开,然后再次通过绑定到其他语言(例如,LibVLCSharp)公开。枚举记录为 here,但我找不到转换或其他详细信息的说明。
更新
我希望在某个时候将其纳入 VLC 文档。虽然状态机可能看起来很明显,但我遇到了一些奇怪的事情,例如 Buffering 事件被调用,但 Media 似乎没有通过 Buffering 状态 - 它仍处于 Playing 状态。
这些小东西加起来可能有助于改善开发人员的体验来添加它们。我正在寻找的解决方案是一个典型的状态机,它至少包括状态、转换以及关于哪些事件在哪些转换上实际触发的注释(以及它们是否发生在状态实际更改之前或之后)。任何与线程相关的问题(例如同步与异步转换)以及在给定状态下允许的操作都是额外的。
解决方法
media.State
应该给你你想要的。
libvlc_state_t
C 枚举在 libvlcsharp 中被简单地定义为 C# 枚举,如下所示:
/// <summary>Note the order of libvlc_state_t enum must match exactly the order of</summary>
/// <remarks>
/// <para>mediacontrol_PlayerStatus,</para>
/// <para>input_state_e enums,</para>
/// <para>and VideoLAN.LibVLCSharp.State (at bindings/cil/src/media.cs).</para>
/// <para>Expected states by web plugins are:</para>
/// <para>IDLE/CLOSE=0,OPENING=1,PLAYING=3,PAUSED=4,</para>
/// <para>STOPPING=5,ENDED=6,ERROR=7</para>
/// </remarks>
public enum VLCState
{
/// <summary>
/// Nothing special happening
/// </summary>
NothingSpecial = 0,/// <summary>
/// Opening media
/// </summary>
Opening = 1,/// <summary>
/// Buffering media
/// </summary>
Buffering = 2,/// <summary>
/// Playing media
/// </summary>
Playing = 3,/// <summary>
/// Paused media
/// </summary>
Paused = 4,/// <summary>
/// Stopped media
/// </summary>
Stopped = 5,/// <summary>
/// Ended media
/// </summary>
Ended = 6,/// <summary>
/// Error media
/// </summary>
Error = 7
}
您还可以订阅媒体上的 StateChanged
事件,以获取有关 State
状态更改的通知。
我做了一些工作来捕捉观察到的行为。这是不完整和不完美的,但也许它可以帮助其他人,因为他们建立在 libvlc/LibVLCSharp 之上(我使用的是 v3.5.1,VideoLAN.LibVLC.Windows v3.0.14)。指向右侧的虚线箭头用于显示某些事件何时触发。请注意,其中一些行为可能特定于媒体类型或通过 MediaInput
界面进行阅读的事实,因此您的里程可能会有所不同。
一些注意事项:
- 如果您尝试过,事情似乎并不总是正常工作,例如在媒体为
Opening
时寻找。例如,我看到.Time
和.Position
永久不同步。我强烈建议等到Play()
操作之后再做很多事情。 - 未发现
Buffering
状态正在使用中,但Buffering
事件至少会触发Opening
和Playing
状态。 - 正如其他人所指出的,一旦媒体结束,您不能简单地调用
Play()
。您需要在Stop()
触发后EndReached
,并且 - 与许多回调一样 - 您需要确保以非死锁方式处理此问题。它可以而且将会悄悄地陷入僵局。即使使用Dispatcher
也可能选择在同一个线程上运行,所以你必须保证一个单独的线程。到目前为止,我很幸运,例如ThreadPool.QueueUserWorkItem(_ => yourMediaPlayer.Stop());
然后您可以钩住Stopped
以触发进一步的行为,例如Play()
。 - 我仍然不确定
ErrorEncountered
周围的确切行为并再次恢复到Play()
;触发这种行为并不容易。
最终,这个状态机允许我在它之上构建一个状态机来处理诸如“到达结尾时再次播放文件”之类的行为。
感谢@mfkl 和许多其他人的辛勤工作 - 通过一些挖掘,这是一个很棒的库!