当前位置: 首页 > article >正文

Windows软件插件-音视频捕获

下载本插件
音视频捕获就是获取电脑外接的话筒,摄像头,或线路输入的音频和视频。
本插件捕获电脑外接的音频和视频。最多可以同时获取4个视频源和4个音频源。插件可以在win32和MFC程序中使用。

使用方法

首先,加载本“捕获”DLL,获得DLL模块句柄。

	HMODULE hCap = LoadLibrary(L"捕获.dll");//加载捕获模块

获取所有导出函数的地址。

typedef int(__cdecl *MYPROC_Sample)(LONGLONG star, LONGLONG end, BYTE* pB, LONG len);struct CAP_INIT
{MYPROC_Sample VideoSample0 = NULL;//视频样本输出函数MYPROC_Sample VideoSample1 = NULL;MYPROC_Sample VideoSample2 = NULL;MYPROC_Sample VideoSample3 = NULL;MYPROC_Sample AudioSample0 = NULL;//音频样本输出函数MYPROC_Sample AudioSample1 = NULL;MYPROC_Sample AudioSample2 = NULL;MYPROC_Sample AudioSample3 = NULL;
};
struct CAP_VIDEO_INFO
{UINT32 Width=0;//视频宽,单位像素UINT32 Height=0;//视频高,单位像素double nFrames=0;//帧率WCHAR Name[MAX_PATH];//视频捕获设备名称
};
struct CAP_AUDIO_INFO
{UINT32 nCh;//声道数WCHAR Name[MAX_PATH];//音频捕获设备名称
};typedef int(__cdecl *MYPROC_CAP_Init)(CAP_INIT init, CAP_VIDEO_INFO*& VideoInfo, CAP_AUDIO_INFO*& AudioInfo);
typedef int(__cdecl *MYPROC_VOID)();MYPROC_CAP_Init CAP_Init=NULL;
MYPROC_VOID CAP_ReleaseDevice=NULL;if (hCap){CAP_Init=(MYPROC_CAP_Init)GetProcAddress(hCap, "Init");//“初始化”函数CAP_ReleaseDevice=(MYPROC_VOID)GetProcAddress(hCap, "ReleaseDevice");//“释放所有捕获设备”函数}

定义8个全局函数,以提供给初始化函数;全局函数用于输出视频和音频样本。

int VideoSample0(LONGLONG star, LONGLONG end, BYTE* pB, LONG len)//视频流1样本输出函数
{return 1; 
}int VideoSample1(LONGLONG star, LONGLONG end, BYTE* pB, LONG len)//视频流2样本输出函数
{return 1; 
}int VideoSample2(LONGLONG star, LONGLONG end, BYTE* pB, LONG len)//视频流3样本输出函数
{return 1; 
}int VideoSample3(LONGLONG star, LONGLONG end, BYTE* pB, LONG len)//视频流4样本输出函数
{return 1; 
}int AudioSample0(LONGLONG star, LONGLONG end, BYTE* pB, LONG len)//音频流1样本输出函数
{return 1; 
}int AudioSample1(LONGLONG star, LONGLONG end, BYTE* pB, LONG len)//音频流2样本输出函数
{return 1; 
}int AudioSample2(LONGLONG star, LONGLONG end, BYTE* pB, LONG len)//音频流3样本输出函数
{return 1; 
}int AudioSample3(LONGLONG star, LONGLONG end, BYTE* pB, LONG len)//音频流4样本输出函数
{return 1; 
}CAP_INIT CapInit;CapInit.VideoSample0 = &VideoSample0;//为视频,音频源指定输出函数CapInit.VideoSample1 = &VideoSample1;CapInit.VideoSample2 = &VideoSample2;CapInit.VideoSample3 = &VideoSample3;CapInit.AudioSample0 = &AudioSample0;CapInit.AudioSample1 = &AudioSample1;CapInit.AudioSample2 = &AudioSample2;CapInit.AudioSample3 = &AudioSample3;

捕获视频和音频。
CAP_Init函数为每一个捕获设备(接口为IMFMediaSource)创建1个源读取器(接口为IMFSourceReader),并指定输出媒体类型;
为每一个捕获设备创建1个线程,在线程中使用源读取器接口读取样本,反复调用CAP_INIT结构提供的样本输出函数输出视频和音频样本。

		CAP_VIDEO_INFO* pVInfo =  new CAP_VIDEO_INFO[4];//结构数组用于存储视频流,音频流信息CAP_VIDEO_INFO* pAInfo = new CAP_AUDIO_INFO[4];WORD w = CAP_Init(CapInit, pVInfo, pAInfo);//获取捕获设备,创建视频流,音频流VCount = LOBYTE(w); //获取视频流数量ACount = HIBYTE(w);//获取音频流数量	

释放所有获取到的捕获设备。
函数将终止所有捕获线程,并释放所有源读取器接口。

		CAP_ReleaseDevice();

有关本插件的使用示例,可以看后续文章“Windows应用-音视频捕获”。

“捕获”DLL的全部代码

DLL.h

#pragma once
#include <SDKDDKVer.h>#define WIN32_LEAN_AND_MEAN             // 从 Windows 头中排除极少使用的资料
#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS      // 某些 CString 构造函数将是显式的
#define _AFX_NO_MFC_CONTROLS_IN_DIALOGS         // 移除对话框中的 MFC 控件支持#ifndef VC_EXTRALEAN
#define VC_EXTRALEAN            // 从 Windows 头中排除极少使用的资料
#endif#include <afx.h>
#include <afxwin.h>         // MFC 核心组件和标准组件
#include <afxext.h>         // MFC 扩展
#ifndef _AFX_NO_OLE_SUPPORT
#include <afxdtctl.h>           // MFC 对 Internet Explorer 4 公共控件的支持
#endif
#ifndef _AFX_NO_AFXCMN_SUPPORT
#include <afxcmn.h>                     // MFC 对 Windows 公共控件的支持
#endif // _AFX_NO_AFXCMN_SUPPORT// Windows 头文件: 
#include <windows.h>#include "mfidl.h"
#include "mfapi.h"
#pragma comment(lib, "mfuuid")
#pragma comment(lib, "mf")
#pragma comment(lib, "mfplat")#include "mfreadwrite.h"
#pragma comment(lib, "mfreadwrite")#ifndef  SAFE_RELEASE
#define SAFE_RELEASEtemplate <class T> void SafeRelease(T** ppT)
{if (*ppT){(*ppT)->Release();*ppT = NULL;}
}#endif //SAFE_RELEASEtypedef int(__cdecl *MYPROC_Sample)(LONGLONG star, LONGLONG end, BYTE* pB, LONG len);struct CAP_INIT
{MYPROC_Sample VideoSample0 = NULL;//视频样本输出函数MYPROC_Sample VideoSample1 = NULL;MYPROC_Sample VideoSample2 = NULL;MYPROC_Sample VideoSample3 = NULL;MYPROC_Sample AudioSample0 = NULL;//音频样本输出函数MYPROC_Sample AudioSample1 = NULL;MYPROC_Sample AudioSample2 = NULL;MYPROC_Sample AudioSample3 = NULL;
};struct CAP_VIDEO_INFO
{UINT32 Width=0;//视频宽,单位像素UINT32 Height=0;//视频高,单位像素double nFrames=0;//帧率WCHAR Name[MAX_PATH];//视频捕获设备名称
};struct CAP_AUDIO_INFO
{UINT32 nCh;//声道数WCHAR Name[MAX_PATH];//音频捕获设备名称
};class Capture
{
public:Capture();~Capture();CAP_INIT mInit;CAP_VIDEO_INFO mVideoInfo[4];HANDLE hEXIT = NULL;HANDLE hVThread[4];HANDLE hAThread[4];IMFSourceReader* pVideoReader[4];//视频源读取器指针数组IMFSourceReader* pAudioReader[4];//音频源读取器指针数组void GetDevice(int& mVideo, CAP_VIDEO_INFO* VideoInfo, int& mAudio, CAP_AUDIO_INFO* AudioInfo);//获取前4个音频,视频捕获设备void ReleaseDevice();//释放捕获的设备int Init(CAP_INIT init, CAP_VIDEO_INFO*& VideoInfo, CAP_AUDIO_INFO*& AudioInfo);//初始化捕获设备
};struct PARAM
{Capture* pCapture = NULL;int index;
};

DLL.cpp

#include "DLL.h"Capture::Capture()
{HRESULT hr = MFStartup(MF_VERSION);hEXIT = CreateEvent(NULL, TRUE, FALSE, NULL);//创建“退出”事件。手动重置,初始无信号
}Capture::~Capture()
{CloseHandle(hEXIT);MFShutdown();
}DWORD WINAPI AudioThread(LPVOID lp);
DWORD WINAPI VideoThread(LPVOID lp);void Capture::GetDevice(int& mVideo, CAP_VIDEO_INFO* VideoInfo, int& mAudio, CAP_AUDIO_INFO* AudioInfo)//获取捕获设备
{HRESULT hr;IMFAttributes *pVideoAttributes = NULL;hr = MFCreateAttributes(&pVideoAttributes, 1);hr = pVideoAttributes->SetGUID(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID);UINT32 countV;IMFActivate **ppVideoDevices = NULL;hr = MFEnumDeviceSources(pVideoAttributes, &ppVideoDevices, &countV);//枚举视频捕获设备SafeRelease(&pVideoAttributes);if (countV > 4){for (int i = 4; i < (int)countV; i++)//释放4个设备后面的设备{ppVideoDevices[i]->Release();}countV = 4;}mVideo = countV;for (DWORD i = 0; i < countV; i++)//获取所有视频源信息,为视频源创建读取样本线程{hr = S_OK;WCHAR *szFriendlyName = NULL;UINT32 cchName;hr = ppVideoDevices[i]->GetAllocatedString(MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME, &szFriendlyName, &cchName); //获取显示名称wmemset(VideoInfo[i].Name, 0, MAX_PATH);CopyMemory(VideoInfo[i].Name, szFriendlyName, 2 * (wcslen(szFriendlyName) + 1));CoTaskMemFree(szFriendlyName);IMFMediaSource *pSource = NULL;if (SUCCEEDED(hr)){hr = ppVideoDevices[i]->ActivateObject(IID_IMFMediaSource, (void**)&pSource);//激活对象}IMFAttributes* pIMFAttributes = NULL;if (SUCCEEDED(hr)){hr = MFCreateAttributes(&pIMFAttributes, 0);//创建空的属性}if (SUCCEEDED(hr)){hr = pIMFAttributes->SetUINT32(MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS, (UINT32)1);//使用基于硬件的媒体基础转换}if (SUCCEEDED(hr)){hr = pIMFAttributes->SetUINT32(MF_SOURCE_READER_ENABLE_VIDEO_PROCESSING, (UINT32)1);//允许源读取器进行有限的视频处理}hr = MFCreateSourceReaderFromMediaSource(pSource, pIMFAttributes, &pVideoReader[i]);//从媒体源创建源读取器SafeRelease(&pIMFAttributes); SafeRelease(&pSource);IMFMediaType* pVideoMTV = NULL;if (SUCCEEDED(hr)){hr = MFCreateMediaType(&pVideoMTV);//创建空的媒体类型}if (SUCCEEDED(hr)){hr = pVideoMTV->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);//设置主要类型为视频}if (SUCCEEDED(hr)){hr = pVideoMTV->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32);//设置子类型RGB32}if (SUCCEEDED(hr)){hr = pVideoReader[i]->SetCurrentMediaType(MF_SOURCE_READER_FIRST_VIDEO_STREAM, NULL, pVideoMTV);//设置源读取器视频输出媒体类型}SafeRelease(&pVideoMTV);IMFMediaType* pMT = NULL;if (SUCCEEDED(hr)){hr = pVideoReader[i]->GetCurrentMediaType(MF_SOURCE_READER_FIRST_VIDEO_STREAM, &pMT);//获取源读取器视频输出媒体类型。此时可以获得完整的输出媒体类型信息}UINT32 Width, Height;if (SUCCEEDED(hr)){hr = MFGetAttributeSize(pMT, MF_MT_FRAME_SIZE, &Width, &Height);//获取视频宽高VideoInfo[i].Width = Width; VideoInfo[i].Height = Height;}UINT32 Numerator, Denominator;if (SUCCEEDED(hr)){hr = MFGetAttributeRatio(pMT, MF_MT_FRAME_RATE, &Numerator, &Denominator);//获取帧率VideoInfo[i].nFrames = (double)Numerator / (double)Denominator;}SafeRelease(&pMT);mVideoInfo[i] = VideoInfo[i];PARAM* pParam = new PARAM();pParam->index = i;pParam->pCapture = this;hVThread[i] = CreateThread(NULL, 0, VideoThread, pParam, 0, NULL);//为视频源创建读取线程}CoTaskMemFree(ppVideoDevices);//释放视频捕获设备接口指针数组使用的内存IMFAttributes *pAudioAttributes = NULL;hr = MFCreateAttributes(&pAudioAttributes, 1);//创建空的属性hr = pAudioAttributes->SetGUID(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_GUID);UINT32 countA;IMFActivate **ppAudioDevices = NULL;hr = MFEnumDeviceSources(pAudioAttributes, &ppAudioDevices, &countA);//枚举音频捕获设备SafeRelease(&pAudioAttributes);if (countA > 4){for (int i = 4; i < (int)countA; i++)//释放4个设备后面的设备{ppAudioDevices[i]->Release();}countA = 4;}mAudio = countA;for (DWORD i = 0; i < countA; i++){hr = S_OK;WCHAR *szFriendlyName = NULL;UINT32 cchName;hr = ppAudioDevices[i]->GetAllocatedString(MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME, &szFriendlyName, &cchName); //获取捕获设备名称wmemset(AudioInfo[i].Name, 0, MAX_PATH);CopyMemory(AudioInfo[i].Name, szFriendlyName, 2*(wcslen(szFriendlyName) + 1));CoTaskMemFree(szFriendlyName);IMFMediaSource *pSource = NULL;if (SUCCEEDED(hr)){hr = ppAudioDevices[i]->ActivateObject(IID_IMFMediaSource, (void**)&pSource);//激活对象}IMFAttributes* pIMFAttributes = NULL;if (SUCCEEDED(hr)){hr = MFCreateAttributes(&pIMFAttributes, 0);}if (SUCCEEDED(hr)){hr = pIMFAttributes->SetUINT32(MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS, (UINT32)1);//使用基于硬件的媒体基础转换}if (SUCCEEDED(hr)){hr = pIMFAttributes->SetUINT32(MF_SOURCE_READER_ENABLE_VIDEO_PROCESSING, (UINT32)1);//允许源读取器进行有限的视频处理}if (SUCCEEDED(hr)){hr = MFCreateSourceReaderFromMediaSource(pSource, pIMFAttributes, &pAudioReader[i]);//从媒体源创建源读取器}SafeRelease(&pIMFAttributes);SafeRelease(&pSource);IMFMediaType* pAudioMTA = NULL;if (SUCCEEDED(hr)){hr = MFCreateMediaType(&pAudioMTA);//创建空的媒体类型}if (SUCCEEDED(hr)){hr = pAudioMTA->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio);//设置主要类型音频}if (SUCCEEDED(hr)){hr = pAudioMTA->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_PCM);//设置子类型PCM}if (SUCCEEDED(hr)){hr = pAudioMTA->SetUINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, (UINT32)16);//设置样本16位}if (SUCCEEDED(hr)){hr = pAudioMTA->SetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, (UINT32)48000);//设置样本采样率48000}if (SUCCEEDED(hr)){hr = pAudioReader[i]->SetCurrentMediaType(MF_SOURCE_READER_FIRST_AUDIO_STREAM, NULL, pAudioMTA);//设置音频输出媒体类型(此时未提供媒体类型全部信息)}SafeRelease(&pAudioMTA);IMFMediaType* pMT = NULL;if (SUCCEEDED(hr)){hr = pAudioReader[i]->GetCurrentMediaType(MF_SOURCE_READER_FIRST_AUDIO_STREAM, &pMT);//获取音频输出媒体类型,此时可以得到完整的媒体类型信息}UINT32 nch;if (SUCCEEDED(hr)){hr = pMT->GetUINT32(MF_MT_AUDIO_NUM_CHANNELS, &nch);//获取声道数AudioInfo[i].nCh = nch;}SafeRelease(&pMT);PARAM* pParam = new PARAM();pParam->index = i;pParam->pCapture = this;hAThread[i] = CreateThread(NULL, 0, AudioThread, pParam, 0, NULL);//为音频源创建读取线程}CoTaskMemFree(ppAudioDevices);//释放音频捕获设备接口指针数组使用的内存
}DWORD WINAPI VideoThread(LPVOID lp)//视频源读取样本线程共用函数
{PARAM* pParam = (PARAM*)lp;Capture* pCapture = pParam->pCapture;int index = pParam->index;HRESULT hr;IMFSourceReader* pIMFSourceReader = pCapture->pVideoReader[index];double dur = (double)10000000 / pCapture->mVideoInfo[index].nFrames;//计算1帧持续时间IMFSample* pMFSample = NULL; DWORD flags;
Agan:hr = pIMFSourceReader->ReadSample(MF_SOURCE_READER_FIRST_VIDEO_STREAM, 0, NULL, &flags, NULL, &pMFSample);//读取视频样本if (hr == S_OK && pMFSample){LONGLONG Cur, Dur;hr = pMFSample->GetSampleTime(&Cur);//获取显示时间hr = pMFSample->GetSampleDuration(&Dur);//获取持续时间DWORD Lt;hr = pMFSample->GetTotalLength(&Lt);//获取有效长度DWORD count;hr = pMFSample->GetBufferCount(&count);//获取缓冲区数量IMFMediaBuffer* pMFBuffer = NULL;if (count == 1)//如果只有1个缓冲区{hr = pMFSample->GetBufferByIndex(0, &pMFBuffer);}else//如果有多个缓冲区{hr = pMFSample->ConvertToContiguousBuffer(&pMFBuffer);}BYTE* pSB = NULL;hr = pMFBuffer->Lock(&pSB, NULL, NULL);//锁定缓冲区switch (index){case 0://第1个视频源pCapture->mInit.VideoSample0(Cur, Cur + Dur, pSB, (LONG)Lt);//发送样本break;case 1://第2个pCapture->mInit.VideoSample1(Cur, Cur + Dur, pSB, (LONG)Lt);break;case 2:pCapture->mInit.VideoSample2(Cur, Cur + Dur, pSB, (LONG)Lt);break;case 3:pCapture->mInit.VideoSample3(Cur, Cur + Dur, pSB, (LONG)Lt);break;}hr = pMFBuffer->Unlock();//解锁缓冲区SafeRelease(&pMFBuffer); SafeRelease(&pMFSample);//释放接口}DWORD mExit = WaitForSingleObject(pCapture->hEXIT, 0);if (mExit == WAIT_OBJECT_0)//有“退出”信号{delete pParam;return 0;}goto Agan;
}DWORD WINAPI AudioThread(LPVOID lp)//读取音频源样本线程共用函数
{PARAM* pParam = (PARAM*)lp;Capture* pCapture = pParam->pCapture;int index = pParam->index;HRESULT hr;IMFSourceReader* pIMFSourceReader = pCapture->pAudioReader[index];IMFSample* pMFSample = NULL; DWORD flags;
Agan:hr = pIMFSourceReader->ReadSample(MF_SOURCE_READER_FIRST_AUDIO_STREAM, 0, NULL, &flags, NULL, &pMFSample);//读取音频样本if (hr == S_OK && pMFSample){LONGLONG Cur, Dur;hr = pMFSample->GetSampleTime(&Cur);//获取显示时间hr = pMFSample->GetSampleDuration(&Dur);//获取持续时间DWORD Lt;hr = pMFSample->GetTotalLength(&Lt);//获取有效长度DWORD count;hr = pMFSample->GetBufferCount(&count);//获取缓冲区数量IMFMediaBuffer* pMFBuffer = NULL;if (count == 1)//如果只有1个缓冲区{hr = pMFSample->GetBufferByIndex(0, &pMFBuffer);}else//如果有多个缓冲区{hr = pMFSample->ConvertToContiguousBuffer(&pMFBuffer);}BYTE* pSB = NULL;hr = pMFBuffer->Lock(&pSB, NULL, NULL);//锁定缓冲区switch (index){case 0://第1个音频源pCapture->mInit.AudioSample0(Cur, Cur + Dur, pSB, (LONG)Lt);//发送样本break;case 1://第2个pCapture->mInit.AudioSample1(Cur, Cur + Dur, pSB, (LONG)Lt);break;case 2:pCapture->mInit.AudioSample2(Cur, Cur + Dur, pSB, (LONG)Lt);break;case 3:pCapture->mInit.AudioSample3(Cur, Cur + Dur, pSB, (LONG)Lt);break;}hr = pMFBuffer->Unlock();//解锁缓冲区SafeRelease(&pMFBuffer); SafeRelease(&pMFSample);//释放接口}DWORD mExit = WaitForSingleObject(pCapture->hEXIT, 0);if (mExit == WAIT_OBJECT_0)//有“退出”信号{delete pParam;return 0;}goto Agan;
}void Capture::ReleaseDevice()
{SetEvent(hEXIT);//发送“退出”信号WaitForMultipleObjects(4, hVThread, TRUE, INFINITE);//等待所有线程退出WaitForMultipleObjects(4, hAThread, TRUE, INFINITE);for (int i = 0; i < 4; i++)//释放所有视频音频源读取器接口{SafeRelease(&pVideoReader[i]); SafeRelease(&pAudioReader[i]);}
}int Capture::Init(CAP_INIT init, CAP_VIDEO_INFO*& VideoInfo, CAP_AUDIO_INFO*& AudioInfo)
{mInit = init;ResetEvent(hEXIT);//设置“退出”无信号int mV, mA;GetDevice(mV,VideoInfo, mA,AudioInfo);//获取前4个音频,视频捕获设备return (int)MAKEWORD((BYTE)mA, (BYTE)mV);
}Capture mCapture;#ifdef __cplusplus    // If used by C++ code, 
extern "C" {          // we need to export the C interface
#endif__declspec(dllexport) int __cdecl Init(CAP_INIT init, CAP_VIDEO_INFO*& VideoInfo, CAP_AUDIO_INFO*& AudioInfo)//最多获取前4个视频音频捕获设备{return mCapture.Init(init, VideoInfo, AudioInfo);}__declspec(dllexport) int __cdecl ReleaseDevice()//释放获取到的捕获设备{mCapture.ReleaseDevice();return 0;}#ifdef __cplusplus
}
#endif

相关文章:

Windows软件插件-音视频捕获

下载本插件 音视频捕获就是获取电脑外接的话筒&#xff0c;摄像头&#xff0c;或线路输入的音频和视频。 本插件捕获电脑外接的音频和视频。最多可以同时获取4个视频源和4个音频源。插件可以在win32和MFC程序中使用。 使用方法 首先&#xff0c;加载本“捕获”DLL&#xff0c…...

go 与面向对象编程(OOP)

Go 语言在设计上与传统面向对象&#xff08;OOP&#xff09;语言&#xff08;如 Java、C&#xff09;有明显差异&#xff0c;官方明确表示它并非纯面向对象语言。然而&#xff0c;它通过独特的方式实现了部分面向对象的核心特性。以下是关键分析&#xff1a; 1. Go 对传统 OOP…...

Mergekit——任务向量合并算法Ties解析

Mergekit——高频合并算法 TIES解析 Ties背景Ties 核心思想具体流程总结 mergekit项目地址 Mergekit提供模型合并方法可以概况为四大类&#xff1a;基本线性加权、基于球面插值、基于任务向量 以及一些专业化方法&#xff0c;今天我们来刷下基于任务向量的ties合并方法&#xf…...

Java 应用中的身份认证与授权:OAuth2.0 实现安全的身份管理

Java 应用中的身份认证与授权&#xff1a;OAuth2.0 实现安全的身份管理 在当今的软件开发领域&#xff0c;身份认证与授权是构建安全可靠应用的关键环节。而 Java 作为广泛使用的编程语言&#xff0c;在实现这一功能上有着诸多成熟的框架和方案。其中&#xff0c;OAuth2.0 凭借…...

【氮化镓】偏置对GaN HEMT 单粒子效应的影响

2025年5月19日,西安电子科技大学的Ling Lv等人在《IEEE Transactions on Electron Devices》期刊发表了题为《Single-Event Effects of AlGaN/GaN HEMTs Under Different Biases》的文章,基于实验和TCAD仿真模拟方法,研究了单粒子效应对关断状态、半开启状态和开启状态下AlG…...

Mysql 索引概述

索引&#xff08;index&#xff09;是帮助Mysql高效获取数据的数据结构 索引优点&#xff1a;1. 提高排序效率 2. 提高查询效率 索引缺点&#xff1a;1.索引占用空间&#xff08;可忽略&#xff09;2.索引降低了更新表的速度&#xff0c;如进行insert,update,delette 时效率降…...

HttpServletRequest常用功能简介-笔记

javax.servlet.http.HttpServletRequest 是 ServletRequest 接口的子接口&#xff0c;专用于处理 HTTP 协议相关的请求。它提供了访问请求行、请求头、请求参数以及请求属性等方法。 1.请求行&#xff08;Request Line&#xff09; ✅ 功能说明 请求行包含客户端发送的 HTTP …...

解决RAGFlow部署中镜像源拉取的问题

报错提示 Error response from daemon: Get "https://registry-1.docker.io/v2/ ": context deadline exceeded 解决方法 这个原因是因为拉取镜像源失败&#xff0c;可以在/etc/docker/daemon.json文件中添加镜像加速器&#xff0c;例如下面所示 {"registry…...

uniapp打包H5,输入网址空白情况

由于客户预算有限&#xff0c;最近写了两个uniapp打包成H5的案例&#xff0c;总结下面注意事项 1. 发行–网站-PCWeb或手机H5按钮&#xff0c;输入名称&#xff0c;网址 点击【发行】&#xff0c;生成文件 把这个给后端&#xff0c;就可以了 为什么空白呢 最重要一点&#xf…...

wsl2中Ubuntu22.04配置静态IP地址

第一步找到/etc/netplan目录下的01-netcfg.yaml文件&#xff0c;&#xff08;如果不存在则自己创建一个&#xff09;在里面配置一下代码&#xff1a; network:version: 2renderer: networkdethernets:eth0:dhcp4: noaddresses: [192.168.3.222/24]routes:- to: 0.0.0.0/0via: …...

C++(21):fstream的读取和写入

目录 1 ios::out 2 ios::in和is_open 3 put()方法 4 get()方法 4.1 读取单个字符 4.2 读取多个字符 4.3 设置终结符 5 getline() 1 ios::out 打开文件用于写入数据。如果文件不存在&#xff0c;则新建该文件&#xff1b;如果文件原来就存在&#xff0c;则打开时清除…...

NAT/代理服务器/内网穿透

目录 一 NAT技术 二 内网穿透/内网打洞 三 代理服务器 一 NAT技术 跨网络传输的时候&#xff0c;私网不能直接访问公网&#xff0c;就引入了NAT能讲私网转换为公网进行访问&#xff0c;主要解决IPv4(2^32)地址不足的问题。 1. NAT原理 当某个内网想访问公网&#xff0c;就必…...

Unity 多时间源Timer定时器实战分享:健壮性、高效性、多线程安全与稳定性能全面解析

简介 Timer 是一个 Unity 环境下高效、灵活的定时任务调度系统&#xff0c;支持以下功能&#xff1a; •支持多种时间源&#xff08;游戏时间 / 非缩放时间 / 真实时间&#xff09; •支持一次性延迟执行和重复执行 •提供 ID、回调、目标对象等多种查询和销毁方式 •内建…...

深入解析Spring Boot与Spring Security的集成实践

深入解析Spring Boot与Spring Security的集成实践 引言 Spring Security是Spring生态中用于处理认证和授权的强大框架。在Spring Boot项目中集成Spring Security可以轻松实现用户认证、权限控制等功能。本文将详细介绍如何从零开始集成Spring Security&#xff0c;并解决实际…...

【iOS】探索消息流程

探索消息流程 Runtime介绍OC三大核心动态特性动态类型动态绑定动态语言 方法的本质代码转换objc_msgSendSELIMPMethod 父类方法在子类中的实现 消息查找流程开始查找快速查找流程慢速查找流程二分查找方法列表父类缓存查找 动态方法解析动态方法决议实例方法类方法优化 消息转发…...

用户账号及权限管理:企业安全的基石与艺术

在当今数字化时代,用户账号及权限管理已成为企业IT安全体系中不可或缺的核心组件。它不仅是保护敏感数据的第一道防线,更是确保业务运营效率和合规性的关键。本文将深入探讨用户账号及权限管理的重要性、最佳实践以及实施策略,助您构建一个安全、高效且灵活的访问控制体系。…...

413 Payload Too Large 问题定位

源头 一般是服务器或者nginx 配置导致的 nginx http {client_max_body_size 50m; # 调整为所需大小&#xff08;如 50MB&#xff09;# 其他配置... }nginx 不配置&#xff0c;默认是1M 服务器 spring 不配置也是有默认值的好像也是1M 如果出现413 可以试着修改配置来避…...

2025年渗透测试面试题总结-360[实习]安全工程师(题目+回答)

网络安全领域各种资源&#xff0c;学习文档&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具&#xff0c;欢迎关注。 目录 1. 自我介绍 2. WAF及其绕过方式 3. IPS/IDS/HIDS 4. 云安全 5. 绕过安骑士/安全狗 6. Gopher扩展…...

Ubuntu16.04升级gcc/g++版本方法

0 前言 gcc与g分别是GNU的c和c编译器&#xff0c;Ubuntu16.04默认的gcc和g的版本是5.4.0&#xff0c;在使用一些交叉编译工具链会提示找不到GLIBC_2.27&#xff0c;而GLIBC_2.27又需要gcc 6.2以上版本&#xff0c;因此本文介绍Ubuntu16.04升级gcc/g版本的方法。 1 Ubuntu16.0…...

微信小程序van-dialog确认验证失败时阻止对话框的关闭

使用官方(Vant Weapp - 轻量、可靠的小程序 UI 组件库)的before-close&#xff1a; wxml&#xff1a; <van-dialog use-slot title"名称" show"{{ show }}" show-cancel-button bind:cancel"onClose" bind:confirm"getBackInfo"…...

边缘计算模块

本文来源 &#xff1a;腾讯元宝 边缘计算模块是一种部署在网络边缘&#xff08;靠近数据源&#xff09;的集成化硬件/软件设备&#xff0c;用于实时处理本地数据&#xff0c;减少云端依赖&#xff0c;提升响应速度与安全性。以下是其核心要点&#xff1a; ​​1. 核心组成​​ …...

【极兔快递Java社招】一面复盘|数据库+线程池+AQS+中间件面面俱到

【极兔快递Java社招】一面复盘&#xff5c;数据库线程池AQS中间件面面俱到 &#x1f4cd;面试公司&#xff1a;极兔快递 &#x1f45c;面试岗位&#xff1a;Java后端开发工程师 &#x1f550;面试时长&#xff1a;约 60 分钟 &#x1f504;面试轮次&#xff1a;第 1 轮技术面&…...

OceanBase 的系统变量、配置项和用户变量有何差异

在继续阅读本文之前&#xff0c;大家不妨先思考一下&#xff0c;数据库中“系统变量”、“用户变量”以及“配置项”这三者之间有何不同。如果感到有些模糊&#xff0c;那么本文将是您理清这些概念的好帮手。 很多用户在使用OceanBase数据库中的“配置项”和“系统变量”&#…...

Git本地使用小Tips

要将本地仓库 d:\test 的更新推送到另一个本地仓库 e:\test&#xff0c;可以使用 Git 的远程仓库功能。以下是具体步骤&#xff1a; ​​在 e:\test 中添加 d:\test 作为远程仓库​​ 在 e:\test 目录中打开 Git Bash 或命令行&#xff0c;执行以下命令&#xff1a; git remo…...

【Python】Jupyter指定具体路径

一、右键Jupyter Notebook 右击Jupyter Notebook点击属性 二、修改以下两个地方...

ThreadLocal作一个缓存工具类

1、工具类 import java.util.HashMap; import java.util.Map;public class ThreadLocalUtil {// 使用Map存储多类型数据private static final ThreadLocal<Map<String, Object>> CONTEXT_HOLDER new ThreadLocal<>();// 存储数据public static void set(Str…...

RNope:结合 RoPE 和 NoPE 的长文本建模架构

TL;DR 2025 年 Cohere 提出的一种高效且强大的长上下文建模架构——RNope-SWA。通过系统分析注意力模式、位置编码机制与训练策略&#xff0c;该架构不仅在长上下文任务上取得了当前最优的表现&#xff0c;还在短上下文任务和训练/推理效率方面实现了良好平衡。 Paper name …...

virtualbox虚拟机中的ubuntu 20.04.6安装新的linux内核5.4.293 | 并增加一个系统调用 | 证书问题如何解决

参考文章&#xff1a;linux添加系统调用【简单易懂】【含32位系统】【含64位系统】_64位 32位 系统调用-CSDN博客 安装新内核 1. 在火狐下载你需要的版本的linux内核压缩包 这里我因为在windows上面下载过&#xff0c;配置过共享文件夹&#xff0c;所以直接复制粘贴通过共享文…...

unity UGUI虚线框shader

Shader "Custom/DottedLineShader" {Properties{_MainTex ("Texture", 2D) "white" {}_Color("Color",COLOR) (1,1,1,1)_LineLength("虚线长度",float) 0.08}SubShader{Tags //设置支持UGUI{ "Queue""Tran…...

vue2、vue3项目打包生成txt文件-自动记录打包日期:git版本、当前分支、提交人姓名、提交日期、提交描述等信息 和 前端项目的版本号json文件

vue2 打包生成text文件 和 前端项目的版本号json文件 项目打包生成txt文件-自动记录git版本、当前分支、提交人姓名、提交日期、提交描述等信息生成版本号json文件-自动记录当前版本号、打包时间等信息新建branch-version-webpack-plugin.js文件 // 同步子进程 const execSyn…...