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
下载本插件
相关文章:
Windows软件插件-音视频文件读取器
下载本插件 本插件读取音频和视频文件,输出音频样本和视频样本,音频样本为16位PCM,采样率48000;视频样本为RGB32。大部分音频和视频文件格式都可以读取。本插件类型为DLL。 本插件是通过创建媒体基础“源读取器”对象实现读取音视…...
考研数一复习之拉格朗日中值定理求解函数极限
最近在复习考研数学,只是简单做题过于乏味,因此便总结了一些笔记,后续若有空,也会将自己的复习笔记分享出来。本篇,我们将重点讲解拉格朗日中值定理在求解函数极限中的应用。同时,作者本人作为python领域创作者,还将在本文分享使用sympy求解高数中函数极…...
聊天服务器分布式改造
目前的聊天室是单节点的,无论是http接口还是socket接口都在同一个进程,无法承受太多人同时在线,容灾性也非常差。因此,一个成熟的IM产品一定是做成分布式的,根据功能分模块,每个模块也使用多个节点并行部署…...
C++11的一些特性
目录 一、C11简介 二、统一的列表初始化 2.1 {}初始化 2.2 std::initializer_list 三、声明 3.1 auto 3.2 decltype 3.3 nullptr 四、范围for循环 五、智能指针 5.1 RAII 5.2 智能指针的原理 5.3 std::auto_ptr…...
【打卡day3】字符串类
例如统计字符个数,字符大小写转换 题目描述:输入一行字符串,计算A-Z大写字母出现的次数 思路: 1 定义一个整型数组,初始化为0,存储每个字母出现的次数,下标0对应字母A, 2,定义字…...
图像滑块对比功能的开发记录
背景介绍 最近,公司需要开发一款在线图像压缩工具,其中的一个关键功能是让用户直观地比较压缩前后的图像效果。因此,我们设计了一个对比组件,它允许用户通过拖动滑块,动态调整两张图像的显示区域,从而清晰…...
【音视频】ffplay常用命令
一、 ffplay常用命令 -x width:强制显示宽度-y height:强制显示高度 强制以 640*360的宽高显示 ffplay 2.mp4 -x 640 -y 360 效果如下 -fs 全屏显示 ffplay -fs 2.mp4效果如下: -an 禁用音频(不播放声音)-vn 禁…...
初识Linux
文章目录 初识Linux:从开源哲学到技术生态的全面解析一、Linux的背景与发展简史:从代码实验到数字基础设施1.1 起源与开源基因1.2 技术哲学之争1.3 GNU/Linux的融合 二、开源:Linux的核心竞争力与生态力量2.1 法律保障与四大自由2.2 社区协作…...
基于遗传算法的IEEE33节点配电网重构程序
一、配电网重构原理 配电网重构(Distribution Network Reconfiguration, DNR)是一项优化操作,旨在通过改变配电网中的开关状态,优化电力系统的运行状态,以达到降低网损、均衡负载、改善电压质量等目标。配电网重构的核…...
manus对比ChatGPT-Deep reaserch进行研究类学术相关数据分析!谁更胜一筹?
没有账号,只能挑选一个案例 一夜之间被这个用全英文介绍全华班出品的新爆款国产AI产品的小胖刷频。白天还没有切换语言的选项,晚上就加上了。简单看了看团队够成,使用很长实践的Monica创始人也在其中。逐渐可以理解,重心放在海外产…...
线程通信---java
线程 我们知道,线程是进程的最小执行单位,一个进程可以拥有多个线程,那么就会引入两个问题: 多个线程之间如何进行通信多个线程对同一个数据进行操作,如何保证程序正确执行,也就是线程安全问题 线程的常…...
python面试常见题目
1、python 有几种数据类型 数字:整形 (int),浮点型 (float)布尔 ( bool):false true字符串 (string)列表 (list)元组 (tuple)字典 &…...
Python中与字符串操作相关的30个常用函数及其示例
以下是Python中与字符串操作相关的30个常用函数及其示例: 1. str.capitalize() 将字符串的第一个字符大写,其余字符小写。 s "hello world" print(s.capitalize()) # 输出: Hello world2. str.lower() 将字符串中的所有字符转换为小写。…...
2025年渗透测试面试题总结-小某鹏汽车-安全工程师(题目+回答)
网络安全领域各种资源,学习文档,以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具,欢迎关注。 目录 小鹏汽车-安全工程师 一、XXE漏洞与SSRF漏洞 1. XXE(XML External Entity)漏洞…...
kafka + flink +mysql 案例
假设你有两个Kafka主题:user_activities_topic 和 product_views_topic,并且你希望将user_activities_topic中的数据写入到user_activities表,而将product_views_topic中的数据写入到product_views表。 maven <dependencies><!-- …...
Windows下配置Flutter移动开发环境以及AndroidStudio安装和模拟机配置
截止 2025/3/9 ,版本更新到了 3.29.1 ,但是为了防止出现一些奇怪的bug,我安装的还是老一点的,3.19,其他版本的安装同理。AndroidStudio用的是 2024/3/1 版本。 — 1 环境变量(Windows) PUB_H…...
【工具类】Springboot 项目日志打印项目版本和构建时间
博主介绍:✌全网粉丝22W,CSDN博客专家、Java领域优质创作者,掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌ 技术范围:SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物…...
p5.js:模拟 n个彩色小球在一个3D大球体内部弹跳
向 豆包 提问:编写一个 p5.js 脚本,模拟 42 个彩色小球在一个3D大球体内部弹跳。每个小球都应留下一条逐渐消失的轨迹。大球体应缓慢旋转,并显示透明的轮廓线。请确保实现适当的碰撞检测,使小球保持在球体内部。 cd p5-demo copy…...
RISC-V医疗芯片工程师复合型转型的路径与策略
从RISC-V到医疗芯片:工程师复合型转型的路径与策略 一、引言 1.1 研究背景 在科技快速发展的当下,芯片技术已然成为推动各行业进步的核心驱动力之一。其中,RISC-V 架构作为芯片领域的新兴力量,正以其独特的优势迅速崛起,对整个芯片产业的格局产生着深远影响。RISC-V 架…...
HTML 文本格式化
HTML 文本格式化 在构建网页的过程中,文本的格式化是一个至关重要的环节。HTML(HyperText Markup Language)提供了丰富的标签和属性来帮助我们实现各种文本格式化的需求。本文将详细介绍HTML中常见的文本格式化方法,包括字体、颜…...
基于RNN+微信小程序+Flask的古诗词生成应用
项目介绍 平台采用B/S结构,后端采用主流的Flask框架进行开发,古诗词生成采用RNN模型进行生成,客户端基于微信小程序开发。是集成了Web后台开发、微信小程序开发、人工智能(RNN)等多个领域的综合性应用,是课…...
【算法】图论 —— Dijkstra算法 python
引入 求非负权边的单源最短路 时间复杂度 O( m l o g n mlogn mlogn) 模板 https://www.luogu.com.cn/problem/P4779 import heapq as hq def dijkstra(s): # dis表示从s到i的最短路 dis [float(inf)] * (n 1) # vis表示i是否出队列 vis [0] * (n 1) q [] dis[s…...
Java:LocalDatTime(代替Calendar)、ZoneDateTime(时区时间)
文章目录 Local(代替Calendar)方法:获取当前代码 LocalDate(年月日星期)LocalTime(时分秒纳秒)LocalDateTime(最常用:年月日时分秒纳秒)ZoneId 时区表示方法 ZoneDateTime(时区时间)方法世界标准时间&#…...
HOW - React 如何在在浏览器绘制之前同步执行 - useLayoutEffect
目录 useEffect vs useLayoutEffectuseEffectuseLayoutEffect主要区别总结选择建议注意事项 useLayoutEffect 使用示例测量 DOM 元素的尺寸和位置示例:自适应弹出框定位 同步更新样式以避免闪烁示例:根据内容动态调整容器高度 图像或 Canvas 绘制前的准备…...
PyTorch系列教程:编写高效模型训练流程
当使用PyTorch开发机器学习模型时,建立一个有效的训练循环是至关重要的。这个过程包括组织和执行对数据、参数和计算资源的操作序列。让我们深入了解关键组件,并演示如何构建一个精细的训练循环流程,有效地处理数据处理,向前和向后…...
VS2019,VCPKG - 为VS2019添加VCPKG
文章目录 VS2019,VCPKG - 为VS2019添加VCPKG概述笔记前置条件迁出vcpkg到本地验证库安装更新已经安装的库删除指定的包安装VS2019能用的boostvcpkg 2025.02.14 版本可以给VS2019用用VCPKG的好处备注END VS2019,VCPKG - 为VS2019添加VCPKG 概述 开源工程用到了VCPKG管理的包。…...
linux下 jq 截取json文件信息
背景:通过‘登录名‘ 获取该对象的其他个人信息如名字。 环境准备:麒麟操作系统V10 jq安装包 jq安装包获取方式:yum install jq 或 使用附件中的rpm 或 git自行下载 https://github.com/stedolan/jq/releases/download/ 实现过程介绍&am…...
测试大语言模型在嵌入式设备部署的可能性-ollama本地部署测试
前言 当今各种大语言模型百花齐放,为了方便使用者更加自由的使用大模型,将大模型变成如同棒球棍一样每个人都能用,并且顺手方便的工具,本地私有化具有重要意义。 本次测试使用ollama完成模型下载,过程简单快捷。 1、进…...
C语言基础系列【21】memcpy、memset
博主介绍:程序喵大人 35- 资深C/C/Rust/Android/iOS客户端开发10年大厂工作经验嵌入式/人工智能/自动驾驶/音视频/游戏开发入门级选手《C20高级编程》《C23高级编程》等多本书籍著译者更多原创精品文章,首发gzh,见文末👇…...
云曦春季开学考复现(2025)
Crypto 划水的dp和dq 下载附件后是简单的RSA算法题,之所以说简单是因为给了公钥e 趁热打铁,昨天刚学的RSA,既然有p有q,也有e,而np*q,可以算出欧拉函数值phi(p-1)*(q-1&…...
探秘 Netty 通信中的 SslHandler 类:保障网络通信安全的基石
引言 在当今数字化时代,网络安全是每一个应用程序都必须重视的关键因素。尤其是在数据传输过程中,防止数据被窃取、篡改至关重要。Netty 作为一个高性能的网络编程框架,为开发者提供了强大的功能来构建可靠的网络应用。其中,SslH…...
Llama factory微调后的模型怎么通过ollama发布
接上一篇博客:用Llama Factory单机多卡微调Qwen2.5时报torch.OutOfMemoryError: CUDA out of memory的解决办法_llama-factory cuda out of memory-CSDN博客 把Lora模块和其基模型merge到一起之后,就可以通过ollama之类的框架提供服务了。不过还是有些格式转换的工作要做: …...
ubuntu 20.04下ZEDmini安装使用
提前安装好显卡驱动和cuda,如果没有安装可以参考我的这两篇文章进行安装: ubuntu20.04配置YOLOV5(非虚拟机)_ubuntu20.04安装yolov5-CSDN博客 ubuntu20.04安装显卡驱动及问题总结_乌班图里怎么备份显卡驱动-CSDN博客 还需要提前…...
CmBacktrace的学习跟移植思路
学习移植CmBacktrace需要从理解其核心功能、适用场景及移植步骤入手,结合理论学习和实践操作。以下是具体的学习思路与移植思路: 一、学习思路 理解CmBacktrace的核心功能 CmBacktrace是针对ARM Cortex-M系列MCU的错误追踪库,支持自动诊断Har…...
Android Glide 缓存模块源码深度解析
一、引言 在 Android 开发领域,图片加载是一个极为常见且关键的功能。Glide 作为一款被广泛使用的图片加载库,其缓存模块是提升图片加载效率和性能的核心组件。合理的缓存机制能够显著减少网络请求,降低流量消耗,同时加快图片显示…...
蓝桥杯备赛:炮弹
题目解析 这道题目是一道模拟加调和级数,难的就是调和级数,模拟过程比较简单。 做法 这道题目的难点在于我们在玩这个跳的过程,可能出现来回跳的情况,那么为了解决这种情况,我们采取的方法是设定其的上限步数。那么…...
死锁问题分析工具
使用 gdb 调试 gdb ./your_program (gdb) run (gdb) thread apply all bt还可以分析pthread_mutex内部,查看owen字段分析哪个线程占用的锁,一个可能的 pthread_mutex 内部结构可以大致表示为: typedef struct pthread_mutex_t {int state; …...
装饰器模式--RequestWrapper、请求流request无法被重复读取
目录 前言一、场景二、原因分析三、解决四、更多 前言 曾经遇见这么一段代码,能看出来是把request又重新包装了一下,核心信息都不会改变 后面了解到这叫 装饰器模式(Decorator Pattern) :也称为包装模式(Wrapper Pat…...
MTK Android12 桌面上显示文件管理器图标
文章目录 需求解决 需求 在MTK平台上,Android12的文件管理器图标未显示在桌面,但在设置里面可以看到,文件管理器是安装的。根据客户要求,需要将文件管理器的图标显示在桌面上。解决 路径:packages/apps/DocumentsUI/…...
SpringBoot实现文件上传
1. 配置文件上传限制 application.yml spring:servlet:multipart:max-file-size: 10MBmax-request-size: 10MB2. 创建文件上传控制器 import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RestController; import…...
【开源免费】基于SpringBoot+Vue.JS青年公寓服务平台(JAVA毕业设计)
本文项目编号 T 233 ,文末自助获取源码 \color{red}{T233,文末自助获取源码} T233,文末自助获取源码 目录 一、系统介绍二、数据库设计三、配套教程3.1 启动教程3.2 讲解视频3.3 二次开发教程 四、功能截图五、文案资料5.1 选题背景5.2 国内…...
django中视图作用和视图功能 以及用法
在 Django REST Framework(DRF)中,视图(View)是处理 HTTP 请求并返回响应的核心组件。DRF 提供了多种视图类,适用于不同的场景和需求。以下是 DRF 中常见的视图类及其作用、使用方法的详细说明: 一、DRF 视图的分类 DRF 的视图可以分为以下几类: 基于函数的视图(Func…...
大语言模型在患者交互任务中的临床使用评估框架
An evaluation framework for clinical use of large language models in patient interaction tasks An evaluation framework for clinical use of large language models in patient interaction tasks | Nature Medicine 2025.1 收到时间:2023 年 8 月 8 日 …...
Python—类class复习
Python——类(class)复习 根据类来创建对象的方法被称为实例化 因此学会使用类(class)来进行编程就是初步进入面向对象编程的大门 1.1 创建和使用类 首先编写一个小狗的简单类Dog,它表示的不是特定的小狗ÿ…...
QT | 信号与槽(超详解)
前言 对qt信号和槽的详细解释 💓 个人主页:普通young man-CSDN博客 ⏩ 文章专栏:C_普通young man的博客-CSDN博客 ⏩ 本人giee: 普通小青年 (pu-tong-young-man) - Gitee.com 若有问题 评论区见📝 🎉欢迎大家点赞&am…...
Codecraft-17 and Codeforces Round 391 E. Bash Plays with Functions 积性函数
题目链接 题目大意 定义函数 f r ( n ) f_r(n) fr(n) : 在 r 0 r0 r0时,为满足 p p p ⋅ \cdot ⋅ q n qn qn , 且 g c d ( p , q ) 1 gcd(p,q)1 gcd(p,q)1 的有序对 ( p , q ) (p,q) (p,q) 个数;在 r r r ≥ \geq ≥ 1 1 1时࿰…...
粉尘环境下的智能生产革命 ——助力矿山行业实现高效自动化作业
在矿山开采领域,运输系统是保障生产连续性的核心环节。然而,粉尘弥漫、环境恶劣、设备分散等问题,长期制约着矿山运输的效率与安全性。传统的集中式控制系统难以适应复杂工况,而远程分布式 IO 模块与 PLC 的深度融合,正…...
更新vscode ,将c++11更新到c++20
要在CentOS系统中安装最新版本的GCC,你可以使用SCL(Software Collections)仓库,它提供了开发工具的最新版本。以下是安装步骤: 1、 添加SCL仓库: 首先,添加CentOS的SCL仓库,该仓库…...
Numpy实训:读取并分析iris数据集中鸢尾花的相关数据
实训中相关数据集,请联系博主邮箱"1438077481qq.com",在邮箱内发送"iris.csv"即可快速获取,无任何套路,秉承开源精神! 1、导入模块 #导入模块 import numpy as np import csv 2、获取数据 iri…...
nats jetstream server code 分析
对象和缩写 jetstream导入两个对象:stream and consumer,在stream 之上构造jetstreamapi。在nats代码中,以下是一些常见的缩写 1.mset is stream 2.jsX is something of jetstream 3.o is consumer 代码分析 对于producer ,发送…...