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

打印 上一主题 下一主题

主题 1055|帖子 1055|积分 3165

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

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

首先,加载本读取器DLL,获得读取器模块句柄。
  1.         HMODULE hSReader = LoadLibrary(L"SReader.dll");
复制代码
定义媒体信息和样本信息结构,定义接收当前位置信息的函数(如果不需要,也可以不定义),定义视频音频样本接收函数:
  1. struct INFO
  2. {
  3.         int VideoWidth=0;//视频宽,单位像素
  4.         int VideoHeight=0;//视频高,单位像素
  5.         LONGLONG FrameCur=0;//帧持续时间,单位100纳秒
  6.         LONGLONG DUR=0;//媒体时长,单位100纳秒
  7.         DWORD AudioSamplePerSec=0;//音频样本采样率
  8.         DWORD StreamCount=0;//流数量
  9. };
  10. struct SAMPLE_INFO//样本信息
  11. {
  12.         BOOL B;//为TRUE,样本为第1个样本
  13.         DWORD STAR;//运行开始时间,单位毫秒
  14.         LONGLONG star;//样本开始时间,单位100纳秒
  15.         LONGLONG end;//样本结束时间,单位100纳秒
  16.         BYTE* pB;//样本缓冲区指针
  17.         int len;//样本的字节大小
  18.         HANDLE hRun;//“运行”事件句柄
  19.         HANDLE hSeek;//“定位”事件句柄
  20. };
  21. void SliderSetPosition(LONGLONG pos)
  22. {
  23. }
  24. int ReceiveVideoSample(SAMPLE_INFO SampleInfo)//视频样本接收函数
  25. {
  26.     return 0;
  27. }
  28. int ReceiveAudioSample(SAMPLE_INFO SampleInfo)//音频样本接收函数
  29. {
  30.     return 0;
  31. }
复制代码
定义函数指针:
  1.         typedef int(__thiscall *MYPROC_ReceiveSample)(SAMPLE_INFO info);
  2.         typedef void(__thiscall *MYPROC_GetPos)(LONGLONG pos);
  3.         typedef INFO(__cdecl *MYPROC_SReader_Init)(wchar_t* Path);
  4.         typedef int(__cdecl *MYPROC_SReader_Run)(MYPROC_ReceiveSample VideoSample, MYPROC_ReceiveSample AudioSample, MYPROC_GetPos Pos);
  5.         typedef int(__cdecl *MYPROC_SReader_Pause)();
  6.         typedef int(__cdecl *MYPROC_SReader_Stop)();
  7.         typedef int(__cdecl *MYPROC_SReader_Seek)(LONGLONG SeekPos);
  8.         typedef int(__cdecl *MYPROC_SReader_GetState)();
  9.         typedef int(__cdecl *MYPROC_SReader_Exit)();
复制代码
获取本读取器导出函数的地址:
  1.         MYPROC_SReader_Init SReader_Init = NULL;
  2.         MYPROC_SReader_GetState SReader_GetState = NULL;
  3.         MYPROC_SReader_Run SReader_Run = NULL;
  4.         MYPROC_SReader_Pause SReader_Pause = NULL;
  5.         MYPROC_SReader_Stop SReader_Stop = NULL;
  6.         MYPROC_SReader_Seek SReader_Seek = NULL;
  7.         MYPROC_SReader_Exit SReader_Exit = NULL;
  8.         MYPROC_GetPos GetPos=NULL;
  9.         MYPROC_ReceiveSample ReceiveVideo=NULL;
  10.         MYPROC_ReceiveSample ReceiveAudio=NULL;
  11.         if (hSReader)
  12.         {
  13.                 SReader_Init = (MYPROC_SReader_Init)GetProcAddress(hSReader, "Init");
  14.                 SReader_GetState = (MYPROC_SReader_GetState)GetProcAddress(hSReader, "GetState");
  15.                 SReader_Run = (MYPROC_SReader_Run)GetProcAddress(hSReader, "Run");
  16.                 SReader_Pause = (MYPROC_SReader_Pause)GetProcAddress(hSReader, "Pause");
  17.                 SReader_Stop = (MYPROC_SReader_Stop)GetProcAddress(hSReader, "Stop");
  18.                 SReader_Seek = (MYPROC_SReader_Seek)GetProcAddress(hSReader, "Seek");
  19.                 SReader_Exit = (MYPROC_SReader_Exit)GetProcAddress(hSReader, "Exit");
  20.                 GetPos = (MYPROC_GetPos)(&SliderSetPosition);       
  21.                 ReceiveVideo=(MYPROC_ReceiveSample)(&ReceiveVideoSample);
  22.                 ReceiveAudio=(MYPROC_ReceiveSample)(&ReceiveAudioSample);
  23.         }
复制代码
初始化本读取器,获取文件媒体信息:
  1.         INFO info;
  2.         wchar_t* path = L"某视频文件.mp4";
  3.         if (SReader_Init != NULL)
  4.                 info = SReader_Init(path);
复制代码
为读取器指定视频样本和音频样本接收函数,和接收位置信息函数(不需要位置信息时,GetPos可以为NULL);运行读取器:
  1.         if (SReader_Run)
  2.         {
  3.                 SReader_Run(ReceiveVideo, ReceiveAudio, GetPos);
  4.         }
复制代码
如许视频音频样本接收函数将被反复调用,参数提供样本的数据和信息。别的导出函数用于读取器的停息,制止和退出;获取读取器当前状态,调用SReader_GetState(),返回状态值。
本读取器为后续文章“播放视频”而计划,读者可以在本代码的底子上添加自己想要的功能,也可以进行更改。
本读取器的全部代码

  1. #include "windows.h"
  2. #include "mmsystem.h"
  3. #pragma comment(lib, "winmm")
  4. #include "mfapi.h"
  5. #include "mfidl.h"
  6. #include "mfreadwrite.h"
  7. #pragma comment(lib, "mfplat")
  8. #pragma comment(lib, "mfreadwrite")
  9. #pragma comment(lib, "mfuuid")
  10. template <class T> void SafeRelease(T** ppT)
  11. {
  12.         if (*ppT)
  13.         {
  14.                 (*ppT)->Release();
  15.                 *ppT = NULL;
  16.         }
  17. }
  18. struct INFO//媒体信息
  19. {
  20.         int VideoWidth;//视频宽,单位像素
  21.         int VideoHeight;//视频高,单位像素
  22.         LONGLONG FrameCur;//帧持续时间,单位100纳秒
  23.         LONGLONG DUR;//媒体时长,单位100纳秒
  24.         DWORD AudioSamplePerSec;//音频样本采样率
  25.         DWORD StreamCount = 0;//流数量
  26. };
  27. struct SAMPLE_INFO//样本信息
  28. {
  29.         BOOL B;//为TRUE,样本为第1个样本
  30.         DWORD STAR;//运行开始时间,单位毫秒
  31.         LONGLONG star;//样本开始时间,单位100纳秒
  32.         LONGLONG end;//样本结束时间,单位100纳秒
  33.         BYTE* pB;//样本缓冲区指针
  34.         int len;//样本的字节大小
  35.         HANDLE hRun;//“运行”事件句柄
  36.         HANDLE hSeek;//“定位”事件句柄
  37. };
  38. typedef int(__cdecl *MYPROC_SendVideo)(SAMPLE_INFO SampleInfo);//定义函数指针
  39. typedef int(__cdecl *MYPROC_SendAudio)(SAMPLE_INFO SampleInfo);
  40. typedef int(__cdecl *MYPROC_SendPos)(LONGLONG pos);
  41. class SReader
  42. {
  43. public:
  44.         SReader()
  45.         {
  46.                 HRESULT hr = MFStartup(MF_VERSION);
  47.                 if (hr != S_OK)
  48.                 {
  49.                         MessageBox(NULL, L"初始化媒体基础失败", L"SourceReader", MB_OK);
  50.                 }
  51.                 hRun = CreateEvent(NULL, TRUE, FALSE, NULL);//手动重置,初始无信号
  52.                 hExit = CreateEvent(NULL, TRUE, FALSE, NULL);//手动重置,初始无信号
  53.                 hSeek = CreateEvent(NULL, TRUE, FALSE, NULL);//手动重置,初始无信号
  54.         }
  55.         ~SReader()
  56.         {
  57.                 SafeRelease(&pIMFSourceReader); CloseHandle(hRun); CloseHandle(hExit); CloseHandle(hSeek);
  58.                 MFShutdown();//关闭媒体基础
  59.         }
  60.         HANDLE hRun, hExit, hSeek;
  61.         IMFSourceReader* pIMFSourceReader = NULL;//源读取器接口指针
  62.         UINT32 Width, Height;//视频宽高
  63.         LONGLONG DUR;//媒体持续时间,100纳秒单位
  64.         LONGLONG CUR;//当前位置,100纳秒单位
  65.         LONGLONG SeekPos;//定位位置
  66.         DWORD STAR;//开始时间
  67.         BOOL VFirst, AFirst;//为TRUE标明第1个样本
  68.         int mState;//状态;0停止,1运行,2暂停
  69.         INFO info;//媒体信息对象
  70.         MYPROC_SendVideo SendVideo = NULL;//视频样本输出函数指针
  71.         MYPROC_SendAudio SendAudio = NULL;//音频样本输出函数指针
  72.         MYPROC_SendPos SendPos = NULL;//当前位置输出函数指针
  73. };
  74. HRESULT GetSample(IMFSourceReader* pIMFSourceReader, UINT SOURCE, LONGLONG& Cur, LONGLONG& Dur)//获取样本
  75. {
  76.         IMFSample* pMFSample = NULL; DWORD flags;
  77.         HRESULT hr = pIMFSourceReader->ReadSample(SOURCE, 0, NULL, &flags, NULL, &pMFSample);//读取视频样本
  78.         hr = pMFSample->GetSampleTime(&Cur);//获取显示时间
  79.         hr = pMFSample->GetSampleDuration(&Dur);//获取持续时间
  80.         SafeRelease(&pMFSample);//释放接口
  81.         return hr;
  82. }
  83. SReader* pSReader = NULL;//SReader类对象指针
  84. HANDLE hVthread = NULL, hAthread = NULL;//视频音频线程句柄
  85. DWORD WINAPI VideoThread(LPVOID lp)//视频线程
  86. {
  87.         HRESULT hr; pSReader->VFirst = TRUE; IMFSample* pMFSample = NULL; DWORD flags;
  88. Agan:
  89.         DWORD mRun = WaitForSingleObject(pSReader->hRun, 0);//检测“运行”信号,不等待
  90.         DWORD mSeek = WaitForSingleObject(pSReader->hSeek, 0);//检测“定位”信号,不等待
  91.         DWORD mExit = WaitForSingleObject(pSReader->hExit, 0);//检测“退出”信号,不等待
  92.         if (mExit == WAIT_OBJECT_0)//有“退出”信号
  93.         {
  94.                 return 0;//退出线程
  95.         }
  96.         if (mSeek == WAIT_OBJECT_0)//有“定位”信号
  97.         {
  98.                 hr = pSReader->pIMFSourceReader->Flush(MF_SOURCE_READER_ALL_STREAMS);//丢弃所有排队的样本并取消所有挂起的样本请求
  99.                 PROPVARIANT pv;
  100.                 PropVariantInit(&pv);
  101.                 pv.vt = 20;
  102.                 pv.hVal.QuadPart = pSReader->SeekPos;
  103.                 hr = pSReader->pIMFSourceReader->SetCurrentPosition(GUID_NULL, pv);//更改源读取器位置
  104.                 PropVariantClear(&pv);
  105.                 /*试验发现,源读取器在媒体中间时间段定位后,音频视频样本不同步(时间戳相差约2秒钟),故添加下面代码以使样本时间同步*/
  106.                 LONGLONG VCur, VDur;
  107.                 hr = GetSample(pSReader->pIMFSourceReader, MF_SOURCE_READER_FIRST_VIDEO_STREAM, VCur, VDur);//获取视频样本时间
  108.                 LONGLONG ACur, ADur;
  109.                 hr = GetSample(pSReader->pIMFSourceReader, MF_SOURCE_READER_FIRST_AUDIO_STREAM, ACur, ADur);//获取音频样本时间
  110.                 if (ACur > VCur + VDur + 100000)//如果音频样本时间过大
  111.                 {
  112.                         while (ACur > VCur + VDur + 100000)
  113.                         {
  114.                                 hr = GetSample(pSReader->pIMFSourceReader, MF_SOURCE_READER_FIRST_VIDEO_STREAM, VCur, VDur);//获取下一个视频样本
  115.                         }
  116.                 }
  117.                 else if (VCur > ACur + ADur + 100000)//如果视频样本时间过大
  118.                 {
  119.                         while (VCur > ACur + ADur + 100000)
  120.                         {
  121.                                 hr = GetSample(pSReader->pIMFSourceReader, MF_SOURCE_READER_FIRST_AUDIO_STREAM, ACur, ADur);//获取下一个音频样本
  122.                         }
  123.                 }
  124.                 pSReader->STAR = timeGetTime();//记录运行开始时间,单位毫秒
  125.                 pSReader->VFirst = TRUE; pSReader->AFirst = TRUE;//设置第1个样本标记为TRUE
  126.                 ResetEvent(pSReader->hSeek);//设置“定位”无信号
  127.         }
  128.         if (mRun == WAIT_OBJECT_0)//有“运行”信号
  129.         {
  130.                 hr = pSReader->pIMFSourceReader->ReadSample(MF_SOURCE_READER_FIRST_VIDEO_STREAM, 0, NULL, &flags, NULL, &pMFSample);//读取视频样本
  131.                 if (hr == S_OK && pMFSample)
  132.                 {
  133.                         LONGLONG Cur, Dur;
  134.                         hr = pMFSample->GetSampleTime(&Cur);//获取显示时间
  135.                         hr = pMFSample->GetSampleDuration(&Dur);//获取持续时间
  136.                         DWORD Lt;
  137.                         hr = pMFSample->GetTotalLength(&Lt);//获取有效长度
  138.                         DWORD count;
  139.                         hr = pMFSample->GetBufferCount(&count);//获取缓冲区数量
  140.                         IMFMediaBuffer* pMFBuffer = NULL;
  141.                         if (count == 1)//如果只有1个缓冲区
  142.                         {
  143.                                 hr = pMFSample->GetBufferByIndex(0, &pMFBuffer);
  144.                         }
  145.                         else//如果有多个缓冲区
  146.                         {
  147.                                 hr = pMFSample->ConvertToContiguousBuffer(&pMFBuffer);
  148.                         }
  149.                         BYTE* pSB = NULL;
  150.                         hr = pMFBuffer->Lock(&pSB, NULL, NULL);//锁定缓冲区
  151.                         SAMPLE_INFO info;
  152.                         info.B = pSReader->VFirst;
  153.                         info.STAR = pSReader->STAR;
  154.                         info.star = Cur;
  155.                         info.end = Cur + Dur;
  156.                         info.pB = pSB;
  157.                         info.len = Lt;
  158.                         info.hRun = pSReader->hRun;
  159.                         info.hSeek = pSReader->hSeek;
  160.                         pSReader->SendVideo(info);//调用视频输出函数,输出样本
  161.                         if (pSReader->VFirst)pSReader->VFirst = FALSE;//只有第1个样本标记为TRUE
  162.                         hr = pMFBuffer->Unlock();//解锁缓冲区
  163.                         SafeRelease(&pMFBuffer); SafeRelease(&pMFSample);//释放接口
  164.                 }
  165.         }
  166.         goto Agan;
  167. }
  168. DWORD WINAPI AudioThread(LPVOID lp)
  169. {
  170.         HRESULT hr; pSReader->AFirst = TRUE; IMFSample* pMFSample = NULL; DWORD flags; pSReader->CUR = 0; int Count = 0;
  171. Agan:
  172.         DWORD mRun = WaitForSingleObject(pSReader->hRun, 0);//检测“运行”信号,不等待
  173.         DWORD mSeek = WaitForSingleObject(pSReader->hSeek, 0);//检测“定位”信号,不等待
  174.         DWORD mExit = WaitForSingleObject(pSReader->hExit, 0);//检测“退出”信号,不等待
  175.         if (mExit == WAIT_OBJECT_0)//有“退出”信号
  176.         {
  177.                 return 0;//退出线程
  178.         }
  179.         if (mSeek == WAIT_OBJECT_0)//有“定位”信号
  180.         {
  181.                 if (pSReader->info.StreamCount == 2)//如果有视频流和音频流
  182.                 {
  183.                         goto Agan;//阻塞(更改位置操作在视频线程中,音频线程等待操作完成)
  184.                 }
  185.                 else//如果只有音频流,在此更改源读取器位置
  186.                 {
  187.                         hr = pSReader->pIMFSourceReader->Flush(MF_SOURCE_READER_ALL_STREAMS);//丢弃所有排队的样本并取消所有挂起的样本请求
  188.                         PROPVARIANT pv;
  189.                         PropVariantInit(&pv);
  190.                         pv.vt = 20;
  191.                         pv.hVal.QuadPart = pSReader->SeekPos;
  192.                         hr = pSReader->pIMFSourceReader->SetCurrentPosition(GUID_NULL, pv);//更改源读取器位置
  193.                         PropVariantClear(&pv);
  194.                         pSReader->STAR = timeGetTime();//记录运行开始时间
  195.                         pSReader->AFirst = TRUE;
  196.                         ResetEvent(pSReader->hSeek);//设置“定位”无信号
  197.                 }
  198.         }
  199.         if (mRun == WAIT_OBJECT_0)//有“运行”信号
  200.         {
  201.                 hr = pSReader->pIMFSourceReader->ReadSample(MF_SOURCE_READER_FIRST_AUDIO_STREAM, 0, NULL, &flags, NULL, &pMFSample);//读取音频样本
  202.                 if (hr == S_OK && pMFSample)
  203.                 {
  204.                         LONGLONG Cur, Dur;
  205.                         hr = pMFSample->GetSampleTime(&Cur);//获取显示时间
  206.                         hr = pMFSample->GetSampleDuration(&Dur);//获取持续时间
  207.                         Count++;
  208.                         if (Count > 9)//每10个样本,发送一次当前位置
  209.                         {
  210.                                 pSReader->CUR = Cur;//赋值当前时间
  211.                                 if(pSReader->SendPos)pSReader->SendPos(Cur);//发送当前时间位置值
  212.                                 Count = 0;
  213.                         }
  214.                         DWORD Lt;
  215.                         hr = pMFSample->GetTotalLength(&Lt);//获取有效长度
  216.                         DWORD count;
  217.                         hr = pMFSample->GetBufferCount(&count);//获取缓冲区数量
  218.                         IMFMediaBuffer* pMFBuffer = NULL;
  219.                         if (count == 1)//如果只有1个缓冲区
  220.                         {
  221.                                 hr = pMFSample->GetBufferByIndex(0, &pMFBuffer);
  222.                         }
  223.                         else//如果有多个缓冲区
  224.                         {
  225.                                 hr = pMFSample->ConvertToContiguousBuffer(&pMFBuffer);
  226.                         }
  227.                         BYTE* pSB = NULL;
  228.                         hr = pMFBuffer->Lock(&pSB, NULL, NULL);//锁定缓冲区
  229.                         SAMPLE_INFO info;
  230.                         info.B = pSReader->AFirst;
  231.                         info.STAR = pSReader->STAR;
  232.                         info.star = Cur;
  233.                         info.end = Cur + Dur;
  234.                         info.pB = pSB;
  235.                         info.len = Lt;
  236.                         info.hRun = pSReader->hRun;
  237.                         info.hSeek = pSReader->hSeek;
  238.                         pSReader->SendAudio(info);//调用音频样本输出函数,发送音频样本
  239.                         if (pSReader->AFirst)pSReader->AFirst = FALSE;//只有第1个样本标记为TRUE
  240.                         hr = pMFBuffer->Unlock();//解锁缓冲区
  241.                         SafeRelease(&pMFBuffer); SafeRelease(&pMFSample);//释放接口
  242.                 }
  243.         }
  244.         goto Agan;
  245. }
  246. //下面是导出函数定义
  247. #pragma warning(disable:4190)
  248. #ifdef __cplusplus    // If used by C++ code,
  249. extern "C" {          // we need to export the C interface
  250. #endif
  251.         __declspec(dllexport) INFO __cdecl Init(wchar_t* Path)
  252.         {
  253.                 if (pSReader)//如果SReader对象已存在
  254.                 {
  255.                         SetEvent(pSReader->hExit);//设置“退出”有信号
  256.                         WaitForSingleObject(hVthread, INFINITE);//等待视频线程退出
  257.                         WaitForSingleObject(hAthread, INFINITE);//等待音频线程退出
  258.                         delete pSReader;//删除SReader对象
  259.                 }
  260.                 pSReader = new SReader();//创建SReader对象
  261.                 IMFAttributes* pIMFAttributes = NULL;
  262.                 HRESULT hr = MFCreateAttributes(&pIMFAttributes, 0);
  263.                 if (SUCCEEDED(hr))
  264.                 {
  265.                         hr = pIMFAttributes->SetUINT32(MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS, (UINT32)1);//使用基于硬件的媒体基础转换
  266.                 }
  267.                 if (SUCCEEDED(hr))
  268.                 {
  269.                         hr = pIMFAttributes->SetUINT32(MF_SOURCE_READER_ENABLE_VIDEO_PROCESSING, (UINT32)1);//允许源读取器进行有限的视频处理
  270.                 }
  271.                 if (SUCCEEDED(hr))
  272.                 {
  273.                         hr = MFCreateSourceReaderFromURL(Path, pIMFAttributes, &pSReader->pIMFSourceReader);//创建源读取器
  274.                 }
  275.                 SafeRelease(&pIMFAttributes);
  276.                 PROPVARIANT var;
  277.                 PropVariantInit(&var);
  278.                 if (SUCCEEDED(hr))
  279.                 {
  280.                         hr = pSReader->pIMFSourceReader->GetPresentationAttribute(MF_SOURCE_READER_MEDIASOURCE, MF_PD_DURATION, &var);//获取媒体时间长度,100纳秒单位
  281.                 }
  282.                 if (SUCCEEDED(hr))
  283.                 {
  284.                         pSReader->info.DUR = pSReader->DUR = (LONGLONG)var.uhVal.QuadPart;
  285.                 }
  286.                 PropVariantClear(&var);
  287.                 IMFMediaType* pAudioMTA = NULL;
  288.                 if (SUCCEEDED(hr))
  289.                 {
  290.                         hr = MFCreateMediaType(&pAudioMTA);//创建空的媒体类型
  291.                 }
  292.                 if (SUCCEEDED(hr))
  293.                 {
  294.                         hr = pAudioMTA->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio);//设置主要类型音频
  295.                 }
  296.                 if (SUCCEEDED(hr))
  297.                 {
  298.                         hr = pAudioMTA->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_PCM);//设置子类型PCM
  299.                 }
  300.                 if (SUCCEEDED(hr))
  301.                 {
  302.                         hr = pAudioMTA->SetUINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, (UINT32)16);//设置样本16位
  303.                 }
  304.                 if (SUCCEEDED(hr))
  305.                 {
  306.                         hr = pAudioMTA->SetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, (UINT32)48000);//设置样本采样率48000
  307.                 }
  308.                 if (SUCCEEDED(hr))
  309.                 {
  310.                         pSReader->info.AudioSamplePerSec = 48000;
  311.                 }
  312.                 if (SUCCEEDED(hr))
  313.                 {
  314.                         hr = pSReader->pIMFSourceReader->SetCurrentMediaType(MF_SOURCE_READER_FIRST_AUDIO_STREAM, NULL, pAudioMTA);//设置音频输出媒体类型(此时未提供媒体类型全部信息)
  315.                 }
  316.                 SafeRelease(&pAudioMTA);
  317.                 IMFMediaType* pAudioMT = NULL;
  318.                 if (SUCCEEDED(hr))
  319.                 {
  320.                         hr = pSReader->pIMFSourceReader->GetCurrentMediaType(MF_SOURCE_READER_FIRST_AUDIO_STREAM, &pAudioMT);//获取当前音频输出媒体类型(获取的媒体类型将包含全部信息)
  321.                 }
  322.                 UINT32 SamplePerSec;
  323.                 if (SUCCEEDED(hr))
  324.                 {
  325.                         hr = pAudioMT->GetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, &SamplePerSec);//获取采样率
  326.                 }
  327.                 SafeRelease(&pAudioMT);
  328.                 if (SUCCEEDED(hr))
  329.                 {
  330.                         pSReader->info.AudioSamplePerSec = SamplePerSec;
  331.                 }
  332.                 pSReader->info.StreamCount = 0;
  333.                 if (SUCCEEDED(hr))
  334.                 {
  335.                         ResetEvent(pSReader->hExit);//设置“退出”无信号
  336.                         pSReader->info.StreamCount++;//流数量
  337.                         hAthread = CreateThread(NULL, 0, AudioThread, pSReader, 0, NULL);//创建音频线程
  338.                 }
  339.                 IMFMediaType* pVideoMTV = NULL;
  340.                 if (SUCCEEDED(hr))
  341.                 {
  342.                         hr = MFCreateMediaType(&pVideoMTV);//创建空的媒体类型
  343.                 }
  344.                 if (SUCCEEDED(hr))
  345.                 {
  346.                         hr = pVideoMTV->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);//设置主要类型为视频
  347.                 }
  348.                 if (SUCCEEDED(hr))
  349.                 {
  350.                         hr = pVideoMTV->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32);//设置子类型RGB32
  351.                 }
  352.                 if (SUCCEEDED(hr))
  353.                 {
  354.                         hr = pSReader->pIMFSourceReader->SetCurrentMediaType(MF_SOURCE_READER_FIRST_VIDEO_STREAM, NULL, pVideoMTV);//设置视频输出媒体类型
  355.                 }
  356.                 SafeRelease(&pVideoMTV);
  357.                 if (SUCCEEDED(hr))
  358.                 {
  359.                         IMFMediaType* pVideoMT = NULL;
  360.                         if (SUCCEEDED(hr))
  361.                         {
  362.                                 hr = pSReader->pIMFSourceReader->GetCurrentMediaType(MF_SOURCE_READER_FIRST_VIDEO_STREAM, &pVideoMT);//获取当前视频媒体类型(此时的媒体类型将包含全部信息)
  363.                         }
  364.                         if (SUCCEEDED(hr))
  365.                         {
  366.                                 hr = MFGetAttributeSize(pVideoMT, MF_MT_FRAME_SIZE, &pSReader->Width, &pSReader->Height);//获取视频图像宽高
  367.                         }
  368.                         SafeRelease(&pVideoMT);
  369.                         if (SUCCEEDED(hr))
  370.                         {
  371.                                 pSReader->info.VideoWidth = pSReader->Width; pSReader->info.VideoHeight = pSReader->Height; pSReader->info.StreamCount++;
  372.                         }
  373.                         hVthread = CreateThread(NULL, 0, VideoThread, pSReader, 0, NULL);//创建视频线程
  374.                 }
  375.                 Sleep(1000);//等待线程初始化完成
  376.                 return pSReader->info;
  377.         }
  378.         __declspec(dllexport) int __cdecl Run(MYPROC_SendVideo SendVideo, MYPROC_SendAudio SendAudio, MYPROC_SendPos SendPos)//运行
  379.         {
  380.                 if (pSReader)
  381.                 {
  382.                         pSReader->SendVideo = SendVideo; pSReader->SendAudio = SendAudio; pSReader->SendPos = SendPos;
  383.                         pSReader->STAR = timeGetTime();//记录运行开始时间
  384.                         pSReader->VFirst = TRUE; pSReader->AFirst = TRUE;
  385.                         SetEvent(pSReader->hRun);//设置“运行”有信号
  386.                         pSReader->mState = 1;//状态标记置1
  387.                         return 0;
  388.                 }
  389.                 return 1;
  390.         }
  391.         __declspec(dllexport) int __cdecl Pause(void)//暂停
  392.         {
  393.                 if (pSReader)
  394.                 {
  395.                         ResetEvent(pSReader->hRun);//设置“运行”无信号
  396.                         pSReader->mState = 2;//状态标记置2
  397.                         return 0;
  398.                 }
  399.                 return 1;
  400.         }
  401.         __declspec(dllexport) int __cdecl Stop(void)//停止
  402.         {
  403.                 if (pSReader)
  404.                 {
  405.                         ResetEvent(pSReader->hRun);//设置“运行”无信号
  406.                         HRESULT hr = pSReader->pIMFSourceReader->Flush(MF_SOURCE_READER_ALL_STREAMS);//丢弃所有排队的样本并取消所有挂起的样本请求
  407.                         Sleep(200);
  408.                         pSReader->SeekPos = 0;
  409.                         PROPVARIANT pv;
  410.                         PropVariantInit(&pv);
  411.                         pv.vt = 20;
  412.                         pv.hVal.QuadPart = 0;
  413.                         hr = pSReader->pIMFSourceReader->SetCurrentPosition(GUID_NULL, pv);//设置源读取器位置0
  414.                         PropVariantClear(&pv);
  415.                         pSReader->mState = 0;//状态标记置0
  416.                         return 0;
  417.                 }
  418.                 return 1;
  419.         }
  420.         __declspec(dllexport) int __cdecl Seek(LONGLONG SeekPos)//定位
  421.         {
  422.                 if (pSReader)
  423.                 {
  424.                         pSReader->SeekPos = SeekPos;//赋值定位位置
  425.                         SetEvent(pSReader->hSeek);//设置“定位”有信号
  426.                         return 0;
  427.                 }
  428.                 return 1;
  429.         }
  430.         __declspec(dllexport) int __cdecl GetState()//获取状态
  431.         {
  432.                 if (pSReader)
  433.                 {
  434.                         return pSReader->mState;
  435.                 }
  436.                 return -1;
  437.         }
  438.         __declspec(dllexport) int __cdecl Exit(void)//退出
  439.         {
  440.                 if (pSReader)
  441.                 {
  442.                         ResetEvent(pSReader->hRun);//设置“运行”无信号
  443.                         SetEvent(pSReader->hExit);//设置“退出”有信号
  444.                         WaitForSingleObject(hVthread, INFINITE);//等待视频线程已退出
  445.                         WaitForSingleObject(hAthread, INFINITE);//等待音频线程已退出
  446.                         delete pSReader; pSReader = NULL;//删除SReader对象
  447.                         return 0;
  448.                 }
  449.                 return 1;
  450.         }
  451. #ifdef __cplusplus
  452. }
  453. #endif
复制代码
下载本插件

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

尚未崩坏

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表