Windows软件插件-音视频文件读取器

下载本插件
本插件读取音频和视频文件,输出音频样本和视频样本,音频样本为16位PCM,采样率48000;视频样本为RGB32。大部分音频和视频文件格式都可以读取。本插件类型为DLL。
本插件是通过创建媒体基础“源读取器”对象实现读取音视频文件。使用MFCreateSourceReaderFromURL函数创建源读取器,源读取器接口为IMFSourceReader,如果读取的是音频文件,只创建音频线程,如果读取视频文件,将创建视频线程和音频线程,在线程中使用IMFSourceReader接口的ReadSample方法读取样本,样本为媒体基础样本;使用IMFSourceReader接口的SetCurrentPosition方法更改当前位置。定义了7个导出函数,用于对本读取器的操作。

使用方法

首先,加载本读取器DLL,获得读取器模块句柄。

	HMODULE hSReader = LoadLibrary(L"SReader.dll");

定义媒体信息和样本信息结构,定义接收当前位置信息的函数(如果不需要,也可以不定义),定义视频音频样本接收函数:

struct INFO
{int VideoWidth=0;//视频宽,单位像素int VideoHeight=0;//视频高,单位像素LONGLONG FrameCur=0;//帧持续时间,单位100纳秒LONGLONG DUR=0;//媒体时长,单位100纳秒DWORD AudioSamplePerSec=0;//音频样本采样率DWORD StreamCount=0;//流数量
};struct SAMPLE_INFO//样本信息
{BOOL B;//为TRUE,样本为第1个样本DWORD STAR;//运行开始时间,单位毫秒LONGLONG star;//样本开始时间,单位100纳秒LONGLONG end;//样本结束时间,单位100纳秒BYTE* pB;//样本缓冲区指针int len;//样本的字节大小HANDLE hRun;//“运行”事件句柄HANDLE hSeek;//“定位”事件句柄
};void SliderSetPosition(LONGLONG pos)
{
}int ReceiveVideoSample(SAMPLE_INFO SampleInfo)//视频样本接收函数
{return 0;
}int ReceiveAudioSample(SAMPLE_INFO SampleInfo)//音频样本接收函数
{return 0;
}

定义函数指针:

	typedef int(__thiscall *MYPROC_ReceiveSample)(SAMPLE_INFO info);typedef void(__thiscall *MYPROC_GetPos)(LONGLONG pos);typedef INFO(__cdecl *MYPROC_SReader_Init)(wchar_t* Path);typedef int(__cdecl *MYPROC_SReader_Run)(MYPROC_ReceiveSample VideoSample, MYPROC_ReceiveSample AudioSample, MYPROC_GetPos Pos);typedef int(__cdecl *MYPROC_SReader_Pause)();typedef int(__cdecl *MYPROC_SReader_Stop)();typedef int(__cdecl *MYPROC_SReader_Seek)(LONGLONG SeekPos);typedef int(__cdecl *MYPROC_SReader_GetState)();typedef int(__cdecl *MYPROC_SReader_Exit)();

获取本读取器导出函数的地址:

	MYPROC_SReader_Init SReader_Init = NULL;MYPROC_SReader_GetState SReader_GetState = NULL;MYPROC_SReader_Run SReader_Run = NULL;MYPROC_SReader_Pause SReader_Pause = NULL;MYPROC_SReader_Stop SReader_Stop = NULL;MYPROC_SReader_Seek SReader_Seek = NULL;MYPROC_SReader_Exit SReader_Exit = NULL;MYPROC_GetPos GetPos=NULL;MYPROC_ReceiveSample ReceiveVideo=NULL;MYPROC_ReceiveSample ReceiveAudio=NULL;if (hSReader){SReader_Init = (MYPROC_SReader_Init)GetProcAddress(hSReader, "Init");SReader_GetState = (MYPROC_SReader_GetState)GetProcAddress(hSReader, "GetState");SReader_Run = (MYPROC_SReader_Run)GetProcAddress(hSReader, "Run");SReader_Pause = (MYPROC_SReader_Pause)GetProcAddress(hSReader, "Pause");SReader_Stop = (MYPROC_SReader_Stop)GetProcAddress(hSReader, "Stop");SReader_Seek = (MYPROC_SReader_Seek)GetProcAddress(hSReader, "Seek");SReader_Exit = (MYPROC_SReader_Exit)GetProcAddress(hSReader, "Exit");GetPos = (MYPROC_GetPos)(&SliderSetPosition);	ReceiveVideo=(MYPROC_ReceiveSample)(&ReceiveVideoSample);ReceiveAudio=(MYPROC_ReceiveSample)(&ReceiveAudioSample);}

初始化本读取器,获取文件媒体信息:

	INFO info;wchar_t* path = L"某视频文件.mp4";if (SReader_Init != NULL)info = SReader_Init(path);

为读取器指定视频样本和音频样本接收函数,和接收位置信息函数(不需要位置信息时,GetPos可以为NULL);运行读取器:

	if (SReader_Run){SReader_Run(ReceiveVideo, ReceiveAudio, GetPos);}

这样视频音频样本接收函数将被反复调用,参数提供样本的数据和信息。其它导出函数用于读取器的暂停,停止和退出;获取读取器当前状态,调用SReader_GetState(),返回状态值。
本读取器为后续文章“播放视频”而设计,读者可以在本代码的基础上添加自己想要的功能,也可以进行更改。

本读取器的全部代码

#include "windows.h"
#include "mmsystem.h"
#pragma comment(lib, "winmm")
#include "mfapi.h"
#include "mfidl.h"
#include "mfreadwrite.h"
#pragma comment(lib, "mfplat")
#pragma comment(lib, "mfreadwrite")
#pragma comment(lib, "mfuuid")template <class T> void SafeRelease(T** ppT)
{if (*ppT){(*ppT)->Release();*ppT = NULL;}
}struct INFO//媒体信息
{int VideoWidth;//视频宽,单位像素int VideoHeight;//视频高,单位像素LONGLONG FrameCur;//帧持续时间,单位100纳秒LONGLONG DUR;//媒体时长,单位100纳秒DWORD AudioSamplePerSec;//音频样本采样率DWORD StreamCount = 0;//流数量
};struct SAMPLE_INFO//样本信息
{BOOL B;//为TRUE,样本为第1个样本DWORD STAR;//运行开始时间,单位毫秒LONGLONG star;//样本开始时间,单位100纳秒LONGLONG end;//样本结束时间,单位100纳秒BYTE* pB;//样本缓冲区指针int len;//样本的字节大小HANDLE hRun;//“运行”事件句柄HANDLE hSeek;//“定位”事件句柄
};typedef int(__cdecl *MYPROC_SendVideo)(SAMPLE_INFO SampleInfo);//定义函数指针
typedef int(__cdecl *MYPROC_SendAudio)(SAMPLE_INFO SampleInfo);
typedef int(__cdecl *MYPROC_SendPos)(LONGLONG pos);class SReader
{
public:SReader(){HRESULT hr = MFStartup(MF_VERSION);if (hr != S_OK){MessageBox(NULL, L"初始化媒体基础失败", L"SourceReader", MB_OK);}hRun = CreateEvent(NULL, TRUE, FALSE, NULL);//手动重置,初始无信号hExit = CreateEvent(NULL, TRUE, FALSE, NULL);//手动重置,初始无信号hSeek = CreateEvent(NULL, TRUE, FALSE, NULL);//手动重置,初始无信号}~SReader(){SafeRelease(&pIMFSourceReader); CloseHandle(hRun); CloseHandle(hExit); CloseHandle(hSeek);MFShutdown();//关闭媒体基础}HANDLE hRun, hExit, hSeek;IMFSourceReader* pIMFSourceReader = NULL;//源读取器接口指针UINT32 Width, Height;//视频宽高LONGLONG DUR;//媒体持续时间,100纳秒单位LONGLONG CUR;//当前位置,100纳秒单位LONGLONG SeekPos;//定位位置DWORD STAR;//开始时间BOOL VFirst, AFirst;//为TRUE标明第1个样本int mState;//状态;0停止,1运行,2暂停INFO info;//媒体信息对象MYPROC_SendVideo SendVideo = NULL;//视频样本输出函数指针MYPROC_SendAudio SendAudio = NULL;//音频样本输出函数指针MYPROC_SendPos SendPos = NULL;//当前位置输出函数指针
};HRESULT GetSample(IMFSourceReader* pIMFSourceReader, UINT SOURCE, LONGLONG& Cur, LONGLONG& Dur)//获取样本
{IMFSample* pMFSample = NULL; DWORD flags;HRESULT hr = pIMFSourceReader->ReadSample(SOURCE, 0, NULL, &flags, NULL, &pMFSample);//读取视频样本hr = pMFSample->GetSampleTime(&Cur);//获取显示时间hr = pMFSample->GetSampleDuration(&Dur);//获取持续时间SafeRelease(&pMFSample);//释放接口return hr;
}SReader* pSReader = NULL;//SReader类对象指针
HANDLE hVthread = NULL, hAthread = NULL;//视频音频线程句柄DWORD WINAPI VideoThread(LPVOID lp)//视频线程
{HRESULT hr; pSReader->VFirst = TRUE; IMFSample* pMFSample = NULL; DWORD flags;
Agan:DWORD mRun = WaitForSingleObject(pSReader->hRun, 0);//检测“运行”信号,不等待DWORD mSeek = WaitForSingleObject(pSReader->hSeek, 0);//检测“定位”信号,不等待DWORD mExit = WaitForSingleObject(pSReader->hExit, 0);//检测“退出”信号,不等待if (mExit == WAIT_OBJECT_0)//有“退出”信号{return 0;//退出线程}if (mSeek == WAIT_OBJECT_0)//有“定位”信号{hr = pSReader->pIMFSourceReader->Flush(MF_SOURCE_READER_ALL_STREAMS);//丢弃所有排队的样本并取消所有挂起的样本请求PROPVARIANT pv;PropVariantInit(&pv);pv.vt = 20;pv.hVal.QuadPart = pSReader->SeekPos;hr = pSReader->pIMFSourceReader->SetCurrentPosition(GUID_NULL, pv);//更改源读取器位置PropVariantClear(&pv);/*试验发现,源读取器在媒体中间时间段定位后,音频视频样本不同步(时间戳相差约2秒钟),故添加下面代码以使样本时间同步*/LONGLONG VCur, VDur;hr = GetSample(pSReader->pIMFSourceReader, MF_SOURCE_READER_FIRST_VIDEO_STREAM, VCur, VDur);//获取视频样本时间LONGLONG ACur, ADur;hr = GetSample(pSReader->pIMFSourceReader, MF_SOURCE_READER_FIRST_AUDIO_STREAM, ACur, ADur);//获取音频样本时间if (ACur > VCur + VDur + 100000)//如果音频样本时间过大{while (ACur > VCur + VDur + 100000){hr = GetSample(pSReader->pIMFSourceReader, MF_SOURCE_READER_FIRST_VIDEO_STREAM, VCur, VDur);//获取下一个视频样本}}else if (VCur > ACur + ADur + 100000)//如果视频样本时间过大{while (VCur > ACur + ADur + 100000){hr = GetSample(pSReader->pIMFSourceReader, MF_SOURCE_READER_FIRST_AUDIO_STREAM, ACur, ADur);//获取下一个音频样本}}pSReader->STAR = timeGetTime();//记录运行开始时间,单位毫秒pSReader->VFirst = TRUE; pSReader->AFirst = TRUE;//设置第1个样本标记为TRUEResetEvent(pSReader->hSeek);//设置“定位”无信号}if (mRun == WAIT_OBJECT_0)//有“运行”信号{hr = pSReader->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);//锁定缓冲区SAMPLE_INFO info;info.B = pSReader->VFirst;info.STAR = pSReader->STAR;info.star = Cur;info.end = Cur + Dur;info.pB = pSB;info.len = Lt;info.hRun = pSReader->hRun;info.hSeek = pSReader->hSeek;pSReader->SendVideo(info);//调用视频输出函数,输出样本if (pSReader->VFirst)pSReader->VFirst = FALSE;//只有第1个样本标记为TRUEhr = pMFBuffer->Unlock();//解锁缓冲区SafeRelease(&pMFBuffer); SafeRelease(&pMFSample);//释放接口}}goto Agan;
}DWORD WINAPI AudioThread(LPVOID lp)
{HRESULT hr; pSReader->AFirst = TRUE; IMFSample* pMFSample = NULL; DWORD flags; pSReader->CUR = 0; int Count = 0;
Agan:DWORD mRun = WaitForSingleObject(pSReader->hRun, 0);//检测“运行”信号,不等待DWORD mSeek = WaitForSingleObject(pSReader->hSeek, 0);//检测“定位”信号,不等待DWORD mExit = WaitForSingleObject(pSReader->hExit, 0);//检测“退出”信号,不等待if (mExit == WAIT_OBJECT_0)//有“退出”信号{return 0;//退出线程}if (mSeek == WAIT_OBJECT_0)//有“定位”信号{if (pSReader->info.StreamCount == 2)//如果有视频流和音频流{goto Agan;//阻塞(更改位置操作在视频线程中,音频线程等待操作完成)}else//如果只有音频流,在此更改源读取器位置{hr = pSReader->pIMFSourceReader->Flush(MF_SOURCE_READER_ALL_STREAMS);//丢弃所有排队的样本并取消所有挂起的样本请求PROPVARIANT pv;PropVariantInit(&pv);pv.vt = 20;pv.hVal.QuadPart = pSReader->SeekPos;hr = pSReader->pIMFSourceReader->SetCurrentPosition(GUID_NULL, pv);//更改源读取器位置PropVariantClear(&pv);pSReader->STAR = timeGetTime();//记录运行开始时间pSReader->AFirst = TRUE;ResetEvent(pSReader->hSeek);//设置“定位”无信号}}if (mRun == WAIT_OBJECT_0)//有“运行”信号{hr = pSReader->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);//获取持续时间Count++;if (Count > 9)//每10个样本,发送一次当前位置{pSReader->CUR = Cur;//赋值当前时间if(pSReader->SendPos)pSReader->SendPos(Cur);//发送当前时间位置值Count = 0;}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);//锁定缓冲区SAMPLE_INFO info;info.B = pSReader->AFirst;info.STAR = pSReader->STAR;info.star = Cur;info.end = Cur + Dur;info.pB = pSB;info.len = Lt;info.hRun = pSReader->hRun;info.hSeek = pSReader->hSeek;pSReader->SendAudio(info);//调用音频样本输出函数,发送音频样本if (pSReader->AFirst)pSReader->AFirst = FALSE;//只有第1个样本标记为TRUEhr = pMFBuffer->Unlock();//解锁缓冲区SafeRelease(&pMFBuffer); SafeRelease(&pMFSample);//释放接口}}goto Agan;
}//下面是导出函数定义
#pragma warning(disable:4190)#ifdef __cplusplus    // If used by C++ code, 
extern "C" {          // we need to export the C interface
#endif__declspec(dllexport) INFO __cdecl Init(wchar_t* Path){if (pSReader)//如果SReader对象已存在{SetEvent(pSReader->hExit);//设置“退出”有信号WaitForSingleObject(hVthread, INFINITE);//等待视频线程退出WaitForSingleObject(hAthread, INFINITE);//等待音频线程退出delete pSReader;//删除SReader对象}pSReader = new SReader();//创建SReader对象IMFAttributes* pIMFAttributes = NULL;HRESULT 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 = MFCreateSourceReaderFromURL(Path, pIMFAttributes, &pSReader->pIMFSourceReader);//创建源读取器}SafeRelease(&pIMFAttributes);PROPVARIANT var;PropVariantInit(&var);if (SUCCEEDED(hr)){hr = pSReader->pIMFSourceReader->GetPresentationAttribute(MF_SOURCE_READER_MEDIASOURCE, MF_PD_DURATION, &var);//获取媒体时间长度,100纳秒单位}if (SUCCEEDED(hr)){pSReader->info.DUR = pSReader->DUR = (LONGLONG)var.uhVal.QuadPart;}PropVariantClear(&var);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)){pSReader->info.AudioSamplePerSec = 48000;}if (SUCCEEDED(hr)){hr = pSReader->pIMFSourceReader->SetCurrentMediaType(MF_SOURCE_READER_FIRST_AUDIO_STREAM, NULL, pAudioMTA);//设置音频输出媒体类型(此时未提供媒体类型全部信息)}SafeRelease(&pAudioMTA);IMFMediaType* pAudioMT = NULL;if (SUCCEEDED(hr)){hr = pSReader->pIMFSourceReader->GetCurrentMediaType(MF_SOURCE_READER_FIRST_AUDIO_STREAM, &pAudioMT);//获取当前音频输出媒体类型(获取的媒体类型将包含全部信息)}UINT32 SamplePerSec;if (SUCCEEDED(hr)){hr = pAudioMT->GetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, &SamplePerSec);//获取采样率}SafeRelease(&pAudioMT);if (SUCCEEDED(hr)){pSReader->info.AudioSamplePerSec = SamplePerSec;}pSReader->info.StreamCount = 0;if (SUCCEEDED(hr)){ResetEvent(pSReader->hExit);//设置“退出”无信号pSReader->info.StreamCount++;//流数量hAthread = CreateThread(NULL, 0, AudioThread, pSReader, 0, NULL);//创建音频线程}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 = pSReader->pIMFSourceReader->SetCurrentMediaType(MF_SOURCE_READER_FIRST_VIDEO_STREAM, NULL, pVideoMTV);//设置视频输出媒体类型}SafeRelease(&pVideoMTV);if (SUCCEEDED(hr)){IMFMediaType* pVideoMT = NULL;if (SUCCEEDED(hr)){hr = pSReader->pIMFSourceReader->GetCurrentMediaType(MF_SOURCE_READER_FIRST_VIDEO_STREAM, &pVideoMT);//获取当前视频媒体类型(此时的媒体类型将包含全部信息)}if (SUCCEEDED(hr)){hr = MFGetAttributeSize(pVideoMT, MF_MT_FRAME_SIZE, &pSReader->Width, &pSReader->Height);//获取视频图像宽高}SafeRelease(&pVideoMT);if (SUCCEEDED(hr)){pSReader->info.VideoWidth = pSReader->Width; pSReader->info.VideoHeight = pSReader->Height; pSReader->info.StreamCount++;}hVthread = CreateThread(NULL, 0, VideoThread, pSReader, 0, NULL);//创建视频线程}Sleep(1000);//等待线程初始化完成return pSReader->info;}__declspec(dllexport) int __cdecl Run(MYPROC_SendVideo SendVideo, MYPROC_SendAudio SendAudio, MYPROC_SendPos SendPos)//运行{if (pSReader){pSReader->SendVideo = SendVideo; pSReader->SendAudio = SendAudio; pSReader->SendPos = SendPos;pSReader->STAR = timeGetTime();//记录运行开始时间pSReader->VFirst = TRUE; pSReader->AFirst = TRUE;SetEvent(pSReader->hRun);//设置“运行”有信号pSReader->mState = 1;//状态标记置1return 0;}return 1;}__declspec(dllexport) int __cdecl Pause(void)//暂停{if (pSReader){ResetEvent(pSReader->hRun);//设置“运行”无信号pSReader->mState = 2;//状态标记置2return 0;}return 1;}__declspec(dllexport) int __cdecl Stop(void)//停止{if (pSReader){ResetEvent(pSReader->hRun);//设置“运行”无信号HRESULT hr = pSReader->pIMFSourceReader->Flush(MF_SOURCE_READER_ALL_STREAMS);//丢弃所有排队的样本并取消所有挂起的样本请求Sleep(200);pSReader->SeekPos = 0;PROPVARIANT pv;PropVariantInit(&pv);pv.vt = 20;pv.hVal.QuadPart = 0;hr = pSReader->pIMFSourceReader->SetCurrentPosition(GUID_NULL, pv);//设置源读取器位置0PropVariantClear(&pv);pSReader->mState = 0;//状态标记置0return 0;}return 1;}__declspec(dllexport) int __cdecl Seek(LONGLONG SeekPos)//定位{if (pSReader){pSReader->SeekPos = SeekPos;//赋值定位位置SetEvent(pSReader->hSeek);//设置“定位”有信号return 0;}return 1;}__declspec(dllexport) int __cdecl GetState()//获取状态{if (pSReader){return pSReader->mState;}return -1;}__declspec(dllexport) int __cdecl Exit(void)//退出{if (pSReader){ResetEvent(pSReader->hRun);//设置“运行”无信号SetEvent(pSReader->hExit);//设置“退出”有信号WaitForSingleObject(hVthread, INFINITE);//等待视频线程已退出WaitForSingleObject(hAthread, INFINITE);//等待音频线程已退出delete pSReader; pSReader = NULL;//删除SReader对象return 0;}return 1;}#ifdef __cplusplus
}
#endif

下载本插件

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在word下写公式

需求 word的可视化编辑公式是好的&#xff0c;但是很丑&#xff08;见下图&#xff09; 我希望公式是这样的&#xff08;见下图&#xff09; 解决方案 1.先转换为“线性”&#xff08;即Latex格式&#xff09; 2.得到下面这个玩意&#xff0c;把\mathrm去掉&#xff08;功能是…

uniapp,自绘仪表盘组件(基础篇)

文章目录 一、为什么需要自绘仪表盘&#xff1f;二、准备知识三、实现基础仪表盘1. 组件模板结构2. 核心绘制逻辑3. 样式优化 四、使用示例五、核心实现原理六、扩展方向七、常见问题 一、为什么需要自绘仪表盘&#xff1f; 在物联网、数据监控等场景中&#xff0c;仪表盘是常…

导入 Excel 规则批量修改或删除 Excel 表格内容

我们前面介绍过按照规则批量修改 Excel 文档内容的操作&#xff0c;可以对大量的 Excel 文档按照一定的规则进行统一的修改&#xff0c;可以很好的解决我们批量修改 Excel 文档内容的需求。但是某些场景下&#xff0c;我们批量修改 Excel 文档内容的场景比较复杂&#xff0c;比…

Python贝壳网二手小区数据爬取(2025年3月更)

文章目录 一、代码整体架构解析二、各部分代码详解1. main()主函数解析2. 会话初始化&#xff08;伪装浏览器身份&#xff09;3. 动态参数生成&#xff08;反爬虫核心机制&#xff09;4. 列表页抓取&#xff08;获取小区列表&#xff09;5. 列表页解析&#xff08;提取小区信息…

C++的内存管理

1. C/C内存分布 我们先来看下面的一段代码和相关问题 int globalVar 1; static int staticGlobalVar 1; void Test() {static int staticVar 1;int localVar 1;int num1[10] { 1, 2, 3, 4 };char char2[] "abcd";const char* pChar3 "abcd";int…

mac本地代理nginx,解决跨域问题

brew install nginxbrew info nginxnginx配置文件 /opt/homebrew/etc/nginx/nginx.conf 如何打开呢&#xff1f; open /opt/homebrew 启动nginx brew services start nginx改配置&#xff1a; server {listen 8080;server_name localhost;#charset koi8-r;#access_…

Clion快捷键、修改字体

文章目录 一、Clion快捷键1.撤销&#xff1a;crtl Z2.重做&#xff1a;crtl shift Z3.删除该行&#xff1a;crtl Y4.多行后退&#xff1a;选中多行 Tab5.多行缩进&#xff1a;选中多行 shift Tab 二、修改注释的斜体 一、Clion快捷键 1.撤销&#xff1a;crtl Z 2.重做…

【漫话机器学习系列】126.多项式回归(Polynomial Regression)

多项式回归&#xff08;Polynomial Regression&#xff09; 1. 什么是多项式回归&#xff1f; 多项式回归&#xff08;Polynomial Regression&#xff09;是一种用于建模非线性关系的回归分析技术。它是线性回归的一种扩展形式&#xff0c;允许模型通过增加自变量的高次项来更…

python网络爬虫开发实战之基本库使用

目录 第二章 基本库的使用 2.1 urllib的使用 1 发送请求 2 处理异常 3 解析链接 4 分析Robots协议 2.2 requests的使用 1 准备工作 2 实例引入 3 GET请求 4 POST请求 5 响应 6 高级用法 2.3 正则表达式 1 实例引入 2 match 3 search 4 findall 5 sub 6 com…

npm : 无法加载文件 C:\Program Files\nodejs\npm.ps1,因为在此系统上禁止运行脚本。

1、在 vscode 终端执行 get-ExecutionPolicy 返回 Restricted 状态是禁止的 返回 RemoteSigned 状态是可正常执行npm命令 2、更改状态 set-ExecutionPolicy RemoteSigned 如果提示需要管理员权限&#xff0c;可加参数运行 Set-ExecutionPolicy -Scope CurrentUser RemoteSi…

数据结构基础之《(19)—矩阵处理》

一、zigzag打印矩阵 Z字形打印矩阵 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 打印顺序&#xff1a;1,2,7,13,8,3,4,9,14... 核心技巧&#xff1a;找到coding上的宏观调度 左上角有A、B两个点&#xff0c;A往右一步一步走&#xff0c;B往下一步一步走 写一个…

OpenCV计算摄影学(17)两个图像之间执行无缝克隆操作函数 seamlessClone()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 图像编辑任务涉及全局更改&#xff08;如颜色/强度校正、滤镜应用、变形&#xff09;或针对选定区域的局部更改。在这里&#xff0c;我们关注的是…

基于Asp.net的零食购物商城网站

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…

MuBlE:为机器人操作任务规划提供了逼真的视觉观察和精确的物理建模

2025-03-05&#xff0c;由华为诺亚方舟实验室、捷克技术大学和帝国理工学院联合开发的MuBlE&#xff08;MuJoCo and Blender simulation Environment&#xff09;模拟环境和基准测试。通过结合MuJoCo物理引擎和Blender高质量渲染&#xff0c;为机器人操作任务规划提供了逼真的视…

文件上传漏洞(upload靶场)

目录 Pass-01&#xff1a;前端绕过 方法一&#xff1a;浏览器禁用js 方法二:直接修改或删除js脚本 方法三&#xff1a;修改后缀绕过 Pass-02:服务器检测 Pess-03:黑名单绕过 Pass-04:.htaccess文件 Pass-05:windows特性和user.ini 方法一&#xff1a;php.自动解析为ph…

blender学习25.3.8

【04-进阶篇】Blender材质及灯光Cycle渲染&后期_哔哩哔哩_bilibili 注意的问题 这一节有一个大重点就是你得打开显卡的渲染&#xff0c;否则cpu直接跑满然后渲染的还十分慢 在这里你要打开GPU计算&#xff0c;但是这还不够 左上角编辑&#xff0c;偏好设置&#xff0c;系…

什么是美颜SDK?从几何变换到深度学习驱动的美颜算法详解

美颜SDK是一种用于处理图像与视频的开发工具&#xff0c;能够提供磨皮、美白、瘦脸、五官优化、动态贴纸等美颜特效。它广泛应用于直播、短视频、社交、在线会议、电商等行业&#xff0c;帮助用户在视频或图片中实现更好的视觉呈现。 一、从几何变换到深度学习&#xff1a;美颜…

【江协科技STM32】ADC数模转换器-学习笔记

ADC简介 ADC&#xff08;Analog-Digital Converter&#xff09;模拟-数字转换器ADC可以将引脚上连续变化的模拟电压转换为内存中存储的数字变量&#xff0c;建立模拟电路到数字电路的桥梁&#xff0c;ADC是一种将连续的模拟信号转换为离散的数字信号的设备或模块12位逐次逼近型…

Docker 安装 Nacos 2.1.1(单机版)

一、拉取镜像 docker pull nacos/nacos-server:v2.1.1 二、新建数据库 官网上下载 对应版本的 nacos zip 包&#xff0c;在 nacos\conf 目录下有 mysql脚本&#xff1a; 新建一个数据库 nacos_config&#xff0c;在数据库中依次执行 nacos-mysql.sql、1.4.0-ipv6_support-up…

【计算机网络入门】初学计算机网络(九)

目录 1.令牌传递协议 2. 局域网&IEEE802 2.1 局域网基本概念和体系结构 3. 以太网&IEEE802.3 3.1 MAC层标准 3.1.1 以太网V2标准 ​编辑 3.2 单播广播 3.3 冲突域广播域 4. 虚拟局域网VLAN 1.令牌传递协议 先回顾一下令牌环网技术&#xff0c;多个主机形成…