下载“Windows应用-音视频捕获”项目
本应用可以同时捕获4个视频源和4个音频源,可以监视视频源图像,监听音频源;可以将视频源图像写入MP4文件,将音频源写入MP3或WAV文件;还可以录制系统播放的声音。本应用使用MFC对话框程序创建。下面是应用的界面图像。
使用方法
启动应用就可以获取捕获设备,也可以按“重新捕获”按钮,再次捕获。上图是,电脑外接1个摄像头和1个话筒获得的界面图像。红色区域中,左侧是视频捕获设备名称,其右是监视按钮,点击可以显示该捕获设备当前视频图像,“SelAu”按钮点击后,会弹出菜单,菜单项是音频捕获设备名称和系统声音,选择菜单项就可以为视频录制指定声音源。点击“录制”按钮,会将该捕获设备的图像和选择的声音,写入MP4文件。
蓝色区域中,左侧是音频捕获设备名称,其右是监听按钮,点击后,电脑可以播放该捕获设备的声音;监听按钮右边的按钮可以选择录制产生的文件的格式(wav或mp3)。点击“录制”按钮,会将该声音源写入音频文件。
应用开发信息
应用使用了4个插件,捕获.dll,写MP4.dll,写wav.dll,写mp3.dll。有关这4个插件的信息可以看前面的文章。捕获.dll使用媒体基础的方法获取捕获设备。虽然DirectShow也可以实现音视频捕获,但由于媒体基础对象可以在win32和MFC程序中创建并使用,所以使用起来更加灵活。
加载捕获DLL,获取两个导出函数的地址。
typedef int(__cdecl *MYPROC_CAP_Init)(CAP_INIT init, CAP_VIDEO_INFO*& VideoInfo, CAP_AUDIO_INFO*& AudioInfo);
typedef int(__cdecl *MYPROC_VOID)();
HMODULE hCap = NULL;//捕获dll模块句柄
MYPROC_CAP_Init CAP_Init = NULL;
MYPROC_VOID CAP_ReleaseDevice = NULL;
hCap = LoadLibrary(L"捕获.dll");//加载捕获模块
if (hCap)
{
CAP_Init=(MYPROC_CAP_Init)GetProcAddress(hCap, "Init");//获取捕获模块“初始化”函数地址
CAP_ReleaseDevice=(MYPROC_VOID)GetProcAddress(hCap, "ReleaseDevice");//获取捕获模块“释放所有捕获设备”函数地址
}
定义捕获初始化结构和视频样本,音频样本输出函数。
typedef int(__cdecl *MYPROC_CAP_Sample)(LONGLONG star, LONGLONG end, BYTE* pB, LONG len);
int VideoSample0(LONGLONG star, LONGLONG end, BYTE* pB, LONG len)//视频流0样本输出函数
{
return 1;
}
....
struct CAP_INIT
{
MYPROC_CAP_Sample VideoSample0 = NULL;//视频样本输出函数
MYPROC_CAP_Sample VideoSample1 = NULL;
MYPROC_CAP_Sample VideoSample2 = NULL;
MYPROC_CAP_Sample VideoSample3 = NULL;
MYPROC_CAP_Sample AudioSample0 = NULL;//音频样本输出函数
MYPROC_CAP_Sample AudioSample1 = NULL;
MYPROC_CAP_Sample AudioSample2 = NULL;
MYPROC_CAP_Sample AudioSample3 = NULL;
};
调用捕获初始化函数,此时将获取捕获设备,创建视频流和音频流。即,视频音频样本输出函数被反复调用,函数的参数提供时间戳,样本缓冲区指针和样本大小。
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;
struct CAP_VIDEO_INFO
{
UINT32 Width = 0;//视频宽,单位像素
UINT32 Height = 0;//视频高,单位像素
double nFrames = 0;//帧率
WCHAR *Name = NULL;//视频捕获设备名称
};
struct CAP_AUDIO_INFO
{
UINT32 nCh;//声道数
WCHAR *Name = NULL;//视频捕获设备名称
};
CAP_VIDEO_INFO* pVInfo = NULL;//结构数组用于存储视频流,音频流信息
CAP_AUDIO_INFO* pAInfo = NULL;
pVInfo = new CAP_VIDEO_INFO[4]; pAInfo = new CAP_AUDIO_INFO[4];//结构数组用于存储视频流,音频流信息
WORD w = CAP_Init(CapInit, pVInfo, pAInfo);//获取捕获设备,创建视频流,音频流
ACount = LOBYTE(w); VCount = HIBYTE(w);//获取音频流,视频流数量
在程序退出时,释放所有捕获设备。
CAP_ReleaseDevice();//释放捕获设备
加载写MP4 DLL,获取所有导出函数地址。
typedef int(__cdecl *MYPROC_MP4_Init)(int index, MW_INIT init);
typedef int(__cdecl *MYPROC_Sample)(BYTE* pB, LONG len);
typedef int(__cdecl *MYPROC_ISample)(int index, BYTE* pB, LONG len);
typedef int(__cdecl *MYPROC_IVSample)(int index, LONGLONG star, LONGLONG end, BYTE* pB, LONG len);
typedef int(__cdecl *MYPROC_IVOID)(int index);
typedef int(__cdecl *H264Set)(int index, VARIANT var);
typedef int(__cdecl *H264Get)(int index, VARIANT& var);
HMODULE hMp4 = NULL;
MYPROC_VOID MP4_Create = NULL;
MYPROC_MP4_Init MP4_Init = NULL;
MYPROC_IVSample MP4_VSample = NULL;
MYPROC_ISample MP4_ASample = NULL;
MYPROC_IVOID MP4_Exit = NULL;
MYPROC_IVOID MP4_GetState = NULL;
MYPROC_IVOID MP4_Stop = NULL;
MYPROC_IVOID MP4_Run = NULL;
MYPROC_VOID MP4_DestroyAll = NULL;
H264Set H264_SetAdaptiveMode = NULL;//自适应地更改帧速率设置函数
H264Set H264_SetRateMode = NULL;//速率控制模式设置函数
H264Set H264_SetQuality = NULL;//质量级别设置函数
H264Set H264_SetQualityVsSpeed = NULL;//质量/速度权衡设置函数
H264Set H264_SetMeanBitRate = NULL;//平均比特率设置函数
H264Get H264_GetMeanBitRate = NULL;
hMp4 = LoadLibrary(L"写MP4.dll");//加载写MP4模块
if (hMp4)
{
MP4_Create = (MYPROC_VOID)GetProcAddress(hMp4, "Create");//创建
MP4_Init=(MYPROC_MP4_Init)GetProcAddress(hMp4, "Init");//初始化
MP4_VSample=(MYPROC_IVSample)GetProcAddress(hMp4, "WriteVideoSample");//写视频样本
MP4_ASample = (MYPROC_ISample)GetProcAddress(hMp4, "WriteAudioSample");//写音频样本
MP4_GetState = (MYPROC_IVOID)GetProcAddress(hMp4, "GetState");//获取状态
MP4_Run=(MYPROC_IVOID)GetProcAddress(hMp4, "Run");//运行
MP4_Stop=(MYPROC_IVOID)GetProcAddress(hMp4, "Stop");//停止
MP4_Exit=(MYPROC_IVOID)GetProcAddress(hMp4, "Exit");//退出
MP4_DestroyAll = (MYPROC_VOID)GetProcAddress(hMp4, "DestroyAll");
H264_SetAdaptiveMode = (H264Set)GetProcAddress(hMp4, "H264_SetAdaptiveMode");//自适应地更改帧速率
H264_SetRateMode = (H264Set)GetProcAddress(hMp4, "H264_SetRateControlMode");//速率控制模式
H264_SetQuality = (H264Set)GetProcAddress(hMp4, "H264_SetQuality");//质量级别
H264_SetQualityVsSpeed = (H264Set)GetProcAddress(hMp4, "H264_SetQualityVsSpeed");//质量/速度权衡
H264_SetMeanBitRate = (H264Set)GetProcAddress(hMp4, "H264_SetMeanBitRate");//平均比特率
H264_GetMeanBitRate = (H264Get)GetProcAddress(hMp4, "H264_GetMeanBitRate");
MP4_Create(); MP4_Create(); MP4_Create(); MP4_Create();//创建4个写MP4对象
}
下面以录制1个视频源举例。
开始录制视频源0:
struct MW_INIT
{
WCHAR* Path;//输出文件路径
UINT VideoWidth;//视频图像宽度,单位像素
UINT VideoHeight;//视频图像高度,单位像素
double nFramePerSec;//视频每秒帧数
BOOL Fixed;//TRUE,样本持续时间是固定值;FALSE,非固定值
UINT BIT_RATE;//视频传输率。为0使用默认传输率
UINT AudioSamplesPerSec;//音频采样率
};
int mvState0=0;//录制状态。在“C音视频捕获Dlg”类中定义
MW_INIT MwInit;
MwInit.Path = L"D:\\1.mp4";
MwInit.VideoWidth = 1280;
MwInit.VideoHeight = 720;
MwInit.nFramePerSec = 30;
MwInit.BIT_RATE = 0;
MwInit.Fixed = FALSE;
MwInit.AudioSamplesPerSec = 48000;
MP4_Init(0, MwInit);
MP4_Run(0);
mvState0 = 1;//录制状态
暂停录制视频源0:
if (mvState0 == 1)
{
mvState0 = 2;
MP4_Stop(0);
}
停止录制视频源0:
mvState0 = 0;
MP4_Stop(0);
MP4_Exit(0);
在视频流0样本输出函数中,写视频样本:
//以下变量在“C音视频捕获Dlg”类中定义
int mvState0, mvState1, mvState2, mvState3;//视频录制状态。0停止,1运行,2暂停
LONGLONG mTime0, mTime1, mTime2, mTime3;
BOOL First0, First1, First2, First3;
LONGLONG mStar0, mStar1, mStar2, mStar3;
LONGLONG mPause0, mPause1, mPause2, mPause3;
int VideoSample0(LONGLONG star, LONGLONG end, BYTE* pB, LONG len)//视频流0样本输出函数
{
C音视频捕获Dlg* pDlg = (C音视频捕获Dlg*)theApp.m_pMainWnd;
if (pDlg->mvState0 == 0)//如果停止
{
pDlg->First0 = TRUE;
pDlg->mTime0 = 0; pDlg->mPause0 = 0;
}
if (pDlg->mvState0 == 1)//如果运行
{
if (pDlg->First0)
{
pDlg->First0 = FALSE;
pDlg->mStar0 = star;
}
pDlg->MP4_VSample(0, pDlg->mPause0 + star - pDlg->mStar0, pDlg->mPause0 + end - pDlg->mStar0, pB, len);
pDlg->mTime0 = pDlg->mPause0 + end - pDlg->mStar0;
}
if (pDlg->mvState0 == 2)//如果暂停
{
pDlg->First0 = TRUE;
pDlg->mPause0 = pDlg->mTime0;
}
return 1;
}
在音频流0样本输出函数中,写音频样本:
int AudioSample0(LONGLONG star, LONGLONG end, BYTE* pB, LONG len)//音频流0样本输出函数
{
C音视频捕获Dlg* pDlg = (C音视频捕获Dlg*)theApp.m_pMainWnd;
if (pDlg->mvState0 == 1 &&pDlg->mAudioSel0 == 0)//如果图像0需要获取此音频
{
if (pDlg->MP4_GetState(0))//如果写MP4已运行
{
pDlg->MP4_ASample(0, pB, len);
}
}
return 1;
}
如果需要全部代码,可以下载“Windows应用-音视频捕获”项目。