最近写了一个屏幕录屏软件,主要是调用ffmpeg来实现录屏,因为是用的VS2015,遇到了不少字符转码的问题,特此记录一下。
①CStdioFile读取txt文本时中文乱码,需要一个CharToUTF8(str)函数
void CharToUTF8(CString &str)
{
char *szBuf = new char[str.GetLength() + 1];//注意“+1”,char字符要求结束符,而CString没有
memset(szBuf, '\0', str.GetLength());
int i;
for (i = 0; i < str.GetLength(); i++)
{
szBuf[i] = (char)str.GetAt(i);
}
szBuf[i] = '\0';//结束符。否则会在末尾产生乱码。
int nLen;
WCHAR *ptch;
CString strOut;
if (szBuf == NULL)
{
return;
}
nLen = MultiByteToWideChar(CP_UTF8, 0, szBuf, -1, NULL, 0);//获得需要的宽字符字节数
ptch = new WCHAR[nLen];
memset(ptch, '\0', nLen);
MultiByteToWideChar(CP_UTF8, 0, szBuf, -1, ptch, nLen);
//str.Format(_T("%s"), ptch);
str = ptch;
if (NULL != ptch)
delete[] ptch;
ptch = NULL;
if (NULL != szBuf)
delete[]szBuf;
szBuf = NULL;
return;
}
②读取完txt后,通过字符串截取获取录音设备名
bool getdevinfo()
{
CString strFile = L"devinfo.txt";
CStdioFile infile;
infile.Open(strFile, CFile::modeRead);
CString str;
while (infile.ReadString(str))
{
CharToUTF8(str);
if (!(str.Find(L"dshow") == -1))
{
if (!(str.Find(L"麦克风") == -1))
{
int pos = str.Find(L"\"");
str=str.Right(str.GetLength()-pos-1);
pos = str.ReverseFind('\"');
str = str.Left(pos);
p_audioname = str;
}
}
}
infile.Close();
return false;
}
③录音设备名此时需要动态给到ffmpeg的avformat_open_input函数,可以这样做
static char *dup_wchar_to_utf8(wchar_t *w)
{
char *s = NULL;
int l = WideCharToMultiByte(CP_UTF8, 0, w, -1, 0, 0, 0, 0);
s = (char *)av_malloc(l);
if (s)
WideCharToMultiByte(CP_UTF8, 0, w, -1, s, l, 0, 0);
return s;
}
//查找输入方式
CString p_audioname;//通过读取txt动态给到p_audioname
AVInputFormat *pAudioInputFmt = av_find_input_format("dshow");
//以Direct Show的方式打开设备,并将 输入方式 关联到格式上下文
wchar_t w[200]=L"";
wsprintf(w, L"audio=%s",p_audioname.GetBuffer());
char * psDevName=dup_wchar_to_utf8(w);
if (avformat_open_input(&pFormatCtx_Audio, psDevName, pAudioInputFmt, NULL) < 0)
{
AfxMessageBox(L"Couldn't open input stream.(无法打开音频输入流)");
return -1;
}
④mfc的控件“按钮”点击开始录制的话,需要新建一个线程,不然会一直锁在录像的死循环中
UINT startrec(LPVOID lParam)
{
getdevinfo();
av_register_all();
avdevice_register_all();
//下面就是常规的录视频和录音频
//此处省略
}
void CLLScreenRecDlg::OnBnClickedButton1()
{
isclickstop = false;
AfxBeginThread(startrec, (LPVOID)this);
GetDlgItem(IDC_BUTTON1)->EnableWindow(false);
GetDlgItem(IDC_BUTTON2)->EnableWindow(true);
GetDlgItem(IDC_STATIC)->SetWindowTextW(L"正在录制中......");
}
可能还有更简单的方法,先记录一下,最起码亲测成功了。。。
讲道理win32宽字符挺恶心人的,各种编码转来转去。。。