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

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个样本标记为TRUE
		ResetEvent(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个样本标记为TRUE
			hr = 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个样本标记为TRUE
			hr = 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;//状态标记置1
			return 0;
		}
		return 1;
	}

	__declspec(dllexport) int __cdecl Pause(void)//暂停
	{
		if (pSReader)
		{
			ResetEvent(pSReader->hRun);//设置“运行”无信号
			pSReader->mState = 2;//状态标记置2
			return 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);//设置源读取器位置0
			PropVariantClear(&pv);
			pSReader->mState = 0;//状态标记置0
			return 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.kler.cn/a/578946.html

相关文章:

  • 稚晖君级硬核:智元公司开源机器人通信框架AimRT入驻GitCode平台
  • Word2Vec向量化语句的计算原理
  • Guava Cache 中LocalCache的分段锁实现
  • UV,纹理,材质,对象
  • electron的通信方式(三种)
  • 健康养生:为生活注入活力
  • 深度链接技术解析:openinstall如何通过场景还原优化用户体验?
  • 【已解决】error setting certificate verify locations
  • 用套接字在网络中传送对象的时候为什么需要序列化?
  • Mac安装jdk教程
  • 深入探讨 Docker 层次结构及其备份策略20250309
  • 《基于Selenium的网页聊天室自动化测试实战报告》
  • android flow中collect和collectLatest的区别
  • [Kubernetes] 7控制平面组件
  • Django ORM 中的 RelatedManager 特殊方法
  • TypeScript系列06-模块系统与命名空间
  • neo4j随笔-将csv文件导入知识图谱
  • 【Java代码审计 | 第八篇】文件操作漏洞成因及防范
  • IntelliJ IDEA 2021版创建springboot项目的五种方式
  • javaEE初阶————多线程进阶(1)