C#编写的基于VLC的播放器

2023-11-08

首先看一下最终的程序效果


实现的功能:

1:打开播放的音视频文件((1)菜单栏“文件”->“打开”,(2)工具栏(下面)“打开”(3)播放器右键->打开)

2:暂停,继续播放,停止音视频文件

3:进度条和右下角文本框显示播放进度

4:拖动进度条对视频定位播放

5:工具栏(下面)“快进”,“快退”均为5s

6:音量调节

7:菜单栏“文件”下可记录最近播放的三个文件

8:在有记录的情况下,初始状态时双击视频播放区或单击“播放”播放上次关闭时播放的视频


需准备的东西:

VLC的动态链接库*.dll

1,在网上直接下载VLC播放器安装http://www.videolan.org点击打开链接/

2,安装好后在VLC安装目录下libvlc.dll,libvlccore.dll及plugins目录下的所有文件拷贝到C#的debug目录下(下左图VLC安装目录,右图C#项目debug目录)

若是release 也需放到release目录



C#编程

(1)创建一个C#的winform项目

(2)c#封装libvlc的API接口

新建一个类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security;
using System.Text;
using System.Threading.Tasks;

namespace WindowsFormsApplication1
{
    class VlcPlayer
    {
        private IntPtr libvlc_instance_;
        private IntPtr libvlc_media_player_;
        private double duration_;
        public VlcPlayer(string pluginPath)
        {
            string plugin_arg = "--plugin-path=" + pluginPath;
            string[] arguments = { "-I", "dummy", "--ignore-config", "--no-video-title", plugin_arg };
            libvlc_instance_ = LibVlcAPI.libvlc_new(arguments);

            libvlc_media_player_ = LibVlcAPI.libvlc_media_player_new(libvlc_instance_);
        }
        public void SetRenderWindow(int wndHandle)
        {
            if (libvlc_instance_ != IntPtr.Zero && wndHandle != 0)
            {
                LibVlcAPI.libvlc_media_player_set_hwnd(libvlc_media_player_, wndHandle);
            }
        }
        public void PlayFile(string filePath)
        {
            IntPtr libvlc_media = LibVlcAPI.libvlc_media_new_path(libvlc_instance_, filePath);
            if (libvlc_media != IntPtr.Zero)
            {
                LibVlcAPI.libvlc_media_parse(libvlc_media);
                duration_ = LibVlcAPI.libvlc_media_get_duration(libvlc_media) / 1000.0;
                LibVlcAPI.libvlc_media_player_set_media(libvlc_media_player_, libvlc_media);
                LibVlcAPI.libvlc_media_release(libvlc_media);
                LibVlcAPI.libvlc_media_player_play(libvlc_media_player_);
            }
        }
        public void Pause()
        {
            if (libvlc_media_player_ != IntPtr.Zero)
            {
                LibVlcAPI.libvlc_media_player_pause(libvlc_media_player_);
            }
        }
        public void Play()
        {
            if (libvlc_media_player_ != IntPtr.Zero)
            {
                LibVlcAPI.libvlc_media_player_play(libvlc_media_player_);
              //  LibVlcAPI.libvlc_media_player_pause(libvlc_media_player_);
            }
        }
        public void Stop()
        {
            if (libvlc_media_player_ != IntPtr.Zero)
            {
                LibVlcAPI.libvlc_media_player_stop(libvlc_media_player_);
            }
        }
      //  public void FastForward()
       // {
        //    if (libvlc_media_player_ != IntPtr.Zero)
         //   {
          //      LibVlcAPI.libvlc_media_player_fastforward(libvlc_media_player_);
           // }
       // }
        public double GetPlayTime()
        {
            return LibVlcAPI.libvlc_media_player_get_time(libvlc_media_player_) / 1000.0;
        }
        public void SetPlayTime(double seekTime)
        {
            LibVlcAPI.libvlc_media_player_set_time(libvlc_media_player_, (Int64)(seekTime * 1000));
        }
        public int GetVolume()
        {
            return LibVlcAPI.libvlc_audio_get_volume(libvlc_media_player_);
        }
        public void SetVolume(int volume)
        {
            LibVlcAPI.libvlc_audio_set_volume(libvlc_media_player_, volume);
        }
        public void SetFullScreen(bool istrue)
        {
            LibVlcAPI.libvlc_set_fullscreen(libvlc_media_player_, istrue ? 1 : 0);
        }
        public double Duration()
        {
            return duration_;
        }
        public string Version()
        {
            return LibVlcAPI.libvlc_get_version();
        }
    }
    internal static class LibVlcAPI
    {
        internal struct PointerToArrayOfPointerHelper
        {
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)]
            public IntPtr[] pointers;
        }
        public static IntPtr libvlc_new(string[] arguments)
        {
            PointerToArrayOfPointerHelper argv = new PointerToArrayOfPointerHelper();
            argv.pointers = new IntPtr[11];
            for (int i = 0; i < arguments.Length; i++)
            {
                argv.pointers[i] = Marshal.StringToHGlobalAnsi(arguments[i]);
            }
            IntPtr argvPtr = IntPtr.Zero;
            try
            {
                int size = Marshal.SizeOf(typeof(PointerToArrayOfPointerHelper));
                argvPtr = Marshal.AllocHGlobal(size);
                Marshal.StructureToPtr(argv, argvPtr, false);
                return libvlc_new(arguments.Length, argvPtr);
            }
            finally
            {
                for (int i = 0; i < arguments.Length + 1; i++)
                {
                    if (argv.pointers[i] != IntPtr.Zero)
                    {
                        Marshal.FreeHGlobal(argv.pointers[i]);
                    }
                }
                if (argvPtr != IntPtr.Zero)
                {
                    Marshal.FreeHGlobal(argvPtr);
                }
            }
        }
        public static IntPtr libvlc_media_new_path(IntPtr libvlc_instance, string path)
        {
            IntPtr pMrl = IntPtr.Zero;
            try
            {
                byte[] bytes = Encoding.UTF8.GetBytes(path);
                pMrl = Marshal.AllocHGlobal(bytes.Length + 1);
                Marshal.Copy(bytes, 0, pMrl, bytes.Length);
                Marshal.WriteByte(pMrl, bytes.Length, 0);
                return libvlc_media_new_path(libvlc_instance, pMrl);
            }
            finally
            {
                if (pMrl != IntPtr.Zero)
                {
                    Marshal.FreeHGlobal(pMrl);
                }
            }
        }
        public static IntPtr libvlc_media_new_location(IntPtr libvlc_instance, string path)
        {
            IntPtr pMrl = IntPtr.Zero;
            try
            {
                byte[] bytes = Encoding.UTF8.GetBytes(path);
                pMrl = Marshal.AllocHGlobal(bytes.Length + 1);
                Marshal.Copy(bytes, 0, pMrl, bytes.Length);
                Marshal.WriteByte(pMrl, bytes.Length, 0);
                return libvlc_media_new_path(libvlc_instance, pMrl);
            }
            finally
            {
                if (pMrl != IntPtr.Zero)
                {
                    Marshal.FreeHGlobal(pMrl);
                }
            }
        }

        // ----------------------------------------------------------------------------------------
        // 以下是libvlc.dll导出函数

        // 创建一个libvlc实例,它是引用计数的
        [DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        private static extern IntPtr libvlc_new(int argc, IntPtr argv);

        // 释放libvlc实例
        [DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        public static extern void libvlc_release(IntPtr libvlc_instance);

        [DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        public static extern String libvlc_get_version();

        // 从视频来源(例如Url)构建一个libvlc_meida
        [DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        private static extern IntPtr libvlc_media_new_location(IntPtr libvlc_instance, IntPtr path);

        // 从本地文件路径构建一个libvlc_media
        [DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        private static extern IntPtr libvlc_media_new_path(IntPtr libvlc_instance, IntPtr path);

        [DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        public static extern void libvlc_media_release(IntPtr libvlc_media_inst);

        // 创建libvlc_media_player(播放核心)
        [DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        public static extern IntPtr libvlc_media_player_new(IntPtr libvlc_instance);

        // 将视频(libvlc_media)绑定到播放器上
        [DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        public static extern void libvlc_media_player_set_media(IntPtr libvlc_media_player, IntPtr libvlc_media);

        // 设置图像输出的窗口
        [DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        public static extern void libvlc_media_player_set_hwnd(IntPtr libvlc_mediaplayer, Int32 drawable);

        [DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        public static extern void libvlc_media_player_play(IntPtr libvlc_mediaplayer);

        /// <summary>
        /// 
        /// </summary>
        /// <param name="libvlc_mediaplayer"></param>
        //[DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        //[SuppressUnmanagedCodeSecurity]
       // public static extern void libvlc_media_player_fastforward(IntPtr libvlc_mediaplayer);

        [DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        public static extern void libvlc_media_player_pause(IntPtr libvlc_mediaplayer);

        [DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        public static extern void libvlc_media_player_stop(IntPtr libvlc_mediaplayer);

        // 解析视频资源的媒体信息(如时长等)
        [DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        public static extern void libvlc_media_parse(IntPtr libvlc_media);

        // 返回视频的时长(必须先调用libvlc_media_parse之后,该函数才会生效)
        [DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        public static extern Int64 libvlc_media_get_duration(IntPtr libvlc_media);

        // 当前播放的时间
        [DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        public static extern Int64 libvlc_media_player_get_time(IntPtr libvlc_mediaplayer);

        // 设置播放位置(拖动)
        [DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        public static extern void libvlc_media_player_set_time(IntPtr libvlc_mediaplayer, Int64 time);

        [DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        public static extern void libvlc_media_player_release(IntPtr libvlc_mediaplayer);

        // 获取和设置音量
        [DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        public static extern int libvlc_audio_get_volume(IntPtr libvlc_media_player);

        [DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        public static extern void libvlc_audio_set_volume(IntPtr libvlc_media_player, int volume);

        // 设置全屏
        [DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        public static extern void libvlc_set_fullscreen(IntPtr libvlc_media_player, int isFullScreen);

    }
}
(3)窗口布局编辑


(3)选几个要点说说,其余参考附件的源码

1,播放过程中的窗口右键菜单问题

注意窗口布局中黑色panel那块有两个panel,一个panel1,一个panel2,panel1位于底层,panel2位于表层,panel2背景色设置为transparent,这么做的原因是panel1在指定成播放后contextMenuStrip属性失效,为了能在播放后仍能在播放区使用右键并且不影响播放,故添加透明的panel2

2,记录之前打开的三次文件

        /// <summary>
        /// 菜单栏文件实现功能
        /// 1 打开待播放文件
        /// 2 记录历史信息
        /// 3 历史信息最多不超过3条
        /// 4 点击历史信息可以实现播放menuitem_Click()
        /// 5 如果点击历史信息不能播放(出现错误)则删除该历史信息item和Menu.ini (方法:try catch)
        /// 6 Menu.ini记录的信息最多不超过3条,不重复记录
        /// 7 在历史信息中右键可以选择删除
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        /// 
        #region 菜单栏-文件


        /// <summary>
        /// 打开ToolStripMenuItem_Click
        /// 打开文件并将文件目录添加到Menu.ini
        /// 若打开相同文件则不添加(这个有Bug,这样的话按tsBtn_play打开的就不是上一个了,因为打开相同的不添加)
        /// 若记录行数超过3个,则先记录后三个数据,再重新建一个Menu.ini(清除数据),接着讲记录的后三个数据写入
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        /// 
        private void 打开ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            //bool isSame = false;
            openFileDialog1.FileName = "";
            if(this.openFileDialog1.ShowDialog()==DialogResult.OK)
            { 
                //StreamReader sr0 = new StreamReader(address + "\\Menu.ini", true);
               // while (sr0.Peek() > -1)
               // {
              //      if ((sr0.ReadLine() == openFileDialog1.FileName)|(openFileDialog1.FileName==""))
              //      {
              //          isSame = true;
               //     }
              //  }
               // sr0.Close();
               // if (isSame == false)// 若打开相同文件则不添加
              //  {
                    StreamWriter s = new StreamWriter(address + "\\Menu.ini", true);
                    s.WriteLine(openFileDialog1.FileName);
                    s.Flush();
                    s.Close();
             //   }
                string[] text = File.ReadAllLines(address + "\\Menu.ini");
                int row = text.Length;//行
                int rowcount;
                string[] tempdata = new string[] {"","",""};
                if (row > 3)// 若记录行数超过3个,则先记录后三个数据,再重新建一个Menu.ini(清除数据),接着讲记录的后三个数据写入
                {
                    StreamReader sr1 = new StreamReader(address + "\\Menu.ini", true);
                    while (sr1.Peek() > -1)
                    {
                        sr1.ReadLine();//空读,跳过原始的第一个数据,从第二个数据开始读
                        for (rowcount = 0; rowcount < 3; rowcount++)
                        {
                            tempdata[rowcount] = sr1.ReadLine();
                        }
                    }
                    sr1.Close();
                    FileStream fs = new FileStream(address + "\\Menu.ini", FileMode.Create, FileAccess.Write);
                    fs.Close();
                    StreamWriter s1 = new StreamWriter(address + "\\Menu.ini", true);
                    s1.WriteLine(tempdata[0]);
                    s1.WriteLine(tempdata[1]);
                    s1.WriteLine(tempdata[2]);
                    s1.Flush();
                    s1.Close();
                }
               // StreamReader sr2 = new StreamReader(address + "\\Menu.ini", true);
               // while(sr2.Pee)
                vlcPlayer.PlayFile(openFileDialog1.FileName);
                trackBar1.SetRange(0, (int)vlcPlayer.Duration());
                trackBar1.Value = 0;
                timer1.Start();
                is_playinig = true;
                tSBtn_play.Image = Properties.Resources.暂停;
                tSBtn_play.Text = "暂停";
                media_is_open = true;              
                //label_media_name.Text = openFileDialog1.FileName.Substring(openFileDialog1.FileName.LastIndexOf('\\') + 1, openFileDialog1.FileName.Length - 1 - openFileDialog1.FileName.LastIndexOf('\\'));
                //获取文件名的另一种方法,不带后缀
                label_media_name.Text = Path.GetFileNameWithoutExtension(openFileDialog1.FileName);
                label_media_name.Show();
            }
        }
        /// <summary>
        /// 将Menu.ini中的历史记录添加到文件菜单栏
        /// </summary>
        private void readFilePath()
        {
            int items_count = this.文件ToolStripMenuItem.DropDownItems.Count;
            switch (items_count)
            {
                case 4:
                    this.文件ToolStripMenuItem.DropDownItems.RemoveAt(1);
                    break;
                case 5:
                    this.文件ToolStripMenuItem.DropDownItems.RemoveAt(1);//移走第一项后原本第二项又成第一项了,所以继续移走第一项
                    this.文件ToolStripMenuItem.DropDownItems.RemoveAt(1);
                    break;
                case 6:
                    this.文件ToolStripMenuItem.DropDownItems.RemoveAt(1);
                    this.文件ToolStripMenuItem.DropDownItems.RemoveAt(1);
                    this.文件ToolStripMenuItem.DropDownItems.RemoveAt(1);
                    break;
                default:
                    break;
            }
            
            StreamReader sr = new StreamReader(address + "\\Menu.ini", true);
            int i =1;
            while (sr.Peek() > -1)//peek是用来确定你read的文件是否结束了,如果结束了会返回int型 -1 
            {
                    ToolStripMenuItem menuitem = new ToolStripMenuItem(sr.ReadLine());
                    this.文件ToolStripMenuItem.DropDownItems.Insert(i, menuitem);
                    i++;
                    menuitem.Click += new EventHandler(menuitem_Click); 
            }
            sr.Close();
        }
        /// <summary>
        /// 打开历史记录并播放
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void menuitem_Click(object sender, EventArgs e)
        {
            try
            {
                ToolStripMenuItem menu = (ToolStripMenuItem)sender;
                vlcPlayer.PlayFile(menu.Text);
                trackBar1.SetRange(0, (int)vlcPlayer.Duration());
                trackBar1.Value = 0;
                timer1.Start();
                is_playinig = true;
                tSBtn_play.Image = Properties.Resources.暂停;
                tSBtn_play.Text = "暂停";
                media_is_open = true;
                label_media_name.Text = Path.GetFileNameWithoutExtension(menu.Text);
                label_media_name.Show();
            }
            catch
            {
                MessageBox.Show("文件不存在", "提示");
            }
        }

        private void 文件ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            readFilePath();
        }
        #endregion

这段代码中这个地方注意:

<span style="white-space:pre">		</span>    this.文件ToolStripMenuItem.DropDownItems.RemoveAt(1);
                    this.文件ToolStripMenuItem.DropDownItems.RemoveAt(1);
                    this.文件ToolStripMenuItem.DropDownItems.RemoveAt(1);
这段原因是每移除菜单选项标号1的历史记录后,原本的标号2又变成标号1,所以继续删除标号1,而不是删除标号2;

3,在有以前播放记录情况下打开软件直接点击播放时播放上次打开的音视频实现代码

private void tSBtn_play_Click(object sender, EventArgs e)
        {
            if (is_playinig)
            {
                vlcPlayer.Pause();
                timer1.Stop();
                is_playinig = false;
                tSBtn_play.Image = Properties.Resources.开始;
                tSBtn_play.Text = "播放";
            }
            else
            {
                try
                {
                    string[] text = File.ReadAllLines(address + "\\Menu.ini");
                    string openfilepath="";
                    int row = text.Length;//行
                    StreamReader sr1 = new StreamReader(address + "\\Menu.ini", true);
                    switch (row)
                    {
                        case 1:
                            openfilepath=sr1.ReadLine();
                            break;
                        case 2:
                            sr1.ReadLine();
                            openfilepath = sr1.ReadLine();
                            break;
                        case 3:
                            sr1.ReadLine();
                            sr1.ReadLine();
                            openfilepath = sr1.ReadLine();
                            break;
                        default:
                            break;
                    }
                    if(row==1||row==2||row==3)
                    {
                        
                        if (!media_is_open) 
                        {
                            vlcPlayer.PlayFile(openfilepath);
                        }
                        trackBar1.SetRange(0, (int)vlcPlayer.Duration());
                        vlcPlayer.SetPlayTime(trackBar1.Value);
                        vlcPlayer.Play();
                        trackBar1.Value = (int)vlcPlayer.GetPlayTime();
                       // trackBar1.Value = 0;
                        timer1.Start();
                        is_playinig = true;
                        tSBtn_play.Image = Properties.Resources.暂停;
                        tSBtn_play.Text = "暂停";
                        media_is_open = true;
                        label_media_name.Text = Path.GetFileNameWithoutExtension(openfilepath);
                        label_media_name.Show();
                    }
                    sr1.Close();
                }
                catch (Exception er)
                {
                    MessageBox.Show("文件不存在", "提示");
                }
            }
        }
4,快进和快退实现方法,以快进为例

private void tSB_forward_Click(object sender, EventArgs e)
        {
            vlcPlayer.Pause();
            int time = (int)vlcPlayer.GetPlayTime() + 5;
            if (time < trackBar1.Maximum)
            {
                vlcPlayer.SetPlayTime(time);
            }
            else
            {
                vlcPlayer.SetPlayTime(trackBar1.Maximum);
            }
            vlcPlayer.Play();
            trackBar1.Value = (int)vlcPlayer.GetPlayTime();
        }
VLC的库中并没有快进快退方法(这个我不太确定,我没发现,若有麻烦告知我下,非常感谢)

所以可以先将视频暂停,然后在重新设置视频的播放时间,再播放即可


其余未说到的地方可以参考源码,欢迎跟帖交流

参考帖子:

http://www.cnblogs.com/haibindev/archive/2011/12/21/2296173.html

http://blog.csdn.net/leixiaohua1020/article/details/42363079

http://bbs.csdn.net/topics/390936942

附源码
http://download.csdn.net/detail/u012342996/9505082


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C#编写的基于VLC的播放器 的相关文章

随机推荐

  • Web自动化测试01:认识web自动化在什么项目中适用

    系列文章目录 软件测试功能到自动化学习路线图 2022年最新版技术栈 软件测试01 从了解测试岗位职能和测试流程开始 附作业 软件测试02 6大实际案例手把手教你设计测试点 软件测试03 用例执行以及缺陷管理的学习 附禅道下载使用流程 软件
  • Dalsa网口线阵相机例程(转载的挺不错的帖子,感谢作者)

    在网上狂搜资料 搜到了两个大佬的两篇好文章 dalsa 8k线阵网口相机c 开发 https blog csdn net baidu 30028771 article details 64628784 DALSA相机SDK不完全教程 htt
  • 【华为OD机试真题 JAVA】快递运输

    JS版 华为OD机试真题 JS 快递运输 标题 快递运输 时间限制 1秒 内存限制 262144K 语言限制 不限 一辆运送快递的货车 运送的快递均放在大小不等的长方体快递盒中 为了能够装载更多的快递 同时不能让货车超载 需要计算最多能装多
  • Jest结合Vue-test-utils使用的初步实践

    介绍 Vue test utils是Vue的官方的单元测试框架 它提供了一系列非常方便的工具 使我们更加轻松的为Vue构建的应用来编写单元测试 主流的 JavaScript 测试运行器有很多 但 Vue Test Utils 都能够支持 它
  • STM32(HAL库)驱动(2.0寸)TFT-LCD彩屏(240*320)

    目录 1 简介 2 CubeMX初始化配置 2 1 基础配置 2 1 1 SYS配置 2 1 2 RCC配置 2 2 屏幕引脚配置 2 3 项目生成 3 KEIL端程序整合 3 1 LCD驱动添加 3 2 函数修改 3 2 1 lcd h修
  • ssm dao层无法注入

    在ssm项目中通过ClassPathXmlApplicationContext获取持久层 然后测试mapper 遇到BindingException异常 org apache ibatis binding BindingException
  • PCIe专题学习——5.0(总线电源管理)

    之前我们讲了对PCIe的一些基础概念作了一个宏观的介绍 了解了PCIe是一种封装分层协议 packet based layered protocol 主要包括事务层 Transaction layer 数据链路层 Data link lay
  • Jmeter教程(一) - 入门

    Jmeter教程 一 入门Jmeter教程 二 自定义变量模拟多用户Jmeter教程 三 Linux中使用命令行进行压测 一 下载 登录官网Jmeter下载 得到压缩包jmeter 5 0 tgz 下载地址 http jmeter apac
  • CMS垃圾回收器

    目录 1 CMS收集器 2 CMS收集过程 3 CMS垃圾收集实践 4 CMS垃圾收集优缺点 4 1 分配担保机制 4 2 CMS的问题 5 小结 前言 虽然新出的G1优点明显 但是CMS算法依然是目前项目中使用的最多的垃圾收集器 G1可能
  • xp系统sc服务器,Windows XP系统服务配置攻略 SC Config

    Windows XP系统服务配置攻略 SC Config IT168 实用技巧 对于经常重装系统的朋友来说 出于优化系统 减少内存占用亦或增强系统安全性能 往往都会修改很多系统服务的启动类型 将大量无用或者危险的服务关闭 参照许多服务优化的
  • Qt5设置窗口、控件背景、字体颜色及无边框

    Qt5设置窗口 控件背景 字体颜色及无边框 无边框设置 以QTextbroswer为例 代码设置 使用样式表 ui gt describeText gt setStyleSheet QTextBrowser border width 0 b
  • 如何使用全局变量QT

    兩種方法 第一 使用extern關鍵字聲明 不推薦 破壞了封裝性 第二 新建一個類 存放全局的變量 函數 第一 使用extern關鍵字聲明 不推薦 破壞了封裝性 在一个头文件中声明int var name全局变量 在另一个cpp文件中引用此
  • Mysql 内置函数大全

    转载并整理 包括 数值进制 字符串长度 截取 填充 删除 拼接等 文件读取 数值绝对值 正负判断 取模 取整 次方 对数 开方 三角函数 反三角函数 随机数 弧度和角度 精确度保留 最大值和最小值等 日期判断 格式 加减 时间戳等 ASCI
  • 使用netty写一个心跳包

    当使用Netty编写一个心跳包时 需要实现一个自定义的ChannelHandler来处理心跳包的发送和接收 以下是一个简单的示例 演示如何使用Netty发送和接收心跳包 import io netty bootstrap Bootstrap
  • 安装Android SDK 报错Download finished with wrong size

    解决方法 可行 tools gt Options gt HTTP Proxy Server 中填入 mirrors opencas cn sdk gdgshanghai com ubuntu buct edu cn mirrors neus
  • count(*)与count(1)的区别

    count 与count 1 的区别 1 如果列为主键 count 列名 效率优于count 如果列不为主键 count 1 效率优于count 列名 如果表中存在主键 count 主键列名 效率最优 如果表中只有一列 则count 星号
  • vue 横纵向打印

    用单选框来切换打印时的方向 div class dialog footer div
  • AI在玩一种很新的艺术,700万网友在线围观,ControlNet又立功了

    梦晨 西风 发自 凹非寺量子位 公众号 QbitAI AI又在玩一种很新的艺术 一组 在离谱与合理的边缘反复试探 的图席卷各大平台 最火的一条 已有近700万查看16 8万点赞 到处有人在求教程 除了棋盘样式 还有一种螺旋样式的也很流行 连
  • 操作系统 第七章 文件管理

    从用户的观点看 操作系统中引入文件系统的目的是 D A 实现虚拟存储 B 保存用户和系统文档及数据 C 保护用户数据 D 实现对文件的按名存取 文件系统中 文件访问控制信息存储的合理位置是 A A 文件控制块 B 系统注册表 C 文件分配表
  • C#编写的基于VLC的播放器

    首先看一下最终的程序效果 实现的功能 1 打开播放的音视频文件 1 菜单栏 文件 gt 打开 2 工具栏 下面 打开 3 播放器右键 gt 打开 2 暂停 继续播放 停止音视频文件 3 进度条和右下角文本框显示播放进度 4 拖动进度条对视频