在近期发布的SkeyeLive多窗口版本中,由于界面的局限性,选择性的将本地采集的音视频参数设置在界面上剔除掉了(暂时还没想好放在哪里,后续版本会在界面调整后添加),大家可以查看SkeyeLive源码中的StartDSCapture函数的参数设置代码进行相应设置;也应近期SkeyeSMS流媒体服务器群(QQ群:102644504,欢迎大家进群交流,任何技术问题,在所知的范围内都能给予解答)中大家提到的参数设置的错误提示以及参数该如何设置的问题,下面我将就参数设置的具体细节和代码关联做详细介绍。
一、查看设备属性
在Windows系统中大多数音视频采集设备都能支持通过DirecShow进行捕获,在捕获之前,我们首先应该了解设备的性能参数,如:视频采集设备的长,宽,色彩格式,图像格式等,以及音频设备的采样率,采样位宽,声道数等;要了解这些,我们可以简单的通过一款微软提供的DShow设备采集小工具“amcap.exe”查看,如下图所示:
在“设备”菜单栏中可以查看到枚举的当前系统中所有的音视频采集设备(包括虚拟设备),选择一个设备即可进行捕获,然后在“选项”一栏中可以进行“预览”或者相应的参数设置,如下图所示:
其中,“视频捕获接口”项是我们经常用到的查看视频的长,宽,色彩格式,图像格式等参数的设备信息,如下图所示:
此外,还有其他一些图像参数的设置,有兴趣的也可以了解下;当然,我们完全可以通过代码来实现这个小工具的功能,在我的另一片文章“SkeyLive中DirectShow采集音视频流程及几种采集方式介绍”中有详细的说明,这里就不做过多赘述。
二、DShow采集参数设置
参数设置我们定义了一个结构,其原型如下:
// 设备捕获参数信息
typedef struct tagDEVICE_CONFIG_INFO
{
int nVideoId;//视频 ID -1==不用,0-n == id
int nAudioId;//音频id -1==不用,0-n == id
int nDeviceId;//设备序号 1,2,3,4,5....
struct tagVideoInfo
{
int nWidth;//视频高度
int nHeight;//视频宽度
int nVideoWndId;//视频关联窗口ID
int nFrameRate;//视频帧率
char strDataType[64];//标识 色彩格式 数据类型,如"YUY2" "YUYV" "UYVY等"
int nRenderType;//呈现方式
int nPinType;//捕获口
}VideoInfo;
struct tagAudioInfo
{
int nChannaels;//通道数
int nBytesPerSample;//采样位数
int nSampleRate;//采样率
DWORD nAudioBufferType;//音频缓存区的大小
int nPinType;//捕获口
}AudioInfo;
}DEVICE_CONFIG_INFO;
结构中参数均有详细说明,这里就比较重要的色彩格式进行举例说明:
-> 色彩格式(strDataType)
色彩格式是指DShow捕获输出的图像数据的色彩格式,主要是RGB和YUV两种,这个参数很重要,在显示和编码时我们都会用到,设置不当可能导致色彩显示不对甚至未知的程序崩溃(一般是指针越界),在SkeyeStreamPusher中支持两种常用的格式YUY2和RGB24,主要是编码时需要进行格式转换或者分支处理。
我们在程序中中进行了简单的设备配置:
//1. 我们来简单配置一个设备信息
m_sDevConfigInfo.nDeviceId = 1;
m_sDevConfigInfo.nVideoId = nCamId;//摄像机视频捕获ID
m_sDevConfigInfo.nAudioId = nAudioId;//音频捕获ID
m_sDevConfigInfo.VideoInfo.nFrameRate = nFps;
m_sDevConfigInfo.VideoInfo.nWidth = nVideoWidth;
m_sDevConfigInfo.VideoInfo.nHeight = nVideoHeight;
strcpy_s(m_sDevConfigInfo.VideoInfo.strDataType, 64, "YUY2");
m_sDevConfigInfo.VideoInfo.nRenderType = 1;
m_sDevConfigInfo.VideoInfo.nPinType = 1;
m_sDevConfigInfo.VideoInfo.nVideoWndId = 0;
m_sDevConfigInfo.AudioInfo.nAudioBufferType = 4096;
m_sDevConfigInfo.AudioInfo.nBytesPerSample = 16;
m_sDevConfigInfo.AudioInfo.nSampleRate = 16000;//44100;
m_sDevConfigInfo.AudioInfo.nChannaels = 2;
m_sDevConfigInfo.AudioInfo.nPinType = 2;
//初始化Pusher结构信息
memset(&m_mediainfo, 0x00, sizeof(Skeye_MEDIA_INFO_T));
m_mediainfo.u32VideoCodec = Skeye_SDK_VIDEO_CODEC_H264;//0x1C;
m_mediainfo.u32VideoFps = nFps;
m_mediainfo.u32AudioCodec = Skeye_SDK_AUDIO_CODEC_AAC;
m_mediainfo.u32AudioChannel = 2;
m_mediainfo.u32AudioSamplerate = 16000;//44100;
如果参数设置不成功,将会出现错误(或者警告)提示,有一种提示是设备不支持内部显示(经测试某些虚拟设备可能出现),这在DShow采集库底层代码中已经做过处理,进行外部打开窗口显示,不影响采集;另有一种提示为“使用默认参数”,这种提示就表明我们设置的参数失败了,可能是设备不支持这种色彩格式或者分辨率;当然,捕获设备通常是成功的,但是,要注意默认的色彩格式和分辨率将有可能和我们的设置参数不一致,这时候就要了解设备的具体参数,然后在编码时进行相应处理,否则可能导致编码失败,或者编码后推送出来的视频色彩不对。
参数设置代码如下:
//得到视频格式大小
AM_MEDIA_TYPE *pmt;
pAMStreamConfig->GetFormat(&pmt);
//设置视频格式
pmt->majortype = MEDIATYPE_Video;
GUID defaultSubType = pmt->subtype;
pmt->subtype = GetMediaTypeGuid(strRGBBytes);
VIDEOINFOHEADER *pvih = reinterpret_cast<VIDEOINFOHEADER *>(pmt->pbFormat);
//设置回去
int nDefualWidth = pvih->bmiHeader.biWidth;
int nDefualHeight = pvih->bmiHeader.biHeight;
pvih->bmiHeader.biWidth = iWidth;
pvih->bmiHeader.biHeight = iHeight;
pvih->bmiHeader.biSizeImage = pmt->lSampleSize = iWidth*iHeight*pvih->bmiHeader.biPlanes*pvih->bmiHeader.biBitCount/8;
pvih->AvgTimePerFrame = (LONGLONG)(10000000/nFrameRate);
hr = pAMStreamConfig->SetFormat(pmt);
if(FAILED(hr))
{
//如果设置失败可以选用默认的,但运用之后,小屏幕初始化时会出现闪动的情况
// pvih->bmiHeader.biWidth = nDefualWidth;
// pvih->bmiHeader.biHeight = nDefualHeight;
// pvih->bmiHeader.biSizeImage = pmt->lSampleSize = nDefualWidth*nDefualHeight*pvih->bmiHeader.biPlanes*pvih->bmiHeader.biBitCount/8;
pmt->subtype = defaultSubType;
hr = pAMStreamConfig->SetFormat(pmt);
CSourceManager* pManager = CSourceManager::Instance();
if (pManager)
{
pManager->LogErr(_T("使用默认参数。"));
}
//AfxMessageBox(_T("使用默认参数。"));
if(FAILED(hr))
{
SAFE_RELEASE(pAMStreamConfig);
FreeMediaType(*pmt);
//ERR_DEBUG("初始化设置视频格式失败");
return hr;
}
一开始,我们就得到了设备的参数,如果参数设置失败后,将色彩格式设置回去,然后提示“使用默认参数。”;理论上来说,我们应该将这个设备的参数保存下来,在设置失败时原封不动的设置回去,然后在外层函数中对其进行容错处理,但是,我们不可能处理所有可能出现的未知的色彩格式或者其他的未知参数类型,为了程序的稳定性,我们通常只处理常用的可控制的参数类型,如果有其他色彩格式的需要,大家应该自己在设置好后,在编码前做相应的色彩格式转换处理,或者把这种格式告诉我,我将会将其添加进SkeyeLive进行兼容。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。