C# 编写VLC视频事件处理程序 libvlc libvlc_event_attach libvlc_event_manager libvlc_event_type ibvlc_event_e用法

一、概述

单位有个项目,程序的主界面就是一张背景图,在键盘上点击不同按键后弹出对应的视频,视频是全屏的,所以没有播放,暂停、前进、后退、进度条等任何控件。开始我用window的Media Player COM组件开发,功能全部实现了,但是有很多视频文件Media Player因为不能解码而播放不了,所以考虑使用VLC,它能支持很数视频格式。刚开始我使用的是Vlc.DotNet Form,但随后发现它的全屏属性似乎不起作用,只能依赖于窗口,对其拉伸实现全屏,这里的全屏并非真正意义上的全屏,因为窗口标题栏还显示着,需要对标题栏进行隐藏。于是又转向了LibVlc API,网上有好多C#使用LibVlc API编写播放器介绍,比如博主”清风明月我“的文章《C#利用VLC播放视频》。我利用LibVlc API实现了全屏,没有对libvlc_media_player_set_hwnd设置视频输出窗口,由Vlc自己生成一个独立窗口,其标题栏名称叫VLC (Direct3D11 output),待视频播放完毕后让它自动关闭,这时就需要用到libvlc事件机制了。经过在网上搜索,没有找到C#使用libvlc的事件,有很多是利用C++来实现的,所以下面来介绍如何使用C#语言注册(订阅)VLC的事件。

二、LIBVLC事件简要说明

libvlc异步事件,可以参看https://videolan.videolan.me/vlc/group__libvlc__event.html。我们用到是它定义的四种结构体(其中第四个是回调)libvlc_event_manager_t,libvlc_event_type_t,libvlc_event_t , void(* libvlc_callback_t) (const struct libvlc_event_t *p_event, void *p_data)
还有订阅事件的函数int libvlc_event_attach (libvlc_event_manager_t *p_event_manager, libvlc_event_type_t i_event_type, libvlc_callback_t f_callback, void *user_data)
至于它的取消订阅函数 void libvlc_event_detach (libvlc_event_manager_t *p_event_manager, libvlc_event_type_t i_event_type, libvlc_callback_t f_callback, void *p_user_data)我没有使用,如果大家需要可以自行实现一下。
我们订阅事件用的是libvlc_event_attach()函数,它的参数决定了我们要用到上面说的四种结构体。第一个参数类型是libvlc_event_manager_t,它叫事件管理器,针对不同的libvlc对象,如libvlc_media_t和 libvlc_media_player_t,它们都有一个相应的libvlc_event_manager_t事件管理器 libvlc_event_manager_t * libvlc_media_event_manager ( libvlc_media_t * p_md )libvlc_event_manager_t * libvlc_media_player_event_manager ( libvlc_media_player_t * p_mi )
第二个参数是libvlc_event_type_t类型,它是枚举类型,它定义了视频打开(libvlc_MediaPlayerOpening )、播放中(libvlc_MediaPlayerPlaying )、暂停(libvlc_MediaPlayerPaused )、结束(libvlc_MediaPlayerStopping)、停止(libvlc_MediaPlayerStopped)等57种事件类型。
第三个参数libvlc_callback_t是回调结构体,它又有两个参数,其中第一个参数libvlc_event_t也是一个结构体,包含 int type,void *p_obj两个类型元素和一个union连合体,type就是回调时发生的事件类型,即上面说的枚举的值,就是说返回了视频播放触发的事件,这个type是我们真正需要的东西。第二个参数p_obj是我们订阅事件函数libvlc_event_attach()的第四参数传入的数据,它是我们用户自己需要用的一些数据,当然也可以不用。这个回调结构体我可能也解释的有点绕了,我也是仔细阅读了文档,才慢慢理解的,不过没关系,如果大家需要理解它,可以打开https://videolan.videolan.me/vlc/group__libvlc__event.html文档慢慢研究,同时参照下面我写的代码,对它的意思也就理解了。
第四个参数void *user_data,是咱们自己自定义数据,可以在回调函数中处理后再传回来,这里我没有使用它。

三、C#的LIBVLC事件代码

上面我们对libvlc的事件作了简要说明,大家可以参照原C++文档仔细阅读理解,也可以不用去了解那么细,只需要知道libvlc订阅(或叫注册)事件的机理就行,也可以把下面的C#代码理解一下也行,或者直接照搬,能用就行。

(一)、参数的语句

针对上面的四种结构体和订阅函数,我们把C++代码转换为C#代码。
首先我们看C++的订阅函数

                  libvlc_event_attach( libvlc_event_manager_t * 	p_event_manager,
                                        libvlc_event_type_t i_event_type,
                                        libvlc_callback_t   f_callback,
                                        void* user_data
                                      )

1、第一个参数,得到media_player的事件管理器

//libvlc_media_player事件
[DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true, CharSet = CharSet.Ansi)]
public static extern IntPtr libvlc_media_player_event_manager(IntPtr libvlc_media_player);

2、第二个参数,是要订阅的事件,根据自己实际需要订阅,比如想得到视频暂停时的事件,就注册一个暂停时的枚举值261即可(libvlc_MediaPlayerPaused),也可以多订阅几个,下面我把所有事件类型都列出来,如果要全部订阅,采用枚举遍历(枚举遍历方法可以看我另一篇”C# enum枚举类型的遍历“)即可。

            #region LIBVLC_EVENT_E  事件类型 ver3.0.19
            /**
            * Event types
            */
            public enum LIBVLC_EVENT_E
            {
                /* Append new event types at the end of a category.
                 * Do not remove, insert or re-order any entry.
                 * Keep this in sync with lib/event.c:libvlc_event_type_name(). */

                [Description("媒体元数据已更改")]
                libvlc_MediaMetaChanged = 0,

                libvlc_MediaSubItemAdded,
                libvlc_MediaDurationChanged,
                libvlc_MediaParsedChanged,
                libvlc_MediaFreed,
                libvlc_MediaStateChanged,
                libvlc_MediaSubItemTreeAdded,

                [Description("播放器媒体已更改")]
                libvlc_MediaPlayerMediaChanged = 0x100,//256

                [Description("播放准备状态")]
                libvlc_MediaPlayerNothingSpecial,//257

                [Description("播放器打开")]
                libvlc_MediaPlayerOpening,//258

                [Description("播放器缓冲")]
                libvlc_MediaPlayerBuffering,//259

                [Description("播放器播放中")]
                libvlc_MediaPlayerPlaying,//260

                [Description("播放器已暂停")]
                libvlc_MediaPlayerPaused,//261

                [Description("播放停止")]
                libvlc_MediaPlayerStopped,//262

                [Description("播放器前进")]
                libvlc_MediaPlayerForward,//263

                [Description("播放器后退")]
                libvlc_MediaPlayerBackward,//264

                [Description("播放结束")]
                libvlc_MediaPlayerEndReached,//265

                [Description("播放器遇到错误")]
                libvlc_MediaPlayerEncounteredError,//266

                libvlc_MediaPlayerTimeChanged,//267
                libvlc_MediaPlayerPositionChanged,//268
                libvlc_MediaPlayerSeekableChanged,//269
                libvlc_MediaPlayerPausableChanged,//270
                libvlc_MediaPlayerTitleChanged,//271
                libvlc_MediaPlayerSnapshotTaken,//272
                libvlc_MediaPlayerLengthChanged,//273
                libvlc_MediaPlayerVout,//274
                libvlc_MediaPlayerScrambledChanged,//275
                libvlc_MediaPlayerESAdded,//276
                libvlc_MediaPlayerESDeleted,//277
                libvlc_MediaPlayerESSelected,//278
                libvlc_MediaPlayerCorked,//279
                libvlc_MediaPlayerUncorked,//280
                libvlc_MediaPlayerMuted,//281
                libvlc_MediaPlayerUnmuted,//282
                libvlc_MediaPlayerAudioVolume,//283
                libvlc_MediaPlayerAudioDevice,//284
                libvlc_MediaPlayerChapterChanged,//285

                libvlc_MediaListItemAdded = 0x200,
                libvlc_MediaListWillAddItem,
                libvlc_MediaListItemDeleted,
                libvlc_MediaListWillDeleteItem,
                libvlc_MediaListEndReached,

                libvlc_MediaListViewItemAdded = 0x300,
                libvlc_MediaListViewWillAddItem,
                libvlc_MediaListViewItemDeleted,
                libvlc_MediaListViewWillDeleteItem,

                libvlc_MediaListPlayerPlayed = 0x400,
                libvlc_MediaListPlayerNextItemSet,
                libvlc_MediaListPlayerStopped,

                /**
                 * \deprecated Useless event, it will be triggered only when calling
                 * libvlc_media_discoverer_start()
                 */
                libvlc_MediaDiscovererStarted = 0x500,
                /**
                 * \deprecated Useless event, it will be triggered only when calling
                 * libvlc_media_discoverer_stop()
                 */
                libvlc_MediaDiscovererEnded,

                libvlc_RendererDiscovererItemAdded,
                libvlc_RendererDiscovererItemDeleted,

                libvlc_VlmMediaAdded = 0x600,
                libvlc_VlmMediaRemoved,
                libvlc_VlmMediaChanged,
                libvlc_VlmMediaInstanceStarted,
                libvlc_VlmMediaInstanceStopped,
                libvlc_VlmMediaInstanceStatusInit,
                libvlc_VlmMediaInstanceStatusOpening,
                libvlc_VlmMediaInstanceStatusPlaying,
                libvlc_VlmMediaInstanceStatusPause,
                libvlc_VlmMediaInstanceStatusEnd,
                libvlc_VlmMediaInstanceStatusError
            };
            #endregion  //LIBVLC_EVENT_E事件类型

3、第三个参数,这是回调函数,在C#中我们用委托定义。在我调试过中程序一直报“尝试读取或写入受保护的内存。这通常指示其他内存已损坏”异常,真是憋屈几天才解决,最终是需要在委托前面加上[UnmanagedFunctionPointer(CallingConvention.Cdecl)]这个属性。

//此语句必加,否则报错“尝试读取或写入受保护的内存。这通常指示其他内存已损坏。”
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void LIB_EVENT_CALLBACK(ref LIBVLC_EVENT_T libvlc_event, IntPtr p_data);

这个回调的第一个参数也是一个结构体,它是内嵌联合体结构的,有两种定义方式,因为我不获取联合体内容,所以用了第一种定义方式。如果要获取联合体内容,可以采用第二种定义方式,只不过要在订阅函数的对应类型要改为IntPtr,用Marshal.PtrToStructure(IntPtr ptr,Type structureType)来获取type,p_obj和联合体内容。其中,联合体中的原C++结构定义我也附上并注释掉了,对获取联合体和理解它的意思有提示作用。

            #region LIBVLC_EVENT_T结构体
            
            [StructLayoutAttribute(LayoutKind.Sequential)]
            public struct LIBVLC_EVENT_T
            {
                public int type;
                public IntPtr p_obj;

                [StructLayoutAttribute(LayoutKind.Explicit)]
                public struct u
                {
                    //struct
                    //{
                    //    libvlc_meta_t meta_type
                    //} media_meta_changed;
                    [FieldOffsetAttribute(0)] public int media_meta_changed_meta_type;

                    //struct
                    //{
                    //  libvlc_media_t* new_child;
                    //} media_subitem_added;
                    [FieldOffsetAttribute(0)] public IntPtr media_subitem_added_new_child;

                    //struct
                    //{
                    //    int64_t new_duration;
                    //} media_duration_changed;
                    [FieldOffsetAttribute(0)] public Int64 media_duration_changed_new_duration;

                    //struct
                    //{
                    //    int new_status; /**< see @ref libvlc_media_parsed_status_t */
                    //} media_parsed_changed;
                    [FieldOffsetAttribute(0)] public int media_parsed_changed_new_status;

                    //struct
                    //{
                    //    int new_state; /**< see @ref libvlc_state_t */
                    //} media_state_changed;
                    [FieldOffsetAttribute(0)] public int media_state_changed_new_state;

                    //struct
                    //{
                    //    libvlc_picture_t* p_thumbnail;
                    //} media_thumbnail_generated;
                    [FieldOffsetAttribute(0)] public IntPtr media_thumbnail_generated_p_thumbnail;

                    //struct
                    //{
                    //    libvlc_media_t* item;
                    //} media_subitemtree_added;
                    [FieldOffsetAttribute(0)] public IntPtr media_subitemtree_added_item;

                    //struct
                    //{
                    //    libvlc_picture_list_t* thumbnails;
                    //} media_attached_thumbnails_found;
                    [FieldOffsetAttribute(0)] public IntPtr media_attached_thumbnails_found_thumbnails;

                    ///* media instance */
                    //struct
                    //{
                    //    float new_cache;
                    //} media_player_buffering;
                    [FieldOffsetAttribute(0)] public float media_player_buffering_new_cache;

                    //struct
                    //{
                    //    int new_chapter;
                    //} media_player_chapter_changed;
                    [FieldOffsetAttribute(0)] public int media_player_chapter_changed_new_chapter;

                    //struct
                    //{
                    //    double new_position;
                    //} media_player_position_changed;
                    [FieldOffsetAttribute(0)] public double media_player_position_changed_new_position;

                    //struct
                    //{
                    //    libvlc_time_t new_time;
                    //} media_player_time_changed;
                    [FieldOffsetAttribute(0)] public Int64 media_player_time_changed_new_time;

                    //struct
                    //{
                    //    const libvlc_title_description_t* title;
                    //    int index;
                    //} media_player_title_selection_changed;
                    [FieldOffsetAttribute(0)] public IntPtr media_player_title_selection_changed_title;
                    [FieldOffsetAttribute(4)] public int media_player_title_selection_changed_index;

                    //struct
                    //{
                    //    int new_seekable;
                    //} media_player_seekable_changed;
                    [FieldOffsetAttribute(0)] public int media_player_seekable_changed_new_seekable;

                    //struct
                    //{
                    //    int new_pausable;
                    //} media_player_pausable_changed;
                    [FieldOffsetAttribute(0)] public int media_player_pausable_changed_new_pausable;

                    //struct
                    //{
                    //    int new_scrambled;
                    //} media_player_scrambled_changed;
                    [FieldOffsetAttribute(0)] public int media_player_scrambled_changed_new_scrambled;

                    //struct
                    //{
                    //    int new_count;
                    //} media_player_vout;
                    [FieldOffsetAttribute(0)] public int media_player_vout_new_count;

                    ///* media list */
                    //struct
                    //{
                    //    libvlc_media_t* item;
                    //    int index;
                    //} media_list_item_added;
                    [FieldOffsetAttribute(0)] public IntPtr list_item_added_item;
                    [FieldOffsetAttribute(4)] public int list_item_added_index;

                    //struct
                    //{
                    //    libvlc_media_t* item;
                    //    int index;
                    //} media_list_will_add_item;
                    [FieldOffsetAttribute(0)] public IntPtr list_will_add_item_item;
                    [FieldOffsetAttribute(4)] public int list_will_add_item_index;

                    //struct
                    //{
                    //    libvlc_media_t* item;
                    //    int index;
                    //} media_list_item_deleted;
                    [FieldOffsetAttribute(0)] public IntPtr media_list_item_deleted_item;
                    [FieldOffsetAttribute(4)] public int media_list_item_deleted_index;

                    //struct
                    //{
                    //    libvlc_media_t* item;
                    //    int index;
                    //} media_list_will_delete_item;
                    [FieldOffsetAttribute(0)] public IntPtr media_list_will_delete_item_item;
                    [FieldOffsetAttribute(4)] public int media_list_will_delete_item_index;

                    ///* media list player */
                    //struct
                    //{
                    //    libvlc_media_t* item;
                    //} media_list_player_next_item_set;
                    [FieldOffsetAttribute(0)] public IntPtr media_list_player_next_item_set_item;

                    ///* snapshot taken */
                    //struct
                    //{
                    //     char* psz_filename;
                    //} media_player_snapshot_taken;
                    [FieldOffsetAttribute(0)] public IntPtr media_player_snapshot_taken_psz_filename;

                    ///* Length changed */
                    //struct
                    //{
                    //    libvlc_time_t new_length;
                    //} media_player_length_changed;
                    [FieldOffsetAttribute(0)] public Int64 media_player_length_changed_new_length;

                    ///* Extra MediaPlayer */
                    //struct
                    //{
                    //    libvlc_media_t* new_media;
                    //} media_player_media_changed;
                    [FieldOffsetAttribute(0)] public IntPtr media_player_media_changed_new_media;

                    ///* ESAdded, ESDeleted, ESUpdated */
                    //struct
                    //{
                    //    libvlc_track_type_t i_type;
                    //    int i_id; /**< Deprecated, use psz_id */
                    //    /** Call libvlc_media_player_get_track_from_id() to get the track
                    //     * description. */
                    //    const char* psz_id;
                    //} media_player_es_changed;
                    [FieldOffsetAttribute(0)] public int media_player_es_changed_i_type;
                    [FieldOffsetAttribute(4)] public int media_player_es_changed_i_id;
                    [FieldOffsetAttribute(8)] public IntPtr media_player_es_changed_psz_id;

                    ///* ESSelected */
                    //struct
                    //{
                    //    libvlc_track_type_t i_type;
                    //    const char* psz_unselected_id;
                    //    const char* psz_selected_id;
                    //} media_player_es_selection_changed;
                    [FieldOffsetAttribute(0)] public int media_player_es_selection_changed_i_type;
                    [FieldOffsetAttribute(4)] public IntPtr media_player_es_selection_changed_psz_unselected_id;
                    [FieldOffsetAttribute(8)] public IntPtr media_player_es_selection_changed_psz_selected_id;

                    ///* ProgramAdded, ProgramDeleted, ProgramUpdated */
                    //struct
                    //{
                    //    int i_id;
                    //} media_player_program_changed;
                    [FieldOffsetAttribute(0)] public int media_player_program_changed_i_id;

                    ///* ProgramSelected */
                    //struct
                    //{
                    //    int i_unselected_id;
                    //    int i_selected_id;
                    //} media_player_program_selection_changed;
                    [FieldOffsetAttribute(0)] public int media_player_program_selection_changed_i_unselected_id;
                    [FieldOffsetAttribute(4)] public int media_player_program_selection_changed_i_selected_id;

                    //struct
                    //{
                    //    float volume;
                    //} media_player_audio_volume;
                    [FieldOffsetAttribute(0)] public float media_player_audio_volume_volume;

                    //struct
                    //{
                    //    const char* device;
                    //} media_player_audio_device;
                    [FieldOffsetAttribute(0)] public IntPtr media_player_audio_device_device;

                    //struct
                    //{
                    //    bool recording;
                    //    /** Only valid when recording ends (recording == false) */
                    //    const char* recorded_file_path;
                    //} media_player_record_changed;
                    [FieldOffsetAttribute(0)] public bool media_player_record_changed_recording;
                    [FieldOffsetAttribute(4)] public IntPtr media_player_record_changed_recorded_file_path;

                    //struct
                    //{
                    //    libvlc_renderer_item_t* item;
                    //} renderer_discoverer_item_added;
                    [FieldOffsetAttribute(0)] public IntPtr renderer_discoverer_item_added_item;

                    //struct
                    //{
                    //    libvlc_renderer_item_t* item;
                    //} renderer_discoverer_item_deleted;
                    [FieldOffsetAttribute(0)] public IntPtr renderer_discoverer_item_deleted_item;

                    //**********

                }
            }

            //[StructLayoutAttribute(LayoutKind.Explicit)]
            //public struct LIBVLC_EVENT_T
            //{
            //    [FieldOffsetAttribute(0)] public int type;
            //    [FieldOffsetAttribute(4)] public IntPtr p_obj;

            //    //struct
            //    //{
            //    //    libvlc_meta_t meta_type
            //    //} media_meta_changed;
            //    [FieldOffsetAttribute(8)] public int media_meta_changed_meta_type;

            //    //struct
            //    //{
            //    //  libvlc_media_t* new_child;
            //    //} media_subitem_added;
            //    [FieldOffsetAttribute(8)] public IntPtr media_subitem_added_new_child;

            //    //struct
            //    //{
            //    //    int64_t new_duration;
            //    //} media_duration_changed;
            //    [FieldOffsetAttribute(8)] public Int64 media_duration_changed_new_duration;

            //    //struct
            //    //{
            //    //    int new_status; /**< see @ref libvlc_media_parsed_status_t */
            //    //} media_parsed_changed;
            //    [FieldOffsetAttribute(8)] public int media_parsed_changed_new_status;

            //    //struct
            //    //{
            //    //    int new_state; /**< see @ref libvlc_state_t */
            //    //} media_state_changed;
            //    [FieldOffsetAttribute(8)] public int media_state_changed_new_state;

            //    //struct
            //    //{
            //    //    libvlc_picture_t* p_thumbnail;
            //    //} media_thumbnail_generated;
            //    [FieldOffsetAttribute(8)] public IntPtr media_thumbnail_generated_p_thumbnail;

            //    //struct
            //    //{
            //    //    libvlc_media_t* item;
            //    //} media_subitemtree_added;
            //    [FieldOffsetAttribute(8)] public IntPtr media_subitemtree_added_item;

            //    //struct
            //    //{
            //    //    libvlc_picture_list_t* thumbnails;
            //    //} media_attached_thumbnails_found;
            //    [FieldOffsetAttribute(8)] public IntPtr media_attached_thumbnails_found_thumbnails;

            //    ///* media instance */
            //    //struct
            //    //{
            //    //    float new_cache;
            //    //} media_player_buffering;
            //    [FieldOffsetAttribute(8)] public float media_player_buffering_new_cache;

            //    //struct
            //    //{
            //    //    int new_chapter;
            //    //} media_player_chapter_changed;
            //    [FieldOffsetAttribute(8)] public int media_player_chapter_changed_new_chapter;

            //    //struct
            //    //{
            //    //    double new_position;
            //    //} media_player_position_changed;
            //    [FieldOffsetAttribute(8)] public double media_player_position_changed_new_position;

            //    //struct
            //    //{
            //    //    libvlc_time_t new_time;
            //    //} media_player_time_changed;
            //    [FieldOffsetAttribute(8)] public Int64 media_player_time_changed_new_time;

            //    //struct
            //    //{
            //    //    const libvlc_title_description_t* title;
            //    //    int index;
            //    //} media_player_title_selection_changed;
            //    [FieldOffsetAttribute(8)] public IntPtr media_player_title_selection_changed_title;
            //    [FieldOffsetAttribute(12)] public int media_player_title_selection_changed_index;

            //    //struct
            //    //{
            //    //    int new_seekable;
            //    //} media_player_seekable_changed;
            //    [FieldOffsetAttribute(8)] public int media_player_seekable_changed_new_seekable;

            //    //struct
            //    //{
            //    //    int new_pausable;
            //    //} media_player_pausable_changed;
            //    [FieldOffsetAttribute(8)] public int media_player_pausable_changed_new_pausable;

            //    //struct
            //    //{
            //    //    int new_scrambled;
            //    //} media_player_scrambled_changed;
            //    [FieldOffsetAttribute(8)] public int media_player_scrambled_changed_new_scrambled;

            //    //struct
            //    //{
            //    //    int new_count;
            //    //} media_player_vout;
            //    [FieldOffsetAttribute(8)] public int media_player_vout_new_count;

            //    ///* media list */
            //    //struct
            //    //{
            //    //    libvlc_media_t* item;
            //    //    int index;
            //    //} media_list_item_added;
            //    [FieldOffsetAttribute(8)] public IntPtr list_item_added_item;
            //    [FieldOffsetAttribute(12)] public int list_item_added_index;

            //    //struct
            //    //{
            //    //    libvlc_media_t* item;
            //    //    int index;
            //    //} media_list_will_add_item;
            //    [FieldOffsetAttribute(8)] public IntPtr list_will_add_item_item;
            //    [FieldOffsetAttribute(12)] public int list_will_add_item_index;

            //    //struct
            //    //{
            //    //    libvlc_media_t* item;
            //    //    int index;
            //    //} media_list_item_deleted;
            //    [FieldOffsetAttribute(8)] public IntPtr media_list_item_deleted_item;
            //    [FieldOffsetAttribute(12)] public int media_list_item_deleted_index;

            //    //struct
            //    //{
            //    //    libvlc_media_t* item;
            //    //    int index;
            //    //} media_list_will_delete_item;
            //    [FieldOffsetAttribute(8)] public IntPtr media_list_will_delete_item_item;
            //    [FieldOffsetAttribute(12)] public int media_list_will_delete_item_index;

            //    ///* media list player */
            //    //struct
            //    //{
            //    //    libvlc_media_t* item;
            //    //} media_list_player_next_item_set;
            //    [FieldOffsetAttribute(8)] public IntPtr media_list_player_next_item_set_item;

            //    ///* snapshot taken */
            //    //struct
            //    //{
            //    //     char* psz_filename;
            //    //} media_player_snapshot_taken;
            //    [FieldOffsetAttribute(8)] public IntPtr media_player_snapshot_taken_psz_filename;

            //    ///* Length changed */
            //    //struct
            //    //{
            //    //    libvlc_time_t new_length;
            //    //} media_player_length_changed;
            //    [FieldOffsetAttribute(8)] public Int64 media_player_length_changed_new_length;

            //    ///* Extra MediaPlayer */
            //    //struct
            //    //{
            //    //    libvlc_media_t* new_media;
            //    //} media_player_media_changed;
            //    [FieldOffsetAttribute(8)] public IntPtr media_player_media_changed_new_media;

            //    ///* ESAdded, ESDeleted, ESUpdated */
            //    //struct
            //    //{
            //    //    libvlc_track_type_t i_type;
            //    //    int i_id; /**< Deprecated, use psz_id */
            //    //    /** Call libvlc_media_player_get_track_from_id() to get the track
            //    //     * description. */
            //    //    const char* psz_id;
            //    //} media_player_es_changed;
            //    [FieldOffsetAttribute(8)] public int media_player_es_changed_i_type;
            //    [FieldOffsetAttribute(12)] public int media_player_es_changed_i_id;
            //    [FieldOffsetAttribute(16)] public IntPtr media_player_es_changed_psz_id;

            //    ///* ESSelected */
            //    //struct
            //    //{
            //    //    libvlc_track_type_t i_type;
            //    //    const char* psz_unselected_id;
            //    //    const char* psz_selected_id;
            //    //} media_player_es_selection_changed;
            //    [FieldOffsetAttribute(8)] public int media_player_es_selection_changed_i_type;
            //    [FieldOffsetAttribute(12)] public IntPtr media_player_es_selection_changed_psz_unselected_id;
            //    [FieldOffsetAttribute(16)] public IntPtr media_player_es_selection_changed_psz_selected_id;

            //    ///* ProgramAdded, ProgramDeleted, ProgramUpdated */
            //    //struct
            //    //{
            //    //    int i_id;
            //    //} media_player_program_changed;
            //    [FieldOffsetAttribute(8)] public int media_player_program_changed_i_id;

            //    ///* ProgramSelected */
            //    //struct
            //    //{
            //    //    int i_unselected_id;
            //    //    int i_selected_id;
            //    //} media_player_program_selection_changed;
            //    [FieldOffsetAttribute(8)] public int media_player_program_selection_changed_i_unselected_id;
            //    [FieldOffsetAttribute(12)] public int media_player_program_selection_changed_i_selected_id;

            //    //struct
            //    //{
            //    //    float volume;
            //    //} media_player_audio_volume;
            //    [FieldOffsetAttribute(8)] public float media_player_audio_volume_volume;

            //    //struct
            //    //{
            //    //    const char* device;
            //    //} media_player_audio_device;
            //    [FieldOffsetAttribute(8)] public IntPtr media_player_audio_device_device;

            //    //struct
            //    //{
            //    //    bool recording;
            //    //    /** Only valid when recording ends (recording == false) */
            //    //    const char* recorded_file_path;
            //    //} media_player_record_changed;
            //    [FieldOffsetAttribute(8)] public bool media_player_record_changed_recording;
            //    [FieldOffsetAttribute(12)] public IntPtr media_player_record_changed_recorded_file_path;

            //    //struct
            //    //{
            //    //    libvlc_renderer_item_t* item;
            //    //} renderer_discoverer_item_added;
            //    [FieldOffsetAttribute(8)] public IntPtr renderer_discoverer_item_added_item;

            //    //struct
            //    //{
            //    //    libvlc_renderer_item_t* item;
            //    //} renderer_discoverer_item_deleted;
            //    [FieldOffsetAttribute(8)] public IntPtr renderer_discoverer_item_deleted_item;

            //}



            #endregion //LIBVLC_EVENT_T

4、第四个参数,是用户需要传递的数据,我这儿用不上,所以设置为空。

(二)、订阅函数的语句

根据原C++订阅函数,我们转换为C#函数

[DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int libvlc_event_attach(IntPtr libvlc_event_manager, int libvlc_event_type, LIB_EVENT_CALLBACK libvlc_callback, IntPtr user_data);

(三)、调用方法

在编写LibVlc API程序时(参见"清风明月我“的文章《C#利用VLC播放视频》),我们肯定是得到了libvlc_media_player,有了它就能订阅事件。

            //订阅事件函数
            public static void libvlc_media_player_events(IntPtr libvlc_media_player)
            {
                //1、获取到事件订阅函数libvlc_event_attach()的第一个参数
                IntPtr mp_e_mananger = libvlc_media_player_event_manager(libvlc_media_player);

                //2、声明回调函数
                LIB_EVENT_CALLBACK handlsEvents = new LIB_EVENT_CALLBACK(libvlcCallBACK);

                //3、注册全部事件
                foreach (LIBVLC_EVENT_E vlc_e in Enum.GetValues(typeof(LIBVLC_EVENT_E)))//
                {
                    int regInt = libvlc_event_attach(mp_e_mananger, vlc_e.GetHashCode(), handlsEvents, IntPtr.Zero);
                    if (regInt != 0)
                        break;
                }
            }



			//回调函数
            public static void libvlcCallBACK(ref LIBVLC_EVENT_T evt, IntPtr userdata)
            {
                //只列出了部分事件回调,可以根据自己需要再增加或删除type值,即LIBVLC_EVENT_E的枚举值
                switch (evt.type)
                {
                    case 256: //媒体改变
                        //你想要做的事情
                        break;
                    case 257://播放准备状态
                        //你想要做的事情
                        break;
                    case 258://播放器打开
                        //你想要做的事情
                        break;
                    case 259://播放器缓冲
                        //你想要做的事情
                        break;
                    case 260://播放器播放中
                        //你想要做的事情
                        break;
                    case 261://播放器已暂停
                        //你想要做的事情
                        break;
                    case 262://播放停止
                        //这儿是我要用到的,等视频播放结束后,我要关闭由libvlc自己生成的全屏播放窗口
                                                
                        //窗口可见就隐藏,因为经过测试是关闭不了它的。
                        //以下是我部分代码,只是起到个例子作用,对大家来说没用可以删除掉,换成自己的代码
                        if (IsWindowVisible(LibVlcHandle))
                        {
                            ShowWindow(LibVlcHandle, 0);
                        }

                        LiveStatus.BeginInvoke(false, null, null);//播放已经停止

                        break;

                    case 263://播放器前进
                        break;
                    case 264://播放器后退
                        break;
                    case 265://播放结束
                        //窗口可见就隐藏,因为经过测试是关闭不了它的
                        if (IsWindowVisible(LibVlcHandle))
                        {
                            ShowWindow(LibVlcHandle, 0);
                        }
                        LiveStatus.BeginInvoke(false, null, null);//播放已经结束
                        break;
                    case 266://播放器遇到错误
                        //你想要做的事情
                        break;
                    default:
                        break;
                }
            }

在实际应用中,我关闭由libvlc自己生成的名为VLC (Direct3D11 output)的播放窗口,在获取到该窗口的句柄后,使用Win32的DestroyWindow(LibVlcHandle)和PostMessage(LibVlcHandle, WM_CLOSE, 0, 0)均无法关闭它,所以只能用ShowWindow来显示和隐藏它。

四、小结

本文不是写LibVlc API编写视频的,只是在特殊场景下对用到LibVlc事件的一个描述,虽然文章有些长,但我也是尽力把C#代码写的详细些。如果能为有相同需求的朋友提供帮助,那是最好不过了,同时也是我自己的一篇笔记吧。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值