基于ffmpeg与SDL的视频播放库

        由于工作需要,自己封装的基于ffmpeg的视频编解码库,显示采用了SDL库。可以播放本地文件或网络流,支持多端口播放,支持文字叠加,截图、视频录制等等。

头文件代码:

#pragma once
#ifdef __DLLEXPORT
#define __DLL_EXP _declspec(dllexport)    
#else
#define __DLL_EXP _declspec(dllimport)    
#endif 

#include <stdio.h>
#include <string>

using namespace std;
//录像状态
enum RecordStatus
{
	Idle,
	Recording,
	Stop
};

//视频存储格式
enum VideoFormat
{
	MP4,
	AVI,
};

//图片存储格式
enum PictureFormat
{
	JPEG,
	PNG,
	BMP,
};

//播放器状态
enum PlayStatus
{
	Close,
	Playing,
	Pause
};

//滤镜种类
enum FilterType
{
	Time,
	Reticle,
	Text,
	Other
};

//颜色
struct RGBAColor
{
	BYTE R;
	BYTE G;
	BYTE B;
	BYTE A;
};

//OSD字体属性结构体
 struct OSDParameter
{
	char* text;
	int fontSize;        //汉字字号
	int fontFamily;      //0=黑体,1=楷体,2=宋体 3:Arial
	RGBAColor fontColor;      //字体颜色 rgb表示
	RGBAColor backColor;      //字体背景色 rgb表示
	float x;             //字体坐标 x:宽度百分比0-1
	float y;             //字体坐标 y:高度百分比0-1
	bool visible;        //是否可见
};

 //格式
 enum  FrameFormat
 {
	 AUDIO16,
	 RGB32,
	 YV12,
	 UVVY,
	 YUVJ420P
 };

 struct FrameInfo
{
	int width;  					   	//画面宽,单位像素。如果是音频数据则为0;
	int height; 					  	//画面高。如果是音频数据则为0;
	int stamp;  					  	//时标信息,单位毫秒。
	FrameFormat format;                 //数据类型,0:AUDIO16,1:RGB32,2:(YUV420P)YV12,3:YUVJ420P 
	int frameRate; 					    //实时帧率。
};

/**
* 功能描述:打开视频
* @param nPort:播放通道号[0,31] 
* @param url:视频文件或视频流地址
* @param data:图像控件句柄,后台录制时,赋值NULL
*
* @return 成功/失败
*/
extern "C" __declspec(dllexport) bool _stdcall VideoPlayer_OpenVideo(int nPort, const char* url, const void* hWnd);

/**
*  功能描述: 开始播放
* @param nPort:播放通道号[0,31]
* @param isRealTimePlay:实时播放,在需要实时播放时开启,如播放摄像头流。为false时,将按照帧率播放。
*/
extern "C" __declspec(dllexport) bool _stdcall VideoPlayer_StartPlay(int nPort,bool isRealTimePlay);

/**
*  功能描述: 暂停播放
* @param nPort:播放通道号[0,31] 
*/
extern "C" __declspec(dllexport) bool _stdcall VideoPlayer_PausePlay(int nPort);


/**
* 功能描述:关闭视频释放资源
* @param nPort:播放通道号[0,31] 
*/
extern "C" __declspec(dllexport)  bool _stdcall VideoPlayer_CloseVideo(int nPort);

/**
* 功能描述:设置文件播放指针的相对位置(百分比)
* @param nPort:播放通道号[0,31] 
* @param pos:播放时间位置  0-100
* @param fReleatePos:0-100
*/
extern "C" __declspec(dllexport) bool _stdcall VideoPlayer_SetPlayPos(int nPort, float fReleatePos);

/**
* 功能描述:播放速度控制
* @param nPort:播放通道号[0,31] 
* @param speed:速度  0:正常播放   1:1.25倍速  2:1.5倍速 3:1.75倍速 4:2倍速  5:0.75倍速  6:0.5倍速 7:0.25倍速
*/
extern "C" __declspec(dllexport) void _stdcall VideoPlayer_ChangeSpeed(int nPort, int speed);

/**
* 功能描述:获取当前播放时间
* @param nPort:播放通道号[0,31] 
* @return 播放时间  单位:秒
*/
extern "C" __declspec(dllexport) bool _stdcall VideoPlayer_GetPlayedTime(int nPort);

/**
* 功能描述:播放窗口缩放
* @param nPort:播放通道号[0,31] 
* @return 成功/失败
*/
extern "C" __declspec(dllexport)  bool _stdcall VideoPlayer_ResizeWindow(int nPort);

/**
* 功能描述:设置录制参数
* @param nPort:播放通道号[0,31]
* @param fps:视频帧率
* @param quality:图像质量(0-10) 越高质量越好,占用内存越大,设置为0时,为自动码率
* @param duration:单个文件时长(min),默认60分钟
* @param frameExtractionMode:抽帧模式 0:不抽帧,以fps进行编码;1:1/2 帧率,以fps/2进行抽帧(保证fps/2为整数,否则会出现丢帧情况)
* @param format:存储格式,默认为mp4
*
* @return 成功/失败
*/
extern "C" __declspec(dllexport) bool _stdcall VideoPlayer_SetRecordParameter(int nPort,int fps, float quality = 5, int duration = 60, int frameExtractionMode = 0, VideoFormat format= VideoFormat::MP4);

/**
* 功能描述:开始录制
* @param nPort:播放通道号[0,31]
* @param path:录像保存路径包含文件名
*
* @return 成功/失败
*/
extern "C" __declspec(dllexport) bool _stdcall VideoPlayer_StartRecord(int nPort, const char* path);

/**
* 功能描述:结束录制
* @param nPort:播放通道号[0,31] 
*/
extern "C" __declspec(dllexport) bool _stdcall VideoPlayer_StopRecord(int nPort);

/**
* 功能描述:视频截图
* @param nPort:播放通道号[0,31]
* @param path: 图像保存的路径,不含后缀名
* @param format:图像格式,默认为jpeg
*
* @return 成功/失败
*/
extern "C" __declspec(dllexport) bool _stdcall VideoPlayer_ShotImage(int nPort, const char* path, PictureFormat format= PictureFormat::JPEG);


/**
* 功能描述:设置某一行的OSD叠加文本
* @param nPort:播放通道号[0,31] 
* @param osdID:OSD文本序号
* @param para:osd属性
*
* @return 成功/失败
*/
extern "C" __declspec(dllexport) bool _stdcall VideoPlayer_SetOSDText(int nPort, int osdID, OSDParameter osdParam);

/**
* 功能描述:设置所有的OSD文本(总共20行)
* @param nPort:播放通道号[0,31]
* @param para:osd属性
*
* @return 成功/失败
*/
extern "C" __declspec(dllexport) bool _stdcall VideoPlayer_SetAllOSDTexts(int nPort, OSDParameter osdParams[]);

/**
* 功能描述:清除所有OSD文本
* @param nPort:播放通道号[0,31] 
*
* @return 成功/失败
*/
extern "C" __declspec(dllexport) bool _stdcall VideoPlayer_ClearOSDText(int nPort);


/**
* 功能描述:设置解码缓存队列大小
* @param nPort:播放通道号[0,31]
* @param size:默认为10,设置过小会丢帧,设置过大可能会导致画面延迟
*
* @return 成功/失败
*/
extern "C" __declspec(dllexport) void _stdcall VideoPlayer_SetDecodedBufferSize(int nPort, int size);

/**
* 功能描述:单帧往后播放 
* @param nPort:播放通道号[0,31]
*/
extern "C" __declspec(dllexport) bool  _stdcall VideoPlayer_NextFrame(int nPort);

/**
* 功能描述:单帧往前播放 
* @param nPort:播放通道号[0,31]
*/
extern "C" __declspec(dllexport) bool  _stdcall VideoPlayer_PrevFrame(int nPort);

/**
* 功能描述:跳转视频到某一时间位置 
* @param nPort:播放通道号[0,31]
* @param pos:视频位置百分比
*/
extern "C" __declspec(dllexport) bool  _stdcall VideoPlayer_SetPlayPos(int nPort,float pos);

/**
* 功能描述:显示/隐藏当前系统时间
* @param nPort:播放通道号[0,31]
* @param visible:是否显示
* @param xPos:坐标位置X,宽度百分比
* @param yPos:坐标位置Y,高度百分比
* @param fontSize:字体大小,默认50
*/
extern "C" __declspec(dllexport) bool  _stdcall VideoPlayer_SetDateTime(int nPort,bool visible, float xPos, float yPos,int fontSize=50);
 
 
/**
* 功能描述:当前解码完成数据回调
* @param nPort:播放通道号[0,31]
* @param pBuf:yuv数据指针
* @param nSize:数据大小
* @param pFrameInfo:帧信息
*/
typedef void(_stdcall* DecodeCallBack)(int nPort, const unsigned char* pBuf, int nSize, FrameInfo& pFrameInfo);

/**
* 功能描述:设置解码回调函数
* @param nPort:播放通道号[0,31]
* @param pDecodeProc:回调函数
*/
extern "C" __declspec(dllexport) bool  _stdcall VideoPlayer_SetDecCallBack(int nPort, DecodeCallBack pDecodeProc);

 

/**
* 功能描述:在显示句柄窗口中绘制文本、图形等
* @param nPort:播放通道号[0,31]
* @param hWnd:视频窗口句柄,用于创建GDI
* @param width:视频窗口宽度
* @param height:视频窗口高度
*/
typedef void(_stdcall* DrawCallBack)(int nPort, const void* hWnd,int width,int height);

extern "C" __declspec(dllexport) bool  _stdcall VideoPlayer_SetDrawCallBack(int nPort, DrawCallBack pDrawProc);

 

 库支持C++,C#调用,以下是C#调用的方法:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using VideoPlayDemo.Onvif;
using static VideoPlayDemo.MYVideoPlay;

namespace VideoPlayDemo
{
    public partial class Form1 : Form
    {

        const int PLAY_PORT1 = 0;
        const int PLAY_PORT2 = 1;
        public event MYVideoPlay.DecodeCallBack decodeCallBack;
        public event MYVideoPlay.DrawCallBack drawCallBack;

        bool[] isRecording = new bool[2];
        bool[] isOpened = new bool[2];

        MYVideoPlay.OSDParameter[] OSDParameters1 = new MYVideoPlay.OSDParameter[20];
        MYVideoPlay.OSDParameter[] OSDParameters2 = new MYVideoPlay.OSDParameter[20];

        public Form1()
        {
            InitializeComponent();
            Timer timer = new Timer();
            timer.Interval = 100;
            timer.Enabled = true;
            timer.Tick += Timer_Tick;

            decodeCallBack += new MYVideoPlay.DecodeCallBack(Form1_decodeCallBack);
            drawCallBack += new MYVideoPlay.DrawCallBack(Form1_drawCallBack);

            //初始化
            for (int i = 0; i < 20; i++)
            {
                OSDParameters1[i] = new MYVideoPlay.OSDParameter();
                OSDParameters1[i].visible = false;
                OSDParameters1[i].text = "test中文"+i.ToString();
                OSDParameters1[i].fontSize = 100;
                OSDParameters1[i].fontFamily = 0;
                OSDParameters1[i].fontColor = new MYVideoPlay.RGBAColor(Color.White);
                OSDParameters1[i].backColor = new MYVideoPlay.RGBAColor(Color.Transparent);

                OSDParameters2[i] = new MYVideoPlay.OSDParameter();
                OSDParameters2[i].visible = false;
                OSDParameters2[i].text = "test中文" + i.ToString();
                OSDParameters2[i].fontSize = 100;
                OSDParameters2[i].fontFamily = 0;
                OSDParameters2[i].fontColor = new MYVideoPlay.RGBAColor(Color.Yellow);
                OSDParameters2[i].backColor = new MYVideoPlay.RGBAColor(Color.Transparent);

            }
        }



        #region 视频播放控制方法
        /// <summary>
        /// 打开视频
        /// </summary>
        /// <param name="port"></param>
        public bool OpenVideo(int port,string url,IntPtr intPtr)
        {
            bool ret = false;
            ret = MYVideoPlay.VideoPlayer_SetDecCallBack(port, decodeCallBack);
            if (!ret)
            {
                MessageBox.Show("设置解码回调函数失败!");
                return ret;
            }
            ret = MYVideoPlay.VideoPlayer_SetDrawCallBack(port, drawCallBack);
            if (!ret)
            {
                MessageBox.Show("设置绘图回调函数失败!");
                return ret;
            }
            ret = MYVideoPlay.VideoPlayer_OpenVideo(port, url, intPtr);
            if (!ret)
            {
                MessageBox.Show("打开视频失败!");
                return ret;
            }
            ret = MYVideoPlay.VideoPlayer_StartPlay(port,false);
            if (!ret)
            {
                MessageBox.Show("播放失败!");
                return ret;
            }

            //叠加时间        
       //     ret = MYVideoPlay.VideoPlayer_SetDateTime(port, true, 0.01f, 0.01f,70);
            return ret;

        }

        /// <summary>
        /// 关闭视频
        /// </summary>
        /// <param name="port"></param>
        private bool CloseVideo(int port)
        {
            return MYVideoPlay.VideoPlayer_CloseVideo(port);
        }

        /// <summary>
        /// 开始录制  帧率60
        /// </summary>
        /// <param name="port"></param>
        /// <param name="halfRate"></param>
        private bool StartRecord(int port,bool halfRate)
        {
            bool ret = false;
            if(halfRate)
              ret = MYVideoPlay.VideoPlayer_SetRecordParameter(port, 60, 5, 60,1);
            else
              ret = MYVideoPlay.VideoPlayer_SetRecordParameter(port, 60, 5, 60, 0);

            string path = string.Format("d:\\video_{0}", port);
            ret = MYVideoPlay.VideoPlayer_StartRecord(port, path);
            if (!ret)
                MessageBox.Show("开启录制失败!");
            return ret;
        }

        /// <summary>
        /// 停止录制
        /// </summary>
        /// <param name="port"></param>
        private bool StopRecord(int port)
        {
            bool ret = MYVideoPlay.VideoPlayer_StopRecord(port);
            return ret;
        }

        /// <summary>
        /// 截图
        /// </summary>
        /// <param name="port"></param>
        /// <returns></returns>
        private bool ShotImage(int port)
        {
            bool ret = MYVideoPlay.VideoPlayer_ShotImage(port, "d:\\" + port.ToString(), MYVideoPlay.PictureFormat.JPEG);
            return ret;
        }

        int[] frameRates = new int[4];

        private void Form1_decodeCallBack(int nPort, IntPtr pBuf, int nSize, ref MYVideoPlay.FrameInfo pFrameInfo)
        {
            frameRates[nPort] = pFrameInfo.frameRate;
            this.Invoke((Action)delegate
            {
                this.lbFPS1.Text = frameRates[0].ToString()+"fps";
                this.lbFPS2.Text = frameRates[1].ToString()+"fps";
            });

        }

        private void Form1_drawCallBack(int nPort, IntPtr hWnd, int width, int height)
        {

        }
        #endregion
         
     
        /// <summary>
        /// 打开视频
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnOpenVideo_Click(object sender, EventArgs e)
        {
            Button btn = sender as Button;
            int n = int.Parse(btn.Tag.ToString());
            if (isOpened[n])
                return;
            string url="";
            IntPtr intPtr= IntPtr.Zero;
            switch (n)
            {
                case 0: url = textBox1.Text;intPtr = pnlVideo1.Handle; break;
                case 1: url = textBox2.Text;intPtr = pnlVideo2.Handle; break;
            }
            Task task = new Task(() =>
            {
                  //网络直播流(非相机流)时设置更大的buffer进行缓存,否则出现马赛克
                  MYVideoPlay.VideoPlayer_SetDecodedBufferSize(n, 250);
                  isOpened[n] = OpenVideo(n,url,intPtr);
            });
            task.Start();
        }

        /// <summary>
        /// 关闭视频
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnCloseVideo_Click(object sender, EventArgs e)
        {
            Button btn = sender as Button;
            int n = int.Parse(btn.Tag.ToString());
            if (!isOpened[n])
                return;
            bool ret = CloseVideo(n);
            isOpened[n] = !ret;
        }


        /// <summary>
        /// 开始录制
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnStartRecord_Click(object sender, EventArgs e)
        {
            Button btn = sender as Button;
            int n = int.Parse(btn.Tag.ToString());
            if (isRecording[n] || !isOpened[n])
                return;
            if (n == 0)
                isRecording[n] = StartRecord(n, true);
            else
                isRecording[n] = StartRecord(n, false);
        }

        /// <summary>
        /// 停止录制
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnStopRecord_Click(object sender, EventArgs e)
        {
            Button btn = sender as Button;
            int n = int.Parse(btn.Tag.ToString());
            if (!isRecording[n] || !isOpened[n])
                return;
            bool ret = StopRecord(n);
            isRecording[n] = !ret;

        }

        /// <summary>
        /// 截图
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnShotImage_Click(object sender, EventArgs e)
        {
            Button btn = sender as Button;
            int n = int.Parse(btn.Tag.ToString());
            ShotImage(n);
        }


        /// <summary>
        /// 叠加字符测试
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Timer_Tick(object sender, EventArgs e)
        {
            Random rd = new Random();
            bool ret = false;
            if (isOpened[PLAY_PORT1])
            {
                OSDParameters1[0].visible = OSDParameters1[1].visible = true;
                OSDParameters1[0].x = (float)rd.NextDouble();
                OSDParameters1[0].y = (float)rd.NextDouble();
                OSDParameters1[1].x = (float)rd.NextDouble();
                OSDParameters1[1].y = (float)rd.NextDouble();
                //ZYVideoPlay.VideoPlayer_SetAllOSDTexts(PLAY_PORT1, OSDParameters1);
            }
            if (isOpened[PLAY_PORT2])
            {
                OSDParameters2[0].visible = OSDParameters2[1].visible = true;
                OSDParameters2[0].x = (float)rd.NextDouble();
                OSDParameters2[0].y = (float)rd.NextDouble();
                OSDParameters2[1].x = (float)rd.NextDouble();
                OSDParameters2[1].y = (float)rd.NextDouble();
             //   ret = ZYVideoPlay.VideoPlayer_SetAllOSDTexts(PLAY_PORT2, OSDParameters2);
            }
        }
 
        private void timer1_Tick(object sender, EventArgs e)
        {
            if (isRecording[PLAY_PORT1])
            {
                if (DateTime.Now.Millisecond < 500)
                    lbRec1.Visible = true;
                else
                    lbRec1.Visible = false;
            }
            else
                lbRec1.Visible = false;


            if (isRecording[PLAY_PORT2])
            {
                if (DateTime.Now.Millisecond < 500)
                    lbRec2.Visible = true;
                else
                    lbRec2.Visible = false;
            }
            else
                lbRec2.Visible = false;

        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            for(int i=0;i<2;i++)
            {
                if (isOpened[i])
                    CloseVideo(i);
            }
        }

   
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/68323.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

SpringCloud实用篇5——elasticsearch基础

目录 1.初识elasticsearch1.1 了解ES1.1.1 elasticsearch的作用1.1.2 ELK技术栈1.1.3 elasticsearch和lucene1.1.4 总结 1.2.倒排索引1.2.1.正向索引1.2.2.倒排索引1.2.3.正向和倒排 1.3 es的一些概念1.3.1 文档和字段1.3.2 索引和映射1.3.3 mysql与elasticsearch 1.4 部署单点…

flutter开发实战-TextPainter计算文本内容的宽度

flutter开发实战-TextPainter计算文本内容的宽度 最近开发过程中根据Text文本的大小判断是否需要进行显示跑马灯效果&#xff0c;获取文本的大小&#xff0c;需要TextPainter来获取Size 一、TextPainter TextPainter主要用于实现文本的绘制。TextPainter类可以将TextSpan渲染…

浏览器多管闲事之跨域

年少时的梦想就是买一台小霸王游戏机 当时的宣传语就是小霸王其乐无穷~。 大些了&#xff0c;攒够了零花钱&#xff0c;在家长的带领下终于买到了 那一刻我感觉就是最幸福的人 风都是甜的&#xff01; 哪成想... 刚到家就被家长扣下了 “”禁止未成年人玩游戏机 (问过卖家了&a…

Window下安装MinGW64

欢迎来到我的酒馆 介绍Windows下&#xff0c;安装MinGW64。 目录 欢迎来到我的酒馆二.MinGW64三.配置系统环境变量 二.MinGW64 从sourceforge下载mingw64&#xff0c; sourceforge下载MinGW https://sourceforge.net/projects/mingw-w64/files/mingw-w64/mingw-w64-release/ 下…

香港站群服务器为什么适合seo优化?

​  香港站群为什么适合seo优化?本文主要从以下四点出发进行原因阐述。 1.香港站群服务器的优势 2.香港站群服务器与国内服务器的对比 3.多IP站群服务器的优势 4.香港站群服务器在SEO优化中的注意事项 1.香港站群服务器的优势 香港站群服务器是为了满足企业SEO优化需求而提供…

实践分享:Vue 项目如何迁移小程序

最近我们小组刚经历了将成熟的 HTML5 项目转换成小程序&#xff0c;并在app中运行的操作&#xff01;记录下来分享给各位。 项目&#xff1a;将已有的 Vue 项目转为小程序&#xff0c; 在集成了FinClip SDK 的 App 中运行。 技术&#xff1a;uni-app、FinClip 两个注意事项&…

[每周一更]-(第57期):用Docker、Docker-compose部署一个完整的前后端go+vue分离项目

文章目录 1.参考项目2.技能点3.GO的Dockerfile配置后端的结构如图Dockerfile先手动docker调试服务是否可以启动报错 4.Vue的Dockerfile配置前端的结构如图nginx_docker.confDockerfile构建 5.docker-compose 整合前后端docker-compose.yml错误记录&#xff08;1&#xff09;ip端…

PS AI版本安装教程

好久没写博客了&#xff0c;今天更新一下子吧&#xff01; 随着chatGPT的提出&#xff0c;各种软件逐渐开始镶嵌人工智能&#xff0c;为我们的生活带来了极大的便利&#xff01;话不多说&#xff0c;开始介绍今天的主角&#xff0c;PS的AI版本。 安装教程&#xff1a; 1.安装…

Docker一键部署项目,无需登录XShell

文章目录 一键部署项目Docker手动部署SpringBoot项目编写docker部署的脚本文件script.sh 脚本内容 特别注意&#xff01;编写dockerfiledockerfile 文件内容 上传后端服务的jar包到服务器中执行 script 脚本部署后端服务 自动部署SpringBoot项目引入jsch依赖编写jsch工具类执行…

工业4.0:欢迎来到智能制造

制造业正在经历一场被称为“工业4.0”的全新技术革命&#xff0c;这场革命将数字化、网络化、智能化和自动化技术融合在一起&#xff0c;旨在打造高质、高效、高产且可持续的智能工厂。工业4.0将彻底改变产品制造的方式&#xff0c;颠覆我们对制造业的传统认知。 什么是工业4.…

【Java】try|catch|throws 具体详解+应用

目录 tryCatch 基本介绍 使用细节 throws异常处理 基本介绍 ​ 使用细节 自定义异常 基本概念 步骤 throw和throws的区别 tryCatch 基本介绍 使用细节 throws异常处理 基本介绍 使用细节 自定义异常 基本概念 步骤 throw和throws的区别

【数据结构】Disruptor环形数组无锁并发框架阅读

Disruptor 是苹国外厂本易公司LMAX开发的一个高件能列&#xff0c;研发的初夷是解决内存队列的延识问顾在性能测试中发现竟然与10操作处于同样的数量级)&#xff0c;基于Disruptor开发的系统单线程能支撑每秒600万订单&#xff0c;2010年在QCn演讲后&#xff0c;获得了业界关注…

MinGW-W64 下载、安装与配置(支持最新版的GCC,目前 GCC 13.2.0)

文章目录 一、简介1. MinGW 和 MinGW-W64 区别和联系2. MSVCRT 和 UCRT 介绍 二、下载1. 从 sourceforge.net 下载2. 从 github 下载3. 从 镜像站点 下载4. 自己编译 三、安装与配置1. 在线安装2. 离线安装3. 环境配置 四、总结 一、简介 1. MinGW 和 MinGW-W64 区别和联系 M…

数组slice、splice字符串substr、split

一、定义 这篇文章主要对数组操作的两种方法进行介绍和使用&#xff0c;包括&#xff1a;slice、splice。对字符串操作的两种方法进行介绍和使用&#xff0c;包括&#xff1a;substr、split (一)、数组 slice:可以操作的数据类型有&#xff1a;数组字符串 splice:数组 操作数组…

【go语言学习笔记】04 Go 语言工程管理

文章目录 一、质量保证1. 单元测试1.1 定义1.2 Go 语言的单元测试1.3 单元测试覆盖率 2. 基准测试2.1 定义2.2 Go 语言的基准测试2.3 计时方法2.4 内存统计2.5 并发基准测试2.6 基准测试实战 3. 特别注意 二、性能优化1. 代码规范检查1.1 定义1.2 golangci-lint1.2.1 安装1.2.2…

vue3 + ts+element-plus学习笔记

子组件通过defineProps方法接收父组件传递过来的数据&#xff0c;是vue3中提供的方法&#xff0c;不需要引入&#xff0c;直接使用 方法的写法&#xff1a; const onClick (){... }自定义事件&#xff1a; 子组件点击事件 全局事件总线 mitt 兄弟组件之间的事件&#x…

【福建事业单位-资料分析】03 比重和平均数

【福建事业单位-资料分析】03 比重和平均数 一、比重&#xff08;现期比重&#xff0c;基期比重、两期比重&#xff09;1.1 现期比重增长贡献量&#xff0c;利润率 1.2基期比重&#xff08;用现期和增长率逆求&#xff09;1.3两期比重&#xff08;难点重点&#xff09;——比较…

基础实验篇 | QGC实时调整控制器参数实验

PART 1 实验名称及目的 QGC实时调整控制器参数实验&#xff1a;在进行硬件在环仿真和真机实验时&#xff0c;常常需要在QGC地面站中观察飞行状态&#xff0c;并对控制器参数进行实时调整&#xff0c;以使得飞机达到最佳的控制效果&#xff0c;但是&#xff0c;在Simulink中设…

改进的麻雀算法优化最大相关峭度解卷积(SCSSA-MCKD),实现早期微弱故障诊断,MATLAB代码实现

01 引言 由于一些设备的早期故障产生的冲击十分微弱&#xff0c;易被系统噪声干扰&#xff0c;如何有效地对设备的原始故障信号进行降噪并增强信号中微弱冲击成分&#xff0c;是进行该类部件早期故障诊断的关键。 最大相关峭度解卷积&#xff08;MCKD&#xff09;通过解卷积运算…

logstash日志换行处理小解

logstash主用于日志实时数据收集、解析&#xff0c;并将数据转发的工具&#xff0c;内置的功能也相当强大。但&#xff0c;同时意味着&#xff0c;他可能接收到各种情况的数据。 此处&#xff0c;我们主要讲解我实际使用中&#xff0c;碰到的一个小问题&#xff0c;换行(\n)。…